-
-
Save buglloc/3ea4cf04a89e318fb58cc6d86886bbe0 to your computer and use it in GitHub Desktop.
WasherNotifier
This file contains 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
## Perform actions when an appliance has finished | |
## | |
## This blueprint is my improved version of an original blueprint by @sbyx: | |
## | |
## Original blueprint: | |
## https://gist.github.com/sbyx/6d8344d3575c9865657ac51915684696 | |
## | |
## Community thread: | |
## https://community.home-assistant.io/t/notify-or-do-something-when-an-appliance-like-a-dishwasher-or-washing-machine-finishes/254841 | |
## | |
## Changelog | |
## ~~~~~~~~~ | |
## - v1.0.1 (2022-09-18) | |
## - Add instructions how to skip (pre) actions. | |
## - v1.0 (2022-09-02) | |
## - Initial release | |
## - Hysteresis presented as a duration selector. | |
## (https://www.home-assistant.io/docs/blueprint/selectors/#duration-selector) | |
## - Entities limited to power sensors by device class | |
## (https://www.home-assistant.io/docs/blueprint/selectors/#device_class) | |
## | |
blueprint: | |
name: Appliance has finished | |
description: Perform one or more actions when an appliance | |
(like a washing machine or dishwasher) | |
has started and finished as detected by a power sensor. | |
source_url: https://github.com/metbril/home-assistant-blueprints/blob/main/automation/appliance_has_finished.yaml | |
domain: automation | |
input: | |
power_sensor: | |
name: Power Sensor | |
description: Power sensor entity (e.g. from a smart plug device). | |
selector: | |
entity: | |
domain: sensor | |
device_class: power | |
multiple: false | |
starting_threshold: | |
name: Starting power threshold | |
description: Power threshold above which we assume the appliance has started. | |
default: 5 | |
selector: | |
number: | |
min: 1.0 | |
max: 100.0 | |
step: 1.0 | |
unit_of_measurement: W | |
mode: slider | |
starting_hysteresis: | |
name: Starting hysteresis | |
description: Time duration the power measurement has to stay above the starting | |
power threshold. | |
default: | |
minutes: 5 | |
selector: | |
duration: | |
finishing_threshold: | |
name: Finishing power threshold | |
description: Power threshold below which we assume the appliance has finished. | |
default: 5 | |
selector: | |
number: | |
min: 1.0 | |
max: 100.0 | |
unit_of_measurement: W | |
mode: slider | |
step: 1.0 | |
finishing_hysteresis: | |
name: Finishing hysteresis | |
description: Time duration the power measurement has to stay below the finishing | |
power threshold. | |
default: | |
minutes: 5 | |
selector: | |
duration: | |
actions: | |
name: Actions | |
description: Actions (e.g. pushing a notification, TTS announcement, ...) | |
To skip, enter a 'Wait for delay' action of `0` seconds. | |
selector: | |
action: {} | |
pre_actions: | |
name: Actions | |
description: Actions when starting threshhold is crossed. | |
To skip, enter a 'Wait for delay' action of `0` seconds. | |
selector: | |
action: {} | |
trigger: | |
- platform: numeric_state | |
entity_id: !input power_sensor | |
for: | |
!input starting_hysteresis | |
above: !input starting_threshold | |
condition: [] | |
action: | |
- choose: [] | |
default: !input pre_actions | |
- wait_for_trigger: | |
- platform: numeric_state | |
entity_id: !input power_sensor | |
below: !input finishing_threshold | |
for: | |
!input finishing_hysteresis | |
- choose: [] | |
default: !input actions | |
mode: single | |
max_exceeded: silent |
This file contains 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
esphome: | |
name: washeresp | |
friendly_name: WasherESP | |
esp32: | |
board: esp32-c3-devkitm-1 | |
framework: | |
type: arduino | |
# Enable logging | |
logger: | |
# Enable Home Assistant API | |
api: | |
encryption: | |
key: "DEADBEEF" | |
ota: | |
password: "deadbeef" | |
wifi: | |
ssid: !secret wifi_ssid | |
password: !secret wifi_password | |
manual_ip: | |
static_ip: 10.11.4.3 | |
gateway: 10.11.0.1 | |
subnet: 255.255.0.0 | |
dns1: 10.11.1.2 | |
# I²C Bus необходим, т.к. к нему подключается vl53l0x | |
i2c: | |
sda: GPIO9 | |
scl: GPIO10 | |
id: bus | |
scan: true | |
# Не люблю много думать о времени, потому всегда использую Home Assistant Time Source | |
# doc: https://esphome.io/components/time/homeassistant.html | |
time: | |
- platform: homeassistant | |
id: homeassistant_time | |
# Status LED Light для того чтобы понимать текущее состояние | |
# doc: https://esphome.io/components/light/status_led | |
status_led: | |
pin: | |
number: GPIO8 | |
inverted: true | |
switch: | |
# Restart Switch, чтобы мочь рестартить MCU из HA | |
# doc: https://esphome.io/components/switch/restart.html | |
- platform: restart | |
name: Restart | |
binary_sensor: | |
# Status Binary Sensor, дабы отрисовывать аптайм | |
# doc: https://esphome.io/components/binary_sensor/status.html | |
- platform: status | |
name: Status | |
# С помощью template перенесем логику обнаружения непосредственно на ESP | |
# doc: https://esphome.io/components/binary_sensor/template.html | |
- platform: template | |
id: washer_window_opened | |
publish_initial_state: true | |
name: "Washer Window" | |
device_class: window | |
sensor: | |
# WiFi Signal Sensor, дабы лучше понимать что с WiFi | |
# doc: https://esphome.io/components/sensor/wifi_signal.html | |
- platform: wifi_signal | |
name: "WiFi Signal Strength" | |
update_interval: 60s | |
# VL53L0X Time Of Flight Distance Sensor, собсно ради него весь и сыр-бор | |
# doc: https://esphome.io/components/sensor/vl53l0x | |
- platform: vl53l0x | |
name: "Washer Door Distance" | |
id: washer_door_distance | |
address: 0x29 | |
update_interval: 5s | |
long_range: false | |
unit_of_measurement: "m" | |
internal: true | |
filters: | |
- lambda: !lambda |- | |
// считаем дверцу открытой, если растояние до нее менее 20 см | |
bool isOpened = x <= 0.20; | |
// дальше меняем состояние бинарного сенсора "washer_window_opened" | |
bool curState = id(washer_window_opened).state; | |
if (isOpened != curState) { | |
id(washer_window_opened).publish_state(isOpened); | |
} | |
return {}; |
This file contains 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
esphome: | |
name: dev01 | |
friendly_name: Dev01 | |
esp32: | |
board: esp32dev | |
framework: | |
type: arduino | |
api: | |
encryption: | |
key: "DEADBEEF" | |
ota: | |
password: "deadbeef" | |
wifi: | |
ssid: !secret wifi_ssid | |
password: !secret wifi_password | |
manual_ip: | |
static_ip: 10.11.9.1 | |
gateway: 10.11.0.1 | |
subnet: 255.255.0.0 | |
dns1: 10.11.1.2 | |
# Больше логов богу логов | |
logger: | |
# Не люблю много думать о времени, потому всегда использую Home Assistant Time Source | |
# doc: https://esphome.io/components/time/homeassistant.html | |
time: | |
- platform: homeassistant | |
id: homeassistant_time | |
sensor: | |
# WiFi Signal Sensor, дабы лучше понимать что с WiFi | |
# doc: https://esphome.io/components/sensor/wifi_signal.html | |
- platform: wifi_signal | |
name: "WiFi Signal Strength" | |
update_interval: 60s | |
# Pulse Counter Sensor с медианой, т.к. у меня стиральная машина стоит на балконе, а там бывает и кот и птицы и люди, хотелось не реагировать на случайные срабатывания | |
# doc: https://esphome.io/components/sensor/pulse_counter.html | |
# doc: https://esphome.io/components/sensor/#median | |
- platform: pulse_counter | |
name: "Washer vibration pulse rate" | |
internal: false | |
id: vibration_pulse_rate | |
icon: mdi:vibrate | |
update_interval: 250ms | |
pin: | |
number: GPIO34 | |
mode: input | |
filters: | |
- median: | |
window_size: 120 # скользяще окно около 30 секунд | |
send_every: 4 # отправляем раз в секунду | |
send_first_at: 3 | |
binary_sensor: | |
# Status Binary Sensor, дабы отрисовывать аптайм | |
# doc: https://esphome.io/components/binary_sensor/status.html | |
- platform: status | |
name: Status | |
# Template Binary Sensor, который будет зажигать лампочку на основе ответа лямбды. Так же устанавливаем ему "delayed_on_off" для минимизации фолзов | |
# doc: https://esphome.io/components/binary_sensor/template.html | |
# doc: https://esphome.io/components/binary_sensor/index.html#delayed-on-off | |
- platform: template | |
name: "Washer Running" | |
device_class: vibration | |
filters: | |
- delayed_on_off: | |
time_on: 20ms | |
time_off: 5min # сглаживаем отпутствие вибрации | |
lambda: |- | |
return id(vibration_pulse_rate).state >= 240; | |
# Restart Switch, чтобы мочь рестартить MCU из HA | |
# doc: https://esphome.io/components/switch/restart.html | |
switch: | |
- platform: restart | |
name: Restart |
This file contains 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
[ | |
{ | |
"id": "054ec8d5ab79c60a", | |
"type": "tab", | |
"label": "Washer notifier", | |
"disabled": false, | |
"info": "", | |
"env": [] | |
}, | |
{ | |
"id": "a46f08dc0b249efa", | |
"type": "api-call-service", | |
"z": "054ec8d5ab79c60a", | |
"name": "Phone notify", | |
"server": "34a16949.b02c86", | |
"version": 5, | |
"debugenabled": false, | |
"domain": "notify", | |
"service": "mobile_app_xiphone", | |
"areaId": [], | |
"deviceId": [], | |
"entityId": [], | |
"data": "{\"title\":\"Твоя стиралочка\",\"message\":\"Д-О-С-Т-И-Р-А-ЛА\"}", | |
"dataType": "json", | |
"mergeContext": "", | |
"mustacheAltTags": false, | |
"outputProperties": [], | |
"queue": "none", | |
"x": 890, | |
"y": 120, | |
"wires": [ | |
[] | |
] | |
}, | |
{ | |
"id": "ee7b86592f593a4d", | |
"type": "server-events", | |
"z": "054ec8d5ab79c60a", | |
"name": "Wait washer state", | |
"server": "34a16949.b02c86", | |
"version": 2, | |
"eventType": "washer_state", | |
"exposeToHomeAssistant": false, | |
"eventData": "", | |
"haConfig": [ | |
{ | |
"property": "name", | |
"value": "" | |
}, | |
{ | |
"property": "icon", | |
"value": "" | |
} | |
], | |
"waitForRunning": true, | |
"outputProperties": [ | |
{ | |
"property": "payload", | |
"propertyType": "msg", | |
"value": "", | |
"valueType": "eventData" | |
} | |
], | |
"event_type": "", | |
"x": 250, | |
"y": 120, | |
"wires": [ | |
[ | |
"62ab59d23bdf9789" | |
] | |
] | |
}, | |
{ | |
"id": "9cc43855da8199d9", | |
"type": "switch", | |
"z": "054ec8d5ab79c60a", | |
"name": "Should ignore?", | |
"property": "payload.ignore", | |
"propertyType": "msg", | |
"rules": [ | |
{ | |
"t": "false" | |
}, | |
{ | |
"t": "else" | |
} | |
], | |
"checkall": "true", | |
"repair": false, | |
"outputs": 2, | |
"x": 640, | |
"y": 100, | |
"wires": [ | |
[ | |
"d8c6bdc4ed04ef3f", | |
"526b285468c6f9e4", | |
"8e61c053f50d9ce4", | |
"a46f08dc0b249efa" | |
], | |
[ | |
"3c3c2d95fa9b230d" | |
] | |
] | |
}, | |
{ | |
"id": "15308a2045f375f7", | |
"type": "inject", | |
"z": "054ec8d5ab79c60a", | |
"name": "Trigger washer done", | |
"props": [ | |
{ | |
"p": "payload" | |
} | |
], | |
"repeat": "", | |
"crontab": "", | |
"once": false, | |
"onceDelay": "1", | |
"topic": "", | |
"payload": "{\"event\":{\"state\":\"done\"}}", | |
"payloadType": "json", | |
"x": 250, | |
"y": 80, | |
"wires": [ | |
[ | |
"62ab59d23bdf9789" | |
] | |
] | |
}, | |
{ | |
"id": "f99d79efc64c3f7f", | |
"type": "inject", | |
"z": "054ec8d5ab79c60a", | |
"name": "Trigger window open", | |
"props": [ | |
{ | |
"p": "payload" | |
} | |
], | |
"repeat": "", | |
"crontab": "", | |
"once": false, | |
"onceDelay": "1", | |
"topic": "", | |
"payload": "{}", | |
"payloadType": "json", | |
"x": 240, | |
"y": 220, | |
"wires": [ | |
[ | |
"146ba045f2884829" | |
] | |
] | |
}, | |
{ | |
"id": "21a347b40c580863", | |
"type": "trigger-state", | |
"z": "054ec8d5ab79c60a", | |
"name": "Washer window", | |
"server": "34a16949.b02c86", | |
"version": 2, | |
"exposeToHomeAssistant": false, | |
"haConfig": [ | |
{ | |
"property": "name", | |
"value": "" | |
}, | |
{ | |
"property": "icon", | |
"value": "" | |
} | |
], | |
"entityid": "binary_sensor.washeresp_washer_window", | |
"entityidfiltertype": "exact", | |
"debugenabled": false, | |
"constraints": [ | |
{ | |
"targetType": "this_entity", | |
"targetValue": "", | |
"propertyType": "previous_state", | |
"propertyValue": "old_state.state", | |
"comparatorType": "is", | |
"comparatorValueDatatype": "bool", | |
"comparatorValue": "false" | |
}, | |
{ | |
"targetType": "this_entity", | |
"targetValue": "", | |
"propertyType": "current_state", | |
"propertyValue": "new_state.state", | |
"comparatorType": "is", | |
"comparatorValueDatatype": "bool", | |
"comparatorValue": "true" | |
} | |
], | |
"inputs": 0, | |
"outputs": 2, | |
"customoutputs": [], | |
"outputinitially": false, | |
"state_type": "habool", | |
"enableInput": false, | |
"x": 260, | |
"y": 260, | |
"wires": [ | |
[ | |
"146ba045f2884829" | |
], | |
[] | |
] | |
}, | |
{ | |
"id": "146ba045f2884829", | |
"type": "function", | |
"z": "054ec8d5ab79c60a", | |
"name": "Cache && format", | |
"func": "flow.set(\"door_opened_at\", Math.round(Date.now() / 1000));\n\nmsg.payload = {};\nreturn msg;", | |
"outputs": 1, | |
"timeout": 0, | |
"noerr": 0, | |
"initialize": "", | |
"finalize": "", | |
"libs": [], | |
"x": 550, | |
"y": 240, | |
"wires": [ | |
[ | |
"526b285468c6f9e4", | |
"d60d356fc395856e" | |
] | |
] | |
}, | |
{ | |
"id": "8e61c053f50d9ce4", | |
"type": "mqtt out", | |
"z": "054ec8d5ab79c60a", | |
"name": "Clock notify", | |
"topic": "awtrix/notify", | |
"qos": "", | |
"retain": "", | |
"respTopic": "", | |
"contentType": "", | |
"userProps": "", | |
"correl": "", | |
"expiry": "", | |
"broker": "346df2a95aac5785", | |
"x": 890, | |
"y": 180, | |
"wires": [] | |
}, | |
{ | |
"id": "526b285468c6f9e4", | |
"type": "debug", | |
"z": "054ec8d5ab79c60a", | |
"name": "Clock dbg", | |
"active": true, | |
"tosidebar": true, | |
"console": false, | |
"tostatus": false, | |
"complete": "payload", | |
"targetType": "msg", | |
"statusVal": "", | |
"statusType": "auto", | |
"x": 890, | |
"y": 240, | |
"wires": [] | |
}, | |
{ | |
"id": "d8c6bdc4ed04ef3f", | |
"type": "debug", | |
"z": "054ec8d5ab79c60a", | |
"name": "Phone dbg", | |
"active": true, | |
"tosidebar": true, | |
"console": false, | |
"tostatus": false, | |
"complete": "payload", | |
"targetType": "msg", | |
"statusVal": "", | |
"statusType": "auto", | |
"x": 890, | |
"y": 80, | |
"wires": [] | |
}, | |
{ | |
"id": "62ab59d23bdf9789", | |
"type": "function", | |
"z": "054ec8d5ab79c60a", | |
"name": "Check && format", | |
"func": "const windowOpenedAt = flow.get(\"door_opened_at\") || 0;\nconst secondsSinceLastOpen = Math.round(Date.now() / 1000) - windowOpenedAt;\nif (secondsSinceLastOpen <= 10) {\n msg.payload = {\n ignore: true,\n windowOpenedAt: windowOpenedAt,\n secondsSinceLastOpen: secondsSinceLastOpen,\n };\n return msg;\n}\n\nmsg.payload = {\n ignore: false,\n text: \"done!!!\",\n gradient: [[255,255,0],[255,0,0]],\n textCase: 1,\n icon: 17544,\n stack: false,\n hold: true,\n};\n\nreturn msg;", | |
"outputs": 1, | |
"timeout": 0, | |
"noerr": 0, | |
"initialize": "", | |
"finalize": "", | |
"libs": [], | |
"x": 450, | |
"y": 100, | |
"wires": [ | |
[ | |
"9cc43855da8199d9" | |
] | |
] | |
}, | |
{ | |
"id": "3c3c2d95fa9b230d", | |
"type": "debug", | |
"z": "054ec8d5ab79c60a", | |
"name": "Sportloto", | |
"active": true, | |
"tosidebar": true, | |
"console": false, | |
"tostatus": false, | |
"complete": "payload", | |
"targetType": "msg", | |
"statusVal": "", | |
"statusType": "auto", | |
"x": 640, | |
"y": 140, | |
"wires": [] | |
}, | |
{ | |
"id": "d60d356fc395856e", | |
"type": "mqtt out", | |
"z": "054ec8d5ab79c60a", | |
"name": "Clock dismiss", | |
"topic": "awtrix/notify/dismiss", | |
"qos": "", | |
"retain": "", | |
"respTopic": "", | |
"contentType": "", | |
"userProps": "", | |
"correl": "", | |
"expiry": "", | |
"broker": "346df2a95aac5785", | |
"x": 900, | |
"y": 280, | |
"wires": [] | |
}, | |
{ | |
"id": "34a16949.b02c86", | |
"type": "server", | |
"name": "Home Assistant", | |
"addon": true | |
}, | |
{ | |
"id": "346df2a95aac5785", | |
"type": "mqtt-broker", | |
"name": "haas", | |
"broker": "10.11.0.1", | |
"port": "1883", | |
"clientid": "", | |
"autoConnect": true, | |
"usetls": false, | |
"protocolVersion": "4", | |
"keepalive": "60", | |
"cleansession": true, | |
"birthTopic": "", | |
"birthQos": "0", | |
"birthPayload": "", | |
"birthMsg": {}, | |
"closeTopic": "", | |
"closeQos": "0", | |
"closePayload": "", | |
"closeMsg": {}, | |
"willTopic": "", | |
"willQos": "0", | |
"willPayload": "", | |
"willMsg": {}, | |
"userProps": "", | |
"sessionExpiry": "" | |
} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment