透過Home Assistant實做魚缸的監控與輔助管理之三:實現輔助管理

因篇幅關係,拆成以下幾篇易於閱讀。

本篇文章來記錄一下在Home Assistant中的各種sensor、script與automation,以及自訂義的timer、input_number與input_boolean,開始之前先講三個前提。

前提一:在Home Assistant裡,我有將configuration.yaml中的各種區塊獨立出來,這樣比較方便管理。

automation: !include automations.yaml
binary_sensor: !include binary_sensor.yaml
input_boolean: !include input_boolean.yaml
input_number: !include input_number.yaml
mqtt: !include mqtt.yaml
script: !include scripts.yaml
sensor: !include sensor.yaml
sql: !include sql.yaml
timer: !include timer.yaml

前提二:需要紀錄的事項會透過notify.notify_line_aquarium(快要停止服務了)把訊息發送到line上,以及透過script.aquarium_logger將訊息寫入文字檔裡,文字檔可轉成網頁並放在lovelace中,詳細介紹可以參考Home Assistant中利用iframe card將文字檔內容嵌入lovelace的方法

雖然是在automation中用到notify.send_message就可以,但因為寫入檔案的訊息前面我都會加上日期時間戳記,所以獨立出一個script.aquarium_logger統一處理日期時間戳記,可以省去不少維護的麻煩,其中{{ msg }}是從automation或script中帶過來的變數。

aquarium_logger:
  alias: Aquarium_Logger
  sequence:
    - action: notify.send_message
      target:
        entity_id: notify.aquarium
      data:
        message: "{{ now().strftime('%Y/%m/%d %H:%M:%S') }} → {{ msg }}"

前提三:篇幅的關係,操作介面的東西擺在另一篇文章中,本文中如果有看起來很累贅的sensor或其他東西,可能是在操作介面中會用到,也有可能是我寫程式的當下頭腦不清楚。另外本文的索引如下

水溫相關

以下二個MQTT sensor是從ESP32發佈的topic中取得的資料原始值

  - name: Aquarium_MainTank_WaterTemperature
    state_topic: "aquarium/maintank/water_temperature"
    value_template: "{{ value }}"
    unit_of_measurement: "°C"
  - name: Aquarium_Bucket_WaterTemperature
    state_topic: "aquarium/bucket/water_temperature"
    value_template: "{{ value }}"
    unit_of_measurement: "°C"

如果ESP32收不到來自DS18B20水溫線的資料,溫度會顯示-127°C,在長時間的溫度追蹤裡會將這種資料移除,並配合automation做警示。

- platform: template
  sensors:
    aquarium_maintank_watertemperature_rendering:
      friendly_name: Aquarium_MainTank_WaterTemperature_Rendering
      value_template: >-
        {% if states('sensor.aquarium_maintank_watertemperature') | float != -127 %}
          {{ states('sensor.aquarium_maintank_watertemperature') }}
        {% endif %}
      unit_of_measurement: "°C"
- platform: template
  sensors:
    aquarium_bucket_watertemperature_rendering:
      friendly_name: Aquarium_Bucket_WaterTemperature_Rendering
      value_template: >-
        {% if states('sensor.aquarium_bucket_watertemperature') | float != -127 %}
          {{ states('sensor.aquarium_bucket_watertemperature') }}
        {% endif %}
      unit_of_measurement: "°C"
- alias: Aquarium:Invalid_WaterTemperature_Alarm
  triggers:
    - trigger: template
      value_template: "{{ states('sensor.aquarium_maintank_watertemperature') | int == -127 or states('sensor.aquarium_bucket_watertemperature') | int == -127 }}"
  actions:
    - variables:
        message: >
          {% if trigger.entity_id == "sensor.aquarium_maintank_watertemperature" %} 主缸水溫線異常。
          {% elif trigger.entity_id == "sensor.aquarium_bucket_watertemperature" %} 補水桶水溫線異常。
          {% else %} 請檢查水溫線。
          {% endif %}
    - action: notify.notify_line_aquarium
      data:
        message: "{{ message }}"
    - action: script.turn_on
      target:
        entity_id: script.aquarium_logger
      data:
        variables:
          msg: "{{ message }}"

利用二個input_number定義出正常水溫的上下限

aquarium_maintank_watertemperature_max:
  name: Aquarium_MainTank_WaterTemperature_Max
  min: 26
  max: 35
  step: 0.5
  unit_of_measurement: "°C"
aquarium_maintank_watertemperature_min:
  name: Aquarium_MainTank_WaterTemperature_Min
  min: 17
  max: 26
  step: 0.5
  unit_of_measurement: "°C"

當水溫超出上限或低於下限時啟動binary_sensor

- platform: template
  sensors:
    aquarium_watertemperature_alarm:
      friendly_name: Aquarium_WaterTemperature_Alarm
      value_template: >
        {{ states('sensor.aquarium_maintank_watertemperature_rendering') | float(default=0) > states('input_number.aquarium_maintank_watertemperature_max') | float(default=0) or states('sensor.aquarium_maintank_watertemperature_rendering') | float(default=0) <= states('input_number.aquarium_maintank_watertemperature_min') | float(default=0) }}

當水溫超出上下限的第五分鐘會發佈第一條警報,之後每半小時檢查一次,若還是超出上下限就再發一條警報,避免水溫在界限附近可能會頻繁地收到太多警報。

- alias: Aquarium:WaterTemperature_Alarm
  triggers:
    - trigger: state
      entity_id: binary_sensor.aquarium_watertemperature_alarm
      from: "off"
      to: "on"
      for:
        minutes: 5
  conditions:
    - condition: template
      value_template: "{{ states('sensor.aquarium_maintank_watertemperature_rendering') != 'unavailable' }}"
  actions:
    - alias: repeat
      repeat:
        while:
          - condition: state
            entity_id: binary_sensor.aquarium_watertemperature_alarm
            state: "on"
        sequence:
          - action: notify.notify_line_aquarium
            data:
              message: >
                水溫超出上下限,目前為{{ states('sensor.aquarium_maintank_watertemperature_rendering') }}。
          - action: script.turn_on
            target:
              entity_id: script.aquarium_logger
            data:
              variables:
                msg: >
                  水溫超出上下限,目前為{{ states('sensor.aquarium_maintank_watertemperature_rendering') }}。
          - delay:
              minutes: 30
  mode: restart

金魚是冷水魚,不怕高溫低溫,但怕溫度急遽地改變,所以監測主缸水溫一小時內的變化。這個沒有現成的sensor平台可以處理,只能從資料庫裡查詢最大值與最小值後相減。

- name: Aquarium_MainTank_WaterTemperature_1HR_Range
  query: >
    SELECT
      MAX(CAST(states.state AS DECIMAL(5,2))) - MIN(CAST(states.state AS DECIMAL(5,2))) AS result
    FROM
      states
      INNER JOIN states_meta ON
        states.metadata_id = states_meta.metadata_id
    WHERE
      states_meta.entity_id = 'sensor.aquarium_maintank_watertemperature_rendering'
      AND FROM_UNIXTIME(last_updated_ts) >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
      AND states.state != 'unavailable'
      AND states.state != 'unknown';
  column: "result"
  unit_of_measurement: "°C"

給一個input_number當警示的上限,溫差是取差值的絕對值且愈小愈好,所以這個沒有下限。

aquarium_maintank_watertemperature_1hr_range_max:
  name: Aquarium_MainTank_WaterTemperature_1HR_Range_Max
  min: 0
  max: 5
  step: 0.1
  unit_of_measurement: "°C"

若溫差超過上限,則binary_sensor為on。

- platform: template
  sensors:
    aquarium_maintank_watertemperature_1hr_range_alarm:
      friendly_name: Aquarium_MainTank_WaterTemperature_1HR_Range_Alarm
      value_template: >
        {{ (states('sensor.aquarium_maintank_watertemperature_1hr_range') | float(default=0) | abs) > (states('input_number.aquarium_maintank_watertemperature_1hr_range_max') | float(default=0)) }}

一樣是發警報,再依情況看要怎麼處置。

- alias: Aquarium:MainTank_WaterTemperature_1HR_Range_Alarm
  triggers:
    - trigger: state
      entity_id: binary_sensor.aquarium_maintank_watertemperature_1hr_range_alarm
      from: "off"
      to: "on"
      for:
        minutes: 5
  actions:
    - variables:
        message: 主缸一小時溫差過大。
    - action: notify.notify_line_aquarium
      data:
        message: "{{ message }}"
    - action: script.turn_on
      target:
        entity_id: script.aquarium_logger
      data:
        variables:
          msg: "{{ message }}"

一樣是溫度急遽地改變的問題,所以自動補水或手動補水前需要確認主缸與補水桶間的溫差,這在後面補水相關再提,其他的與前面邏輯雷同。

- platform: template
  sensors:
    aquarium_watertemperature_gap:
      value_template: >
        {{ (states('sensor.aquarium_maintank_watertemperature_rendering') | float - states('sensor.aquarium_bucket_watertemperature_rendering') | float) | round(2) }}
      unit_of_measurement: "°C"
- platform: template
  sensors:
    aquarium_watertemperature_gap_alarm:
      friendly_name: Aquarium_WaterTemperature_Gap_Alarm
      value_template: >
        {{ states('sensor.aquarium_watertemperature_gap') | float(default=0) > states('input_number.aquarium_watertemperature_gap_max') | float(default=0) }}
- alias: Aquarium:WaterTemperature_Gap_Alarm
  triggers:
    - trigger: state
      entity_id: binary_sensor.aquarium_watertemperature_gap_alarm
      from: "off"
      to: "on"
      for:
        minutes: 5
  actions:
    - variables:
        message: 主缸與補水桶的溫差過大。
    - action: notify.notify_line_aquarium
      data:
        message: "{{ message }}"
    - action: script.turn_on
      target:
        entity_id: script.aquarium_logger
      data:
        variables:
          msg: "{{ message }}"

pH值相關

ESP32可以從pH模組得到pH探棒的電壓值,做完電壓值對pH值的校正後,電壓值才能轉為pH值。校正的參數可以寫在ESP32中,但這樣每校一次都需要做ESP32的更新,這樣有點麻煩,我的做法是把參數放在Home Assistant的input_number中,當參數改變時會發佈MQTT的訊息,ESP32再去更新校正的參數即可。

aquarium_ph_slope:
  name: Aquarium_pH_Slope
  min: -10
  max: 0
  step: 0.0001

aquarium_ph_intercept:
  name: Aquarium_pH_Intercept
  min: -100
  max: 100
  step: 0.0001
- alias: Aquarium:Update_pH_Calibration_Slope
  triggers:
    - trigger: state
      entity_id: input_number.aquarium_ph_slope
      for:
        seconds: 5
  actions:
    - action: mqtt.publish
      data:
        topic: "aquarium/others/ph_slope"
        payload: "{{ states('input_number.aquarium_ph_slope') }}"
        qos: 1
        retain: true
    - action: script.turn_on
      target:
        entity_id: script.aquarium_logger
      data:
        variables:
          msg: >
            pH校正斜率從{{ trigger.from_state.state }}更改至{{ trigger.to_state.state }}

- alias: Aquarium:Update_pH_Calibration_Intercept
  triggers:
    - trigger: state
      entity_id: input_number.aquarium_ph_intercept
      for:
        seconds: 5
  actions:
    - action: mqtt.publish
      data:
        topic: "aquarium/others/ph_intercept"
        payload: "{{ states('input_number.aquarium_ph_intercept') }}"
        qos: 1
        retain: true
    - action: script.turn_on
      target:
        entity_id: script.aquarium_logger
      data:
        variables:
          msg: >
            pH校正截距從{{ trigger.from_state.state }}更改至{{ trigger.to_state.state }}

pH值本身沒有單位,但若不給個空白單位,在Home Assistant中的歷史資料不會以折線圖表示。

  - name: Aquarium_MainTank_PH
    state_topic: "aquarium/maintank/ph"
    value_template: "{{ value }}"
    unit_of_measurement: ""

這個pH模組我用起來覺得讀值不太穩定,雖然在ESP32中已經做過多點取樣平均的動作,但還是偶爾會看到奇異點的出現。原始值拉進來後我做一個合理性的改寫,先取得過去一小時的平均值與標準差,這個只能用SQL來做。

- name: Aquarium_pH_Average_1HR
  query: >
    SELECT
      CAST(AVG(states.state) AS DECIMAL(5,2)) AS result
    FROM
      states
      INNER JOIN states_meta ON
        states.metadata_id = states_meta.metadata_id
    WHERE
      states_meta.entity_id = 'sensor.aquarium_maintank_ph'
      AND FROM_UNIXTIME(last_updated_ts) >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
      AND states.state != 'unavailable'
      AND states.state != 'unknown';
  column: "result"
  unit_of_measurement: ""

- name: Aquarium_pH_StandDev_1HR
  query: >
    SELECT
      CAST(STDDEV(states.state) AS DECIMAL(5,2)) AS result
    FROM
      states
      INNER JOIN states_meta ON
        states.metadata_id = states_meta.metadata_id
    WHERE
      states_meta.entity_id = 'sensor.aquarium_maintank_ph'
      AND FROM_UNIXTIME(last_updated_ts) >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
      AND states.state != 'unavailable'
      AND states.state != 'unknown';
  column: "result"
  unit_of_measurement: ""

再將原始讀值超過平均值加減三倍標準差的值給排除,這裡用template sensor來做。

- platform: template
  sensors:
    aquarium_maintank_ph_rendering:
      friendly_name: Aquarium_MainTank_pH_Rendering
      value_template: >
        {% set ph_value = states('sensor.aquarium_maintank_ph') | float %}
        {% set avg = states('sensor.aquarium_ph_average_1hr') | float %}
        {% set stddev = states('sensor.aquarium_ph_standdev_1hr') | float %}
        {% set upper_bound = avg + 3 * stddev %}
        {% set lower_bound = avg - 3 * stddev %}
        {% if ph_value >= lower_bound and ph_value <= upper_bound %}
          {{ ph_value }}
        {% else %}
          {{ avg }}
        {% endif %}
      unit_of_measurement: ""

這樣資料會比較收斂一些。

警報的部分,與溫度警報基本上雷同,不多贅述。

aquarium_ph_max:
  name: Aquarium_pH_Max
  min: 0
  max: 14
  step: 0.1

aquarium_ph_min:
  name: Aquarium_pH_Min
  min: 0
  max: 14
  step: 0.1
- platform: template
  sensors:
    aquarium_ph_alarm:
      friendly_name: Aquarium_pH_Alarm
      value_template: >
        {{ states('sensor.aquarium_maintank_ph_rendering') | float(default=0) > states('input_number.aquarium_ph_max') | float(default=0) or states('sensor.aquarium_maintank_ph_rendering') | float(default=0) <= states('input_number.aquarium_ph_min') | float(default=0) }}
- alias: Aquarium:pH_Alarm
  triggers:
    - trigger: state
      entity_id: binary_sensor.aquarium_ph_alarm
      from: "off"
      to: "on"
      for:
        minutes: 5
  conditions:
    - condition: template
      value_template: "{{ states('sensor.aquarium_maintank_ph_rendering') != 'unavailable' }}"
  actions:
    - alias: repeat
      repeat:
        while:
          - condition: state
            entity_id: binary_sensor.aquarium_ph_alarm
            state: "on"
        sequence:
          - action: notify.notify_line_aquarium
            data:
              message: >
                pH超出上下限,目前為{{ states('sensor.aquarium_maintank_ph_rendering') }}。
          - action: script.turn_on
            target:
              entity_id: script.aquarium_logger
            data:
              variables:
                msg: >
                  pH超出上下限,目前為{{ states('sensor.aquarium_maintank_ph_rendering') }}。
          - delay:
              minutes: 30
  mode: restart

TDS值相關

  - name: Aquarium_MainTank_TDS
    state_topic: "aquarium/maintank/tds"
    value_template: "{{ value }}"
    unit_of_measurement: "ppm"

同pH,有做合理性的改寫。

- name: Aquarium_TDS_Average_1HR
  query: >
    SELECT
      CAST(AVG(states.state) AS DECIMAL(5,2)) AS result
    FROM
      states
      INNER JOIN states_meta ON
        states.metadata_id = states_meta.metadata_id
    WHERE
      states_meta.entity_id = 'sensor.aquarium_maintank_tds'
      AND FROM_UNIXTIME(last_updated_ts) >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
      AND states.state != 'unavailable'
      AND states.state != 'unknown';
  column: "result"
  unit_of_measurement: "ppm"

- name: Aquarium_TDS_StandDev_1HR
  query: >
    SELECT
      CAST(STDDEV(states.state) AS DECIMAL(5,2)) AS result
    FROM
      states
      INNER JOIN states_meta ON
        states.metadata_id = states_meta.metadata_id
    WHERE
      states_meta.entity_id = 'sensor.aquarium_maintank_tds'
      AND FROM_UNIXTIME(last_updated_ts) >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
      AND states.state != 'unavailable'
      AND states.state != 'unknown';
  column: "result"
  unit_of_measurement: "ppm"
- platform: template
  sensors:
    aquarium_maintank_tds_rendering:
      friendly_name: Aquarium_MainTank_TDS_Rendering
      value_template: >-
        {% set tds_value = states('sensor.aquarium_maintank_tds') | float %}
        {% set avg = states('sensor.aquarium_tds_average_1hr') | float %}
        {% set stddev = states('sensor.aquarium_tds_standdev_1hr') | float %}
        {% set upper_bound = avg + 3 * stddev %}
        {% set lower_bound = avg - 3 * stddev %}
        {% if tds_value >= lower_bound and tds_value <= upper_bound %}
          {{ tds_value }}
        {% else %}
          {{ avg }}
        {% endif %}
      unit_of_measurement: "ppm"
aquarium_tds_max:
  name: Aquarium_TDS_Max
  min: 100
  max: 300
  step: 5
  unit_of_measurement: "ppm"
aquarium_tds_min:
  name: Aquarium_TDS_Min
  min: 100
  max: 300
  step: 5
  unit_of_measurement: "ppm"
- platform: template
  sensors:
    aquarium_tds_alarm:
      friendly_name: Aquarium_TDS_Alarm
      value_template: >
        {{ states('sensor.aquarium_maintank_tds_rendering') | float(default=0) > states('input_number.aquarium_tds_max') | float(default=0) or states('sensor.aquarium_maintank_tds_rendering') | float(default=0) <= states('input_number.aquarium_tds_min') | float(default=0) }}
- alias: Aquarium:TDS_Alarm
  triggers:
    - trigger: state
      entity_id: binary_sensor.aquarium_tds_alarm
      from: "off"
      to: "on"
      for:
        minutes: 5
  conditions:
    - condition: template
      value_template: "{{ states('sensor.aquarium_maintank_tds_rendering') != 'unavailable' }}"
  actions:
    - alias: repeat
      repeat:
        while:
          - condition: state
            entity_id: binary_sensor.aquarium_tds_alarm
            state: "on"
        sequence:
          - action: notify.notify_line_aquarium
            data:
              message: >
                TDS超出上下限,目前為{{ states('sensor.aquarium_maintank_tds_rendering') }}。
          - action: script.turn_on
            target:
              entity_id: script.aquarium_logger
            data:
              variables:
                msg: >
                  TDS超出上下限,目前為{{ states('sensor.aquarium_maintank_tds_rendering') }}。
          - delay:
              minutes: 30
  mode: restart

控制器狀態

家裡的路由器是Mikrotik,Home Assistant HACS中有對應的integration可以使用,該integration中有監測裝置是否離線的功能。因為監測資料都是ESP32來的,如果斷線或是無線網路不穩定,可能會有疑慮。

- alias: Aquarium:Controller_Offline
  triggers:
    - trigger: state
      entity_id:
        - device_tracker.093_a340
        - device_tracker.094_ebdc
      from: "home"
      to: "not_home"
      for:
        minutes: 3
  actions:
    - variables:
        message: >
          {% if trigger.entity_id == "device_tracker.093_a340" %} 主控制器離線。
          {% elif trigger.entity_id == "device_tracker.094_ebdc" %} 副控制器離線。
          {% else %} 未知的控制器狀態變化。
          {% endif %}
    - alias: repeat
      repeat:
        while:
          - condition: template
            value_template: "{{ states('sdevice_tracker.093_a340') == 'not_home' or states('sdevice_tracker.094_ebdc') == 'not_home' }}"
        sequence:
          - action: notify.notify_line_aquarium
            data:
              message: "{{ message }}"
          - action: script.turn_on
            target:
              entity_id: script.aquarium_logger
            data:
              variables:
                msg: "{{ message }}"
          - delay:
              minutes: 30
  mode: restart

維護模式

一個簡單的input_boolean,使用者可以自行開啟關閉。

aquarium_maintenance:
  name: Aquarium_Maintenance

我的魚缸有個上蓋,上蓋邊緣跟主缸有一個門窗感應器來判斷上蓋有沒有被拿起,當上蓋拿起來的時候通常就是要維護的時候,所以會自動觸發維護模式。

- alias: Aquarium:Maintenance_AutoOn
  triggers:
    - trigger: state
      entity_id: binary_sensor.aquarium_tankcover_contactsensor_contact
      from: "off"
      to: "on"
      for:
        seconds: 3
  conditions:
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
  actions:
    - action: input_boolean.turn_on
      entity_id: input_boolean.aquarium_maintenance
  mode: queued

- alias: Aquarium:Maintenance_AutoOff
  triggers:
    - trigger: state
      entity_id: binary_sensor.aquarium_tankcover_contactsensor_contact
      from: "on"
      to: "off"
      for:
        seconds: 3
  conditions:
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "on"
  actions:
    - action: input_boolean.turn_off
      entity_id: input_boolean.aquarium_maintenance
  mode: queued

維護模式觸發後,會把魚缸燈和加熱棒關掉,並且開啟該區域的照明燈方便作業並停用該區域的燈光自動化。

- alias: Aquarium:Maintenance_Mode_On
  triggers:
    - trigger: state
      entity_id: input_boolean.aquarium_maintenance
      from: "off"
      to: "on"
  actions:
    - variables:
        message: 維護模式開啟。
    - action: switch.turn_off
      entity_id:
        - switch.gosund_powerstrip_aquarium_switch1
        - switch.gosund_powerstrip_aquarium_switch4
    - action: input_boolean.turn_off
      entity_id: input_boolean.light_automation_restaurant
    - action: light.turn_on
      entity_id:
        - light.restaurant
    - action: notify.notify_line_aquarium
      data:
        message: "{{ message }}"
    - action: script.turn_on
      target:
        entity_id: script.aquarium_logger
      data:
        variables:
          msg: "{{ message }}"
  mode: queued

- alias: Aquarium:Maintenance_Mode_Off
  triggers:
    - trigger: state
      entity_id: input_boolean.aquarium_maintenance
      from: "on"
      to: "off"
  actions:
    - variables:
        message: 維護模式關閉。
    - action: input_boolean.turn_on
      entity_id: input_boolean.light_automation_restaurant
    - action: light.turn_off
      entity_id:
        - light.restaurant
    - action: notify.notify_line_aquarium
      data:
        message: "{{ message }}"
    - action: script.turn_on
      target:
        entity_id: script.aquarium_logger
      data:
        variables:
          msg: "{{ message }}"
  mode: queued

設備相關

燈光在非維護模式下,14:00開燈到22:00。

- alias: Aquarium:Light_AutoOn
  triggers:
    - trigger: time
      at: "14:00:00"
  conditions:
    - condition: state
      entity_id: switch.gosund_powerstrip_aquarium_switch1
      state: "off"
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
  actions:
    - action: switch.turn_on
      data: {}
      entity_id: switch.gosund_powerstrip_aquarium_switch1
  mode: queued

- alias: Aquarium:Light_AutoOff
  triggers:
    - trigger: time
      at: "22:00:00"
  conditions:
    - condition: state
      entity_id: switch.gosund_powerstrip_aquarium_switch1
      state: "on"
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
  actions:
    - action: switch.turn_off
      data: {}
      entity_id: switch.gosund_powerstrip_aquarium_switch1
  mode: queued

補水馬達在補水桶水位過低時,應該被切斷電源。

- alias: Aquarium:RefillWater_Pump_TurnOff_When_WaterLowLevel
  triggers:
    - trigger: state
      entity_id: input_number.aquarium_bucket_waterlevel
      from: "2"
      to: "1"
  actions:
    - action: switch.turn_off
      entity_id: switch.gosund_powerstrip_aquarium_switch2
  mode: queued

沉水馬達在沉馬格水位過低時,應該被切斷電源。

- alias: Aquarium:Submersible_Pump_TurnOff_When_WaterLowLevel
  triggers:
    - trigger: state
      entity_id: input_number.aquarium_pumptank_waterlevel
      from: "0.5"
      to: "0"
  actions:
    - action: switch.turn_off
      entity_id: switch.gosund_powerstrip_aquarium_switch3
  mode: queued

另外還做了停止後自動延遲啟動的功能,可以用在餵食或簡單的換棉。先來個倒數計時器

submersible_pump_duration:
  name: Submersible_Pump_Duration

用腳本啟動這個功能,當沉水馬達是啟動的狀態下,會開始倒數指定的時間並將沉水馬達關掉,當沉水馬達是關閉的狀態下,會直接停止計時器,並將沉水馬達的電源打開。

aquarium_pump_delay:
  alias: Aquarium_Pump_Delay
  sequence:
    - choose:
        - conditions:
            - condition: state
              entity_id: switch.gosund_powerstrip_aquarium_switch3
              state: "on"
          sequence:
            - action: timer.start
              target:
                entity_id: timer.submersible_pump_duration
              data:
                duration: >
                  00:{{ '%02d' | format(states('input_number.submersible_pump_duration') | int) }}:00
            - action: switch.turn_off
              entity_id: switch.gosund_powerstrip_aquarium_switch3
        - conditions:
            - condition: state
              entity_id: switch.gosund_powerstrip_aquarium_switch3
              state: "off"
          sequence:
            - action: timer.finish
              target:
                entity_id: timer.submersible_pump_duration
            - action: switch.turn_on
              entity_id: switch.gosund_powerstrip_aquarium_switch3

當計時器結束後就打開沉馬的電源

- alias: Aquarium:Submersible_Pump_Delay_Start
  triggers:
    - trigger: event
      event_type: timer.finished
      event_data:
        entity_id: timer.submersible_pump_duration
  actions:
    - action: switch.turn_on
      entity_id: switch.gosund_powerstrip_aquarium_switch3
  mode: queued

冷水魚會用到加溫棒的機會不大,買著防身而已,我買的加溫棒有自帶控制器,這樣等於是雙重保險。先用input_number建立加溫棒啟動跟停止的上下限

aquarium_heater_on_threshold:
  name: Aquarium_Heater_On_Threshold
  min: 20
  max: 26
  step: 0.5
  unit_of_measurement: "°C"
aquarium_heater_off_threshold:
  name: Aquarium_Heater_Off_Threshold
  min: 23
  max: 29
  step: 0.5
  unit_of_measurement: "°C"

低於下限時啟動,高於上限時停止。

- alias: Aquarium:Heater_TurnOn
  triggers:
    - trigger: numeric_state
      entity_id: sensor.aquarium_maintank_watertemperature_rendering
      below: input_number.aquarium_heater_on_threshold
      for:
        minutes: 1
  conditions:
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
    - condition: state
      entity_id: switch.gosund_powerstrip_aquarium_switch4
      state: "off"
  actions:
    - action: switch.turn_on
      entity_id: switch.gosund_powerstrip_aquarium_switch4
  mode: queued

- alias: Aquarium:Heater_TurnOff
  triggers:
    - trigger: numeric_state
      entity_id: sensor.aquarium_maintank_watertemperature_rendering
      above: input_number.aquarium_heater_off_threshold
      for:
        minutes: 1
  conditions:
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
    - condition: state
      entity_id: switch.gosund_powerstrip_aquarium_switch4
      state: "on"
  actions:
    - action: switch.turn_off
      entity_id: switch.gosund_powerstrip_aquarium_switch4
  mode: queued

自帶電池的不斷電打氣機,控制了開關也沒用,除非電池沒電不然不會停止。

跟加溫棒邏輯相同,先建立上下限

aquarium_fan_on_threshold:
  name: Aquarium_Fan_On_Threshold
  min: 26
  max: 32
  step: 0.5
  unit_of_measurement: "°C"
aquarium_fan_off_threshold:
  name: Aquarium_Fan_Off_Threshold
  min: 23
  max: 29
  step: 0.5
  unit_of_measurement: "°C"

然後自動控制

- alias: Aquarium:Fan_TurnOn
  triggers:
    - trigger: numeric_state
      entity_id: sensor.aquarium_maintank_watertemperature_rendering
      above: input_number.aquarium_fan_on_threshold
      for:
        minutes: 1
  conditions:
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
    - condition: state
      entity_id: switch.gosund_powerstrip_aquarium_switch6
      state: "off"
  actions:
    - action: switch.turn_on
      entity_id: switch.gosund_powerstrip_aquarium_switch6
  mode: queued

- alias: Aquarium:Fan_TurnOff
  triggers:
    - trigger: numeric_state
      entity_id: sensor.aquarium_maintank_watertemperature_rendering
      below: input_number.aquarium_fan_off_threshold
      for:
        minutes: 1
  conditions:
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
    - condition: state
      entity_id: switch.gosund_powerstrip_aquarium_switch6
      state: "on"
  actions:
    - action: switch.turn_off
      entity_id: switch.gosund_powerstrip_aquarium_switch6
  mode: queued

這條延長線很奇怪,除了延長線總開關外沒有控制單一插座的實體開關,如果我要手動開關插座就一定得拿手機操作,所以後來補了一個無線開關來控制燈光和風扇。

- alias: Aquarium:Button_Single
  triggers:
    - trigger: state
      entity_id: sensor.aquarium_control_wirelessbutton_action
      to: "single"
  actions:
    - action: switch.toggle
      data: {}
      entity_id: switch.gosund_powerstrip_aquarium_switch1
  mode: queued

- alias: Aquarium:Button_Hold
  triggers:
    - trigger: state
      entity_id: sensor.aquarium_control_wirelessbutton_action
      to: "hold"
  actions:
    - action: switch.toggle
      data: {}
      entity_id: switch.gosund_powerstrip_aquarium_switch6
  mode: queued

除了燈光外,其他五個插座若意外地啟動或關閉都有可能出事,所以也警報一下。

- alias: Aquarium:Device_StatusOn_Monitor
  triggers:
    - trigger: state
      entity_id:
        - switch.gosund_powerstrip_aquarium_switch2
        - switch.gosund_powerstrip_aquarium_switch3
        - switch.gosund_powerstrip_aquarium_switch4
        - switch.gosund_powerstrip_aquarium_switch5
        - switch.gosund_powerstrip_aquarium_switch6
      from: "off"
      to: "on"
  conditions:
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
  actions:
    - variables:
        message: >
          {% if trigger.entity_id == "switch.gosund_powerstrip_aquarium_switch2" %} 開始補水。
          {% elif trigger.entity_id == "switch.gosund_powerstrip_aquarium_switch3" %} 沉水馬達電源開啟。
          {% elif trigger.entity_id == "switch.gosund_powerstrip_aquarium_switch4" %} 加溫棒電源開啟。
          {% elif trigger.entity_id == "switch.gosund_powerstrip_aquarium_switch5" %} 打氣機電源開啟。
          {% elif trigger.entity_id == "switch.gosund_powerstrip_aquarium_switch6" %} 風扇電源開啟。
          {% else %} 未知的設備狀態變化。
          {% endif %}
    - action: notify.notify_line_aquarium
      data:
        message: "{{ message }}"
    - action: script.turn_on
      target:
        entity_id: script.aquarium_logger
      data:
        variables:
          msg: "{{ message }}"
  mode: queued

- alias: Aquarium:Device_StatusOff_Monitor
  triggers:
    - trigger: state
      entity_id:
        - switch.gosund_powerstrip_aquarium_switch2
        - switch.gosund_powerstrip_aquarium_switch3
        - switch.gosund_powerstrip_aquarium_switch4
        - switch.gosund_powerstrip_aquarium_switch5
        - switch.gosund_powerstrip_aquarium_switch6
      from: "on"
      to: "off"
  conditions:
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
  actions:
    - variables:
        message: >
          {% if trigger.entity_id == "switch.gosund_powerstrip_aquarium_switch2" %} 停止補水。
          {% elif trigger.entity_id == "switch.gosund_powerstrip_aquarium_switch3" %} 沉水馬達電源關閉。
          {% elif trigger.entity_id == "switch.gosund_powerstrip_aquarium_switch4" %} 加溫棒電源關閉。
          {% elif trigger.entity_id == "switch.gosund_powerstrip_aquarium_switch5" %} 打氣機電源關閉。
          {% elif trigger.entity_id == "switch.gosund_powerstrip_aquarium_switch6" %} 風扇電源關閉。
          {% else %} 未知的設備狀態變化。
          {% endif %}
    - action: notify.notify_line_aquarium
      data:
        message: "{{ message }}"
    - action: script.turn_on
      target:
        entity_id: script.aquarium_logger
      data:
        variables:
          msg: "{{ message }}"
  mode: queued

可以從插座功率跟插座開關狀態去監控設備是否失效,比如說沉水馬達正常情況功耗是35W,但在沉馬水達的插座為開的情況下,只有18W的輸出,那表示應該發生什麼事需要檢查了。但這條延長線並沒有針對單一插座做功耗監控,只有整條延長線的總功耗,雖然這樣判斷上就比較模糊一點,但還是可以做。

先計算功耗目標值,初始值設為0,再慢慢依照插座開關狀態往上加。

- platform: template
  sensors:
    aquarium_power_target:
      value_template: >
        {% set power = 0 %}
        {% if states('switch.gosund_powerstrip_aquarium_switch1') == "on" %}
          {% set power = power + 20.6 %}
        {% endif %}
        {% if states('switch.gosund_powerstrip_aquarium_switch2') == "on" %}
          {% set power = power + 25 %}
        {% endif %}
        {% if states('switch.gosund_powerstrip_aquarium_switch3') == "on" %}
          {% set power = power + 32 %}
        {% endif %}
        {% if states('switch.gosund_powerstrip_aquarium_switch4') == "on" %}
          {% set power = power + 200 %}
        {% endif %}
        {% if states('switch.gosund_powerstrip_aquarium_switch5') == "on" %}
          {% set power = power + 3 %}
        {% endif %}
        {% if states('switch.gosund_powerstrip_aquarium_switch6') == "on" %}
          {% set power = power + 3 %}
        {% endif %}
        {{ power }}

比較實際功耗與目標功耗,若「實際功耗超出1.05倍目標功耗」或是「實際功耗低於0.95倍目標功耗」那就可能有什麼問題。

- platform: template
  sensors:
    aquarium_power_check:
      value_template: >
        {{ states('sensor.gosund_powerstrip_aquarium_power') | float(default=0) <= (states('sensor.aquarium_power_target') | float(default=1))*0.95 or states('sensor.gosund_powerstrip_aquarium_power') | float(default=1) >= (states('sensor.aquarium_power_target') | float(default=0))*1.05 }}
- alias: Aquarium:Device_Power_Monitor_Fail
  triggers:
    - trigger: state
      entity_id: binary_sensor.aquarium_power_check
      from: "off"
      to: "on"
      for:
        minutes: 5
  conditions:
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
  actions:
    - variables:
        message: >
          設備功耗異常,功耗目標值為{{ states('sensor.aquarium_power_target') }},實際值為{{ states('sensor.gosund_powerstrip_aquarium_power') }}。
    - action: notify.notify_line_aquarium
      data:
        message: "{{ message }}"
    - action: script.turn_on
      target:
        entity_id: script.aquarium_logger
      data:
        variables:
          msg: "{{ message }}"
  mode: queued

自動補水

目標是要在該補水的時候判斷能不能補水,該補水的時機點是

  • 背濾沉馬格水位太低,沉馬抽不到水。
  • 背濾濾材格水位太低,水流沒經過濾材。

第二點會比第一點早發生,而如果第一點發生了,會直接把沉馬給停了避免沉馬損壞,所以觸發補水時機點用第二點來做。

補水前要先判斷適不適合補水,如果有以下情況也不適合補水

  • 主缸水位太高,那可能是棉塞住了,補了只會更高。
  • 補水桶水位太低,沒水可以補。

所以先來一個判斷水位的配套,這在之前的在Home Assistant中利用動態圖片來呈現魚缸水位的變化一文中有提到。

aquarium_bucket_waterlevel:
  name: Aquarium_Bucket_Waterlevel
  min: -1
  max: 2
  step: 0.5
aquarium_maintank_waterlevel:
  name: Aquarium_Maintank_Waterlevel
  min: -1
  max: 2
  step: 0.5
aquarium_filtertank_waterlevel:
  name: Aquarium_Filtertank_Waterlevel
  min: -1
  max: 2
  step: 0.5
aquarium_pumptank_waterlevel:
  name: Aquarium_Pumptank_Waterlevel
  min: -1
  max: 2
  step: 0.5
- alias: Aquarium:Water_Level_Rendering(Varied)
  triggers:
    - trigger: state
      entity_id:
        - sensor.aquarium_bucket_waterlevel
        - sensor.aquarium_maintank_waterlevel
        - sensor.aquarium_filtertank_waterlevel
        - sensor.aquarium_pumptank_waterlevel
  conditions:
    - condition: template
      value_template: "{{ trigger.from_state.state != 'unavailable' and trigger.to_state.state != 'unavailable' and trigger.from_state.state != trigger.to_state.state }}"
  actions:
    - action: input_number.set_value
      target:
        entity_id: >
          {% if trigger.entity_id == "sensor.aquarium_bucket_waterlevel" %} input_number.aquarium_bucket_waterlevel
          {% elif trigger.entity_id == "sensor.aquarium_maintank_waterlevel" %} input_number.aquarium_maintank_waterlevel
          {% elif trigger.entity_id == "sensor.aquarium_filtertank_waterlevel" %} input_number.aquarium_filtertank_waterlevel
          {% elif trigger.entity_id == "sensor.aquarium_pumptank_waterlevel" %} input_number.aquarium_pumptank_waterlevel
          {% else %} input_number.dummy_number
          {% endif %}
      data:
        value: >
          {% if trigger.entity_id == "sensor.aquarium_pumptank_waterlevel" %}
            {% if trigger.from_state.state == '1' and trigger.to_state.state == '2' %} 1.5
            {% elif trigger.from_state.state == '2' and trigger.to_state.state == '1' %} 1.5
            {% elif trigger.from_state.state == '0' and trigger.to_state.state == '1' %} 0.5
            {% elif trigger.from_state.state == '1' and trigger.to_state.state == '0' %} 0.5
            {% else %} -1
            {% endif %}
          {% else %}
            1
          {% endif %}
  mode: parallel
  max: 30

- alias: Aquarium:Water_Level_Rendering(Stable)
  triggers:
    - trigger: state
      entity_id:
        - sensor.aquarium_bucket_waterlevel
        - sensor.aquarium_maintank_waterlevel
        - sensor.aquarium_filtertank_waterlevel
        - sensor.aquarium_pumptank_waterlevel
      for:
        minutes: 2
  conditions:
    - condition: template
      value_template: "{{ trigger.from_state.state != 'unavailable' and trigger.to_state.state != 'unavailable' and trigger.from_state.state != trigger.to_state.state }}"
  actions:
    - action: input_number.set_value
      target:
        entity_id: >
          {% if trigger.entity_id == "sensor.aquarium_bucket_waterlevel" %} input_number.aquarium_bucket_waterlevel
          {% elif trigger.entity_id == "sensor.aquarium_maintank_waterlevel" %} input_number.aquarium_maintank_waterlevel
          {% elif trigger.entity_id == "sensor.aquarium_filtertank_waterlevel" %} input_number.aquarium_filtertank_waterlevel
          {% elif trigger.entity_id == "sensor.aquarium_pumptank_waterlevel" %} input_number.aquarium_pumptank_waterlevel
          {% else %} input_number.dummy_number
          {% endif %}
      data:
        value: >
          {% if trigger.entity_id == "sensor.aquarium_pumptank_waterlevel" %}
            {% if trigger.from_state.state == '1' and trigger.to_state.state == '2' %} 2
            {% elif trigger.from_state.state == '2' and trigger.to_state.state == '1' %} 1
            {% elif trigger.from_state.state == '0' and trigger.to_state.state == '1' %} 1
            {% elif trigger.from_state.state == '1' and trigger.to_state.state == '0' %} 0
            {% else %} -1
            {% endif %}
          {% else %}
            {% if trigger.from_state.state == '0' and trigger.to_state.state == '2' %} 2
            {% elif trigger.from_state.state == '2' and trigger.to_state.state == '0' %} 0
            {% else %} -1
            {% endif %}
          {% endif %}
  mode: parallel
  max: 30

再來是依據各種狀況來判斷補水狀態的sensor

- platform: template
  sensors:
    aquarium_tank_refill_condition:
      friendly_name: Aquarium_Tank_Refill_Condition
      value_template: >
        {% if states('switch.gosund_powerstrip_aquarium_switch2') == "on" %}
          補水中
        {% elif states('input_boolean.aquarium_maintenance') == "on" %}
          維護模式
        {% elif states('sensor.aquarium_watertemperature_gap') | float < states('input_number.aquarium_water_refill_temperature_gap') | float and states('input_number.aquarium_pumptank_waterlevel') | int != 2 and states('input_number.aquarium_bucket_waterlevel') | int == 2 and states('input_number.aquarium_maintank_waterlevel') | int == 0 and states('input_boolean.aquarium_maintenance') == "off" and states('switch.gosund_powerstrip_aquarium_switch2') == "off" %}
          待命中
        {% elif states('sensor.aquarium_watertemperature_gap') | float >= states('input_number.aquarium_water_refill_temperature_gap') | float %}
          補水桶溫差過大
        {% elif states('sensor.aquarium_waterlevel_check') != "安全" %}
          水位異常        
        {% endif %}

執行手動補水的腳本,若是要手動補水就單純執行這個腳本,但只有「待命中」和「維護模式」二種狀況下可以手動補水,補水量是由馬達啟動的時間來控制。自動補水則是從automation那邊延伸過來。

aquarium_water_refill_duration:
  name: Aquarium_Water_Refill_Duration
  min: 0
  max: 20
  step: 1
  unit_of_measurement: "秒"
aquarium_maintank_manually_refill:
  alias: Aquarium_MainTank_Manually_Refill
  sequence:
    - choose:
        - conditions:
            - condition: or
              conditions:
                - condition: state
                  entity_id: sensor.aquarium_tank_refill_condition
                  state: "待命中"
                - condition: state
                  entity_id: sensor.aquarium_tank_refill_condition
                  state: "維護模式"
          sequence:
            - action: switch.turn_on
              entity_id: switch.gosund_powerstrip_aquarium_switch2
            - delay:
                seconds: "{{ states('input_number.aquarium_water_refill_duration') | int }}"
            - action: switch.turn_off
              entity_id: switch.gosund_powerstrip_aquarium_switch2

自動補水的部分,寫二條automation,第一條是在滿足背濾濾材格水位太低時觸發,第二條則是固定時間的確認。第二條在彌補第一條的不足,否則若第一條因為某些原因沒有觸發(Home Assistant重新啟動之類的),那就都不會補水了。

另外actions中用到了choose,這裡用choose會比用conditions搭配template的if/else還來的簡單一點。

- alias: Aquarium:Auto_Refill
  triggers:
    - trigger: template
      value_template: "{{ states('input_number.aquarium_filtertank_waterlevel') | int == 0 }}"
  conditions:
    - condition: state
      entity_id: device_tracker.093_a340
      state: "home"
  actions:
    - choose:
        - conditions:
            - condition: state
              entity_id: sensor.aquarium_tank_refill_condition
              state: "待命中"
          sequence:
            - variables:
                message: >
                  滿足待命時自動補水,12小時內已補過{{ states('sensor.aquarium_maintank_refill_count_12') }}次。
            - action: notify.notify_line_aquarium
              data:
                message: "{{ message }}"
            - action: script.turn_on
              target:
                entity_id: script.aquarium_logger
              data:
                variables:
                  msg: "{{ message }}"
            - action: script.turn_on
              data:
                entity_id: script.aquarium_maintank_refill
        - conditions:
            - condition: or
              conditions:
                - condition: state
                  entity_id: sensor.aquarium_tank_refill_condition
                  state: "補水桶溫差過大"
                - condition: state
                  entity_id: sensor.aquarium_tank_refill_condition
                  state: "水位異常"
          sequence:
            - variables:
                message: >
                  自動補水條件未滿足,原因為{{ states('sensor.aquarium_tank_refill_condition') }}。
            - action: notify.notify_line_aquarium
              data:
                message: "{{ message }}"
            - action: script.turn_on
              target:
                entity_id: script.aquarium_logger
              data:
                variables:
                  msg: "{{ message }}"

- alias: Aquarium:Auto_Refill_Regular_Check
  triggers:
    - trigger: time_pattern
      minutes: "/10"
  conditions:
    - condition: template
      value_template: >
        {{ states('input_number.aquarium_filtertank_waterlevel') | int == 0 and states('device_tracker.093_a340') == "home" and states('sensor.aquarium_tank_refill_condition') != "維護模式" }}
  actions:
    - choose:
        - conditions:
            - condition: state
              entity_id: sensor.aquarium_tank_refill_condition
              state: "待命中"
          sequence:
            - variables:
                message: >
                  滿足待命時自動補水,12小時內已補過{{ states('sensor.aquarium_maintank_refill_count_12') }}次。
            - action: notify.notify_line_aquarium
              data:
                message: "{{ message }}"
            - action: script.turn_on
              target:
                entity_id: script.aquarium_logger
              data:
                variables:
                  msg: "{{ message }}"
            - action: script.turn_on
              data:
                entity_id: script.aquarium_maintank_refill
        - conditions:
            - condition: or
              conditions:
                - condition: state
                  entity_id: sensor.aquarium_tank_refill_condition
                  state: "補水桶溫差過大"
                - condition: state
                  entity_id: sensor.aquarium_tank_refill_condition
                  state: "水位異常"
          sequence:
            - variables:
                message: >
                  自動補水條件未滿足,原因為{{ states('sensor.aquarium_tank_refill_condition') }}。
            - action: notify.notify_line_aquarium
              data:
                message: "{{ message }}"
            - action: script.turn_on
              target:
                entity_id: script.aquarium_logger
              data:
                variables:
                  msg: "{{ message }}"

自動補水的腳本獨立出來的原因是

  • 要計算過去12小時內補過幾次水,幾週跑下來大概都是補1次,如果有超過就要看一下是不是哪裡有問題。
  • 可以省略補水條件的檢查,因為在automation中的condition已經檢查過。
aquarium_maintank_refill:
  alias: Aquarium_MainTank_Refill
  sequence:
    - action: switch.turn_on
      entity_id: switch.gosund_powerstrip_aquarium_switch2
    - delay:
        seconds: "{{ states('input_number.aquarium_water_refill_duration') | int }}"
    - action: switch.turn_off
      entity_id: switch.gosund_powerstrip_aquarium_switch2
- platform: history_stats
  name: Aquarium_MainTank_Refill_Count_12
  entity_id: script.aquarium_maintank_refill
  state: "on"
  type: count
  start: "{{ as_timestamp(now()) - 12 * 60 * 60 }}"
  end: "{{ now() }}"

最後再來一條停止自動補水的安全措施,避免意外地補水馬達沒有關閉造成水漫金山。用馬達持續啟動時間來做,分別在+2、+7與+15秒時觸發。

- alias: Aquarium:Tank_Stop_Refill
  triggers:
    - trigger: state
      entity_id: device_tracker.093_a340
      to: "not_home"
    - trigger: state
      entity_id: switch.gosund_powerstrip_aquarium_switch2
      from: "off"
      to: "on"
      for:
        seconds: "{{ states('input_number.aquarium_water_refill_duration') | int + 2 }}"
    - trigger: state
      entity_id: switch.gosund_powerstrip_aquarium_switch2
      from: "off"
      to: "on"
      for:
        seconds: "{{ states('input_number.aquarium_water_refill_duration') | int + 7 }}"
    - trigger: state
      entity_id: switch.gosund_powerstrip_aquarium_switch2
      from: "off"
      to: "on"
      for:
        seconds: "{{ states('input_number.aquarium_water_refill_duration') | int + 15 }}"
  conditions:
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
  actions:
    - action: switch.turn_off
      entity_id: switch.gosund_powerstrip_aquarium_switch2
  mode: queued

水位相關

- alias: Aquarium:Water_Level_Alarm
  triggers:
    - trigger: state
      entity_id:
        - input_number.aquarium_bucket_waterlevel
        - input_number.aquarium_maintank_waterlevel
        - input_number.aquarium_filtertank_waterlevel
        - input_number.aquarium_pumptank_waterlevel
  conditions:
    - condition: state
      entity_id: input_boolean.aquarium_maintenance
      state: "off"
  actions:
    - variables:
        message: >
          {% if trigger.entity_id == "input_number.aquarium_bucket_waterlevel" %}
            {% if trigger.to_state.state | float == 0 %}
              補水桶水位過低。
            {% elif trigger.to_state.state | float == 1 %}
              補水桶水位在交界處。
            {% elif trigger.to_state.state | float == 2 %}
              補水桶水位正常。
            {% else %}
              檢查水位 {{ trigger.entity_id }} from {{ trigger.from_state.state }} to {{ trigger.to_state.state }}
            {% endif %}
          {% elif trigger.entity_id == "input_number.aquarium_maintank_waterlevel" %}
            {% if trigger.to_state.state | float == 0 %}
              主缸水位正常。
            {% elif trigger.to_state.state | float == 1 %}
              主缸水位在交界處。
            {% elif trigger.to_state.state | float == 2 %}
              主缸水位過高。
            {% else %}
              檢查水位 {{ trigger.entity_id }} from {{ trigger.from_state.state }} to {{ trigger.to_state.state }}
            {% endif %}
          {% elif trigger.entity_id == "input_number.aquarium_filtertank_waterlevel" %}
            {% if trigger.to_state.state | float == 0 %}
              過濾槽水位過低。
            {% elif trigger.to_state.state | float == 1 %}
              過濾槽水位在交界處。
            {% elif trigger.to_state.state | float == 2 %}
              過濾槽水位正常。
            {% else %}
              檢查水位 {{ trigger.entity_id }} from {{ trigger.from_state.state }} to {{ trigger.to_state.state }}
            {% endif %}
          {% elif trigger.entity_id == "input_number.aquarium_pumptank_waterlevel" %}
            {% if trigger.to_state.state | float == 0 %}
              沉馬格水位過低。
            {% elif trigger.to_state.state | float == 0.5 %}
              沉馬格水位在低水位交界處。
            {% elif trigger.to_state.state | float == 1 %}
              沉馬格水位正常。
            {% elif trigger.to_state.state | float == 1.5 %}
              沉馬格水位在高水位交界處。
            {% elif trigger.to_state.state | float == 2 %}
              沉馬格水位過高。
            {% else %}
              檢查水位 {{ trigger.entity_id }} from {{ trigger.from_state.state }} to {{ trigger.to_state.state }}
            {% endif %}
          {% else %}
            請檢查水位。
          {% endif %}
    - action: notify.notify_line_aquarium
      data:
        message: "{{ message }}"
    - action: script.turn_on
      target:
        entity_id: script.aquarium_logger
      data:
        variables:
          msg: "{{ message }}"
  mode: parallel
  max: 30

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

返回頂端