7. Using the relay for control - ControlBits/EMIT GitHub Wiki
As you've made it this far, you already have a functional Environmental Monitoring IoT Sensor sending data via MQTT, but we don't have to stop there ... EMIT has an on-board relay that we can use to provide some local control such as turning ON a heater when the temperature falls below a pre-set threshold (i.e. build a thermostat).
The relay could be used for any number of other use cases, including triggering a watering pump, fan or even an audible alarm but in this particular case, we're going to stick with adding a temperature based control loop to EMIT.
IMPORTANT SAFETY NOTICE: EMIT's maximum operating Voltage is 12 volts. UNDER NO CIRCUMSTANCES should you attempt to switch any voltages higher than 12 volts with on-board relay.
7.1 Setting up the relay in boot.py
The ESP32's GPIO pins can not provide enough power to directly drive a relay so the EMIT PCB has a built in 'FET relay driver' which is connected to GPIO pin 26. Setting this pin to '1' will cause the FET relay driver to turn the relay ON, setting it to '0' will turn the relay OFF.
The first thing we need to do (in boot.py) is configure GPIO pin 26 as an output pin and set it to 0 to ensure the relay is off by default. We do this in exactly the same way as we did the LEDs earlier in this guide.
Relay = machine.Pin(26, machine.Pin.OUT)
Relay.value(0)
We will be adding the 'relay state' to our MQTT messages, to make this easier we'll define a 'relayState' variable (of type string) in boot.py and set the initial relay state to 'OFF'.
relayState = 'OFF' # define relayState string and set to 'OFF'
We also need to define a 'temperature set point', which is the point we wish the relay to turn ON or OFF. We do this by adding the following line to boot.py:
tempSet = 21.0 # temperature set point for relay (Celsius)
That's the setup done ... now onto the relay control loop.
7.2 Adding the relay control loop to main.py
Our relay control loop is very simple:
If the 'current temperature' is greater than or equal to the 'temperature set point' turn the relay OFF, otherwise turn the relay ON
Re-writing this control loop logic in MicroPython we get:
if tempC >= tempSet:
Relay.value(0) # turn relay OFF
relayState = 'OFF' # set relayState string to 'OFF'
else:
Relay.value(1) # turn relay ON
relayState = 'ON' # set relayState string to 'ON'
This control loop needs to be added to our main.py just after the AM2302 has been read and decoded.
7.3 Adding relay status to our MQTT message
The last thing left to do is add our 'temperature set point' (tempSet) and the 'relayState' to our MQTT message. We do this by appending two new attributes: 'TempSetPointC' and 'Relay' to our existing MQTTmsg string as follows:
JSONstring ='{"TimeUTC":"' + get_time_str() + '","TemperatureC":"' + str(tempC) + '","Humidity":"' + str(humidity) + '","TempSetPointC":"' + str(tempSet) + '","Relay":"' + relayState + '"}'
With our relay control loop and revised JSONstring added, the complete main.py should look like this:
# connect to wifi
wifi_connect()
# wait 5 seconds for network to settle
time.sleep(5)
# synchronise local clock with NTP time
sync_to_NTP()
# wait 1 second
time.sleep(1)
# set up MQTT connection and subscribe
client = mqtt_connect()
# this is the main program loop
while True:
time.sleep(5) # wait 5 seconds
RedLED.value(1) # turn RedLED ON
AM2302.measure() # start AM2302 measurement
RedLED.value(0) # turn RedLED OFF
tempC = AM2302.temperature() # get temperature (Celsius) from AM2302
humidity = AM2302.humidity() # get humidity from AM2302
# add relay control loop
if tempC >= tempSet:
Relay.value(0) # turn relay OFF
relayState = 'OFF' # set relayState string to 'OFF'
else:
Relay.value(1) # turn relay ON
relayState = 'ON' # set relayState string to 'ON'
JSONstring ='{"TimeUTC":"' + get_time_str() + '","TemperatureC":"' + str(tempC) + '","Humidity":"' + str(humidity) + '","TempSetPointC":"' + str(tempSet) + '","Relay":"' + relayState + '"}'
print(JSONstring)
MQTTmsg = bytes(JSONstring, 'utf-8')
try:
client.publish(topic, MQTTmsg)
except:
print("Can not publish message - reconnecting")
mqtt_connect()
If you upload the new boot.py and main.py files, and head back over to the EMIT 'LIVE' dashboard, you should now see the relay status and relay set point displayed like this:
But we're not done quite yet ... there is one more improvement we can make ... add some 'hysteresis' to our relays control loop.
7.4 Adding hysteresis to our control loop
The simple control loop that we've created above works well but isn't ideal because the resolution of the temperature sensor is 0.1 Celsius - making it very sensitive to minor changes in temperature.
As a result of this sensitivity, it is not uncommon for the temperature to change every time it is read - this can in turn result in the relay turning 'ON' or 'OFF' with every measurement - every 10 seconds! This behaviour is not helpful and can actually reduce the life of the relay.
We can overcome this problem by add 'hysteresis' to our relay's control loop. Hysteresis effectively reduces the sensitivity of the control loop by adding a 'dead band'.
Once our relay has turned OFF, we want it to stay OFF until is has passed a lower threshold set by as our: 'temperature set point' less the 'hysteresis' we wish to set.
As an example, if our temperature set point is 21.0 Celsius, if we introduce a hysteresis of 0.5 Celsius, we don't want the relay to turn back on until the temperature drops below 21.0 - 0.5 = 20.5 Celsius.
Thankfully, this is easier to implement than explain!
In boot.py just add a 'hysteresis' variable:
hysteresis = 0.5 # relay control loop hysteresis (Celcius)
Then, on our Main.py we just need to add a third, intermediate stage to add the hysteresis to our control loop. This is done as follows:
if (tempC > (tempSet - hysteresis)) and relayState == 'OFF':
Relay.value(0) # keep relay off
relayState = 'OFF' # set relayState string to 'OFF'
This needs to be added between the 'if' and 'else' statements in our existing control loop.
With the hysteresis added, the complete main.py should look like this:
# connect to wifi
wifi_connect()
# wait 5 seconds for network to settle
time.sleep(5)
# synchronise local clock with NTP time
sync_to_NTP()
# wait 1 second
time.sleep(1)
# set up MQTT connection and subscribe
client = mqtt_connect()
# this is the main program loop
while True:
time.sleep(5) # wait 5 seconds
RedLED.value(1) # turn RedLED ON
AM2302.measure() # start AM2302 measurement
RedLED.value(0) # turn RedLED OFF
tempC = AM2302.temperature() # get temperature (Celsius) from AM2302
humidity = AM2302.humidity() # get humidity from AM2302
# add relay control loop
if tempC >= tempSet:
Relay.value(0) # turn relay OFF
relayState = 'OFF' # set relayState string to 'OFF'
if (tempC > (tempSet - hysteresis)) and relayState == 'OFF':
Relay.value(0) # keep relay off
relayState = 'OFF' # set relayState string to 'OFF'
else:
Relay.value(1) # turn relay ON
relayState = 'ON' # set relayState string to 'ON'
JSONstring ='{"TimeUTC":"' + get_time_str() + '","TemperatureC":"' + str(tempC) + '","Humidity":"' + str(humidity) + '","TempSetPointC":"' + str(tempSet) + '","Relay":"' + relayState + '"}'
print(JSONstring)
MQTTmsg = bytes(JSONstring, 'utf-8')
try:
client.publish(topic, MQTTmsg)
except:
print("Can not publish message - reconnecting")
mqtt_connect()