Various home automation projects centered around a RaspberryPi as a MQTT broker with ESP32 edge-devices. See P36-Home-Automation for more
Overview:
Compile and build this tagged commit to verify communication between your local mqtt broker and the esp32 as a mqtt client. The esp32 will blink itself on and off every 3 seconds, but can also be turned on/off via the inTopic
mqtt topic (note sending an "ON"/"OFF" command via mqtt will not affect the blink timing which just toggles the state every 3 seconds).
To run:
- Start a mqtt broker on a local server (e.g.
mosquitto
on a RasPi) - Get the broker local IP address (for the next step)
- Rename
fakeSecrets.h
tosecrets.h
and modify as necessary (WiFi name, password, MQTT server IP) - Compile and Upload to ESP32
The ESP32 will now toggle its built-in led every 3 seconds and print "hello I'm blinking" to the Serial Monitor.
When it receives an MQTT message to the "inTopic" it will print it on the serial monitor.
- If the message is "ON" or "OFF" it will turn the built-in led ON or OFF
- It will also deliver an MQTT message to the "outTopic" topic
On local machine:
# use SSH from a terminal to get into the Pi server
ssh [email protected]
# ... enter user/pass ...
In a server terminal (or after SSHing in):
# print IP address (should match the one in `secrets.h`)
hostname -I
# ...
# check the `mosquitto` status:
systemctl status mosquitto.service
# ... if status is running try:
mosquitto_pub -d -t inTopic -m "ON"
# which should turn the builtin on the ESP32 ON if it is OFF
If necessary restart the mosquitto service with
sudo systemctl restart mosquitto
If we want to see the
outTopic
responses from the ESP32 we can open up another terminal on the MQTT broker and subscripe to this topic e.g.mosquitto_sub -d -t outTopic
Or to subscribe to all topics do:mosquitto_sub -d -t "#"
Notes/Gotchas
- the mosquitto broker has to be configured to accept anonymous connections (disabled by default)
- put the ESP32 in "flash" mode by (1) pressing and holding BOOT (2) pressing and releasing ENABLE (3) releasing BOOT
This tagged commit demonstrates
- creating an mqtt publish string with c-style strings, in the form
<gateway>/<client-ID>/<function>/<sensor-type>/<sensor-units>
- deep sleep and waking upon an interrupt
- adds a 3 min watchdog timer for the main loop, to make sure there are no hangups with e.g. connecting to the server
- reading sensor data from an
bme280
sensor with the Adafruit Library
Description:
- In
setup()
we check the reset reason, then set an external wakeup interrupt on pin 33 - In
loop()
, we will enter sleep at the end of the loop, so it only runs once - First we add a watchdog timer for the current thread
- We make sure we are connected to WiFi and the MQTT broker as defined in
secrets.h
before continuing - We read the
bme280
sensor and publish to mqtt- data is stored in RTC memory to be accesible after deep sleep
- We get ready to sleep
- reset the watchdog
- disconnect from wifi and mqtt
- Then we sleep for 30 mins
MQTT Topic Example:
- For example, the mqtt publishing topic for temperature is
home/esp-01/status/temperature/C
. - This topic string structure was chosen since later we will send commands to the device in the form
home/esp-01/set/led
=ON
- Units are also included in the topic string for clarity to the user/broker
- This is created on the fly with dynamic memory allocation and is destructed later in the
publishSensorVal()
function (It is better to handle strings with C++string
types, but I wanted to demonstrate/learn about cstrings).
Deep Sleep and Wake Upon Interrupt Example Hardware setup: Wakeup when Pin 33 -> LOW
- Pin 33 -> T1 of Pushbutton
- T1 of Pushbutton -> Resistor -> 3V3 (PULLUP)
- T2 of Pushbutton -> GND
Putting the ESP32 into deep sleep will only keep variables that have been placed into the RTC memory e.g.
RTC_DATA_ATTR float value{0};
We go to sleep with:
esp_sleep_enable_timer_wakeup(time_in_us);
esp_deep_sleep_start();
Set an external wakeup (ext0
type) when Pin 33 goes LOW
:
esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, 0)
When starting up, check if we were woken up by the external wakeup:
#include "esp_sleep.h"
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) {
// ...
}
This tagged commit demonstrates:
- implementing an external interrupt with a raindrop sensor (like this one)
- if there is rain, the ESP disables the
ext0
interrupt, since we do not want to keep waking up - if there is no rain, the interrupt is re-enabled
Hardware Connections
- Rain Sensor
D0
→ ESPD4
- Rain Sensor
A0
→ ESPD33
- VCC → 3.3V
- Ground
The sleep values were changed to
D0
is the digital output of the comparator on the rain sensor control board. This is normally HIGH
. When a raindrop is detected, this pin goes LOW
(and turns on the on-board D0
LED).
The sensitivity is set by the potentiometer (clockwise raises Vref so this will be more sensitive).
Detailed Description
The inputs to the comparator are A0
and V_SENSE
. V_SENSE
is a voltage divider from VCC
, based on the potentiometer value. A0
's voltage is from a voltage divider between a 10K pullup resistor from VCC
and the resistance of the rain drop module (infinite when no rain). When it's not raining this rain drop module is an open circuit, so A0
=VCC
. When it rains, this resistance decreases, so it pulls A0
lower, an amount depending on the amount of water on the board (more water = less resistance). If this voltage is pulled below the V_SENSE
voltage, then the comparator output, thus D0
swings LOW
.
- to minimize corrosion we would want to disconnect the voltage to the raindrop monitor when we already know it's raining and we're in deep sleep, we could do this either in hardware using the
D0
pin as a gate input (since once this is low we know it is raining), or in software via the ESP.