4
\$\begingroup\$

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()
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\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\$ Commented Jun 22, 2020 at 18:36

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.