I'm running MicroPython on an ESP32 relaying sensor data to my MQTT server for Home Assistant. I only want it to emit a message when state has changed and a motion detected state to hold for a minute before returning to a clear state. I see a lot of examples using sleep, but I don't like the blocking nature of sleep as I will be adding more sensors. Instead I've been using ticks_ms() and ticks_diff() to keep the state from fluttering on/off too much, but I can't help but think there's a better/more elegant way to do this that I'm not seeing.
There's some repetition and nesting that sticks out to me
from umqtt.robust import MQTTClient
from machine import Pin, unique_id
from time import ticks_diff, ticks_ms
from ubinascii import hexlify
#Config
MQTT_SERVER = "X.X.X.X"
MQTT_PORT = 1883
MQTT_USER = b"USER"
MQTT_PASSWORD = b"PASSWORD"
MQTT_CLIENT_ID = hexlify(unique_id())
MQTT_TOPIC = b"esp/motion"
mqtt = MQTTClient(MQTT_CLIENT_ID, MQTT_SERVER, MQTT_PORT, MQTT_USER, MQTT_PASSWORD)
ledPin = Pin(2, Pin.OUT)
motPin = Pin(15, Pin.IN)
previousState = 0
delay_ms = 60000
clock = ticks_ms()
def main():
global clock, previousState, delay_ms
try:
mqtt.connect()
while True:
state = motPin.value()
if state == 1:
ledPin.on()
if previousState == 0:
if ticks_diff(ticks_ms(), clock) >= 0:
print('motion_start')
mqtt.publish(MQTT_TOPIC, 'motion_start')
clock = ticks_ms() + delay_ms
previousState = state
else:
clock = ticks_ms() + delay_ms
else:
ledPin.off()
if previousState == 1:
if ticks_diff(ticks_ms(), clock) >= 0:
print('motion_stop')
mqtt.publish(MQTT_TOPIC, 'motion_stop')
previousState = state
finally:
ledPin.off()
mqtt.publish(MQTT_TOPIC, 'motion_stop')
mqtt.disconnect()
if __name__ == "__main__":
main()
1 Answer 1
Fluttering
if previousState == 0:
if ticks_diff(ticks_ms(), clock) >= 0:
This is called a soft debounce. It may or may not be adequate. My usual recommendation is to do hard debounce instead (or maybe in addition) via a first-order RC lowpass filter followed by hysteresis in a Schmitt trigger. If none of that makes sense to you, then that's a question for https://electronics.stackexchange.com/ .
Truthiness
I would sooner write
if state:
rather than
if state == 1:
snake_case
Per PEP8, previousState
should be previous_state
.
-
\$\begingroup\$ What I'm aiming for isn't necessarily debouncing as the sensor has digital signal processing; multiple motion events all within a minute just tend to present issues with home automation. Agreed on the state boolean - I had that initially, but thought that might obfuscate sensor value too much - but it is indeed cleaner. \$\endgroup\$weird.turned.pro– weird.turned.pro2020年06月22日 18:36:56 +00:00Commented Jun 22, 2020 at 18:36