Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b948f67
feat(cover,lock): support impulse gates, garage doors, door entry loc…
GreenGrassBlueOcean Oct 9, 2026
60e50a7
fix(typing,compat): maintain strict-typing ratchet and dual-compat wi…
GreenGrassBlueOcean Oct 9, 2026
2490431
fix(lock,typing): support moved LockEntityFeature in HA 2026.10 and l…
GreenGrassBlueOcean Oct 9, 2026
a38741a
test(coverage): achieve 100% coverage on access_policy, cover, light,…
GreenGrassBlueOcean Oct 9, 2026
ee64e41
test(lock): ensure accept_who6 achieves 100% statement coverage on re…
GreenGrassBlueOcean Oct 9, 2026
5bcf44c
feat(blueprints): add multi-language support (EN, IT, NL, DE, FR) wit…
GreenGrassBlueOcean Oct 9, 2026
2de1c24
feat(events): support WHO 8 video intercom calls and add anonymized M…
GreenGrassBlueOcean Oct 9, 2026
10931e0
fix(tests): add backward-compatible OWNDoorEntryEvent fallback for re…
GreenGrassBlueOcean Oct 9, 2026
0b058a7
feat(access,docs): address audit findings on safety architecture, thr…
GreenGrassBlueOcean Oct 9, 2026
72812cd
docs(covers): add ASCII architecture and trace sequence diagrams for …
GreenGrassBlueOcean Oct 9, 2026
c38c7c6
test(domains): update cover WHO mapping assertion for WHO 1 and WHO 2
GreenGrassBlueOcean Oct 9, 2026
56757ec
fix(access): resolve security audit findings for impulse covers and l…
GreenGrassBlueOcean Oct 9, 2026
cc1e801
fix(typing): replace unreachable or with inspect.isawaitable in cover…
GreenGrassBlueOcean Oct 9, 2026
8090750
fix(test): decorate dispatcher listener with @callback to execute syn…
GreenGrassBlueOcean Oct 9, 2026
8835bd8
fix(cover,lock,doorbell): address the PR 667 audit
GreenGrassBlueOcean Oct 9, 2026
e0ecd70
fix(door_entry): fire doorbell only for entrance panel calls, not int…
GreenGrassBlueOcean Oct 9, 2026
5f0f9fd
test: cover the PR 667 guards to restore 100% coverage
GreenGrassBlueOcean Oct 9, 2026
e5ae517
fix(blueprint,access): resolve audit items for motion blueprint and P…
GreenGrassBlueOcean Oct 10, 2026
af6d22e
feat(cover): make the impulse access policy optional, never withhold …
GreenGrassBlueOcean Oct 13, 2026
ce9fe5d
test(cover): count pulse frames only, so the direct-mode tests hold o…
GreenGrassBlueOcean Oct 13, 2026
c4e8888
test(door_entry): patch the legacy call flags on the class, they are …
GreenGrassBlueOcean Oct 13, 2026
852334b
test(door-entry): verify WHO 8 call kind 7 and 59-frame intercom-ts10…
GreenGrassBlueOcean Oct 16, 2026
b86e309
fix(cover,lock,access): resolve PR #667 technical audit findings
GreenGrassBlueOcean Oct 18, 2026
7b0f5c2
test(door-entry,lock): replay Issue #669 MH202 visitor doorbell and l…
GreenGrassBlueOcean Oct 18, 2026
9aba134
test(door-entry): use spec=OWNDoorEntryEvent for WHO 6/8 translation …
GreenGrassBlueOcean Oct 18, 2026
ea95d41
test(cover,intercom): add live F461 + BT-F411/4 WHAT=18 impulse and W…
GreenGrassBlueOcean Oct 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ We now maintain a comprehensive, community-curated **[GitHub Wiki](https://githu
|---|---|---|
| **`light`** | WHO=1 | On/Off, Dimmers with brightness control & transitions (stepped & native), DALI DT8 Tunable White (Dimension 14, 2000K–6535K), HS/RGB colour, Hardware-offloaded bus timers (`myhome.turn_on_timed` / `timer` parameter) |
| **`switch`** | WHO=1 | Relays, auxiliary switches, socket actuators (switch/outlet device classes), Hardware-offloaded bus timers (`myhome.turn_on_timed` / `timer` parameter) |
| **`cover`** | WHO=2 | Motorized shutters, blinds, roll-ups with state tracking, position-reporting actuators & virtual travel-time positioning |
| **`cover`** | WHO=1 / WHO=2 | Motorized shutters, blinds, roll-ups with state tracking, position-reporting actuators & virtual travel-time positioning; impulse gates & garage doors (`WHO=1`) with sensor feedback and an optional multi-factor approval workflow |
| **`lock`** | WHO=6 | Native video door entry strikes (`WHO=6`, configured in `myhome.yaml`) with constant-time PIN authentication and auto-relock |
| **`climate`** | WHO=4 | Heating, cooling, 4-pipe systems, thermostats, setpoints, fancoil 3-speed modes, offset tracking, Central Unit 3550 (`#0`) & 4695 (`#0#1`) master coordination & seasonal propagation |
| **`alarm_control_panel`** | WHO=5 | Central units (3485/3486), read-only state (disarmed / armed away / triggered), zone 0 broadcast sync; arm/disarm via AUX frames ([docs](docs/configuration/alarm.md)) |
| **`binary_sensor`** | WHO=1 / 9 / 25 | Magnetic contacts, door/window sensors, PIR motion, AUX channels (1–9), dry contacts (F482/3477), inverted contacts |
Expand Down
209 changes: 209 additions & 0 deletions blueprints/automation/myhome/door_gate_motion_notification.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
blueprint:
name: "MyHOME: Door & Gate Motion & Open-Alert Notifications"
description: >-
Sends real-time push notifications when a protected MyHOME garage door or gate
starts opening, begins closing, or reaches confirmed closed state, plus an alert
if the door is left open for too long.
domain: automation
source_url: https://github.com/OpenWebNet-HA/MyHOME/blob/v2-phase1-architecture/blueprints/automation/myhome/door_gate_motion_notification.yaml
input:
target_cover:
name: "Gate or Garage Door"
description: "Select the MyHOME cover entity to monitor."
selector:
entity:
domain: cover
integration: myhome
notify_service:
name: "Mobile App Notify Action"
description: "Target mobile app notify action (e.g. notify.mobile_app_iphone)."
selector:
text:
language:
name: "Notification Language"
description: "Language for push notifications (English, Italiano, Nederlands, Deutsch, Français)."
default: "en"
selector:
select:
options:
- label: "English"
value: "en"
- label: "Italiano"
value: "it"
- label: "Nederlands"
value: "nl"
- label: "Deutsch"
value: "de"
- label: "Français"
value: "fr"
notify_on_opening:
name: "Notify When Opening Starts"
default: true
selector:
boolean:
notify_on_closed:
name: "Notify When Fully Closed"
default: true
selector:
boolean:
notify_on_closing:
name: "Notify When Closing Starts"
default: false
selector:
boolean:
left_open_minutes:
name: "Alert If Left Open (Minutes)"
description: "Send a reminder alert if the door remains open longer than this duration (0 = disabled)."
default: 10
selector:
number:
min: 0
max: 120
step: 1
unit_of_measurement: "min"
mode: slider

mode: parallel
max: 10
max_exceeded: silent

trigger:
# 1. Door starts opening
- platform: state
entity_id: !input target_cover
to: "opening"
id: "opening"

# 2. Door starts closing
- platform: state
entity_id: !input target_cover
to: "closing"
id: "closing"

# 3. Door confirmed closed
- platform: state
entity_id: !input target_cover
to: "closed"
id: "closed"

# 4. Door left open for prolonged duration
- platform: state
entity_id: !input target_cover
to: "open"
for:
minutes: !input left_open_minutes
id: "left_open"

variables:
cover_entity: !input target_cover
cover_name: "{{ state_attr(cover_entity, 'friendly_name') | default(cover_entity) }}"
notify_opening_enabled: !input notify_on_opening
notify_closing_enabled: !input notify_on_closing
notify_closed_enabled: !input notify_on_closed
open_minutes: !input left_open_minutes
lang: !input language
i18n:
en:
opening_title: "🚪 {{ cover_name }} is opening"
opening_msg: "The door/gate is moving open."
closing_title: "⚠️ {{ cover_name }} is closing"
closing_msg: "The door/gate is moving closed."
closed_title: "✅ {{ cover_name }} is closed"
closed_msg: "The door/gate is now safely and fully closed."
left_open_title: "⚠️ Alert: {{ cover_name }} is open!"
left_open_msg: "The door/gate has been left open for more than {{ open_minutes }} minutes."
it:
opening_title: "🚪 {{ cover_name }} si sta aprendo"
opening_msg: "La porta/cancello è in movimento verso l'apertura."
closing_title: "⚠️ {{ cover_name }} si sta chiudendo"
closing_msg: "La porta/cancello è in movimento verso la chiusura."
closed_title: "✅ {{ cover_name }} è chiuso"
closed_msg: "La porta/cancello è ora completamente e sicuramente chiusa."
left_open_title: "⚠️ Attenzione: {{ cover_name }} è aperta!"
left_open_msg: "La porta/cancello è rimasta aperta per più di {{ open_minutes }} minuti."
nl:
opening_title: "🚪 {{ cover_name }} wordt geopend"
opening_msg: "De deur/poort is in beweging richting open."
closing_title: "⚠️ {{ cover_name }} begint te sluiten"
closing_msg: "De deur/poort is in beweging richting dicht."
closed_title: "✅ {{ cover_name }} is gesloten"
closed_msg: "De deur/poort is nu veilig en volledig gesloten."
left_open_title: "⚠️ Opgelet: {{ cover_name }} staat open!"
left_open_msg: "De deur/poort staat al langer dan {{ open_minutes }} minuten open."
de:
opening_title: "🚪 {{ cover_name }} wird geöffnet"
opening_msg: "Das Tor/die Tür öffnet sich."
closing_title: "⚠️ {{ cover_name }} schließt sich"
closing_msg: "Das Tor/die Tür schließt sich."
closed_title: "✅ {{ cover_name }} ist geschlossen"
closed_msg: "Das Tor/die Tür ist jetzt sicher und vollständig geschlossen."
left_open_title: "⚠️ Achtung: {{ cover_name }} ist offen!"
left_open_msg: "Das Tor/die Tür steht seit mehr als {{ open_minutes }} Minuten offen."
fr:
opening_title: "🚪 {{ cover_name }} est en cours d'ouverture"
opening_msg: "La porte/le portail est en mouvement vers l'ouverture."
closing_title: "⚠️ {{ cover_name }} commence à se fermer"
closing_msg: "La porte/le portail est en mouvement vers la fermeture."
closed_title: "✅ {{ cover_name }} est fermé"
closed_msg: "La porte/le portail est maintenant bien et totalement fermé."
left_open_title: "⚠️ Attention: {{ cover_name }} est ouvert!"
left_open_msg: "La porte/le portail est ouvert depuis plus de {{ open_minutes }} minutes."
dict: "{{ i18n[lang] if lang in i18n else i18n['en'] }}"

action:
- choose:
# Opening
- conditions:
- condition: trigger
id: "opening"
- condition: template
value_template: "{{ notify_opening_enabled }}"
sequence:
- action: !input notify_service
data:
title: "{{ dict.opening_title }}"
message: "{{ dict.opening_msg }}"
data:
tag: "myhome_door_motion_{{ cover_entity }}"

# Closing
- conditions:
- condition: trigger
id: "closing"
- condition: template
value_template: "{{ notify_closing_enabled }}"
sequence:
- action: !input notify_service
data:
title: "{{ dict.closing_title }}"
message: "{{ dict.closing_msg }}"
data:
tag: "myhome_door_motion_{{ cover_entity }}"

# Closed
- conditions:
- condition: trigger
id: "closed"
- condition: template
value_template: "{{ notify_closed_enabled }}"
sequence:
- action: !input notify_service
data:
title: "{{ dict.closed_title }}"
message: "{{ dict.closed_msg }}"
data:
tag: "myhome_door_motion_{{ cover_entity }}"

# Left Open Alert
- conditions:
- condition: trigger
id: "left_open"
- condition: template
value_template: "{{ open_minutes > 0 }}"
sequence:
- action: !input notify_service
data:
title: "{{ dict.left_open_title }}"
message: "{{ dict.left_open_msg }}"
data:
tag: "myhome_door_left_open_{{ cover_entity }}"
162 changes: 162 additions & 0 deletions blueprints/automation/myhome/doorbell_intercom_notification.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
blueprint:
name: "MyHOME: Intercom & Doorbell Press Notification"
description: >-
Dispatches an actionable mobile push notification with sound, optional live camera snapshot,
and a one-tap 'Open Gate / Unlock Door' button whenever someone rings the BTicino
intercom entrance panel (WHO=6 doorbell event).
domain: automation
source_url: https://github.com/OpenWebNet-HA/MyHOME/blob/v2-phase1-architecture/blueprints/automation/myhome/doorbell_intercom_notification.yaml
input:
notify_service:
name: "Mobile App Notify Action"
description: "Target mobile app notify action (e.g. notify.mobile_app_iphone or notify.mobile_app_pixel)."
selector:
text:
camera_entity:
name: "Intercom / Entrance Camera (Optional)"
description: "Camera entity pointing at the entrance to attach a live snapshot to the notification."
default: ""
selector:
entity:
domain: camera
door_entity:
name: "Pedestrian Door Lock to Release (Optional)"
description: >-
Electric pedestrian strike (lock entity) to release from the notification.
SAFETY NOTE: Motorized gates and garage doors (covers) are deliberately excluded from this
one-tap action. Machinery safety requires motorized impulse covers to be operated interactively
via the Home Assistant app to trigger the multi-factor approval and sensor validation policy.
default: ""
selector:
entity:
domain: lock
lock_code:
name: "Door Lock PIN Code (Optional)"
description: "Optional PIN code required to unlock the configured lock entity (leave empty if the lock has no code)."
default: ""
selector:
text:
type: password
language:
name: "Notification Language"
description: "Language for push notifications and action buttons (English, Italiano, Nederlands, Deutsch, Français)."
default: "en"
selector:
select:
options:
- label: "English"
value: "en"
- label: "Italiano"
value: "it"
- label: "Nederlands"
value: "nl"
- label: "Deutsch"
value: "de"
- label: "Français"
value: "fr"
custom_title:
name: "Custom Notification Title (Optional)"
description: "Leave empty to use the standard translated title."
default: ""
selector:
text:
custom_message:
name: "Custom Notification Message (Optional)"
description: "Leave empty to use the standard translated message."
default: ""
selector:
text:

mode: restart
max_exceeded: silent

trigger:
- platform: event
event_type: myhome_doorbell_event

variables:
door_target: !input door_entity
lock_code_val: !input lock_code
camera_target: !input camera_entity
lang: !input language
custom_title_val: !input custom_title
custom_message_val: !input custom_message
action_open: "MYHOME_DOORBELL_OPEN_{{ trigger.event.data.where }}_{{ now().timestamp() | int }}_{{ range(100000, 999999) | random }}"
action_dismiss: "MYHOME_DOORBELL_DISMISS_{{ now().timestamp() | int }}_{{ range(100000, 999999) | random }}"
i18n:
en:
title: "🔔 Doorbell: Someone is ringing!"
message: "Incoming call from entrance panel"
open_action: "🔓 Release Lock"
dismiss_action: "❌ Dismiss"
it:
title: "🔔 Citofono: Qualcuno sta suonando!"
message: "Chiamata in arrivo dal posto esterno"
open_action: "🔓 Apri Serratura"
dismiss_action: "❌ Ignora"
nl:
title: "🔔 Deurbel: Iemand belt aan!"
message: "Er wordt aangebeld bij de buitenpost"
open_action: "🔓 Ontgrendel Deur"
dismiss_action: "❌ Negeren"
de:
title: "🔔 Türklingel: Jemand klingelt!"
message: "Eingehender Anruf von der Türstation"
open_action: "🔓 Tür öffnen"
dismiss_action: "❌ Ablehnen"
fr:
title: "🔔 Sonnette: Quelqu'un sonne!"
message: "Appel entrant depuis la platine de rue"
open_action: "🔓 Déverrouiller"
dismiss_action: "❌ Ignorer"
resolved_title: >-
{{ custom_title_val if custom_title_val != '' else (i18n[lang].title if lang in i18n else i18n['en'].title) }}
resolved_message: >-
{% set base = custom_message_val if custom_message_val != '' else (i18n[lang].message if lang in i18n else i18n['en'].message) %}
{{ base }} ({{ trigger.event.data.where }})
action_open_title: >-
{{ i18n[lang].open_action if lang in i18n else i18n['en'].open_action }}
action_dismiss_title: >-
{{ i18n[lang].dismiss_action if lang in i18n else i18n['en'].dismiss_action }}

action:
- action: !input notify_service
data:
title: "{{ resolved_title }}"
message: "{{ resolved_message }}"
data: >-
{% set payload = {
"push": {
"sound": "chime.caf",
"category": "MYHOME_DOORBELL"
},
"actions": [
{"action": action_open, "title": action_open_title, "destructive": false, "authenticationRequired": true},
{"action": action_dismiss, "title": action_dismiss_title, "destructive": true}
] if door_target != '' else [
{"action": action_dismiss, "title": action_dismiss_title, "destructive": false}
]
} %}
{% if camera_target != '' %}
{% set _ = payload.update({"entity_id": camera_target, "image": "/api/camera_proxy/" ~ camera_target}) %}
{% endif %}
{{ payload }}

- choose:
- conditions:
- condition: template
value_template: "{{ door_target != '' }}"
sequence:
- wait_for_trigger:
- platform: event
event_type: mobile_app_notification_action
event_data:
action: "{{ action_open }}"
timeout: "00:01:00"
continue_on_timeout: false
- action: lock.unlock
target:
entity_id: !input door_entity
data: >-
{{ {'code': lock_code_val} if lock_code_val != '' else {} }}

Loading
Loading