Using Raspberry Pi Pico W with Home Assistant
We started our journey with the Raspberry Pi Pico W as a web server to start getting more familiar with how to use it as a IOT device. If you have not read that yet, I would suggest popping over to that post to get you started and a little more familiar with all the concept that are used. Or if you think you are already up to date then you can simply follow along here. However I will not be covering any of the setup or hardware connections in this post again.
If you have not yet grabbed yours, go checkout the kits that we designed specially for this project. It has everything you need to get you started.
Initially we had assumed that all the big companies would release samples of this within the first few weeks after the launch. But we could not find any really good documentation. So we started working on this on our own. And we are very happy to share how we did it with you.
From here I will be assuming that you already have Home Assistant up and running, and have already started familiarizing yourself with the architecture and adding some devices. If you have not yet, you can head over to our blog post on getting you started first.
The Code
Jumping straight in, let’s look at the micropython code on the Raspberry Pi Pico W.
# Import required libraries
import network
import socket
from time import sleep
import dht
from machine import Pin
import json
# Pin setup
intled = machine.Pin("LED", machine.Pin.OUT)
sensor = dht.DHT22(Pin(2))
# Indicate that the app started
intled.value(1)
sleep(3)
intled.value(0)
Similar to displaying a web page we start with importing the libraries we will use. Setting up our GPIO pins. And showing some sign of life on startup.
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# prevent the wireless chip from activating power-saving mode when it is idle
wlan.config(pm = 0xa11140)
# sets a static ip for this Pico
wlan.ifconfig(('10.0.0.94', '255.255.255.0', '10.0.0.2', '8.8.8.8'))
# Connect to your AP using your login details
wlan.connect("mySSID", "myPASSWORD")
# Search for up to 10 seconds for network connection
max_wait = 10
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
intled.value(1)
print('waiting for connection...')
sleep(1)
# Raise an error if Pico is unable to connect
if wlan.status() != 3:
intled.value(0)
raise RuntimeError('network connection failed')
else:
print('connected')
status = wlan.ifconfig()
print( 'ip = ' + status[0] )
# Open a socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(1)
# Display your IP address
print('listening on', addr)
Then moving on to creating the network connection, assigning the static IP address and establishing a connection.
while True:
# If pico is connected to wifi put the onboard LED on else off
if wlan.status() == 3:
intled.value(1)
else:
intled.value(0)
try:
cl, addr = s.accept()
print('client connected from', addr)
request = cl.recv(1024)
request = str(request)
print(request)
# Get the data from the DHT22 sensor
sensor.measure()
temperature = sensor.temperature()
humidity = sensor.humidity()
print(f"Temperature: {temperature}°C Humidity: {humidity}% ")
Our main loop also starts very similar to the last project.
# prep the data to send to Home Assistant as type Json
data = { "hum": humidity, "temp": temperature }
JsonData = json.dumps(data)
# Send headers notifying the receiver that the data is of type Json for application consumption
cl.send('HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n')
# Send the Json data
cl.send(JsonData)
# Close the connection
cl.close()
This next part is where we start seeing something a little different. Now instead of creating an HTML string so that we can publish it to a web page. We are formatting the same data into a json structure so that we have something that Home Assistant can work with. Using headers to clarify to HA that this is the structure to expect.
Then we can send the data and close the connection again as a little bit of house keeping.
Home Assistant
The rest sensor platform is consuming a given endpoint which is exposed by a RESTful API of a device, an application, or a web service. The sensor has support for GET and POST requests.
Tip: If you want to create multiple sensors using the same endpoint, use the RESTful configuration instructions. To read more on how this works have a look at the the Rest sensor Docs. The configuration used in those examples show how to extract multiple values from a dictionary with json_attributes and template. This avoids flooding the REST service by only requesting the result once, then creating multiple attributes from that single result using templates. By default, the sensor state would be set to the full JSON — there, that would exceed the 255-character maximum allowed length for the state, so we override that default by using value_template to set a static value of OK.
Moving over to our HA dashboard. Go to Visual Studio Code from the left pane. Select the file called configuration.yaml. At the bottom of this file under sensor: add the following configuration:
sensor:
- platform: rest
name: "Test Temp Pico W"
scan_interval: 30
json_attributes:
- hum
resource: "http://10.0.0.94:80/"
unit_of_measurement: "°C"
value_template: "{{ value_json.temp }}"
- platform: template
sensors:
picohum:
friendly_name: "Test Humidity"
value_template: "{{ state_attr('sensor.test_temp_pico_w', 'hum')}}"
unit_of_measurement: "%"
device_class: humidity
Start by giving your sensor an identifiable name. I just used Test Temp Pico W, but you can change this to whatever will fit your project. Adding the static IP address that you gave your Raspberry Pi Pico W on port 80 as a resource. Then providing some information to HA with how to format the received information as the json structuring that we gave the Pico. On the Pico, we gave the json keys of “hum” and “temp”, which you can see is what we call from the HA config file in “{{ value_json.temp }}” and (‘sensor.test_temp_pico_w’, ‘hum’). These along with setting up the json_attributes are the sections that you would want to focus on when you start adding some more of your own sensors.
As a second platform, give the second sensor reading an identifiable name and do a similar setup for it. If any of the above does not make sense to you, looking at the json_attributes section of the above mentioned docs should provide some much needed clarification.
You can change how often you want home assistant to check the sensor readings. Seeing that temperature doesn’t change by the second, maybe we can update the readings every 5 minutes? For that to happen you can change the scan interval.
scan_interval: 3000
Where did we get the value of 3000? Easy, 5 minutes x 60 seconds = 3000