diff --git a/addons/appdaemon/grow_monitor/Readme.MD b/addons/appdaemon/grow_monitor/Readme.MD index 8f7fc41..d66e593 100644 --- a/addons/appdaemon/grow_monitor/Readme.MD +++ b/addons/appdaemon/grow_monitor/Readme.MD @@ -69,7 +69,13 @@ An intelligent AppDaemon-based monitoring system for cannabis grow rooms with AI class: GrowRoomAIMonitor openai_api_key: "sk-YOUR_OPENAI_API_KEY_HERE" ``` -3. Create Home Assistant Helper Entities (YAML)Copy and paste the following block into your Home Assistant configuration.yaml file (or a separate YAML file that you !include, like input_helpers.yaml). Then, restart Home Assistant (or Reload Input Helpers from Developer Tools).Replace YOUR_PREFIX_ with your desired prefix (e.g., f1_, grow_room_) and update the ENTITIES dictionary in grow_monitor.py accordingly.# In your configuration.yaml or a dedicated !include file for inputs + +### 3. Create Home Assistant Helper Entities (YAML) + +Copy and paste the following block into your Home Assistant `configuration.yaml` (or a separate YAML file that you `!include`, like `input_helpers.yaml`). Then restart Home Assistant (or **Reload Input Helpers** from Developer Tools). + +Replace `YOUR_PREFIX_` with your desired prefix (e.g. `f1_`, `grow_room_`) and update the `ENTITIES` dictionary in `grow_monitor.py` accordingly. + ```yaml input_datetime: YOUR_PREFIX_lights_on_time: @@ -269,9 +275,12 @@ input_number: unit_of_measurement: "mS/cm" icon: mdi:flash-outline ``` -4. Create Home Assistant Mute Script -In your Home Assistant scripts.yaml file (or a separate file if you include a scripts directory), add the following script: -``` + +### 4. Create the Home Assistant Mute Script + +In your Home Assistant `scripts.yaml` (or a separate file if you use a scripts directory), add the following script: + +```yaml grow_monitor_mute_sensor: alias: "Grow Monitor Mute Sensor Action" description: "Fires an event to mute a specific grow monitor sensor." @@ -290,66 +299,71 @@ grow_monitor_mute_sensor: mode: single ``` -Reload Home Assistant scripts (Developer Tools > YAML Configuration > Reload Scripts). -5. Configure Entities in grow_monitor.py -Open grow_monitor.py. -At the top, find the ENTITIES dictionary. -Update all entity IDs here to match your specific Home Assistant entities (sensors, and the helpers you just created with YOUR_PREFIX_). -6. Restart AppDaemon -After all files and entities are configured, restart the AppDaemon addon from the Home Assistant UI. - Using the Monitor -Automatic Operation: The script runs in the background. -Notifications: - -When issues are detected and not suppressed by cooldowns or mutes, an AI-summarized notification is sent. -Actions: "Mute [Sensor] (1h)", "Mute [Sensor] (6h)", "Pause ALL Alerts". - - -Muting: Clicking a mute action silences that specific sensor for the chosen duration. The overall notification system will also enter a 6-hour quiet period (new critical alerts still come through). -Global Pause: Toggle the alerts_paused input_boolean in HA or use the notification action. - Alert Severity & Cooldowns -Severity Levels: IGNORE, NORMAL, URGENT, CRITICAL (determined by violation duration and trend). +Reload Home Assistant scripts (**Developer Tools → YAML → Reload Scripts**). -A violation must typically last >= 60 seconds to become "NORMAL" severity. +### 5. Configure Entities in `grow_monitor.py` +Open `grow_monitor.py`, find the `ENTITIES` dictionary near the top, and update all +entity IDs to match your Home Assistant entities (sensors, plus the `YOUR_PREFIX_` +helpers you just created). -Cooldowns: +### 6. Restart AppDaemon -Base: 1 hour between notifications. -After Acknowledgment (Mute): 6 hours quiet period. -New Critical Alerts: Bypass cooldowns. +Once all files and entities are configured, restart the AppDaemon add-on from the +Home Assistant UI. +## Using the Monitor - Data Persistence -The script saves its state (muted sensors, last notification times) to grow_monitor_data.pkl in its app_dir (e.g., /config/apps/grow_monitor_data.pkl). This allows state to survive AppDaemon restarts. - Troubleshooting -No Notifications: +- **Automatic operation:** the script runs in the background. +- **Notifications:** when issues are detected and not suppressed by cooldowns or mutes, + an AI-summarised notification is sent. Actions: *Mute [Sensor] (1h)*, + *Mute [Sensor] (6h)*, *Pause ALL Alerts*. +- **Muting:** clicking a mute action silences that sensor for the chosen duration; the + whole notification system also enters a 6-hour quiet period (new critical alerts still + come through). +- **Global pause:** toggle the `alerts_paused` `input_boolean` in HA, or use the + notification action. -Check AppDaemon logs for errors. -Verify YOUR_PREFIX_environmental_alerts_paused is off. -Confirm time_zone in appdaemon.yaml is correct. -Ensure sensor values violate thresholds for sufficient duration (default >60s for "NORMAL"). -Delete grow_monitor_data.pkl and restart AppDaemon to clear stuck mutes. -Test your notify service from HA Developer Tools. +## Alert Severity & Cooldowns +- **Severity levels:** IGNORE, NORMAL, URGENT, CRITICAL — determined by violation + duration and trend. A violation must typically last ≥ 60 seconds to reach NORMAL. +- **Cooldowns:** + - Base 1 hour between notifications. + - 6-hour quiet period after acknowledgment (mute). + - New critical alerts bypass cooldowns. -Mute Actions Not Working: +## Data Persistence -Ensure script.grow_monitor_mute_sensor exists and is correctly configured in HA. -Verify EVENT_GROW_MONITOR_MUTE in grow_monitor.py matches the event: in the HA script. +The script saves its state (muted sensors, last notification times) to +`grow_monitor_data.pkl` in its `app_dir` (e.g. `/config/apps/grow_monitor_data.pkl`), +so state survives AppDaemon restarts. +## Troubleshooting -AI Summary Issues: +**No notifications** +- Check AppDaemon logs for errors. +- Verify `YOUR_PREFIX_environmental_alerts_paused` is off. +- Confirm `time_zone` in `appdaemon.yaml` is correct. +- Ensure sensor values violate thresholds for long enough (default > 60 s for NORMAL). +- Delete `grow_monitor_data.pkl` and restart AppDaemon to clear stuck mutes. +- Test your notify service from HA Developer Tools. -Check openai_api_key in apps.yaml. -Look for API errors in AppDaemon logs. +**Mute actions not working** +- Ensure `script.grow_monitor_mute_sensor` exists and is configured correctly. +- Verify `EVENT_GROW_MONITOR_MUTE` in `grow_monitor.py` matches the `event:` in the HA script. +**AI summary issues** +- Check `openai_api_key` in `apps.yaml`. +- Look for API errors in the AppDaemon logs. -Log Timestamps Incorrect: +**Log timestamps incorrect** +- Ensure `time_zone` in the `appdaemon.yaml` that AppDaemon actually reads is set to your local timezone. -Ensure time_zone in the appdaemon.yaml that AppDaemon is actually reading is set to your local timezone. +--- +Monitor your grow environment effectively with intelligent, summarised, actionable alerts. - Monitor your grow environment effectively with intelligent, summarized, and actionable alerts!Version: 3.1 -Last Updated: May 24, 2025 -Compatibility: Home Assistant 2023.x+, AppDaemon 4.x+ +- **Version:** 3.1 +- **Last updated:** 2025-05-24 +- **Compatibility:** Home Assistant 2023.x+, AppDaemon 4.x+ diff --git a/automations/co2_automation.MD b/automations/co2_automation.MD index 198565f..1f39340 100644 --- a/automations/co2_automation.MD +++ b/automations/co2_automation.MD @@ -1,634 +1,102 @@ +# CO₂ Control and Alerts — import notes -Blueprint import url: https://gist.github.com/JakeTheRabbit/41fbc01a62006cfef7172dc5b8534b60 +Import notes and logic overview for the CO₂ blueprint. The blueprint itself is the +single source of truth: -```mermaid -graph TD - Start[Start] -->|Trigger| WhichTrigger{Which Trigger?} +**[`../blueprints/co2_control_and_alerts.yaml`](../blueprints/co2_control_and_alerts.yaml)** - WhichTrigger -->|"CO2 Sensor State Change
co2_sensor_state_change"| CO2ControlLogic[CO2 Control Logic] - WhichTrigger -->|"CO2 Target Input Change
co2_target_state_change"| CO2ControlLogic - WhichTrigger -->|"CO2 Tolerance Input Change
co2_tolerance_state_change"| CO2ControlLogic - WhichTrigger -->|"CO2 On Time Trigger
co2_on_time_trigger"| DaytimeAdjustment[Daytime CO2 Target Adjustment] - WhichTrigger -->|"CO2 Off Time Trigger
co2_off_time_trigger"| NighttimeAdjustment[Nighttime CO2 Target Adjustment] - WhichTrigger -->|"Low CO2 Alert Trigger
low_co2_alert_trigger"| LowCO2Alert[Low CO2 Alert] - WhichTrigger -->|"High CO2 Alert Trigger
high_co2_alert_trigger"| HighCO2AlertPrimary[High CO2 Alert Primary Sensor] - WhichTrigger -->|"High CO2 Alert Trigger Secondary
high_co2_alert_trigger_secondary"| HighCO2AlertSecondary[High CO2 Alert Secondary Sensor] +> This file used to embed a full copy of the blueprint YAML. That copy drifted out +> of date, so it has been removed — always import the blueprint file above rather +> than any snippet pasted here. Requires **Home Assistant 2024.10+**. - %% Daytime CO2 Target Adjustment - DaytimeAdjustment --> GetDaytimeTarget[Get Daytime Target Value] - GetDaytimeTarget --> ValidateDaytimeTarget{Is Target Value Valid?} - ValidateDaytimeTarget -->|Yes| SetDaytimeTarget[Set CO2 Target Input Number] - ValidateDaytimeTarget -->|No| End[End] +## Import - %% Nighttime CO2 Target Adjustment - NighttimeAdjustment --> GetNighttimeTarget[Get Nighttime Target Value] - GetNighttimeTarget --> ValidateNighttimeTarget{Is Target Value Valid?} - ValidateNighttimeTarget -->|Yes| SetNighttimeTarget[Set CO2 Target Input Number] - ValidateNighttimeTarget -->|No| End +1. **Settings → Automations & Scenes → Blueprints → Import Blueprint**. +2. Paste the raw URL of [`blueprints/co2_control_and_alerts.yaml`](https://github.com/JakeTheRabbit/HAGR/blob/main/blueprints/co2_control_and_alerts.yaml) and import. +3. **Create automation** from it and fill in the inputs. - %% Low CO2 Alert - LowCO2Alert --> CheckLowCO2Time{Is Current Time Within Alert Window?} - CheckLowCO2Time -->|Yes| ValidateLowCO2Value{Is CO2 Value Valid?} - CheckLowCO2Time -->|No| End - ValidateLowCO2Value -->|Yes| SendLowCO2Notification[Send Low CO2 Notification] - SendLowCO2Notification --> AdjustLightsLow[Adjust Lights to Low Brightness] - ValidateLowCO2Value -->|No| End +For local development you can instead drop the file into +`/blueprints/automation//` and reload. - %% High CO2 Alert (Primary Sensor) - HighCO2AlertPrimary --> ValidateHighCO2Primary{Is CO2 Level Valid?} - ValidateHighCO2Primary -->|Yes| SendHighCO2NotificationPrimary[Send High CO2 Notification] - SendHighCO2NotificationPrimary --> TurnOffControlSwitchPrimary[Turn Off CO2 Control Switch] - TurnOffControlSwitchPrimary --> CreatePersistentNotificationPrimary[Create Persistent Notification] - CreatePersistentNotificationPrimary --> SendTTSPMessagePrimary[Send TTS Message] - ValidateHighCO2Primary -->|No| End +## Helpers to create first - %% High CO2 Alert (Secondary Sensor) - HighCO2AlertSecondary --> CheckSecondarySensor{Is Secondary Sensor Defined?} - CheckSecondarySensor -->|Yes| ValidateHighCO2Secondary{Is CO2 Level Valid?} - CheckSecondarySensor -->|No| End - ValidateHighCO2Secondary -->|Yes| SendHighCO2NotificationSecondary[Send High CO2 Notification] - SendHighCO2NotificationSecondary --> TurnOffControlSwitchSecondary[Turn Off CO2 Control Switch] - TurnOffControlSwitchSecondary --> CreatePersistentNotificationSecondary[Create Persistent Notification] - CreatePersistentNotificationSecondary --> SendTTSPMessageSecondary[Send TTS Message] - ValidateHighCO2Secondary -->|No| End +Create these under **Settings → Devices & Services → Helpers** (or in YAML) before +creating the automation: - %% CO2 Control Logic - CO2ControlLogic --> ValidateCO2Values{Are CO2 Values Valid?} - ValidateCO2Values -->|Yes| CheckCO2LowerLimit{"Is CO2 Below Lower Limit
(co2_target - co2_tolerance)?"} - ValidateCO2Values -->|No| End - CheckCO2LowerLimit -->|Yes| CheckControlSwitchOff{Is CO2 Control Switch Off?} - CheckControlSwitchOff -->|Yes| TurnOnControlSwitch[Turn On CO2 Control Switch] - CheckControlSwitchOff -->|No| End - CheckCO2LowerLimit -->|No| CheckCO2UpperLimit{"Is CO2 Above Upper Limit
(co2_target + co2_tolerance)?"} - CheckCO2UpperLimit -->|Yes| CheckControlSwitchOn{Is CO2 Control Switch On?} - CheckCO2UpperLimit -->|No| End - CheckControlSwitchOn -->|Yes| TurnOffControlSwitch[Turn Off CO2 Control Switch] - CheckControlSwitchOn -->|No| End - CheckCO2UpperLimit -->|No| End +```yaml +input_number: + co2_target_input: { name: CO₂ Target Input, min: 0, max: 5000, step: 1, unit_of_measurement: ppm, mode: box } + co2_tolerance_input: { name: CO₂ Tolerance Input, min: 0, max: 1000, step: 1, unit_of_measurement: ppm, mode: box } + co2_day_target_input: { name: Daytime CO₂ Target Input, min: 0, max: 5000, step: 1, unit_of_measurement: ppm, mode: box } + co2_night_target_input:{ name: Nighttime CO₂ Target Input,min: 0, max: 5000, step: 1, unit_of_measurement: ppm, mode: box } - End[End] +input_datetime: + co2_on_time: { name: CO₂ Target On Time, has_time: true, has_date: false } + co2_off_time: { name: CO₂ Target Off Time, has_time: true, has_date: false } + low_co2_time_start: { name: Low CO₂ Alert Start Time, has_time: true, has_date: false } + low_co2_time_end: { name: Low CO₂ Alert End Time, has_time: true, has_date: false } + last_low_co2_alert: { name: Last Low CO₂ Alert Time, has_time: true, has_date: true } + last_high_co2_alert: { name: Last High CO₂ Alert Time, has_time: true, has_date: true } ``` -### **Explanation of the Diagram:** - -- **Start:** The automation begins when any of the specified triggers occur. - -- **Trigger Decision Point (B):** Determines which trigger activated the automation and directs the flow accordingly. - -#### **CO₂ Target Adjustments:** - -- **Daytime CO₂ Target Adjustment (D):** - - Gets the daytime target value. - - Checks if the value is valid. - - Sets the CO₂ target input number if valid. - -- **Nighttime CO₂ Target Adjustment (E):** - - Similar to daytime adjustment but uses the nighttime target value. - -#### **Low CO₂ Alert (F):** - -- Checks if the current time is within the low CO₂ alert window. -- Validates the CO₂ sensor value. -- If valid, sends a low CO₂ notification and adjusts lights to the specified low brightness. - -#### **High CO₂ Alert (Primary Sensor) (G):** - -- Validates the CO₂ level from the primary sensor. -- If valid, performs the following actions: - - Sends a high CO₂ notification with CO₂ levels. - - Turns off the CO₂ control switch. - - Creates a persistent notification. - - Sends a TTS message. - -#### **High CO₂ Alert (Secondary Sensor) (H):** - -- Checks if the secondary sensor is defined. -- Validates the CO₂ level from the secondary sensor. -- If valid, performs similar actions as the primary sensor alert. - -#### **CO₂ Control Logic (C):** - -- Validates the CO₂ sensor values and input numbers. -- Checks if the CO₂ level is below the lower limit (target minus tolerance): - - If yes, and the CO₂ control switch is off, turns on the switch. -- Checks if the CO₂ level is above the upper limit (target plus tolerance): - - If yes, and the CO₂ control switch is on, turns off the switch. - -### **Notes:** - -- **Validation Steps:** At multiple points, the automation checks if values are valid (not `None`, `unknown`, or `unavailable`) before proceeding. - -- **End Nodes (I):** The automation ends if any conditions are not met or after actions are executed. - -- **Sequence Flow:** The diagram illustrates the flow of logic based on the triggers and conditions, helping to visualize how the automation processes each event. - -### **How to Use the Diagram:** - -- **Understanding Triggers:** Use the diagram to see what happens when each trigger occurs. - -- **Following the Logic:** Trace the path from the trigger through conditions and actions to understand the automation's behavior. - -- **Identifying Conditions:** The decision points (diamonds) show where the automation checks for specific conditions before proceeding. - -- **Actions:** Rectangular nodes represent actions taken by the automation. - -### **Additional Considerations:** -- **Customizing the Automation:** - - You can adjust thresholds, durations, and targets to fit your needs. - - Ensure that any changes maintain the logical flow depicted in the diagram. - -- **Testing:** - - Use the diagram as a reference when testing each part of the automation. - - Confirm that triggers and actions occur as expected. - - -Blueprint: +The two `last_*_alert` datetimes back the alert cooldowns and must have both +`has_time` and `has_date` set to `true`. + +## What it does + +The automation is one loop that runs on sensor changes, a 1-minute tick, the day/night +schedule, and the safety triggers. Each run walks these independent steps: + +1. **Day/night target** — sets `co2_target_input` to the day or night value based on the + on/off times (handles windows that cross midnight; leaves the target unchanged if the + times are unavailable). +2. **High-CO₂ safety** — if the primary sensor, or the optional backup sensor, is over its + threshold: close the CO₂ valve, notify (push + persistent + optional TTS), and stamp the + high-alert cooldown. The backup sensor is polled, so leaving it blank is safe. +3. **Relay-stuck / empty-tank safety** — if the valve has been on longer than the max + runtime, force it closed and alert. +4. **Low-CO₂ alert** — if the sensor is sustained-low inside the alert window and the + cooldown has elapsed: notify and (optionally) snapshot + dim the lights. +5. **Low-CO₂ recovery** — when CO₂ climbs back, restore the lights to their pre-dim state. +6. **Control loop** — hysteresis switching (`target ± tolerance`) with fail-safes: it will + not open the valve while either sensor reads high, closes the valve if the primary sensor + is unavailable, and treats a target of 0 (e.g. CO₂ off at night) as "hold closed". +```mermaid +graph TD + Triggers["Triggers: sensor change · 1-min tick · on/off time · low/high/recovered · valve-on too long · HA start"] --> Step1 + + Step1["1 · Day/night target adjust"] --> Step2 + Step2{"2 · Either sensor over high threshold?"} + Step2 -->|Yes| HighAct["Close valve → notify + persistent + TTS → stamp cooldown"] --> Step3 + Step2 -->|No| Step3 + + Step3{"3 · Valve on longer than max runtime?"} + Step3 -->|Yes| Stuck["Force valve closed → alert (empty tank / stuck relay)"] --> Step4 + Step3 -->|No| Step4 + + Step4{"4 · Sustained low in window + cooldown ok?"} + Step4 -->|Yes| LowAct["Notify → snapshot + dim lights → stamp cooldown"] --> Step5 + Step4 -->|No| Step5 + + Step5{"5 · Recovered trigger + snapshot exists?"} + Step5 -->|Yes| Restore["Restore lights to pre-dim brightness"] --> Step6 + Step5 -->|No| Step6 + + Step6{"6 · Control loop"} + Step6 -->|Primary unavailable| Off1["Valve OFF (fail-safe)"] + Step6 -->|Target = 0| Off2["Valve OFF (night / disabled)"] + Step6 -->|"Below target − tolerance AND not high"| On["Valve ON"] + Step6 -->|Above target + tolerance| Off3["Valve OFF"] ``` -blueprint: - name: CO₂ Control and Alerts - description: > - Controls CO₂ levels by adjusting targets at specified times, manages switches based on CO₂ readings, - sends low and high CO₂ alerts, and adjusts lights accordingly. - - **Helpers to Add:** - Copy and paste the following into your `configuration.yaml` to create the necessary helpers. - - ```yaml - input_number: - co2_target_input: - name: CO₂ Target Input - min: 0 - max: 5000 - step: 1 - unit_of_measurement: 'ppm' - co2_tolerance_input: - name: CO₂ Tolerance Input - min: 0 - max: 1000 - step: 1 - unit_of_measurement: 'ppm' - co2_day_target_input: - name: Daytime CO₂ Target Input - min: 0 - max: 5000 - step: 1 - unit_of_measurement: 'ppm' - co2_night_target_input: - name: Nighttime CO₂ Target Input - min: 0 - max: 5000 - step: 1 - unit_of_measurement: 'ppm' - - input_datetime: - co2_on_time: - name: CO₂ Target On Time - has_time: true - has_date: false - co2_off_time: - name: CO₂ Target Off Time - has_time: true - has_date: false - low_co2_time_start: - name: Low CO₂ Alert Start Time - has_time: true - has_date: false - low_co2_time_end: - name: Low CO₂ Alert End Time - has_time: true - has_date: false - ``` - - **Explanation:** - - This blueprint performs the following functions: - - 1. **CO₂ Target Adjustment:** - - Adjusts the CO₂ target at specified times using `input_datetime` helpers. - - Daytime and nighttime targets are set using `input_number` helpers. - - 2. **CO₂ Control Logic:** - - Monitors a CO₂ sensor and controls a switch based on CO₂ levels, target, and tolerance. - - The switch turns on when CO₂ is below the lower limit and off when above the upper limit. - 3. **Low CO₂ Alert:** - - Sends notifications and dims specified lights when CO₂ levels are below a threshold during a specified time window. +## Notes - 4. **High CO₂ Alert:** - - Sends notifications, turns off a switch, and sends a TTS message when CO₂ levels exceed certain thresholds. - - Supports monitoring a secondary CO₂ sensor for high CO₂ alerts. - - **Features:** - - - **Dynamic Scheduling:** Adjusts CO₂ targets based on user-defined times. - - **Customizable Thresholds:** Set your own CO₂ targets, tolerances, and alert thresholds. - - **Notifications:** Receive alerts via multiple notification services. - - **Light Control:** Automatically dims lights when CO₂ is low. - - **Text-To-Speech Alerts:** Get audible alerts when CO₂ levels are high. - - **Limitations and Gotchas:** - - - **Ensure Helpers Exist:** All `input_number` and `input_datetime` helpers must be created as specified. - - **Time Format:** `input_datetime` helpers must have `has_time: true` and `has_date: false`. - - **Notification Services:** Must select valid notification and TTS services using entity selectors. - - **Entity IDs:** Verify that all entity IDs used in the automation exist in your Home Assistant setup. - - **Automation Mode:** The automation is set to `mode: restart` to ensure timely execution but may interrupt ongoing actions. - - **Usage:** - - - **Import the Blueprint:** Follow the instructions below to add this blueprint to your Home Assistant. - - **Create an Automation:** Use the blueprint to create an automation, filling in all required fields. - - **Adjust Helpers:** Set your desired CO₂ targets, tolerances, and times using the helpers. - - **Test the Automation:** Verify that all parts of the automation work as expected. - - **Important Considerations:** - - - **Testing:** It's recommended to test each feature individually before relying on the automation. - - **Time Zones:** Ensure your Home Assistant time zone settings are correct to avoid scheduling issues. - - **Service Compatibility:** Ensure that your selected notification and TTS services support the data parameters used. - - **Entity Verification:** Double-check that all entity IDs selected during blueprint instantiation exist and are correctly configured in your Home Assistant setup. - - domain: automation - input: - co2_sensor: - name: CO₂ Sensor - description: The primary CO₂ sensor entity to monitor. - selector: - entity: - domain: sensor - co2_sensor_secondary: - name: Secondary CO₂ Sensor (Optional) - description: > - A secondary CO₂ sensor entity to monitor for high CO₂ alerts. Leave blank if not used. - default: '' - selector: - entity: - domain: sensor - co2_target_input: - name: CO₂ Target Input Number - description: The input_number entity for the current CO₂ target. - selector: - entity: - domain: input_number - co2_tolerance_input: - name: CO₂ Tolerance Input Number - description: The input_number entity for CO₂ tolerance. - selector: - entity: - domain: input_number - co2_day_target_input: - name: Daytime CO₂ Target Input Number - description: The input_number entity for the daytime CO₂ target. - selector: - entity: - domain: input_number - co2_night_target_input: - name: Nighttime CO₂ Target Input Number - description: The input_number entity for the nighttime CO₂ target. - selector: - entity: - domain: input_number - co2_on_time: - name: CO₂ Target On Time - description: The input_datetime entity for when to set the daytime CO₂ target. - selector: - entity: - domain: input_datetime - co2_off_time: - name: CO₂ Target Off Time - description: The input_datetime entity for when to set the nighttime CO₂ target. - selector: - entity: - domain: input_datetime - co2_control_switch: - name: CO₂ Control Switch - description: The switch to control based on CO₂ levels. - selector: - entity: - domain: switch - low_co2_threshold: - name: Low CO₂ Threshold - description: The CO₂ level below which to trigger a low CO₂ alert. - default: 600 - selector: - number: - min: 0 - max: 2000 - unit_of_measurement: ppm - mode: box - low_co2_duration: - name: Low CO₂ Duration (Minutes) - description: Duration for CO₂ level to be below threshold before alerting. - default: 1 - selector: - number: - min: 0 - max: 60 - unit_of_measurement: minutes - mode: box - low_co2_lights: - name: Lights to Adjust on Low CO₂ - description: Lights to dim when CO₂ is low. - selector: - target: - entity: - domain: light - low_co2_brightness_pct: - name: Low CO₂ Brightness Percentage - description: Brightness percentage to set the lights to when CO₂ is low. - default: 60 - selector: - number: - min: 0 - max: 100 - unit_of_measurement: "%" - mode: slider - low_co2_time_start: - name: Low CO₂ Alert Start Time - description: Input_datetime for the start time of low CO₂ alert period. - selector: - entity: - domain: input_datetime - low_co2_time_end: - name: Low CO₂ Alert End Time - description: Input_datetime for the end time of low CO₂ alert period. - selector: - entity: - domain: input_datetime - high_co2_threshold: - name: High CO₂ Threshold - description: The CO₂ level above which to trigger a high CO₂ alert. - default: 1800 - selector: - number: - min: 0 - max: 5000 - unit_of_measurement: ppm - mode: box - high_co2_duration: - name: High CO₂ Duration (Seconds) - description: Duration for CO₂ level to be above threshold before alerting. - default: 11 - selector: - number: - min: 0 - max: 600 - unit_of_measurement: seconds - mode: box - high_co2_threshold_secondary: - name: High CO₂ Threshold (Secondary Sensor) - description: The CO₂ level above which to trigger a high CO₂ alert from the secondary sensor. - default: 2500 - selector: - number: - min: 0 - max: 5000 - unit_of_measurement: ppm - mode: box - high_co2_duration_secondary: - name: High CO₂ Duration (Secondary Sensor) (Seconds) - description: Duration for CO₂ level to be above threshold before alerting (secondary sensor). - default: 11 - selector: - number: - min: 0 - max: 600 - unit_of_measurement: seconds - mode: box - notification_service: - name: Notification Service - description: The notification services to send alerts to. - selector: - entity: - domain: notify - multiple: true - tts_notification_service: - name: TTS Notification Service - description: The TTS service to send audible alerts. - selector: - entity: - domain: tts - notification_title_low: - name: Low CO₂ Notification Title - description: Title for low CO₂ notifications. - default: "CO₂ LOW" - selector: - text: - notification_message_low: - name: Low CO₂ Notification Message - description: Message for low CO₂ notifications. - default: "CO₂ is low, lights have been dimmed to {{ low_co2_brightness_pct }}%" - selector: - text: - notification_title_high: - name: High CO₂ Notification Title - description: Title for high CO₂ notifications. - default: "High CO₂ Alert" - selector: - text: - notification_message_high: - name: High CO₂ Notification Message - description: Message for high CO₂ notifications. - default: "High CO₂ levels detected." - selector: - text: - tts_message_high: - name: High CO₂ TTS Message - description: Message for Text-To-Speech when high CO₂ detected. - default: "Attention: CO₂ levels are high." - selector: - text: - -mode: restart -max_exceeded: silent -trigger: - # CO₂ Sensor or Input Numbers Change (Control Logic) - - platform: state - entity_id: !input co2_sensor - id: co2_sensor_state_change - - platform: state - entity_id: !input co2_target_input - id: co2_target_state_change - - platform: state - entity_id: !input co2_tolerance_input - id: co2_tolerance_state_change - # Time Triggers for Target Adjustment - - platform: time - at: !input co2_on_time - id: co2_on_time_trigger - - platform: time - at: !input co2_off_time - id: co2_off_time_trigger - # Low CO₂ Alert Trigger - - platform: numeric_state - entity_id: !input co2_sensor - below: !input low_co2_threshold - for: - minutes: !input low_co2_duration - id: low_co2_alert_trigger - # High CO₂ Alert Trigger (Primary Sensor) - - platform: numeric_state - entity_id: !input co2_sensor - above: !input high_co2_threshold - for: - seconds: !input high_co2_duration - id: high_co2_alert_trigger - # High CO₂ Alert Trigger (Secondary Sensor) - - platform: numeric_state - entity_id: !input co2_sensor_secondary - above: !input high_co2_threshold_secondary - for: - seconds: !input high_co2_duration_secondary - id: high_co2_alert_trigger_secondary -conditions: [] -action: - - choose: - # Daytime CO₂ Target Adjustment - - conditions: - - condition: trigger - id: co2_on_time_trigger - sequence: - - variables: - target_value: "{{ states('!input co2_day_target_input') | float(0) }}" - - condition: template - value_template: "{{ target_value > 0 }}" - - service: input_number.set_value - target: - entity_id: !input co2_target_input - data: - value: "{{ target_value }}" - # Nighttime CO₂ Target Adjustment - - conditions: - - condition: trigger - id: co2_off_time_trigger - sequence: - - variables: - target_value: "{{ states('!input co2_night_target_input') | float(0) }}" - - condition: template - value_template: "{{ target_value > 0 }}" - - service: input_number.set_value - target: - entity_id: !input co2_target_input - data: - value: "{{ target_value }}" - # Low CO₂ Alert - - conditions: - - condition: trigger - id: low_co2_alert_trigger - - condition: template - value_template: > - {% set time_now = now().time() %} - {% set time_start_str = states('!input low_co2_time_start') %} - {% set time_end_str = states('!input low_co2_time_end') %} - {% set time_start = strptime(time_start_str, '%H:%M') %} - {% set time_end = strptime(time_end_str, '%H:%M') %} - {% set start_time = time_start.time() %} - {% set end_time = time_end.time() %} - {{ start_time <= time_now <= end_time }} - - condition: template - value_template: "{{ states('!input co2_sensor') | float(0) < low_co2_threshold }}" - sequence: - - repeat: - for_each: "{{ notification_service }}" - sequence: - - service: "{{ repeat.item }}" - data: - title: "{{ notification_title_low }}" - message: "{{ notification_message_low }}" - - service: light.turn_on - target: !input low_co2_lights - data: - brightness_pct: "{{ low_co2_brightness_pct }}" - # High CO₂ Alert (Primary Sensor) - - conditions: - - condition: trigger - id: high_co2_alert_trigger - sequence: - - variables: - co2_level: "{{ states('!input co2_sensor') | float(0) }}" - co2_sensor_name: "{{ state_attr('!input co2_sensor', 'friendly_name') or '!input co2_sensor' }}" - - condition: template - value_template: "{{ co2_level > high_co2_threshold }}" - - repeat: - for_each: "{{ notification_service }}" - sequence: - - service: "{{ repeat.item }}" - data: - title: "{{ notification_title_high }}" - message: > - {{ co2_sensor_name }} CO₂ level: {{ co2_level }} ppm. - - service: switch.turn_off - target: - entity_id: !input co2_control_switch - - service: persistent_notification.create - data: - title: "{{ notification_title_high }}" - message: "{{ co2_sensor_name }} CO₂ level: {{ co2_level }} ppm." - - service: !input tts_notification_service - data: - message: "{{ tts_message_high }}" - # High CO₂ Alert (Secondary Sensor) - - conditions: - - condition: trigger - id: high_co2_alert_trigger_secondary - - condition: template - value_template: "{{ co2_sensor_secondary != '' }}" - sequence: - - variables: - co2_level_secondary: "{{ states('!input co2_sensor_secondary') | float(0) }}" - co2_sensor_secondary_name: "{{ state_attr('!input co2_sensor_secondary', 'friendly_name') or '!input co2_sensor_secondary' }}" - - condition: template - value_template: "{{ co2_level_secondary > high_co2_threshold_secondary }}" - - repeat: - for_each: "{{ notification_service }}" - sequence: - - service: "{{ repeat.item }}" - data: - title: "{{ notification_title_high }}" - message: > - {{ co2_sensor_secondary_name }} CO₂ level: {{ co2_level_secondary }} ppm. - - service: switch.turn_off - target: - entity_id: !input co2_control_switch - - service: persistent_notification.create - data: - title: "{{ notification_title_high }}" - message: "{{ co2_sensor_secondary_name }} CO₂ level: {{ co2_level_secondary }} ppm." - - service: !input tts_notification_service - data: - message: "{{ tts_message_high }}" - default: - # CO₂ Control Logic - - variables: - co2_value: "{{ states('!input co2_sensor') | float(0) }}" - co2_target: "{{ states('!input co2_target_input') | float(0) }}" - co2_tolerance: "{{ states('!input co2_tolerance_input') | float(0) }}" - - condition: template - value_template: > - {{ co2_value > 0 and co2_target > 0 and co2_tolerance > 0 }} - - variables: - co2_lower_limit: "{{ co2_target - co2_tolerance }}" - co2_upper_limit: "{{ co2_target + co2_tolerance }}" - - choose: - - conditions: - - condition: template - value_template: "{{ co2_value < co2_lower_limit }}" - - condition: state - entity_id: !input co2_control_switch - state: 'off' - sequence: - - service: switch.turn_on - target: - entity_id: !input co2_control_switch - - conditions: - - condition: template - value_template: "{{ co2_value > co2_upper_limit }}" - - condition: state - entity_id: !input co2_control_switch - state: 'on' - sequence: - - service: switch.turn_off - target: - entity_id: !input co2_control_switch -``` +- **Interface changed in the 2024.10 rewrite.** If you imported an earlier version, + re-import: `high_co2_duration_secondary` and `tts_service_name` were removed; + `max_co2_on_minutes` and a `tts_engine` entity were added; the lights input is now an + entity list (was a target); TTS uses `tts.speak` and notifications use + `notify.send_message`. +- Enable **TTS** only after picking a `tts_engine` and media player, or leave it off. +- See [`../blueprints/README.md`](../blueprints/README.md) for the full blueprint set and the + helpers each one needs.