Created
July 11, 2022 19:22
-
-
Save zeroping/0a2543cb33147cf20d376fbb6f682ef9 to your computer and use it in GitHub Desktop.
ESPHome template for the Milfra MFA05 Motion-sensing wall switch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#--- | |
#substitutions: | |
# https://esphome.io/guides/configuration-types.html#substitutions | |
# device_name: garage-overhead # hostname & entity_id | |
# motion_on_time: '15s' # time to leave the relay on after motion is sensed | |
# motion_off_holdoff: '2s' # how long to ignore motion if turned off a short press of the button | |
# button_hold_for_hold_on_time: '2s' # how long to press and hold the button to switch to hold-on mode | |
# This is for the Milfra MFA05 single-button PIR-motion relay switch | |
# This config implements local control of the relay using the button or detected motion | |
# We have two main modes: motion-sensing mode, and hold-on mode | |
# In motion-sensing mode: | |
# If there is motion, the relay is turned on | |
# When the motion stops, the relay waits motion_on_time before turning the lights off | |
# A button press also turns off the relay | |
# Once the relay is off, we ignore motion events for a hold-off period, so we don't re-trigger to quickly | |
# If the button is held down, you switch to hold-on mode | |
# In hold-on mode: | |
# The light stays on indefinately | |
# Pressing the button turns the relay off (and takes us back to motion-sensing mode) | |
# The green LED is used to indicate the relay output state | |
# The blue LED is used to indicate that we're in the most-motion hold-off mode | |
# The blue LED is also used for indicating device status (wifi) | |
## example config (for using this template | |
#substitutions: | |
## https://esphome.io/guides/configuration-types.html#substitutions | |
#device_name: pantry # hostname & entity_id | |
#motion_on_time: '120' # time (in seconds) to leave the relay on after motion is sensed | |
#motion_off_holdoff: '5' # how long (in seconds) to ignore motion if turned off via button or motion ending | |
#button_hold_for_hold_on_time: '1s' # how long to press and hold the button to switch to hold-on mode | |
#<<: !include milfra-mfa05.base.yaml | |
## end example config | |
esphome: | |
name: ${device_name} | |
platform: ESP8266 | |
board: esp8285 | |
wifi: | |
# https://esphome.io/components/wifi | |
ssid: !secret wifi_ssid | |
password: !secret wifi_password | |
logger: | |
# https://esphome.io/components/logger | |
level: INFO | |
#level: VERBOSE | |
ota: | |
web_server: | |
captive_portal: | |
api: | |
#password: !secret esphome_api_password | |
# https://esphome.io/components/api | |
#reboot_timeout: 0s #disable auto-reboot if homeassistant is not connecting | |
light: | |
- platform: status_led | |
id: led2 | |
pin: | |
# Blue LED | |
number: GPIO13 | |
inverted: true | |
# The green LED appears to mask the blue | |
# It also appears to be overridden by the relay | |
output: | |
- platform: gpio | |
# Green LED | |
id: led1 | |
pin: GPIO16 | |
switch: | |
- platform: gpio | |
name: "${device_name}_Relay" | |
id: relay | |
restore_mode: ALWAYS_OFF | |
pin: GPIO12 | |
on_turn_on: | |
- output.turn_off: led1 | |
on_turn_off: | |
- output.turn_off: led1 | |
binary_sensor: | |
- platform: gpio | |
id: button | |
pin: | |
number: GPIO0 | |
mode: INPUT_PULLUP | |
inverted: true | |
on_click: | |
- script.execute: press_action | |
on_multi_click: | |
- timing: | |
- ON for at least ${button_hold_for_hold_on_time} | |
then: | |
- script.execute: hold_on_action | |
- platform: gpio | |
name: ${device_name}_Motion_Sense | |
device_class: "motion" | |
pin: | |
number: GPIO5 | |
inverted: true | |
mode: INPUT_PULLUP | |
on_press: | |
then: | |
- logger.log: | |
format: "state %d, motion high" | |
args: [ 'id(motion_state)' ] | |
- if: | |
condition: | |
lambda: |- | |
return ( id(motion_state) == 0 || id(motion_state) == 1); | |
then: | |
- script.stop: motion_stopped | |
- script.stop: motion_holdoff | |
- light.turn_off: led2 | |
- globals.set: | |
id: motion_state | |
value: "1" | |
- switch.turn_on: relay | |
on_release: | |
#- output.turn_off: led1 | |
then: | |
- logger.log: | |
format: "state %d, motion low" | |
args: [ 'id(motion_state)' ] | |
- if: | |
condition: | |
lambda: |- | |
return ( id(motion_state) == 1 || id(motion_state) == 4 ) ; | |
then: | |
- script.stop: motion_holdoff | |
- script.execute: motion_stopped | |
- light.turn_off: led2 | |
- platform: gpio | |
name: ${device_name}_Light_Sense | |
device_class: "light" | |
pin: | |
number: GPIO14 | |
mode: INPUT | |
globals: | |
- id: motion_state | |
type: int | |
restore_value: no | |
initial_value: '0' | |
# 0 = off | |
# 1 = on by motion | |
# 2 = off after motion, in hold-off | |
# 3 = hold-on state | |
# 4 = quick on via button when no motion | |
- id: motion_keep_on_seconds_remaining | |
type: int | |
restore_value: no | |
initial_value: '0' | |
- id: motion_hold_off_seconds | |
type: int | |
restore_value: no | |
initial_value: '0' | |
script: | |
# immediately stops the timer and turns everything off | |
# only runs if we're turned on by motion or a quick press | |
- id: motion_stopped | |
mode: restart | |
then: | |
- light.turn_off: led2 # the hold-on light | |
- globals.set: | |
id: motion_state | |
value: "1" | |
- globals.set: | |
id: motion_keep_on_seconds_remaining | |
value: ${motion_on_time} | |
- while: | |
condition: | |
lambda: |- | |
return(id(motion_keep_on_seconds_remaining) > 0); | |
then: | |
- logger.log: | |
format: "off after motion, seconds_remaining %d" | |
args: [ 'id(motion_keep_on_seconds_remaining)' ] | |
- lambda: |- | |
id(motion_keep_on_seconds_remaining) -= 1; | |
- delay: 1s | |
- switch.turn_off: relay | |
#now the relay is off, but we need to do a hold-off delay, in case turning off the lights re-triggers us | |
- script.execute: motion_holdoff | |
- id: motion_holdoff | |
mode: restart | |
then: | |
- light.turn_on: led2 # the hold-on light | |
- globals.set: | |
id: motion_hold_off_seconds | |
value: ${motion_off_holdoff} | |
- globals.set: | |
id: motion_state | |
value: "2" | |
- while: | |
condition: | |
lambda: |- | |
return(id(motion_hold_off_seconds) > 0); | |
then: | |
- logger.log: | |
format: "hold off, seconds_remaining %d" | |
args: [ 'id(motion_hold_off_seconds)' ] | |
- lambda: |- | |
id(motion_hold_off_seconds) -= 1; | |
- delay: 1s | |
- light.turn_off: led2 | |
- globals.set: | |
id: motion_state | |
value: "0" | |
- id: press_action | |
then: | |
- logger.log: | |
format: "press action" | |
- if: | |
condition: | |
lambda: |- # on by motion or buttons | |
return ( id(motion_state) == 1 || id(motion_state) == 3 || id(motion_state) == 4); | |
then: | |
- logger.log: | |
format: "state %d, force off" | |
args: [ 'id(motion_state)' ] | |
- script.stop: motion_stopped | |
- light.turn_off: led2 | |
- script.execute: motion_holdoff # we start the holdoff so we ignore motion events for a moment | |
- switch.turn_off: relay | |
else: | |
- logger.log: | |
format: "state %d -> 4, short on" | |
args: [ 'id(motion_state)' ] | |
- script.stop: motion_holdoff | |
- script.stop: motion_stopped | |
- light.turn_off: led2 | |
- switch.turn_on: relay | |
- globals.set: | |
id: motion_state | |
value: "4" | |
- id: hold_on_action | |
then: | |
- logger.log: | |
format: "hold_on_action" | |
- if: | |
condition: | |
lambda: |- # on by motion or buttons | |
return ( id(motion_state) == 1 || id(motion_state) == 3 || id(motion_state) == 4); | |
then: | |
- logger.log: | |
format: "state %d, long force off" | |
args: [ 'id(motion_state)' ] | |
- script.stop: motion_stopped | |
- script.execute: motion_holdoff # we start the holdoff so we ignore motion events for a moment | |
- switch.turn_off: relay | |
else: | |
- script.stop: motion_stopped | |
- script.stop: motion_holdoff | |
- light.turn_off: led2 | |
- switch.turn_on: relay | |
#- output.turn_off: led1 | |
- logger.log: | |
format: "state %d -> 3, hold on" | |
args: [ 'id(motion_state)' ] | |
- globals.set: | |
id: motion_state | |
value: "3" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The ones I bought from aliexpress were labeled as wanted MFA05 but I got wanted MFA05F