Have you ever wanted to connect a simple button or sensor to Home Assistant using Circuit Python? This script demonstrates registering a device with Home Assistant so that it can be automatically connected to an Automation. The script triggers its event on power-on. The example uses the "trigger" type, which is better than "button" for a simple remote control. Other MQTT integrations could put a sensor reading on the dashboard, or turn your CircuitPython board into a WiFi light or fan.
Ingredients
- ESP32-C3 board running CircuitPython 9.1.4
- Home Assistant with the MQTT integration and broker, accessible to the local network
This script also demonstrates setting a BSSID, a 12-digit hexadecimal string, to connect to a specific access point.
I was not able to connect to my local mosquitto MQTT broker over ssl; something about how the the MQTT client and broker interact prevents CircuitPython from validating the certificate. The comments include an example of loading a custom root certificate for the connection.
How It Works
Home Assistant's MQTT integration listens on the homeassistant/device_automation/# topic for discovery messages. When it sees a properly formatted message, it adds or updates that device under Settings > Devices and Services > MQTT > devices. It also listens on topic, here circuitpy/{unique_id}/action, for commands from the device. For a two-way device, you can also set a topic for Home Assistant to send commands back to CircuitPython.
Now, we can add our device to an automation in Home Assistant without any additional configuration.
Going Further
Can we send our configuration messages with mqtt_client.publish(topic, msg, retain=True) so Home Assistant will remember us, even if it restarts before we do?
Can we configure our CircuitPython board as a Home Assistant temperature sensor?
Can we put the device in low power mode, wake on a pin change, and make a real battery-operated remote control?
Use nginx to proxy SSL instead of mosqitto's idiosyncratic support.
# code.py
"""
CircuitPython + Home Assistant
This program demonstrates a MQTT device that automatically shows up in Home
Assistant. On power up, it will connect to wifi, register a device, and trigger
its action. Device registrations can be made persistent in MQTT; also,
automations connected to a device may continue to work even when the MQTT
integration has been restarted.
"""
import os
import wifi
import socketpool
import json
import adafruit_minimqtt.adafruit_minimqtt as MQTT
print()
print("Connecting to WiFi")
# Connect to your SSID
# bssid= provides a speedup, wifi.radio.ap_inf.bssid.hex();
# Lets us choose our preferred AP when we have more than one
bssid = os.getenv("WIFI_BSSID")
if bssid:
bssid = bytes.fromhex(bssid)
wifi.radio.connect(
os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"), bssid=bssid
)
print("Connected to WiFi")
## Home Assistant discovery message(s)
# See https://www.home-assistant.io/integrations/mqtt/#mqtt-discovery,
# https://www.home-assistant.io/integrations/device_trigger.mqtt/#left-arrow-click-configuration
unique_id = wifi.radio.mac_address.hex()
topic = f"homeassistant/device_automation/{unique_id}/%s/config"
# Home Assistant will listen on "topic" for "payload"
trigger = {
"automation_type": "trigger",
"type": "button_short_press",
"subtype": "button_1",
"payload": "1",
"topic": f"circuitpy/{unique_id}/action",
"device": {
"identifiers": [f"circuitpy_{unique_id}"],
"name": unique_id,
"sw_version": "CircuitPython",
"model": "ESP32-C3",
},
}
# Add another button to the same device
trigger_2 = {
"automation_type": "trigger",
"type": "button_short_press",
"subtype": "button_2",
"payload": "2",
"topic": trigger["topic"],
"device": {"identifiers": [trigger["device"]["identifiers"][0]]},
}
default_topic = trigger["topic"]
## MQTT callbacks
def connected(client, userdata, flags, rc):
# advertise our device to home assistant
for button in trigger, trigger_2:
# registration topic must be unique per sensor or button on our device
client.publish(topic % button["subtype"], json.dumps(button))
# tell home assistant that our "button" has been pressed
client.publish(trigger["topic"], trigger["payload"])
def disconnected(client, userdata, rc):
print("Disconnected from MQTT Broker!")
def message(client, topic, message):
print(f"New message on topic {topic}: {message}")
## Connect
pool = socketpool.SocketPool(wifi.radio)
# Despair awaits with mosquitto + letsencrypt default RSA configuration, even though we can adafruit_requests.get("https://same-server").
# May be a mosquitto limitation.
# ssl_context = ssl.create_default_context()
# ssl_context.load_verify_locations(cadata=open("isrg-root-x1-cross-signed.pem").read())
# ssl_context.load_verify_locations(cadata=open("isrg-root-x2-cross-signed.pem").read())
# ssl_context.check_hostname=False
# Set up a MiniMQTT Client
mqtt_client = MQTT.MQTT(
broker=os.getenv("MQTT_BROKER"),
is_ssl=False, # or connection errors will occur when port=8883
port=1883,
socket_pool=pool,
# ssl_context=ssl_context,
username=os.getenv("MQTT_USER"),
password=os.getenv("MQTT_PASS"),
)
# Setup the callback methods above
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = message
# Connect the client to the MQTT broker.
mqtt_client.connect()
for i in range(3):
# Poll the message queue
mqtt_client.loop(1)
print("Loop")
# settings.toml CIRCUITPY_WEB_API_PORT = 8080 CIRCUITPY_WEB_API_PASSWORD = "webpassword" CIRCUITPY_WIFI_SSID = "ssid" CIRCUITPY_WIFI_PASSWORD = "password" WIFI_BSSID = "00112233445566" MQTT_BROKER = "192.168.50.2" MQTT_USER = "circuit" MQTT_PASS = "circuit"
This page (Home Assistant WiFi Button with CircuitPython) was last updated on October 12, 2024.