Last active
September 21, 2025 16:43
-
-
Save yougotborked/5f3270e8fc6da9f82f72832cc48946a1 to your computer and use it in GitHub Desktop.
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
| blueprint: | |
| name: Tuya Zigbee Siren/Doorbell | |
| description: "Set Tuya Zigbee sirens to play a selected melody before activating them." | |
| domain: script | |
| input: | |
| devices: | |
| name: Tuya Zigbee Devices | |
| selector: | |
| device: | |
| integration: zha | |
| multiple: true | |
| melody: | |
| name: Melody | |
| selector: | |
| select: | |
| options: | |
| - Melody 00 (Doorbell Chime) | |
| - Melody 01 (Fur Elise) | |
| - Melody 02 (Westminster Chimes) | |
| - Melody 03 (Fast double door bell) | |
| - Melody 04 (William Tell Overture) | |
| - Melody 05 (Turkish March) | |
| - Melody 06 (Safe/Security Alarm) | |
| - Melody 07 (Chemical Spill Alert) | |
| - Melody 08 (Piercing Alarm Clock) | |
| - Melody 09 (Smoke Alarm) | |
| - Melody 10 (Dog Barking) | |
| - Melody 11 (Police Siren) | |
| - Melody 12 (Doorbell Chime reverb) | |
| - Melody 13 (Mechanical Telephone) | |
| - Melody 14 (Fire/Ambulance) | |
| - Melody 15 (3/1 Elevator) | |
| - Melody 16 (Buzzing Alarm Clock) | |
| - Melody 17 (School Bell) | |
| duration: | |
| name: Duration (seconds) | |
| default: 15 | |
| selector: | |
| number: | |
| min: 1 | |
| max: 60 | |
| step: 1 | |
| mode: slider | |
| volume: | |
| name: Volume | |
| selector: | |
| select: | |
| options: [Low, Medium, High] | |
| variables: | |
| devices: !input devices | |
| duration: !input duration | |
| volume_label: !input volume | |
| melody_label: !input melody | |
| melody_num: > | |
| {% set m = melody_label | regex_findall_index('Melody\\s*(\\d+)', 0) %} | |
| {{ '%02d' | format((m | int(0))) }} | |
| sequence: | |
| - repeat: | |
| for_each: "{{ devices | list }}" | |
| sequence: | |
| - variables: | |
| ents: "{{ device_entities(repeat.item) | list }}" | |
| number_ents: "{{ ents | select('search','^number\\.') | list }}" | |
| select_ents: "{{ ents | select('search','^select\\.') | list }}" | |
| switch_ents: "{{ ents | select('search','^switch\\.') | list }}" | |
| siren_ents: "{{ ents | select('search','^siren\\.') | list }}" | |
| # Prefer your observed names | |
| vol_exact: "{{ select_ents | select('search', '_alarm_volume$') | list }}" | |
| mel_exact: "{{ select_ents | select('search', '_alarm_ringtone$') | list }}" | |
| vol_guess: "{{ select_ents | select('search','volume|level') | list }}" | |
| mel_guess: "{{ select_ents | select('search','melody|ringtone|sound|tone|tune|doorbell|music') | list }}" | |
| vol_entity: > | |
| {% set c = (vol_exact if vol_exact|length>0 else vol_guess) %} | |
| {{ c[0] if c|length>0 else '' }} | |
| mel_entity: > | |
| {% set c = (mel_exact if mel_exact|length>0 else mel_guess) %} | |
| {{ c[0] if c|length>0 else '' }} | |
| dur_entity: > | |
| {% set c = number_ents | select('search','duration|time|seconds|length') | list %} | |
| {{ c[0] if c|length>0 else '' }} | |
| siren_entity: "{{ siren_ents[0] if siren_ents|length>0 else '' }}" | |
| sw_entity: > | |
| {% set pref = switch_ents | select('search','siren|alarm|doorbell|buzzer') | list %} | |
| {{ pref[0] if pref|length>0 else (switch_ents[0] if switch_ents|length>0 else '') }} | |
| # ---- Robust volume mapping ---- | |
| # Map Low/Medium/High to common option spellings (low/quiet/level 1/etc). | |
| resolved_volume: > | |
| {% if vol_entity %} | |
| {% set opts = (state_attr(vol_entity, 'options') or []) | list %} | |
| {% set want = (volume_label|string)|lower %} | |
| {% set patterns = { | |
| 'low': ['\\blow\\b','\\bquiet\\b','\\blevel\\s*1\\b','^1$'], | |
| 'medium': ['\\bmedium\\b','\\bmid(dle)?\\b','\\blevel\\s*2\\b','^2$'], | |
| 'high': ['\\bhigh\\b','\\bloud\\b','\\blevel\\s*3\\b','^3$'] | |
| } %} | |
| {% set pats = patterns.get(want, []) %} | |
| {% set match = '' %} | |
| {% for o in opts %} | |
| {% if not match %} | |
| {% set ol = (o|string)|lower %} | |
| {% for p in pats %} | |
| {% if ol is search(p, ignorecase=True) %} | |
| {% set match = o %} | |
| {% endif %} | |
| {% endfor %} | |
| {% endif %} | |
| {% endfor %} | |
| {% if not match %} | |
| {# fallback to exact-case tries #} | |
| {% set tries = [volume_label, volume_label|title, volume_label|lower, volume_label|upper] %} | |
| {% for t in tries %} | |
| {% if not match and (t in opts) %} | |
| {% set match = t %} | |
| {% endif %} | |
| {% endfor %} | |
| {% endif %} | |
| {{ match if match else (opts[0] if opts|length>0 else '') }} | |
| {% else %}{{ '' }}{% endif %} | |
| # Melody resolution stays the same | |
| resolved_melody: > | |
| {% if mel_entity %} | |
| {% set opts = state_attr(mel_entity, 'options') or [] %} | |
| {% set exact = 'Melody ' ~ melody_num %} | |
| {% set m = (opts | select('equalto', exact) | list) %} | |
| {% if m|length == 0 %} | |
| {% set m = (opts | select('search', '^Melody\\s*' ~ (melody_num|int)) | list) %} | |
| {% endif %} | |
| {% if m|length == 0 %} | |
| {% set m = (opts | select('search', melody_num) | list) %} | |
| {% endif %} | |
| {{ (m[0] if m|length>0 else (opts[0] if opts|length>0 else '')) }} | |
| {% else %}{{ '' }}{% endif %} | |
| # Duration (optional) | |
| - choose: | |
| - conditions: "{{ dur_entity|length > 0 }}" | |
| sequence: | |
| - service: number.set_value | |
| target: { entity_id: "{{ dur_entity }}" } | |
| data: { value: "{{ duration | int }}" } | |
| # ----- ORDER & tiny delays help many Tuya sirens ----- | |
| # 1) Volume first | |
| - choose: | |
| - conditions: "{{ vol_entity|length > 0 and resolved_volume|length > 0 }}" | |
| sequence: | |
| - service: select.select_option | |
| target: { entity_id: "{{ vol_entity }}" } | |
| data: { option: "{{ resolved_volume }}" } | |
| - delay: "00:00:00.50" | |
| # 2) Melody second | |
| - choose: | |
| - conditions: "{{ mel_entity|length > 0 and resolved_melody|length > 0 }}" | |
| sequence: | |
| - service: select.select_option | |
| target: { entity_id: "{{ mel_entity }}" } | |
| data: { option: "{{ resolved_melody }}" } | |
| - delay: "00:00:00.30" | |
| # 3) Activate | |
| - choose: | |
| - conditions: "{{ siren_entity|length > 0 }}" | |
| sequence: | |
| - service: siren.turn_on | |
| target: { entity_id: "{{ siren_entity }}" } | |
| - conditions: "{{ siren_entity|length == 0 and sw_entity|length > 0 }}" | |
| sequence: | |
| - service: switch.turn_on | |
| target: { entity_id: "{{ sw_entity }}" } | |
| mode: parallel | |
| max_exceeded: silent |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment