Now let's go over the code that runs on the sensor. The code checks the temperature and humidity, formats it, then publishes directly to the MQTT server.
MQTT Secrets Settings
Since the code publishes directly to the MQTT server, there are a few more secret settings that the code expects to find. If your MQTT server has no username and password, you can change the value to None
, however in general, the Home Assistant MQTT broker is setup to be password protected by default.
MQTT_BROKER = "192.168.1.1" MQTT_PORT = 1883 MQTT_USERNAME = "myusername" MQTT_PASSWORD = "mypassword"
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries # # SPDX-License-Identifier: MIT """ SHTC3 Temperature/Humidity Sensor Example for using CircuitPython with Home Assistant Author: Melissa LeBlanc-Williams for Adafruit Industries """ import os import time import ssl import json import alarm import board import socketpool import wifi import adafruit_minimqtt.adafruit_minimqtt as MQTT import adafruit_shtc3 PUBLISH_DELAY = 60 MQTT_TOPIC = "state/temp-sensor" USE_DEEP_SLEEP = True # Connect to the Sensor i2c = board.I2C() # uses board.SCL and board.SDA # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller sht = adafruit_shtc3.SHTC3(i2c) wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD")) print("Connected to %s!" % os.getenv("CIRCUITPY_WIFI_SSID")) # Create a socket pool pool = socketpool.SocketPool(wifi.radio) # Set up a MiniMQTT Client mqtt_client = MQTT.MQTT( broker=os.getenv("MQTT_BROKER"), port=os.getenv("MQTT_PORT"), username=os.getenv("MQTT_USERNAME"), password=os.getenv("MQTT_PASSWORD"), socket_pool=pool, ssl_context=ssl.create_default_context(), ) print("Attempting to connect to %s" % mqtt_client.broker) mqtt_client.connect() while True: temperature, relative_humidity = sht.measurements output = { "temperature": temperature, "humidity": relative_humidity, } print("Publishing to %s" % MQTT_TOPIC) mqtt_client.publish(MQTT_TOPIC, json.dumps(output)) if USE_DEEP_SLEEP: mqtt_client.disconnect() pause = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + PUBLISH_DELAY) alarm.exit_and_deep_sleep_until_alarms(pause) else: last_update = time.monotonic() while time.monotonic() < last_update + PUBLISH_DELAY: mqtt_client.loop()
How the Code Works
First we start with our imports. Many of the imports are ESP32-S2 specific because of the built Wi-Fi functionality, but this list also includes json
, adafruit_minimqtt
, and adafruit_shtc3
, which we'll go over later.
import os import time import ssl import json import alarm import board import socketpool import wifi import adafruit_minimqtt.adafruit_minimqtt as MQTT import adafruit_shtc3
In the next section, there are a few settings that you can adjust.
First, the PUBLISH_DELAY
setting is the amount of time in seconds to wait before updating the temperature and humidity.
The MQTT_TOPIC
is the topic that is published on the MQTT server. To read more about MQTT Topics, you can check out the MQTT Topics section of our All the Internet of Things Protocols guide.
The USE_DEEP_SLEEP
setting defines how we want to wait until we publish. If the setting is True
, it uses Deep Sleep to stop execution, put the board into a low power mode, and then restart the script after a certain amount of time, so it will need a little additional time to reconnect to WiFi. If the setting is False
, it will just wait the amount of time in PUBLISH_DELAY
and the publish again. You can read more about the Deep Sleep feature in our Deep Sleep with CircuitPython guide.
If you plan to modify the code to respond to MQTT requests, you will want to have USE_DEEP_SLEEP
set to false. However, setting up an MQTT subscription will not be covered in this guide because Home Assistant won't be polling for the Temperature/Humidity sensor.
PUBLISH_DELAY = 60 MQTT_TOPIC = "state/temp-sensor" USE_DEEP_SLEEP = True
The next line, we initialize to the sensor by passing in the I2C bus.
# Connect to the Sensor sht = adafruit_shtc3.SHTC3(board.I2C())
Now that the code has secrets, it uses that to connect to the WiFi access point and create a socket pool. Sockets are how CircuitPython establishes communication over the internet.
wifi.radio.connect(secrets["ssid"], secrets["password"]) print("Connected to %s!" % secrets["ssid"]) # Create a socket pool pool = socketpool.SocketPool(wifi.radio)
The MQTT library is initialized next using the settings in the secrets file and the socket pool. Once it is initialized, the code attempts to connect to the MQTT server.
# Set up a MiniMQTT Client mqtt_client = MQTT.MQTT( broker=os.getenv("MQTT_BROKER"), port=os.getenv("MQTT_PORT"), username=os.getenv("MQTT_USERNAME"), password=os.getenv("MQTT_PASSWORD"), socket_pool=pool, ssl_context=ssl.create_default_context(), ) print("Attempting to connect to %s" % mqtt_client.broker) mqtt_client.connect()
Now we get to the main loop. The loop will really only come into play if USE_DEEP_SLEEP
is False which we'll explain in the next section.
First we grab our temperature and humidity from the sensor. Then we create a dict that will hold the structure for our JSON output. We are adding a temperature and humidity settings to the dict. Finally we use the json.dumps()
function to convert the dict structure to a JSON string.
temperature, relative_humidity = sht.measurements output = { "temperature": temperature, "humidity": relative_humidity, } print("Publishing to %s" % MQTT_TOPIC) mqtt_client.publish(MQTT_TOPIC, json.dumps(output))
This last section is all about waiting until it is time to publish the temperature and humidity again.
If USE_DEEP_SLEEP
is True
, then we create an alarm to tell the program to stop running and restart from the beginning after a certain amount of time.
Otherwise, we'll make use of the loop. The last_update
is set to time.monotonic()
, which is a running counter that keeps the relative time and is useful for measuring elapsed time. Then a simple while
loop is used to wait until it is time to publish again. Inside this loop, the mqtt_client.loop()
function is called which is useful if you plan on having the code respond to a subscription.
if USE_DEEP_SLEEP: mqtt_client.disconnect() pause = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + PUBLISH_DELAY) alarm.exit_and_deep_sleep_until_alarms(pause) else: last_update = time.monotonic() while time.monotonic() < last_update + PUBLISH_DELAY: mqtt_client.loop()
Debugging the Sensor
If you would like to monitor what the sensor is doing, you can look at our guide on Connecting to the Serial Console with CircuitPython. Once you are connected, it can help with any troubleshooting.
If you would like to use other Temperature and Humidity sensors, then you can modify the code to do so. You'll need to change the import line to your sensor and a simple test example is usually included with each library for the sensor that allows you to get the values that you need.
Once you have the values, you can just plug them into the dict and the rest should just work.
Text editor powered by tinymce.