diff --git a/CO2_Ventilation_Alert.yaml b/CO2_Ventilation_Alert.yaml new file mode 100644 index 0000000..bfac266 --- /dev/null +++ b/CO2_Ventilation_Alert.yaml @@ -0,0 +1,397 @@ +blueprint: + name: CO₂ ventilation alert – Apollo R PRO-1 (LED + buzzer) + description: >- + Visual and audible CO₂ alerts on an Apollo R PRO-1. + + + **LED**: off below the "ventilation recommended" level. From that level + it turns yellow and fades towards red as CO₂ approaches the "ventilation + needed" level; at or above it, it is solid red. + + + **Buzzer**: at or above the "start beeping" level the beep action is + repeated at the chosen interval, but only while CO₂ is NOT dropping. + "Dropping" means the newest CO₂ reading is lower than the reading about + one minute earlier (taken from a Statistics helper, see the + "CO₂ change" input). Beeping stops as soon as CO₂ is falling, at any level. + domain: automation + input: + co2_sensor: + name: CO₂ sensor + description: The R PRO-1 CO₂ sensor (ppm). + selector: + entity: + filter: + - domain: sensor + device_class: carbon_dioxide + change_sensor: + name: CO₂ change over the last minute + description: >- + A Statistics helper based on the CO₂ sensor above. Settings: State + characteristic = "Change", Max age = 1 minute (use 90 s if your + sensor reports slower than every ~20 s). Its state is newest reading + minus oldest reading in the window, so a negative value means CO₂ is + dropping. + selector: + entity: + filter: + - domain: sensor + led: + name: R PRO-1 RGB LED + description: The light entity of the R PRO-1 RGB LED. + selector: + entity: + filter: + - domain: light + beep_action: + name: Beep action + description: >- + Action(s) that make the R PRO-1 beep. Use the ESPHome action of your + device, for example `esphome._play_buzzer` with data + `song_str: "co2:d=8,o=6,b=180:c,p,c"`. Keep the tune short, it is + repeated at the beep interval. + default: [] + selector: + action: {} + recommended_level: + name: Ventilation recommended (ppm) + description: LED turns on (yellow) at this level. + default: 1000 + selector: + number: + min: 400 + max: 5000 + step: 50 + unit_of_measurement: ppm + mode: box + needed_level: + name: Ventilation needed (ppm) + description: LED is fully red at this level. + default: 1500 + selector: + number: + min: 400 + max: 5000 + step: 50 + unit_of_measurement: ppm + mode: box + beep_level: + name: Start beeping (ppm) + description: Beeping starts at this level (unless CO₂ is dropping). + default: 2000 + selector: + number: + min: 400 + max: 10000 + step: 50 + unit_of_measurement: ppm + mode: box + min_drop: + name: Minimum drop to count as "dropping" (ppm) + description: >- + 0 = any decrease stops the beeping. Raise to 5–10 if sensor jitter + makes the beeping stop and start at a plateau. + default: 0 + selector: + number: + min: 0 + max: 100 + step: 1 + unit_of_measurement: ppm + mode: box + beep_interval: + name: Beep repeat interval + default: "/30" + selector: + select: + options: + - label: Every 10 seconds + value: "/10" + - label: Every 15 seconds + value: "/15" + - label: Every 20 seconds + value: "/20" + - label: Every 30 seconds + value: "/30" + brightness: + name: LED brightness (%) + default: 60 + selector: + number: + min: 1 + max: 100 + step: 1 + unit_of_measurement: "%" + mode: slider + led_off_when_ok: + name: Turn LED off below "recommended" + description: >- + If enabled, the LED is switched off when CO₂ is below the + recommended level. Disable if you use the LED for other things. + default: true + selector: + boolean: {} + +mode: queued +max: 10 +max_exceeded: silent + +variables: + co2_sensor: !input co2_sensor + change_sensor: !input change_sensor + rec_level: !input recommended_level + need_level: !input needed_level + beep_level: !input beep_level + min_drop: !input min_drop + led_brightness: !input brightness + led_off_when_ok: !input led_off_when_ok + +triggers: + - trigger: state + entity_id: !input co2_sensor + id: reading + - trigger: time_pattern + seconds: !input beep_interval + id: beep_tick + +actions: + - variables: + co2: "{{ states(co2_sensor) | float(none) }}" + change: "{{ states(change_sensor) | float(0) }}" + dropping: "{{ change < -(min_drop | float(0)) }}" + span: "{{ [need_level - rec_level, 1] | max }}" + frac: >- + {{ ([[(co2 - rec_level) / span, 0] | max, 1] | min) + if co2 is not none else 0 }} + hue: "{{ (60 * (1 - frac)) | round(0) | int }}" + - condition: template + value_template: "{{ co2 is not none }}" + - choose: + # --- LED: update on every new CO2 reading ------------------------- + - conditions: + - condition: trigger + id: reading + sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ co2 >= rec_level }}" + sequence: + - action: light.turn_on + target: + entity_id: !input led + data: + hs_color: "{{ [hue, 100] }}" + brightness_pct: "{{ led_brightness | int }}" + - conditions: + - condition: template + value_template: "{{ led_off_when_ok }}" + sequence: + - action: light.turn_off + target: + entity_id: !input led + # --- Buzzer: repeat while high AND not dropping ------------------- + - conditions: + - condition: trigger + id: beep_tick + - condition: template + value_template: "{{ co2 >= beep_level and not dropping }}" + sequence: !input beep_actionblueprint: + name: CO₂ ventilation alert – Apollo R PRO-1 (LED + buzzer) + description: >- + Visual and audible CO₂ alerts on an Apollo R PRO-1. + + + **LED**: off below the "ventilation recommended" level. From that level + it turns yellow and fades towards red as CO₂ approaches the "ventilation + needed" level; at or above it, it is solid red. + + + **Buzzer**: at or above the "start beeping" level the beep action is + repeated at the chosen interval, but only while CO₂ is NOT dropping. + "Dropping" means the newest CO₂ reading is lower than the reading about + one minute earlier (taken from a Statistics helper, see the + "CO₂ change" input). Beeping stops as soon as CO₂ is falling, at any level. + domain: automation + input: + co2_sensor: + name: CO₂ sensor + description: The R PRO-1 CO₂ sensor (ppm). + selector: + entity: + filter: + - domain: sensor + device_class: carbon_dioxide + change_sensor: + name: CO₂ change over the last minute + description: >- + A Statistics helper based on the CO₂ sensor above. Settings: State + characteristic = "Change", Max age = 1 minute (use 90 s if your + sensor reports slower than every ~20 s). Its state is newest reading + minus oldest reading in the window, so a negative value means CO₂ is + dropping. + selector: + entity: + filter: + - domain: sensor + led: + name: R PRO-1 RGB LED + description: The light entity of the R PRO-1 RGB LED. + selector: + entity: + filter: + - domain: light + beep_action: + name: Beep action + description: >- + Action(s) that make the R PRO-1 beep. Use the ESPHome action of your + device, for example `esphome._play_buzzer` with data + `song_str: "co2:d=8,o=6,b=180:c,p,c"`. Keep the tune short, it is + repeated at the beep interval. + default: [] + selector: + action: {} + recommended_level: + name: Ventilation recommended (ppm) + description: LED turns on (yellow) at this level. + default: 1000 + selector: + number: + min: 400 + max: 5000 + step: 50 + unit_of_measurement: ppm + mode: box + needed_level: + name: Ventilation needed (ppm) + description: LED is fully red at this level. + default: 1500 + selector: + number: + min: 400 + max: 5000 + step: 50 + unit_of_measurement: ppm + mode: box + beep_level: + name: Start beeping (ppm) + description: Beeping starts at this level (unless CO₂ is dropping). + default: 2000 + selector: + number: + min: 400 + max: 10000 + step: 50 + unit_of_measurement: ppm + mode: box + min_drop: + name: Minimum drop to count as "dropping" (ppm) + description: >- + 0 = any decrease stops the beeping. Raise to 5–10 if sensor jitter + makes the beeping stop and start at a plateau. + default: 0 + selector: + number: + min: 0 + max: 100 + step: 1 + unit_of_measurement: ppm + mode: box + beep_interval: + name: Beep repeat interval + default: "/30" + selector: + select: + options: + - label: Every 10 seconds + value: "/10" + - label: Every 15 seconds + value: "/15" + - label: Every 20 seconds + value: "/20" + - label: Every 30 seconds + value: "/30" + brightness: + name: LED brightness (%) + default: 60 + selector: + number: + min: 1 + max: 100 + step: 1 + unit_of_measurement: "%" + mode: slider + led_off_when_ok: + name: Turn LED off below "recommended" + description: >- + If enabled, the LED is switched off when CO₂ is below the + recommended level. Disable if you use the LED for other things. + default: true + selector: + boolean: {} + +mode: queued +max: 10 +max_exceeded: silent + +variables: + co2_sensor: !input co2_sensor + change_sensor: !input change_sensor + rec_level: !input recommended_level + need_level: !input needed_level + beep_level: !input beep_level + min_drop: !input min_drop + led_brightness: !input brightness + led_off_when_ok: !input led_off_when_ok + +triggers: + - trigger: state + entity_id: !input co2_sensor + id: reading + - trigger: time_pattern + seconds: !input beep_interval + id: beep_tick + +actions: + - variables: + co2: "{{ states(co2_sensor) | float(none) }}" + change: "{{ states(change_sensor) | float(0) }}" + dropping: "{{ change < -(min_drop | float(0)) }}" + span: "{{ [need_level - rec_level, 1] | max }}" + frac: >- + {{ ([[(co2 - rec_level) / span, 0] | max, 1] | min) + if co2 is not none else 0 }} + hue: "{{ (60 * (1 - frac)) | round(0) | int }}" + - condition: template + value_template: "{{ co2 is not none }}" + - choose: + # --- LED: update on every new CO2 reading ------------------------- + - conditions: + - condition: trigger + id: reading + sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ co2 >= rec_level }}" + sequence: + - action: light.turn_on + target: + entity_id: !input led + data: + hs_color: "{{ [hue, 100] }}" + brightness_pct: "{{ led_brightness | int }}" + - conditions: + - condition: template + value_template: "{{ led_off_when_ok }}" + sequence: + - action: light.turn_off + target: + entity_id: !input led + # --- Buzzer: repeat while high AND not dropping ------------------- + - conditions: + - condition: trigger + id: beep_tick + - condition: template + value_template: "{{ co2 >= beep_level and not dropping }}" + sequence: !input beep_action