various tidyups
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
@@ -1 +1 @@
|
|||||||
{"pid": 71, "version": 1, "ha_version": "2026.8.3", "start_ts": 1788051080.3314128}
|
{"pid": 71, "version": 1, "ha_version": "2026.9.2", "start_ts": 1789211351.1286738}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
TP-Link Deco Guest Wi-Fi Recovery Archive
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
Version: 1.0.0
|
||||||
|
Created: 2026-09-02
|
||||||
|
Project: P026 Flounder downstairs guest-area controls
|
||||||
|
|
||||||
|
Purpose
|
||||||
|
-------
|
||||||
|
|
||||||
|
This archive preserves the locally maintained TP-Link Deco Guest Wi-Fi
|
||||||
|
customisation. The upstream tplink_deco integration does not provide this
|
||||||
|
service or sensor. Reinstalling or overwriting custom_components/tplink_deco
|
||||||
|
can remove them.
|
||||||
|
|
||||||
|
Archive
|
||||||
|
-------
|
||||||
|
|
||||||
|
File: docs/tplink_deco_guest_wifi_recovery_2026-09-02.tgz
|
||||||
|
SHA-256: 452ed7b7be5e8c469dc7740d5297959179204d24593a22c965f1915ca727c48d
|
||||||
|
|
||||||
|
Contents
|
||||||
|
--------
|
||||||
|
|
||||||
|
- custom_components/tplink_deco/api.py
|
||||||
|
- custom_components/tplink_deco/__init__.py
|
||||||
|
- custom_components/tplink_deco/const.py
|
||||||
|
- custom_components/tplink_deco/services.yaml
|
||||||
|
- custom_components/tplink_deco/coordinator.py
|
||||||
|
- custom_components/tplink_deco/binary_sensor.py
|
||||||
|
- packages/tplink_deco_guest_wifi.yaml
|
||||||
|
|
||||||
|
Behaviour Preserved
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- Service: tplink_deco.set_guest_network
|
||||||
|
- Service field: enable (boolean)
|
||||||
|
- Router state: binary_sensor.data_cupboard_new_sundamage_12_deco_guest_network
|
||||||
|
- Requested state: input_boolean.wifi_guest_network
|
||||||
|
- Flounder control: the requested-state helper; the package reconciles it to
|
||||||
|
the router-confirmed sensor.
|
||||||
|
- Write protocol: read each returned wireless band, retain its host, guest and
|
||||||
|
backhaul settings, set only guest.enable, add radio.channel from host.channel,
|
||||||
|
write each band separately, then read back and verify every written band.
|
||||||
|
- Deco firmware can return a malformed successful response containing
|
||||||
|
{"error_code": 0}; the integration accepts that response only for writes and
|
||||||
|
relies on the read-back verification as the final confirmation.
|
||||||
|
|
||||||
|
Recovery Procedure
|
||||||
|
------------------
|
||||||
|
|
||||||
|
1. Stop before updating, reinstalling, or deleting custom_components/tplink_deco.
|
||||||
|
2. Verify the archive checksum above.
|
||||||
|
3. Extract the archive from /homeassistant, preserving the listed paths.
|
||||||
|
4. Run Home Assistant configuration validation and Python compilation for the
|
||||||
|
restored integration files.
|
||||||
|
5. Restart Home Assistant. A restart is required for custom integration code.
|
||||||
|
6. Confirm tplink_deco.set_guest_network is registered and the Guest Network
|
||||||
|
binary sensor is available before operating Guest Wi-Fi.
|
||||||
|
|
||||||
|
Update Policy
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Do not replace custom_components/tplink_deco with an upstream or HACS update
|
||||||
|
without first comparing it to this archive and deliberately reapplying the
|
||||||
|
Guest Wi-Fi customisation. The archive contains no credentials, tokens, session
|
||||||
|
cookies, or router address.
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
--- a/esp-bedside-panel.yaml
|
||||||
|
+++ b/esp-bedside-panel.yaml
|
||||||
|
@@ -5,6 +5,7 @@
|
||||||
|
# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-bedside-panel.yaml
|
||||||
|
#:########################################################################################:#
|
||||||
|
# VERSIONS:
|
||||||
|
+# V1.56 2026-09-04 Added latched blackout after 10 seconds below 1 lx with immediate exit
|
||||||
|
# V1.55 2026-08-16 Show only Clock time and date in Blackout ambient-light mode
|
||||||
|
# V1.54 2026-08-16 Dimmed Clock time and date palette in Blackout ambient-light mode
|
||||||
|
@@ -248,7 +249,6 @@
|
||||||
|
# Bright light: approximately 642-643 lx
|
||||||
|
ambient_lux_multiplier_default: "200"
|
||||||
|
-
|
||||||
|
- display_blackout_lux_threshold_default: "2"
|
||||||
|
display_dark_lux_threshold_default: "20"
|
||||||
|
display_bright_lux_threshold_default: "250"
|
||||||
|
@@ -921,21 +921,6 @@
|
||||||
|
step: 5
|
||||||
|
mode: box
|
||||||
|
|
||||||
|
- - platform: template
|
||||||
|
- id: display_blackout_lux_threshold
|
||||||
|
- name: "${friendly_name} Blackout Lux Threshold"
|
||||||
|
- icon: mdi:brightness-1
|
||||||
|
- entity_category: config
|
||||||
|
- optimistic: true
|
||||||
|
- restore_value: true
|
||||||
|
- initial_value: "${display_blackout_lux_threshold_default}"
|
||||||
|
- unit_of_measurement: "lx"
|
||||||
|
- min_value: 0
|
||||||
|
- max_value: 20
|
||||||
|
- step: 0.5
|
||||||
|
- mode: box
|
||||||
|
-
|
||||||
|
- platform: template
|
||||||
|
id: display_dark_lux_threshold
|
||||||
|
@@ -1228,6 +1213,45 @@
|
||||||
|
update_interval: 3s
|
||||||
|
lambda: |-
|
||||||
|
const float voltage = id(ambient_light_voltage).state;
|
||||||
|
+
|
||||||
|
+ if (isnan(voltage)) {
|
||||||
|
+ return NAN;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ float multiplier = id(ambient_lux_multiplier).state;
|
||||||
|
+
|
||||||
|
+ if (isnan(multiplier) || multiplier <= 0.0f) {
|
||||||
|
+ multiplier = 200.0f;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return voltage * multiplier;
|
||||||
|
+ on_value:
|
||||||
|
+ then:
|
||||||
|
+ - if:
|
||||||
|
+ condition:
|
||||||
|
+ lambda: |-
|
||||||
|
+ return !isnan(x) && x >= 1.0f;
|
||||||
|
+ then:
|
||||||
|
+ - script.stop: latch_display_blackout
|
||||||
|
+ - lambda: |-
|
||||||
|
+ id(display_blackout_active) = false;
|
||||||
|
+ - if:
|
||||||
|
+ condition:
|
||||||
|
+ lambda: |-
|
||||||
|
+ return id(lvgl_ready) && id(display_is_dimmed);
|
||||||
|
+ then:
|
||||||
|
+ - script.execute: apply_dim_backlight
|
||||||
|
+ else:
|
||||||
|
+ - if:
|
||||||
|
+ condition:
|
||||||
|
+ lambda: |-
|
||||||
|
+ return id(lvgl_ready);
|
||||||
|
+ then:
|
||||||
|
+ - script.execute: apply_active_backlight
|
||||||
|
+ else:
|
||||||
|
+ - if:
|
||||||
|
+ condition:
|
||||||
|
+ lambda: |-
|
||||||
|
+ return !isnan(x) && x < 1.0f && !id(display_blackout_active);
|
||||||
|
+ then:
|
||||||
|
+ - script.execute: latch_display_blackout
|
||||||
|
- float multiplier = id(ambient_lux_multiplier).state;
|
||||||
|
-
|
||||||
|
- if (isnan(voltage)) {
|
||||||
|
- return NAN;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (isnan(multiplier) || multiplier <= 0.0f) {
|
||||||
|
- multiplier = 200.0f;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- return voltage * multiplier;
|
||||||
|
|
||||||
|
- platform: homeassistant
|
||||||
|
@@ -1918,6 +1942,12 @@
|
||||||
|
restore_value: false
|
||||||
|
initial_value: "false"
|
||||||
|
|
||||||
|
+ # True after ambient light remains below 1 lx for 10 continuous seconds.
|
||||||
|
+ - id: display_blackout_active
|
||||||
|
+ type: bool
|
||||||
|
+ restore_value: false
|
||||||
|
+ initial_value: "false"
|
||||||
|
+
|
||||||
|
# True only while the Security page is visible.
|
||||||
|
@@ -3133,31 +3163,52 @@
|
||||||
|
- # Four ambient ranges are used:
|
||||||
|
- # Blackout: lux < Blackout Lux Threshold
|
||||||
|
- # Dark: Blackout threshold to Dark Lux Threshold
|
||||||
|
- # Normal: between Dark and Bright thresholds
|
||||||
|
- # Bright: lux >= Bright Lux Threshold
|
||||||
|
+ # Blackout latches after ambient light remains below 1 lx for 10 seconds and
|
||||||
|
+ # exits immediately when ambient light reaches 1 lx. The remaining ranges are:
|
||||||
|
+ # Dark: lux <= Dark Lux Threshold
|
||||||
|
+ # Normal: between Dark and Bright thresholds
|
||||||
|
+ # Bright: lux >= Bright Lux Threshold
|
||||||
|
#
|
||||||
|
# The active and clock/idle brightness levels are independently adjustable
|
||||||
|
# and restored after reboot.
|
||||||
|
|
||||||
|
+ - id: latch_display_blackout
|
||||||
|
+ mode: single
|
||||||
|
+ then:
|
||||||
|
+ - delay: 10s
|
||||||
|
+ - if:
|
||||||
|
+ condition:
|
||||||
|
+ lambda: |-
|
||||||
|
+ const float lux = id(ambient_light_illuminance).state;
|
||||||
|
+ return !isnan(lux) && lux < 1.0f;
|
||||||
|
+ then:
|
||||||
|
+ - lambda: |-
|
||||||
|
+ id(display_blackout_active) = true;
|
||||||
|
+ - if:
|
||||||
|
+ condition:
|
||||||
|
+ lambda: |-
|
||||||
|
+ return id(lvgl_ready) && id(display_is_dimmed);
|
||||||
|
+ then:
|
||||||
|
+ - script.execute: apply_dim_backlight
|
||||||
|
+ else:
|
||||||
|
+ - if:
|
||||||
|
+ condition:
|
||||||
|
+ lambda: |-
|
||||||
|
+ return id(lvgl_ready);
|
||||||
|
+ then:
|
||||||
|
+ - script.execute: apply_active_backlight
|
||||||
|
+
|
||||||
|
# Keep the idle Clock unobtrusive at the minimum usable backlight level.
|
||||||
|
- id: apply_clock_blackout_palette
|
||||||
|
@@ -3146,15 +3197,7 @@
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: |-
|
||||||
|
- const float lux = id(ambient_light_illuminance).state;
|
||||||
|
- float blackout_threshold =
|
||||||
|
- id(display_blackout_lux_threshold).state;
|
||||||
|
-
|
||||||
|
- if (isnan(blackout_threshold)) {
|
||||||
|
- blackout_threshold = 2.0f;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- return !isnan(lux) && lux < blackout_threshold;
|
||||||
|
+ return id(display_blackout_active);
|
||||||
|
@@ -3212,22 +3255,12 @@
|
||||||
|
brightness: !lambda |-
|
||||||
|
const float lux = id(ambient_light_illuminance).state;
|
||||||
|
|
||||||
|
- float blackout_threshold =
|
||||||
|
- id(display_blackout_lux_threshold).state;
|
||||||
|
float dark_threshold =
|
||||||
|
id(display_dark_lux_threshold).state;
|
||||||
|
float bright_threshold =
|
||||||
|
id(display_bright_lux_threshold).state;
|
||||||
|
|
||||||
|
- if (isnan(blackout_threshold)) {
|
||||||
|
- blackout_threshold = 2.0f;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
if (
|
||||||
|
isnan(dark_threshold) ||
|
||||||
|
- dark_threshold <= blackout_threshold
|
||||||
|
+ dark_threshold <= 0.0f
|
||||||
|
) {
|
||||||
|
dark_threshold = 20.0f;
|
||||||
|
}
|
||||||
|
@@ -3239,7 +3272,7 @@
|
||||||
|
|
||||||
|
float brightness_percent;
|
||||||
|
|
||||||
|
- if (!isnan(lux) && lux < blackout_threshold) {
|
||||||
|
+ if (id(display_blackout_active)) {
|
||||||
|
brightness_percent =
|
||||||
|
id(display_blackout_brightness).state;
|
||||||
|
@@ -3280,22 +3313,12 @@
|
||||||
|
brightness: !lambda |-
|
||||||
|
const float lux = id(ambient_light_illuminance).state;
|
||||||
|
|
||||||
|
- float blackout_threshold =
|
||||||
|
- id(display_blackout_lux_threshold).state;
|
||||||
|
float dark_threshold =
|
||||||
|
id(display_dark_lux_threshold).state;
|
||||||
|
float bright_threshold =
|
||||||
|
id(display_bright_lux_threshold).state;
|
||||||
|
|
||||||
|
- if (isnan(blackout_threshold)) {
|
||||||
|
- blackout_threshold = 2.0f;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
if (
|
||||||
|
isnan(dark_threshold) ||
|
||||||
|
- dark_threshold <= blackout_threshold
|
||||||
|
+ dark_threshold <= 0.0f
|
||||||
|
) {
|
||||||
|
dark_threshold = 20.0f;
|
||||||
|
}
|
||||||
|
@@ -3307,7 +3330,7 @@
|
||||||
|
|
||||||
|
float brightness_percent;
|
||||||
|
|
||||||
|
- if (!isnan(lux) && lux < blackout_threshold) {
|
||||||
|
+ if (id(display_blackout_active)) {
|
||||||
|
brightness_percent =
|
||||||
|
id(display_blackout_brightness).state;
|
||||||
@@ -1,26 +1,28 @@
|
|||||||
#:########################################################################################:#
|
#:########################################################################################:#
|
||||||
# PACKAGE: Office Lights Home Assistant Fallback Synchronization
|
# PACKAGE: Office Lights Home Assistant Fallback Synchronization
|
||||||
# FILE: Lighting_2Way_Sync/office_lights_ha_fallback_sync.yaml
|
# FILE: Lighting_2Way_Sync/office_lights_ha_fallback_sync.yaml
|
||||||
# VERSION: v1.0.0
|
# VERSION: v1.2.0
|
||||||
# DATE: 2026-08-16
|
# DATE: 2026-09-12
|
||||||
#:########################################################################################:#
|
#:########################################################################################:#
|
||||||
#
|
#
|
||||||
# PURPOSE:
|
# PURPOSE:
|
||||||
# Provides the Home Assistant API transport for Office two-way light control
|
# Provides Home Assistant-primary synchronization for the Office two-way
|
||||||
# when MQTT is unavailable. Direct MQTT remains the HA-down transport.
|
# light controls. Direct MQTT peer control is the HA-down transport.
|
||||||
#
|
#
|
||||||
# OPERATION:
|
# OPERATION:
|
||||||
# - Synchronizes the Office bunker and overhead control pairs in both directions.
|
# - Synchronizes the Office bunker and overhead control pairs in both directions.
|
||||||
# - Uses idempotent Home Assistant actions, so MQTT and HA may both be online
|
# - ESPHome permits direct MQTT peer synchronization only while HA's native
|
||||||
# without creating a control loop.
|
# API state subscription is disconnected, preventing competing controllers.
|
||||||
# - Does not reconcile state during Home Assistant startup, preventing a stale
|
# - Does not reconcile state during Home Assistant startup, preventing a stale
|
||||||
# restored entity state from changing a physical light.
|
# restored entity state from changing a physical light.
|
||||||
#
|
#
|
||||||
# DEPENDENCIES:
|
# DEPENDENCIES:
|
||||||
# - Blueprint: zorruno/two_three_way_sync.yaml
|
# - Blueprint: zorruno/two_three_way_sync.yaml
|
||||||
# - esp-officelights and esp-officeduallights native ESPHome API connections.
|
# - esp-officelights v3.2 and esp-officeduallights v3.0 or later.
|
||||||
#
|
#
|
||||||
# VERSION HISTORY:
|
# VERSION HISTORY:
|
||||||
|
# - v1.2.0 (2026-09-12): Enable after guarded HA-primary firmware deployment.
|
||||||
|
# - v1.1.0 (2026-09-12): Disabled until guarded HA-primary firmware deployment.
|
||||||
# - v1.0.0 (2026-08-16): Initial MQTT-down HA fallback for Office lights.
|
# - v1.0.0 (2026-08-16): Initial MQTT-down HA fallback for Office lights.
|
||||||
#:########################################################################################:#
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#:########################################################################################:#
|
||||||
|
# PACKAGE: Office Lights Home Assistant Fallback Synchronization
|
||||||
|
# FILE: Lighting_2Way_Sync/office_lights_ha_fallback_sync.yaml
|
||||||
|
# VERSION: v1.1.0
|
||||||
|
# DATE: 2026-09-12
|
||||||
|
#:########################################################################################:#
|
||||||
|
#
|
||||||
|
# PURPOSE:
|
||||||
|
# Provides the Home Assistant API transport for Office two-way light control
|
||||||
|
# when MQTT is unavailable. Direct MQTT remains the HA-down transport.
|
||||||
|
#
|
||||||
|
# OPERATION:
|
||||||
|
# - Synchronizes the Office bunker and overhead control pairs in both directions.
|
||||||
|
# - The automations remain disabled until both ESPHome devices enforce the
|
||||||
|
# HA-primary/MQTT-fallback authority boundary.
|
||||||
|
# - Does not reconcile state during Home Assistant startup, preventing a stale
|
||||||
|
# restored entity state from changing a physical light.
|
||||||
|
#
|
||||||
|
# DEPENDENCIES:
|
||||||
|
# - Blueprint: zorruno/two_three_way_sync.yaml
|
||||||
|
# - esp-officelights and esp-officeduallights native ESPHome API connections.
|
||||||
|
#
|
||||||
|
# VERSION HISTORY:
|
||||||
|
# - v1.1.0 (2026-09-12): Disable until guarded HA-primary firmware is deployed.
|
||||||
|
# - v1.0.0 (2026-08-16): Initial MQTT-down HA fallback for Office lights.
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
automation:
|
||||||
|
#:##########################################################################:#
|
||||||
|
# BUNKER LIGHTS
|
||||||
|
#:##########################################################################:#
|
||||||
|
- id: office_bunker_lights_ha_fallback_sync
|
||||||
|
alias: "Office Bunker Lights HA Fallback Sync"
|
||||||
|
initial_state: false
|
||||||
|
use_blueprint:
|
||||||
|
path: zorruno/two_three_way_sync.yaml
|
||||||
|
input:
|
||||||
|
members:
|
||||||
|
- switch.office_office_main_lightswitch_3_relay_1_bunker_lights
|
||||||
|
- light.esp_officeduallights_light_1_right_hand_bunker_light
|
||||||
|
sync_on_start: false
|
||||||
|
startup_delay: 5
|
||||||
|
|
||||||
|
#:##########################################################################:#
|
||||||
|
# OVERHEAD LIGHTS
|
||||||
|
#:##########################################################################:#
|
||||||
|
- id: office_overhead_lights_ha_fallback_sync
|
||||||
|
alias: "Office Overhead Lights HA Fallback Sync"
|
||||||
|
initial_state: false
|
||||||
|
use_blueprint:
|
||||||
|
path: zorruno/two_three_way_sync.yaml
|
||||||
|
input:
|
||||||
|
members:
|
||||||
|
- switch.office_office_main_lightswitch_3_relay_2_overhead_lights
|
||||||
|
- light.esp_officeduallights_light_2_cool_white_overhead_lights
|
||||||
|
sync_on_start: false
|
||||||
|
startup_delay: 5
|
||||||
@@ -9,9 +9,13 @@
|
|||||||
# packages/Pool_Controls/pool_light_operation.yaml
|
# packages/Pool_Controls/pool_light_operation.yaml
|
||||||
#
|
#
|
||||||
# VERSION:
|
# VERSION:
|
||||||
# V1.2 2026-07-20
|
# V1.3 2026-09-06
|
||||||
#
|
#
|
||||||
# VERSION HISTORY:
|
# VERSION HISTORY:
|
||||||
|
# V1.3 2026-09-06
|
||||||
|
# - Treat the colour selector's "0= OFF" as a true Operation Mode OFF and
|
||||||
|
# arm the midnight TIMER reset.
|
||||||
|
#
|
||||||
# V1.2 2026-07-20
|
# V1.2 2026-07-20
|
||||||
# - Corrected the documented package filename.
|
# - Corrected the documented package filename.
|
||||||
# - Documented the relationship with the native ESPHome controls.
|
# - Documented the relationship with the native ESPHome controls.
|
||||||
@@ -151,6 +155,40 @@ automation:
|
|||||||
target:
|
target:
|
||||||
entity_id: input_boolean.timer_light_midnight_pending
|
entity_id: input_boolean.timer_light_midnight_pending
|
||||||
|
|
||||||
|
- id: pool_light_schedule_timer_when_operation_mode_off
|
||||||
|
alias: "Pool Light - Schedule TIMER When Operation Mode Is OFF"
|
||||||
|
description: "Arms the midnight TIMER reset for direct Operation Mode OFF commands."
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id: select.esp_poollightpower2_operation_mode
|
||||||
|
to: "OFF"
|
||||||
|
|
||||||
|
action:
|
||||||
|
- action: input_boolean.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: input_boolean.timer_light_midnight_pending
|
||||||
|
|
||||||
|
- id: pool_light_send_off_when_colour_off_selected
|
||||||
|
alias: "Pool Light - Send OFF When Colour Off Is Selected"
|
||||||
|
description: "Converts colour selector 0= OFF into Operation Mode OFF with midnight reset."
|
||||||
|
mode: restart
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id: select.esp_poollightpower2_pool_light_mode
|
||||||
|
to: "0= OFF"
|
||||||
|
|
||||||
|
action:
|
||||||
|
- action: mqtt.publish
|
||||||
|
data:
|
||||||
|
topic: "viewroad-commands/poollight-timer/operation"
|
||||||
|
payload: "OFF"
|
||||||
|
- action: input_boolean.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: input_boolean.timer_light_midnight_pending
|
||||||
|
|
||||||
- id: pool_light_sync_ui_switch_with_real_output
|
- id: pool_light_sync_ui_switch_with_real_output
|
||||||
alias: "Pool Light - Sync UI Switch With Real Output"
|
alias: "Pool Light - Sync UI Switch With Real Output"
|
||||||
description: "Keeps the UI switch aligned with the real ESPHome pool light output without sending MQTT commands."
|
description: "Keeps the UI switch aligned with the real ESPHome pool light output without sending MQTT commands."
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Package: BYD Lock Button
|
||||||
|
# Purpose:
|
||||||
|
# Provides a voice-assistant-safe BYD lock control that can only issue a lock command.
|
||||||
|
# Notes:
|
||||||
|
# The icon reflects the live state of the underlying BYD lock. This button has no
|
||||||
|
# unlock action.
|
||||||
|
# Version history:
|
||||||
|
# - 1.0.0: Initial lock-only BYD button.
|
||||||
|
#
|
||||||
|
#:########################################################################################:#
|
||||||
|
# Template Button
|
||||||
|
#:########################################################################################:#
|
||||||
|
template:
|
||||||
|
- button:
|
||||||
|
- name: "BYD Lock"
|
||||||
|
unique_id: byd_lock_button
|
||||||
|
default_entity_id: button.byd_lock
|
||||||
|
availability: "{{ has_value('lock.atto_3_lock') }}"
|
||||||
|
icon: >-
|
||||||
|
{{ 'mdi:lock' if is_state('lock.atto_3_lock', 'locked') else 'mdi:lock-open' }}
|
||||||
|
press:
|
||||||
|
- action: lock.lock
|
||||||
|
target:
|
||||||
|
entity_id: lock.atto_3_lock
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
# PACKAGE: Energy Cost Monitoring
|
# PACKAGE: Energy Cost Monitoring
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Version: 1.3.0
|
# Version: 1.3.1
|
||||||
# Date: 2026-08-23
|
# Date: 2026-09-01
|
||||||
#
|
#
|
||||||
# Purpose:
|
# Purpose:
|
||||||
# Track GST-inclusive electricity costs for the three-phase grid supply and
|
# Track GST-inclusive electricity costs for the three-phase grid supply and
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
# boundary without averaging the old and new rates.
|
# boundary without averaging the old and new rates.
|
||||||
#
|
#
|
||||||
# Version history:
|
# Version history:
|
||||||
|
# 1.3.1 (2026-09-01): Move Downstairs Fridge and Freezer shared power-cost
|
||||||
|
# telemetry from X41PP to X68PM.
|
||||||
# 1.3.0 (2026-08-24): Add Drinks Fridge and Vertical Freezer energy and
|
# 1.3.0 (2026-08-24): Add Drinks Fridge and Vertical Freezer energy and
|
||||||
# cost monitoring.
|
# cost monitoring.
|
||||||
# 1.2.0 (2026-08-23): Add Downstairs Lounge North GPO (X48PM) energy and
|
# 1.2.0 (2026-08-23): Add Downstairs Lounge North GPO (X48PM) energy and
|
||||||
@@ -326,11 +328,11 @@ template:
|
|||||||
unique_id: energy_cost_downstairs_fridge_rate
|
unique_id: energy_cost_downstairs_fridge_rate
|
||||||
unit_of_measurement: "NZD/h"
|
unit_of_measurement: "NZD/h"
|
||||||
state_class: measurement
|
state_class: measurement
|
||||||
availability: "{{ has_value('sensor.downstairs_fridge_power_x41pp_power') }}"
|
availability: "{{ has_value('sensor.downstairs_fridge_gpo_power_x68pm_power') }}"
|
||||||
state: >-
|
state: >-
|
||||||
{{
|
{{
|
||||||
(
|
(
|
||||||
states('sensor.downstairs_fridge_power_x41pp_power') | float(0)
|
states('sensor.downstairs_fridge_gpo_power_x68pm_power') | float(0)
|
||||||
/ 1000
|
/ 1000
|
||||||
* states('sensor.electricity_current_price') | float(0)
|
* states('sensor.electricity_current_price') | float(0)
|
||||||
) | round(6)
|
) | round(6)
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
#:########################################################################################:#
|
#:########################################################################################:#
|
||||||
# PACKAGE: Fridge and Freezer Monitoring
|
# PACKAGE: Fridge and Freezer Monitoring
|
||||||
# FILE: packages/fridge_freezer_monitoring.yaml
|
# FILE: packages/fridge_freezer_monitoring.yaml
|
||||||
# VERSION: v1.11.0 2026-08-30
|
# VERSION: v1.13.0 2026-09-03
|
||||||
|
# - Moves Downstairs Freezer temperature, humidity, and battery monitoring
|
||||||
|
# from X62TS to X70TS.
|
||||||
|
# - Moves shared Downstairs Fridge and Freezer power monitoring from X41PP to
|
||||||
|
# the metering-only X68PM GPO.
|
||||||
|
# - Reports an unavailable Main Kitchen Fridge battery monitor explicitly,
|
||||||
|
# rather than showing an unqualified issue.
|
||||||
# - Moves Main Kitchen Fridge temperature, humidity, and battery monitoring to
|
# - Moves Main Kitchen Fridge temperature, humidity, and battery monitoring to
|
||||||
# X65TS and adds X64LS illuminance-based door monitoring.
|
# X65TS and adds X64LS illuminance-based door monitoring.
|
||||||
# - v1.10.0 2026-08-29: Adds Downstairs Freezer temperature, battery, door, humidity, and shared
|
# - v1.10.0 2026-08-29: Adds Downstairs Freezer temperature, battery, door, humidity, and shared
|
||||||
@@ -61,8 +67,7 @@
|
|||||||
# - Seven configured fridge/freezer temperature and battery monitor pairs.
|
# - Seven configured fridge/freezer temperature and battery monitor pairs.
|
||||||
# - switch.upstairs_fridge_power_x31pp
|
# - switch.upstairs_fridge_power_x31pp
|
||||||
# - sensor.upstairs_fridge_power_x31pp_power
|
# - sensor.upstairs_fridge_power_x31pp_power
|
||||||
# - switch.downstairs_fridge_power_x41pp
|
# - sensor.downstairs_fridge_gpo_power_x68pm_power
|
||||||
# - sensor.downstairs_fridge_power_x41pp_power
|
|
||||||
# - switch.drinks_fridge_power_x59pm
|
# - switch.drinks_fridge_power_x59pm
|
||||||
# - sensor.drinks_fridge_power_x59pm_power
|
# - sensor.drinks_fridge_power_x59pm_power
|
||||||
# - switch.vertical_freezer_power_x60pm
|
# - switch.vertical_freezer_power_x60pm
|
||||||
@@ -173,7 +178,7 @@ sensor:
|
|||||||
- platform: statistics
|
- platform: statistics
|
||||||
name: "Downstairs Freezer Temperature Average 7 Days"
|
name: "Downstairs Freezer Temperature Average 7 Days"
|
||||||
unique_id: downstairs_freezer_temperature_average_7_days
|
unique_id: downstairs_freezer_temperature_average_7_days
|
||||||
entity_id: sensor.downstairs_freezer_temperature_x62ts_temperature
|
entity_id: sensor.downstairs_freezer_temperature_x70ts_temperature
|
||||||
state_characteristic: average_step
|
state_characteristic: average_step
|
||||||
max_age:
|
max_age:
|
||||||
days: 7
|
days: 7
|
||||||
@@ -182,7 +187,7 @@ sensor:
|
|||||||
- platform: statistics
|
- platform: statistics
|
||||||
name: "Downstairs Freezer Temperature 95th Percentile 7 Days"
|
name: "Downstairs Freezer Temperature 95th Percentile 7 Days"
|
||||||
unique_id: downstairs_freezer_temperature_95th_percentile_7_days
|
unique_id: downstairs_freezer_temperature_95th_percentile_7_days
|
||||||
entity_id: sensor.downstairs_freezer_temperature_x62ts_temperature
|
entity_id: sensor.downstairs_freezer_temperature_x70ts_temperature
|
||||||
state_characteristic: percentile
|
state_characteristic: percentile
|
||||||
percentile: 95
|
percentile: 95
|
||||||
max_age:
|
max_age:
|
||||||
@@ -192,7 +197,7 @@ sensor:
|
|||||||
- platform: derivative
|
- platform: derivative
|
||||||
name: "Downstairs Freezer Temperature Change Rate"
|
name: "Downstairs Freezer Temperature Change Rate"
|
||||||
unique_id: downstairs_freezer_temperature_change_rate
|
unique_id: downstairs_freezer_temperature_change_rate
|
||||||
source: sensor.downstairs_freezer_temperature_x62ts_temperature
|
source: sensor.downstairs_freezer_temperature_x70ts_temperature
|
||||||
unit_time: h
|
unit_time: h
|
||||||
time_window: "00:30:00"
|
time_window: "00:30:00"
|
||||||
max_sub_interval: "00:05:00"
|
max_sub_interval: "00:05:00"
|
||||||
@@ -414,11 +419,10 @@ template:
|
|||||||
unique_id: downstairs_fridge_power_draw_lost
|
unique_id: downstairs_fridge_power_draw_lost
|
||||||
device_class: problem
|
device_class: problem
|
||||||
state: >-
|
state: >-
|
||||||
{% set power = states('sensor.downstairs_fridge_power_x41pp_power') | float(none) %}
|
{% set power = states('sensor.downstairs_fridge_gpo_power_x68pm_power') | float(none) %}
|
||||||
{% set changed = states.sensor.downstairs_fridge_power_x41pp_power.last_changed %}
|
{% set changed = states.sensor.downstairs_fridge_gpo_power_x68pm_power.last_changed %}
|
||||||
{{
|
{{
|
||||||
is_state('switch.downstairs_fridge_power_x41pp', 'on')
|
power is not none
|
||||||
and power is not none
|
|
||||||
and power < 1
|
and power < 1
|
||||||
and (now() - changed).total_seconds() >= 4 * 60 * 60
|
and (now() - changed).total_seconds() >= 4 * 60 * 60
|
||||||
}}
|
}}
|
||||||
@@ -450,7 +454,11 @@ template:
|
|||||||
{{
|
{{
|
||||||
temperature_missing
|
temperature_missing
|
||||||
or illuminance_missing
|
or illuminance_missing
|
||||||
or (states('sensor.main_kitchen_fridge_temperature_x65ts_battery') | float(-1)) <= 20
|
or battery_missing
|
||||||
|
or (
|
||||||
|
not battery_missing
|
||||||
|
and (states('sensor.main_kitchen_fridge_temperature_x65ts_battery') | float(0)) <= 20
|
||||||
|
)
|
||||||
or is_state('binary_sensor.main_kitchen_fridge_door_open_too_long', 'on')
|
or is_state('binary_sensor.main_kitchen_fridge_door_open_too_long', 'on')
|
||||||
or (
|
or (
|
||||||
not temperature_missing
|
not temperature_missing
|
||||||
@@ -477,7 +485,9 @@ template:
|
|||||||
{% if illuminance_missing %}
|
{% if illuminance_missing %}
|
||||||
{% set ns.items = ns.items + ['Door monitor unavailable'] %}
|
{% set ns.items = ns.items + ['Door monitor unavailable'] %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not battery_missing and (states('sensor.main_kitchen_fridge_temperature_x65ts_battery') | float(-1)) <= 20 %}
|
{% if battery_missing %}
|
||||||
|
{% set ns.items = ns.items + ['Battery monitor unavailable'] %}
|
||||||
|
{% elif (states('sensor.main_kitchen_fridge_temperature_x65ts_battery') | float(0)) <= 20 %}
|
||||||
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if states('switch.upstairs_fridge_power_x31pp') in ['unknown', 'unavailable'] or power_missing %}
|
{% if states('switch.upstairs_fridge_power_x31pp') in ['unknown', 'unavailable'] or power_missing %}
|
||||||
@@ -596,7 +606,6 @@ template:
|
|||||||
{% set threshold = [9, percentile + 0.5] | min if percentile is not none else 9 %}
|
{% set threshold = [9, percentile + 0.5] | min if percentile is not none else 9 %}
|
||||||
{{
|
{{
|
||||||
temperature_missing
|
temperature_missing
|
||||||
or battery_missing
|
|
||||||
or (states('sensor.lcd_temp_humidity_btt04_battery') | float(-1)) <= 20
|
or (states('sensor.lcd_temp_humidity_btt04_battery') | float(-1)) <= 20
|
||||||
or (not temperature_missing and (states('sensor.lcd_temp_humidity_btt04_temperature') | float(0)) > threshold)
|
or (not temperature_missing and (states('sensor.lcd_temp_humidity_btt04_temperature') | float(0)) > threshold)
|
||||||
}}
|
}}
|
||||||
@@ -608,8 +617,8 @@ template:
|
|||||||
{% set battery_missing = not has_value('sensor.lcd_temp_humidity_btt04_battery') %}
|
{% set battery_missing = not has_value('sensor.lcd_temp_humidity_btt04_battery') %}
|
||||||
{% set percentile = states('sensor.wine_fridge_temperature_95th_percentile_7_days') | float(none) %}
|
{% set percentile = states('sensor.wine_fridge_temperature_95th_percentile_7_days') | float(none) %}
|
||||||
{% set threshold = [9, percentile + 0.5] | min if percentile is not none else 9 %}
|
{% set threshold = [9, percentile + 0.5] | min if percentile is not none else 9 %}
|
||||||
{% if temperature_missing or battery_missing %}
|
{% if temperature_missing %}
|
||||||
{% set ns.items = ns.items + ['Monitor offline'] %}
|
{% set ns.items = ns.items + ['Temperature monitor unavailable'] %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not battery_missing and (states('sensor.lcd_temp_humidity_btt04_battery') | float(-1)) <= 20 %}
|
{% if not battery_missing and (states('sensor.lcd_temp_humidity_btt04_battery') | float(-1)) <= 20 %}
|
||||||
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
||||||
@@ -638,7 +647,7 @@ template:
|
|||||||
{% set temperature_missing = not has_value('sensor.downstairs_fridge_temperature_x43ts_temperature') %}
|
{% set temperature_missing = not has_value('sensor.downstairs_fridge_temperature_x43ts_temperature') %}
|
||||||
{% set battery_missing = not has_value('sensor.downstairs_fridge_temperature_x43ts_battery') %}
|
{% set battery_missing = not has_value('sensor.downstairs_fridge_temperature_x43ts_battery') %}
|
||||||
{% set illuminance_missing = not has_value('sensor.downstairs_fridge_light_sensor_x58ls_illuminance') %}
|
{% set illuminance_missing = not has_value('sensor.downstairs_fridge_light_sensor_x58ls_illuminance') %}
|
||||||
{% set power_missing = not has_value('sensor.downstairs_fridge_power_x41pp_power') %}
|
{% set power_missing = not has_value('sensor.downstairs_fridge_gpo_power_x68pm_power') %}
|
||||||
{% set percentile = states('sensor.downstairs_fridge_temperature_95th_percentile_7_days') | float(none) %}
|
{% set percentile = states('sensor.downstairs_fridge_temperature_95th_percentile_7_days') | float(none) %}
|
||||||
{% set threshold = [10, percentile + 0.5] | min if percentile is not none else 10 %}
|
{% set threshold = [10, percentile + 0.5] | min if percentile is not none else 10 %}
|
||||||
{{
|
{{
|
||||||
@@ -651,7 +660,6 @@ template:
|
|||||||
and not is_state('binary_sensor.downstairs_fridge_temperature_recovery_grace', 'on')
|
and not is_state('binary_sensor.downstairs_fridge_temperature_recovery_grace', 'on')
|
||||||
and (states('sensor.downstairs_fridge_temperature_x43ts_temperature') | float(0)) > threshold
|
and (states('sensor.downstairs_fridge_temperature_x43ts_temperature') | float(0)) > threshold
|
||||||
)
|
)
|
||||||
or states('switch.downstairs_fridge_power_x41pp') != 'on'
|
|
||||||
or power_missing
|
or power_missing
|
||||||
or is_state('binary_sensor.downstairs_fridge_power_draw_lost', 'on')
|
or is_state('binary_sensor.downstairs_fridge_power_draw_lost', 'on')
|
||||||
}}
|
}}
|
||||||
@@ -662,7 +670,7 @@ template:
|
|||||||
{% set temperature_missing = not has_value('sensor.downstairs_fridge_temperature_x43ts_temperature') %}
|
{% set temperature_missing = not has_value('sensor.downstairs_fridge_temperature_x43ts_temperature') %}
|
||||||
{% set battery_missing = not has_value('sensor.downstairs_fridge_temperature_x43ts_battery') %}
|
{% set battery_missing = not has_value('sensor.downstairs_fridge_temperature_x43ts_battery') %}
|
||||||
{% set illuminance_missing = not has_value('sensor.downstairs_fridge_light_sensor_x58ls_illuminance') %}
|
{% set illuminance_missing = not has_value('sensor.downstairs_fridge_light_sensor_x58ls_illuminance') %}
|
||||||
{% set power_missing = not has_value('sensor.downstairs_fridge_power_x41pp_power') %}
|
{% set power_missing = not has_value('sensor.downstairs_fridge_gpo_power_x68pm_power') %}
|
||||||
{% set percentile = states('sensor.downstairs_fridge_temperature_95th_percentile_7_days') | float(none) %}
|
{% set percentile = states('sensor.downstairs_fridge_temperature_95th_percentile_7_days') | float(none) %}
|
||||||
{% set threshold = [10, percentile + 0.5] | min if percentile is not none else 10 %}
|
{% set threshold = [10, percentile + 0.5] | min if percentile is not none else 10 %}
|
||||||
{% if temperature_missing %}
|
{% if temperature_missing %}
|
||||||
@@ -674,10 +682,8 @@ template:
|
|||||||
{% if not battery_missing and (states('sensor.downstairs_fridge_temperature_x43ts_battery') | float(-1)) <= 20 %}
|
{% if not battery_missing and (states('sensor.downstairs_fridge_temperature_x43ts_battery') | float(-1)) <= 20 %}
|
||||||
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if states('switch.downstairs_fridge_power_x41pp') in ['unknown', 'unavailable'] or power_missing %}
|
{% if power_missing %}
|
||||||
{% set ns.items = ns.items + ['Power monitoring unavailable'] %}
|
{% set ns.items = ns.items + ['Power monitoring unavailable'] %}
|
||||||
{% elif not is_state('switch.downstairs_fridge_power_x41pp', 'on') %}
|
|
||||||
{% set ns.items = ns.items + ['Power switched off'] %}
|
|
||||||
{% elif is_state('binary_sensor.downstairs_fridge_power_draw_lost', 'on') %}
|
{% elif is_state('binary_sensor.downstairs_fridge_power_draw_lost', 'on') %}
|
||||||
{% set ns.items = ns.items + ['Power lost - no power draw for 4 hours'] %}
|
{% set ns.items = ns.items + ['Power lost - no power draw for 4 hours'] %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -701,7 +707,7 @@ template:
|
|||||||
{{ [10, percentile + 0.5] | min if percentile is not none else 10 }}
|
{{ [10, percentile + 0.5] | min if percentile is not none else 10 }}
|
||||||
change_rate: "{{ states('sensor.downstairs_fridge_temperature_change_rate') }}"
|
change_rate: "{{ states('sensor.downstairs_fridge_temperature_change_rate') }}"
|
||||||
battery: "{{ states('sensor.downstairs_fridge_temperature_x43ts_battery') }}"
|
battery: "{{ states('sensor.downstairs_fridge_temperature_x43ts_battery') }}"
|
||||||
power: "{{ states('sensor.downstairs_fridge_power_x41pp_power') }}"
|
power: "{{ states('sensor.downstairs_fridge_gpo_power_x68pm_power') }}"
|
||||||
door_open: "{{ is_state('binary_sensor.downstairs_fridge_door_open', 'on') }}"
|
door_open: "{{ is_state('binary_sensor.downstairs_fridge_door_open', 'on') }}"
|
||||||
illuminance: "{{ states('sensor.downstairs_fridge_light_sensor_x58ls_illuminance') }}"
|
illuminance: "{{ states('sensor.downstairs_fridge_light_sensor_x58ls_illuminance') }}"
|
||||||
|
|
||||||
@@ -710,22 +716,22 @@ template:
|
|||||||
device_class: problem
|
device_class: problem
|
||||||
delay_on: "00:01:00"
|
delay_on: "00:01:00"
|
||||||
state: >-
|
state: >-
|
||||||
{% set temperature_missing = not has_value('sensor.downstairs_freezer_temperature_x62ts_temperature') %}
|
{% set temperature_missing = not has_value('sensor.downstairs_freezer_temperature_x70ts_temperature') %}
|
||||||
{% set battery_missing = not has_value('sensor.downstairs_freezer_temperature_x62ts_battery') %}
|
{% set battery_missing = not has_value('sensor.downstairs_freezer_temperature_x70ts_battery') %}
|
||||||
{% set power_missing = not has_value('sensor.downstairs_fridge_power_x41pp_power') %}
|
{% set illuminance_missing = not has_value('sensor.downstairs_freezer_light_sensor_x61ls_illuminance') %}
|
||||||
|
{% set power_missing = not has_value('sensor.downstairs_fridge_gpo_power_x68pm_power') %}
|
||||||
{% set percentile = states('sensor.downstairs_freezer_temperature_95th_percentile_7_days') | float(none) %}
|
{% set percentile = states('sensor.downstairs_freezer_temperature_95th_percentile_7_days') | float(none) %}
|
||||||
{% set threshold = [-5, percentile + 0.5] | min if percentile is not none else -5 %}
|
{% set threshold = [-5, percentile + 0.5] | min if percentile is not none else -5 %}
|
||||||
{{
|
{{
|
||||||
temperature_missing
|
temperature_missing
|
||||||
or battery_missing
|
or illuminance_missing
|
||||||
or (states('sensor.downstairs_freezer_temperature_x62ts_battery') | float(-1)) <= 20
|
or (states('sensor.downstairs_freezer_temperature_x70ts_battery') | float(-1)) <= 20
|
||||||
or is_state('binary_sensor.downstairs_freezer_door_open_too_long', 'on')
|
or is_state('binary_sensor.downstairs_freezer_door_open_too_long', 'on')
|
||||||
or (
|
or (
|
||||||
not temperature_missing
|
not temperature_missing
|
||||||
and not is_state('binary_sensor.downstairs_freezer_temperature_recovery_grace', 'on')
|
and not is_state('binary_sensor.downstairs_freezer_temperature_recovery_grace', 'on')
|
||||||
and (states('sensor.downstairs_freezer_temperature_x62ts_temperature') | float(0)) > threshold
|
and (states('sensor.downstairs_freezer_temperature_x70ts_temperature') | float(0)) > threshold
|
||||||
)
|
)
|
||||||
or states('switch.downstairs_fridge_power_x41pp') != 'on'
|
|
||||||
or power_missing
|
or power_missing
|
||||||
or is_state('binary_sensor.downstairs_fridge_power_draw_lost', 'on')
|
or is_state('binary_sensor.downstairs_fridge_power_draw_lost', 'on')
|
||||||
}}
|
}}
|
||||||
@@ -733,21 +739,23 @@ template:
|
|||||||
appliance: "Downstairs Freezer"
|
appliance: "Downstairs Freezer"
|
||||||
issues: >-
|
issues: >-
|
||||||
{% set ns = namespace(items=[]) %}
|
{% set ns = namespace(items=[]) %}
|
||||||
{% set temperature_missing = not has_value('sensor.downstairs_freezer_temperature_x62ts_temperature') %}
|
{% set temperature_missing = not has_value('sensor.downstairs_freezer_temperature_x70ts_temperature') %}
|
||||||
{% set battery_missing = not has_value('sensor.downstairs_freezer_temperature_x62ts_battery') %}
|
{% set battery_missing = not has_value('sensor.downstairs_freezer_temperature_x70ts_battery') %}
|
||||||
{% set power_missing = not has_value('sensor.downstairs_fridge_power_x41pp_power') %}
|
{% set illuminance_missing = not has_value('sensor.downstairs_freezer_light_sensor_x61ls_illuminance') %}
|
||||||
|
{% set power_missing = not has_value('sensor.downstairs_fridge_gpo_power_x68pm_power') %}
|
||||||
{% set percentile = states('sensor.downstairs_freezer_temperature_95th_percentile_7_days') | float(none) %}
|
{% set percentile = states('sensor.downstairs_freezer_temperature_95th_percentile_7_days') | float(none) %}
|
||||||
{% set threshold = [-5, percentile + 0.5] | min if percentile is not none else -5 %}
|
{% set threshold = [-5, percentile + 0.5] | min if percentile is not none else -5 %}
|
||||||
{% if temperature_missing or battery_missing %}
|
{% if temperature_missing %}
|
||||||
{% set ns.items = ns.items + ['Monitor offline'] %}
|
{% set ns.items = ns.items + ['Temperature monitor unavailable'] %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not battery_missing and (states('sensor.downstairs_freezer_temperature_x62ts_battery') | float(-1)) <= 20 %}
|
{% if illuminance_missing %}
|
||||||
|
{% set ns.items = ns.items + ['Door monitor unavailable'] %}
|
||||||
|
{% endif %}
|
||||||
|
{% if not battery_missing and (states('sensor.downstairs_freezer_temperature_x70ts_battery') | float(-1)) <= 20 %}
|
||||||
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if states('switch.downstairs_fridge_power_x41pp') in ['unknown', 'unavailable'] or power_missing %}
|
{% if power_missing %}
|
||||||
{% set ns.items = ns.items + ['Shared power monitoring unavailable'] %}
|
{% set ns.items = ns.items + ['Shared power monitoring unavailable'] %}
|
||||||
{% elif not is_state('switch.downstairs_fridge_power_x41pp', 'on') %}
|
|
||||||
{% set ns.items = ns.items + ['Shared power switched off'] %}
|
|
||||||
{% elif is_state('binary_sensor.downstairs_fridge_power_draw_lost', 'on') %}
|
{% elif is_state('binary_sensor.downstairs_fridge_power_draw_lost', 'on') %}
|
||||||
{% set ns.items = ns.items + ['Shared power lost - no power draw for 4 hours'] %}
|
{% set ns.items = ns.items + ['Shared power lost - no power draw for 4 hours'] %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -755,7 +763,7 @@ template:
|
|||||||
{% set ns.items = ns.items + ['Door open too long'] %}
|
{% set ns.items = ns.items + ['Door open too long'] %}
|
||||||
{% elif not temperature_missing and is_state('binary_sensor.downstairs_freezer_temperature_recovery_grace', 'on') %}
|
{% elif not temperature_missing and is_state('binary_sensor.downstairs_freezer_temperature_recovery_grace', 'on') %}
|
||||||
{% set ns.items = ns.items + ['Temperature alert delayed - door recently open'] %}
|
{% set ns.items = ns.items + ['Temperature alert delayed - door recently open'] %}
|
||||||
{% elif not temperature_missing and (states('sensor.downstairs_freezer_temperature_x62ts_temperature') | float(0)) > threshold %}
|
{% elif not temperature_missing and (states('sensor.downstairs_freezer_temperature_x70ts_temperature') | float(0)) > threshold %}
|
||||||
{% if (states('sensor.downstairs_freezer_temperature_change_rate') | float(0)) >= 2 %}
|
{% if (states('sensor.downstairs_freezer_temperature_change_rate') | float(0)) >= 2 %}
|
||||||
{% set ns.items = ns.items + ['Warming rapidly - possible open door'] %}
|
{% set ns.items = ns.items + ['Warming rapidly - possible open door'] %}
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -763,15 +771,15 @@ template:
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ ns.items }}
|
{{ ns.items }}
|
||||||
temperature: "{{ states('sensor.downstairs_freezer_temperature_x62ts_temperature') }}"
|
temperature: "{{ states('sensor.downstairs_freezer_temperature_x70ts_temperature') }}"
|
||||||
humidity: "{{ states('sensor.downstairs_freezer_temperature_x62ts_humidity') }}"
|
humidity: "{{ states('sensor.downstairs_freezer_temperature_x70ts_humidity') }}"
|
||||||
average_7_days: "{{ states('sensor.downstairs_freezer_temperature_average_7_days') }}"
|
average_7_days: "{{ states('sensor.downstairs_freezer_temperature_average_7_days') }}"
|
||||||
alert_threshold: >-
|
alert_threshold: >-
|
||||||
{% set percentile = states('sensor.downstairs_freezer_temperature_95th_percentile_7_days') | float(none) %}
|
{% set percentile = states('sensor.downstairs_freezer_temperature_95th_percentile_7_days') | float(none) %}
|
||||||
{{ [-5, percentile + 0.5] | min if percentile is not none else -5 }}
|
{{ [-5, percentile + 0.5] | min if percentile is not none else -5 }}
|
||||||
change_rate: "{{ states('sensor.downstairs_freezer_temperature_change_rate') }}"
|
change_rate: "{{ states('sensor.downstairs_freezer_temperature_change_rate') }}"
|
||||||
battery: "{{ states('sensor.downstairs_freezer_temperature_x62ts_battery') }}"
|
battery: "{{ states('sensor.downstairs_freezer_temperature_x70ts_battery') }}"
|
||||||
power: "{{ states('sensor.downstairs_fridge_power_x41pp_power') }}"
|
power: "{{ states('sensor.downstairs_fridge_gpo_power_x68pm_power') }}"
|
||||||
door_open: "{{ is_state('binary_sensor.downstairs_freezer_door_open', 'on') }}"
|
door_open: "{{ is_state('binary_sensor.downstairs_freezer_door_open', 'on') }}"
|
||||||
illuminance: "{{ states('sensor.downstairs_freezer_light_sensor_x61ls_illuminance') }}"
|
illuminance: "{{ states('sensor.downstairs_freezer_light_sensor_x61ls_illuminance') }}"
|
||||||
|
|
||||||
@@ -787,7 +795,6 @@ template:
|
|||||||
{% set threshold = [-5, percentile + 0.5] | min if percentile is not none else -5 %}
|
{% set threshold = [-5, percentile + 0.5] | min if percentile is not none else -5 %}
|
||||||
{{
|
{{
|
||||||
temperature_missing
|
temperature_missing
|
||||||
or battery_missing
|
|
||||||
or (states('sensor.drinks_freezer_environment_lcd_btt02_battery') | float(-1)) <= 20
|
or (states('sensor.drinks_freezer_environment_lcd_btt02_battery') | float(-1)) <= 20
|
||||||
or states('switch.drinks_fridge_power_x59pm') != 'on'
|
or states('switch.drinks_fridge_power_x59pm') != 'on'
|
||||||
or power_missing
|
or power_missing
|
||||||
@@ -803,8 +810,8 @@ template:
|
|||||||
{% set power_missing = not has_value('sensor.drinks_fridge_power_x59pm_power') %}
|
{% set power_missing = not has_value('sensor.drinks_fridge_power_x59pm_power') %}
|
||||||
{% set percentile = states('sensor.drinks_freezer_temperature_95th_percentile_7_days') | float(none) %}
|
{% set percentile = states('sensor.drinks_freezer_temperature_95th_percentile_7_days') | float(none) %}
|
||||||
{% set threshold = [-5, percentile + 0.5] | min if percentile is not none else -5 %}
|
{% set threshold = [-5, percentile + 0.5] | min if percentile is not none else -5 %}
|
||||||
{% if temperature_missing or battery_missing %}
|
{% if temperature_missing %}
|
||||||
{% set ns.items = ns.items + ['Monitor offline'] %}
|
{% set ns.items = ns.items + ['Temperature monitor unavailable'] %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not battery_missing and (states('sensor.drinks_freezer_environment_lcd_btt02_battery') | float(-1)) <= 20 %}
|
{% if not battery_missing and (states('sensor.drinks_freezer_environment_lcd_btt02_battery') | float(-1)) <= 20 %}
|
||||||
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
||||||
@@ -845,7 +852,6 @@ template:
|
|||||||
{% set threshold = [-10, percentile + 6] | min if percentile is not none else -10 %}
|
{% set threshold = [-10, percentile + 6] | min if percentile is not none else -10 %}
|
||||||
{{
|
{{
|
||||||
temperature_missing
|
temperature_missing
|
||||||
or battery_missing
|
|
||||||
or (states('sensor.lcd_temp_humidity_btt03_battery') | float(-1)) <= 20
|
or (states('sensor.lcd_temp_humidity_btt03_battery') | float(-1)) <= 20
|
||||||
or states('switch.vertical_freezer_power_x60pm') != 'on'
|
or states('switch.vertical_freezer_power_x60pm') != 'on'
|
||||||
or power_missing
|
or power_missing
|
||||||
@@ -861,8 +867,8 @@ template:
|
|||||||
{% set power_missing = not has_value('sensor.vertical_freezer_power_x60pm_power') %}
|
{% set power_missing = not has_value('sensor.vertical_freezer_power_x60pm_power') %}
|
||||||
{% set percentile = states('sensor.vertical_freezer_temperature_95th_percentile_7_days') | float(none) %}
|
{% set percentile = states('sensor.vertical_freezer_temperature_95th_percentile_7_days') | float(none) %}
|
||||||
{% set threshold = [-10, percentile + 6] | min if percentile is not none else -10 %}
|
{% set threshold = [-10, percentile + 6] | min if percentile is not none else -10 %}
|
||||||
{% if temperature_missing or battery_missing %}
|
{% if temperature_missing %}
|
||||||
{% set ns.items = ns.items + ['Monitor offline'] %}
|
{% set ns.items = ns.items + ['Temperature monitor unavailable'] %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not battery_missing and (states('sensor.lcd_temp_humidity_btt03_battery') | float(-1)) <= 20 %}
|
{% if not battery_missing and (states('sensor.lcd_temp_humidity_btt03_battery') | float(-1)) <= 20 %}
|
||||||
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
{% set ns.items = ns.items + ['Low monitor battery'] %}
|
||||||
|
|||||||
@@ -9,9 +9,12 @@
|
|||||||
# packages/garage_corner_light_cctv_motion.yaml
|
# packages/garage_corner_light_cctv_motion.yaml
|
||||||
#
|
#
|
||||||
# VERSION:
|
# VERSION:
|
||||||
# V1.0 2026-06-29
|
# V1.1 2026-08-31
|
||||||
#
|
#
|
||||||
# VERSION HISTORY:
|
# VERSION HISTORY:
|
||||||
|
# V1.1 2026-08-31
|
||||||
|
# - Restrict CCTV motion activation to one hour before sunset through one hour after sunrise.
|
||||||
|
#
|
||||||
# V1.0 2026-06-29
|
# V1.0 2026-06-29
|
||||||
# - Initial package.
|
# - Initial package.
|
||||||
# - Turns the garage external corner light on when CCTV motion MQTT payload "1" is received.
|
# - Turns the garage external corner light on when CCTV motion MQTT payload "1" is received.
|
||||||
@@ -20,7 +23,8 @@
|
|||||||
# - Adds a Home Assistant enable switch for CCTV movement triggers.
|
# - Adds a Home Assistant enable switch for CCTV movement triggers.
|
||||||
#
|
#
|
||||||
# PURPOSE:
|
# PURPOSE:
|
||||||
# Turns on the garage external corner light from selected CCTV motion MQTT triggers.
|
# Turns on the garage external corner light from selected CCTV motion MQTT triggers
|
||||||
|
# during the configured night window.
|
||||||
#
|
#
|
||||||
# NOTES:
|
# NOTES:
|
||||||
# - The light is:
|
# - The light is:
|
||||||
@@ -31,6 +35,7 @@
|
|||||||
#
|
#
|
||||||
# - Turning OFF "Garage corner light movement triggers" prevents new CCTV triggers.
|
# - Turning OFF "Garage corner light movement triggers" prevents new CCTV triggers.
|
||||||
# - If a timer is already running, it will still finish and turn the light off.
|
# - If a timer is already running, it will still finish and turn the light off.
|
||||||
|
# - CCTV triggers run from one hour before sunset until one hour after sunrise.
|
||||||
#
|
#
|
||||||
#:########################################################################################:#
|
#:########################################################################################:#
|
||||||
# User Configuration #
|
# User Configuration #
|
||||||
@@ -91,6 +96,12 @@ automation:
|
|||||||
entity_id: input_boolean.garage_corner_light_movement_triggers
|
entity_id: input_boolean.garage_corner_light_movement_triggers
|
||||||
state: "on"
|
state: "on"
|
||||||
|
|
||||||
|
- condition: sun
|
||||||
|
after: sunset
|
||||||
|
after_offset: "-01:00:00"
|
||||||
|
before: sunrise
|
||||||
|
before_offset: "01:00:00"
|
||||||
|
|
||||||
action:
|
action:
|
||||||
- service: switch.turn_on
|
- service: switch.turn_on
|
||||||
target:
|
target:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
# jobs_tracker_appliance_completion_triggers.yaml
|
# jobs_tracker_appliance_completion_triggers.yaml
|
||||||
#
|
#
|
||||||
# VERSION:
|
# VERSION:
|
||||||
# V1.0 2026-08-15
|
# V1.1 2026-09-03
|
||||||
#
|
#
|
||||||
# PURPOSE:
|
# PURPOSE:
|
||||||
# Provides time-qualified appliance door and lid triggers for Jobs Tracker completion.
|
# Provides time-qualified appliance door and lid triggers for Jobs Tracker completion.
|
||||||
@@ -19,9 +19,13 @@
|
|||||||
#
|
#
|
||||||
# OPERATION:
|
# OPERATION:
|
||||||
# Each contact must remain open for five seconds before its corresponding Jobs Tracker
|
# Each contact must remain open for five seconds before its corresponding Jobs Tracker
|
||||||
# completion route is called. The job registry owns the completion entity mappings.
|
# completion route is called. Starting the dryer or washer clears only a previous Due
|
||||||
|
# unload job, so the next finished cycle creates its own new unload task.
|
||||||
#
|
#
|
||||||
# VERSION HISTORY:
|
# VERSION HISTORY:
|
||||||
|
# V1.1 2026-09-03
|
||||||
|
# - Clear a pending dryer or washer unload job when its next cycle starts.
|
||||||
|
#
|
||||||
# V1.0 2026-08-15
|
# V1.0 2026-08-15
|
||||||
# - Added five-second door and lid open completion triggers for dryer and washer jobs.
|
# - Added five-second door and lid open completion triggers for dryer and washer jobs.
|
||||||
#
|
#
|
||||||
@@ -63,3 +67,43 @@ automation:
|
|||||||
data:
|
data:
|
||||||
completion_entity: binary_sensor.washing_machine_lid_status_x39rs_contact
|
completion_entity: binary_sensor.washing_machine_lid_status_x39rs_contact
|
||||||
completion_to_state: "on"
|
completion_to_state: "on"
|
||||||
|
|
||||||
|
- id: jobs_tracker_clear_dryer_unload_on_start
|
||||||
|
alias: "Jobs Tracker - Clear Dryer Unload on Start"
|
||||||
|
description: "Clears an outstanding Empty the Dryer job when a new dryer cycle starts."
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: state
|
||||||
|
entity_id: sensor.appliance_monitor_dryer_monitor
|
||||||
|
to: Operating
|
||||||
|
|
||||||
|
conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: sensor.jobs_tracker_empty_dryer
|
||||||
|
state: Due
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- action: script.jobs_tracker_dispatch
|
||||||
|
data:
|
||||||
|
job_id: empty_dryer
|
||||||
|
|
||||||
|
- id: jobs_tracker_clear_washer_unload_on_start
|
||||||
|
alias: "Jobs Tracker - Clear Washer Unload on Start"
|
||||||
|
description: "Clears an outstanding Empty the Washer job when a new washer cycle starts."
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: state
|
||||||
|
entity_id: sensor.appliance_monitor_washing_machine_monitor
|
||||||
|
to: Operating
|
||||||
|
|
||||||
|
conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: sensor.jobs_tracker_empty_washing_machine
|
||||||
|
state: Due
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- action: script.jobs_tracker_dispatch
|
||||||
|
data:
|
||||||
|
job_id: empty_washing_machine
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#:########################################################################################:#
|
||||||
|
# Jobs Tracker Appliance Completion Triggers Package #
|
||||||
|
#:########################################################################################:#
|
||||||
|
#
|
||||||
|
# TITLE:
|
||||||
|
# Jobs Tracker Appliance Completion Triggers
|
||||||
|
#
|
||||||
|
# FILE:
|
||||||
|
# jobs_tracker_appliance_completion_triggers.yaml
|
||||||
|
#
|
||||||
|
# VERSION:
|
||||||
|
# V1.0 2026-08-15
|
||||||
|
#
|
||||||
|
# PURPOSE:
|
||||||
|
# Provides time-qualified appliance door and lid triggers for Jobs Tracker completion.
|
||||||
|
#
|
||||||
|
# DEPENDS ON:
|
||||||
|
# packages/Job_Chore_Tracking/jobs_tracker_jobs.yaml V3.5 or newer.
|
||||||
|
#
|
||||||
|
# OPERATION:
|
||||||
|
# Each contact must remain open for five seconds before its corresponding Jobs Tracker
|
||||||
|
# completion route is called. The job registry owns the completion entity mappings.
|
||||||
|
#
|
||||||
|
# VERSION HISTORY:
|
||||||
|
# V1.0 2026-08-15
|
||||||
|
# - Added five-second door and lid open completion triggers for dryer and washer jobs.
|
||||||
|
#
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
automation:
|
||||||
|
- id: jobs_tracker_empty_dryer_door_open
|
||||||
|
alias: "Jobs Tracker - Empty Dryer on Door Open"
|
||||||
|
description: "Marks Empty the Dryer complete after the dryer door is open for five seconds."
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: state
|
||||||
|
entity_id: binary_sensor.dryer_door_status_x34rs_contact
|
||||||
|
to: "on"
|
||||||
|
for:
|
||||||
|
seconds: 5
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- action: script.jobs_tracker_route_completion
|
||||||
|
data:
|
||||||
|
completion_entity: binary_sensor.dryer_door_status_x34rs_contact
|
||||||
|
completion_to_state: "on"
|
||||||
|
|
||||||
|
- id: jobs_tracker_empty_washing_machine_lid_open
|
||||||
|
alias: "Jobs Tracker - Empty Washer on Lid Open"
|
||||||
|
description: "Marks Empty the Washer complete after the washer lid is open for five seconds."
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: state
|
||||||
|
entity_id: binary_sensor.washing_machine_lid_status_x39rs_contact
|
||||||
|
to: "on"
|
||||||
|
for:
|
||||||
|
seconds: 5
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- action: script.jobs_tracker_route_completion
|
||||||
|
data:
|
||||||
|
completion_entity: binary_sensor.washing_machine_lid_status_x39rs_contact
|
||||||
|
completion_to_state: "on"
|
||||||
@@ -635,8 +635,11 @@ script:
|
|||||||
entity_id: input_datetime.outdoor_lighting_number_16_last_schedule_event
|
entity_id: input_datetime.outdoor_lighting_number_16_last_schedule_event
|
||||||
data:
|
data:
|
||||||
datetime: "{{ (selected_event_ts | int(0)) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}"
|
datetime: "{{ (selected_event_ts | int(0)) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}"
|
||||||
- action: script.outdoor_lighting_ramp_number_16
|
- action: script.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: script.outdoor_lighting_ramp_number_16
|
||||||
data:
|
data:
|
||||||
|
variables:
|
||||||
target_brightness: "{{ selected_target | int(0) }}"
|
target_brightness: "{{ selected_target | int(0) }}"
|
||||||
ramp_seconds: "{{ ramp_to_use | int(0) }}"
|
ramp_seconds: "{{ ramp_to_use | int(0) }}"
|
||||||
|
|
||||||
@@ -787,8 +790,11 @@ script:
|
|||||||
entity_id: input_datetime.outdoor_lighting_main_entrance_last_schedule_event
|
entity_id: input_datetime.outdoor_lighting_main_entrance_last_schedule_event
|
||||||
data:
|
data:
|
||||||
datetime: "{{ (selected_event_ts | int(0)) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}"
|
datetime: "{{ (selected_event_ts | int(0)) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}"
|
||||||
- action: script.outdoor_lighting_ramp_main_entrance
|
- action: script.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: script.outdoor_lighting_ramp_main_entrance
|
||||||
data:
|
data:
|
||||||
|
variables:
|
||||||
target_brightness: "{{ selected_target | int(0) }}"
|
target_brightness: "{{ selected_target | int(0) }}"
|
||||||
ramp_seconds: "{{ ramp_to_use | int(0) }}"
|
ramp_seconds: "{{ ramp_to_use | int(0) }}"
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#:########################################################################################:#
|
#:########################################################################################:#
|
||||||
# Package: Pet Feeding and Jobs Timing
|
# Package: Pet Feeding and Jobs Timing
|
||||||
# File: pet_feeding_and_jobs.yaml
|
# File: pet_feeding_and_jobs.yaml
|
||||||
# Version: v1.4.0
|
# Version: v1.5.2
|
||||||
# Date: 2026-07-26
|
# Date: 2026-09-09
|
||||||
#
|
#
|
||||||
# Purpose:
|
# Purpose:
|
||||||
# Provides legacy MQTT pet activity sensors and Jobs-derived timing sensors for
|
# Provides legacy MQTT pet activity sensors and Jobs-derived timing sensors for
|
||||||
@@ -17,6 +17,11 @@
|
|||||||
# instead of exposing a numeric sentinel value.
|
# instead of exposing a numeric sentinel value.
|
||||||
#
|
#
|
||||||
# Version History:
|
# Version History:
|
||||||
|
# - v1.5.2 (2026-09-12): Ignore stale restored dog-button event states so
|
||||||
|
# reconnects cannot create false timestamps or visual feedback.
|
||||||
|
# - v1.5.1 (2026-09-09): Extended dog-button feedback intervals to 500 ms.
|
||||||
|
# - v1.5.0 (2026-09-09): Added visual feedback flashes for physical dog
|
||||||
|
# completion buttons, using the Lounge outside light relay.
|
||||||
# - v1.4.0 (2026-07-26): Announce four physical job completions on the Sony
|
# - v1.4.0 (2026-07-26): Announce four physical job completions on the Sony
|
||||||
# lounge TV and both Pushover devices.
|
# lounge TV and both Pushover devices.
|
||||||
# - v1.3.0 (2026-07-26): Restore retained dog-fed and jobs-done activity
|
# - v1.3.0 (2026-07-26): Restore retained dog-fed and jobs-done activity
|
||||||
@@ -122,7 +127,12 @@ automation:
|
|||||||
conditions:
|
conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: >-
|
value_template: >-
|
||||||
{{ trigger.to_state.state not in ['unknown', 'unavailable'] }}
|
{% set valid_state = trigger.to_state is not none
|
||||||
|
and trigger.to_state.state not in ['unknown', 'unavailable'] %}
|
||||||
|
{% set event_ts = as_timestamp(trigger.to_state.state, 0)
|
||||||
|
if valid_state else 0 %}
|
||||||
|
{% set event_age = as_timestamp(now()) - event_ts %}
|
||||||
|
{{ valid_state and event_ts > 0 and event_age >= 0 and event_age <= 30 }}
|
||||||
actions:
|
actions:
|
||||||
- action: input_datetime.set_datetime
|
- action: input_datetime.set_datetime
|
||||||
target:
|
target:
|
||||||
@@ -145,7 +155,12 @@ automation:
|
|||||||
conditions:
|
conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: >-
|
value_template: >-
|
||||||
{{ trigger.to_state.state not in ['unknown', 'unavailable'] }}
|
{% set valid_state = trigger.to_state is not none
|
||||||
|
and trigger.to_state.state not in ['unknown', 'unavailable'] %}
|
||||||
|
{% set event_ts = as_timestamp(trigger.to_state.state, 0)
|
||||||
|
if valid_state else 0 %}
|
||||||
|
{% set event_age = as_timestamp(now()) - event_ts %}
|
||||||
|
{{ valid_state and event_ts > 0 and event_age >= 0 and event_age <= 30 }}
|
||||||
actions:
|
actions:
|
||||||
- action: input_datetime.set_datetime
|
- action: input_datetime.set_datetime
|
||||||
target:
|
target:
|
||||||
@@ -227,3 +242,64 @@ automation:
|
|||||||
title: "Jobs Announcement"
|
title: "Jobs Announcement"
|
||||||
short_announcement: "{{ completion_message }}"
|
short_announcement: "{{ completion_message }}"
|
||||||
long_announcement: "{{ completion_message }}"
|
long_announcement: "{{ completion_message }}"
|
||||||
|
|
||||||
|
#:######################################################################################:#
|
||||||
|
# AUTOMATION: Physical Dog-Button Visual Feedback
|
||||||
|
#:######################################################################################:#
|
||||||
|
- id: dog_button_visual_feedback
|
||||||
|
alias: "Jobs - Dog Button Visual Feedback"
|
||||||
|
description: >-
|
||||||
|
Flashes the Lounge outside light relay for one physical single-press,
|
||||||
|
preserving its original state after dog feeding or depooping is recorded.
|
||||||
|
mode: queued
|
||||||
|
max: 10
|
||||||
|
triggers:
|
||||||
|
- trigger: state
|
||||||
|
entity_id:
|
||||||
|
- event.jobs_dog_fed_button_x14bt_action
|
||||||
|
- event.jobs_dog_depooped_button_x15bt_action
|
||||||
|
conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: >-
|
||||||
|
{% set valid_state = trigger.to_state is not none
|
||||||
|
and trigger.to_state.state not in ['unknown', 'unavailable'] %}
|
||||||
|
{% set event_ts = as_timestamp(trigger.to_state.state, 0)
|
||||||
|
if valid_state else 0 %}
|
||||||
|
{% set event_age = as_timestamp(now()) - event_ts %}
|
||||||
|
{{
|
||||||
|
valid_state
|
||||||
|
and event_ts > 0
|
||||||
|
and event_age >= 0
|
||||||
|
and event_age <= 30
|
||||||
|
and trigger.to_state.attributes.event_type == 'single'
|
||||||
|
}}
|
||||||
|
actions:
|
||||||
|
- variables:
|
||||||
|
initial_state: "{{ states('switch.esp_loungesouthleftswitch_relay_2_outside_light_1') }}"
|
||||||
|
flash_count: >-
|
||||||
|
{{ 2 if trigger.entity_id == 'event.jobs_dog_fed_button_x14bt_action' else 3 }}
|
||||||
|
- repeat:
|
||||||
|
count: "{{ flash_count | int }}"
|
||||||
|
sequence:
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ initial_state == 'off' }}"
|
||||||
|
sequence:
|
||||||
|
- action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: switch.esp_loungesouthleftswitch_relay_2_outside_light_1
|
||||||
|
- delay: "00:00:00.500"
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.esp_loungesouthleftswitch_relay_2_outside_light_1
|
||||||
|
- delay: "00:00:00.500"
|
||||||
|
default:
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.esp_loungesouthleftswitch_relay_2_outside_light_1
|
||||||
|
- delay: "00:00:00.500"
|
||||||
|
- action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: switch.esp_loungesouthleftswitch_relay_2_outside_light_1
|
||||||
|
- delay: "00:00:00.500"
|
||||||
|
|||||||
@@ -9,42 +9,24 @@
|
|||||||
# quiet_time_on_off_actions.yaml
|
# quiet_time_on_off_actions.yaml
|
||||||
#
|
#
|
||||||
# VERSION:
|
# VERSION:
|
||||||
# V1.2 2026-06-20
|
# V1.3 2026-09-04
|
||||||
#
|
|
||||||
# VERSION HISTORY:
|
|
||||||
# V1.2 2026-06-20
|
|
||||||
# - Added Quiet Time OFF action to change OpenHASP panel openhasp_1
|
|
||||||
# back to page 1.
|
|
||||||
#
|
|
||||||
# V1.1 2026-06-15
|
|
||||||
# - Added separate Quiet Time ON and Quiet Time OFF action sections.
|
|
||||||
# - Added support for non-binary Quiet Time OFF actions.
|
|
||||||
# - Sets input_number.openhasp_1_backlight_level to 200 when Quiet Time ends.
|
|
||||||
#
|
|
||||||
# V1.0 2026-06-15
|
|
||||||
# - Initial standalone package split out from the main Quiet Time package.
|
|
||||||
# - Turns selected entities on/off when input_boolean.quiet_time changes.
|
|
||||||
#
|
#
|
||||||
# PURPOSE:
|
# PURPOSE:
|
||||||
# Runs local Home Assistant actions when Quiet Time is turned ON or OFF.
|
# Runs local Home Assistant actions when Quiet Time is turned ON or OFF.
|
||||||
#
|
#
|
||||||
# The main Quiet Time package should continue to own:
|
# The main Quiet Time package owns the helper, daily reset behaviour, and MQTT
|
||||||
# - input_boolean.quiet_time
|
# publishing. This package owns extra local Quiet Time actions.
|
||||||
# - daily reset behaviour
|
|
||||||
# - MQTT quiet_time state publishing
|
|
||||||
#
|
#
|
||||||
# This package only handles extra local actions that should happen when
|
# VERSION HISTORY:
|
||||||
# Quiet Time starts or ends.
|
# V1.3 2026-09-04
|
||||||
|
# - Disables Flounder Motion Wake during Quiet Time and requests a one-off
|
||||||
|
# 10-second presence fade to Screen Off.
|
||||||
|
# - Restores Flounder Motion Wake when Quiet Time ends.
|
||||||
#
|
#
|
||||||
# EDITING NOTES:
|
# V1.2 2026-06-20
|
||||||
# - Add normal on/off entities to the relevant entity lists.
|
# - Added Quiet Time OFF action to change OpenHASP panel openhasp_1 back to
|
||||||
# - Empty lists are fine and will simply do nothing.
|
# page 1.
|
||||||
# - Use the "Other Quiet Time OFF Actions" section for things that are not
|
|
||||||
# simple on/off actions, such as setting input_numbers, selects, scenes,
|
|
||||||
# scripts, MQTT commands, or custom service calls.
|
|
||||||
#
|
#
|
||||||
################################################################################
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# AUTOMATIONS
|
# AUTOMATIONS
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -56,56 +38,15 @@ automation:
|
|||||||
mode: single
|
mode: single
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
##########################################################################
|
|
||||||
# QUIET TIME ON ACTION LISTS
|
|
||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# These actions run when input_boolean.quiet_time changes to "on".
|
|
||||||
#
|
|
||||||
|
|
||||||
quiet_time_on_turn_off_entities:
|
quiet_time_on_turn_off_entities:
|
||||||
- light.led_matrix_display_led_matrix_display_display
|
- light.led_matrix_display_led_matrix_display_display
|
||||||
|
|
||||||
quiet_time_on_turn_on_entities: []
|
quiet_time_on_turn_on_entities: []
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
# QUIET TIME OFF ACTION LISTS
|
|
||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# These actions run when input_boolean.quiet_time changes to "off".
|
|
||||||
#
|
|
||||||
|
|
||||||
quiet_time_off_turn_off_entities: []
|
quiet_time_off_turn_off_entities: []
|
||||||
|
|
||||||
quiet_time_off_turn_on_entities:
|
quiet_time_off_turn_on_entities:
|
||||||
- light.led_matrix_display_led_matrix_display_display
|
- light.led_matrix_display_led_matrix_display_display
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
# OTHER QUIET TIME OFF ACTION VALUES
|
|
||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# Use this list for input_number helpers that should be set when Quiet Time
|
|
||||||
# ends.
|
|
||||||
#
|
|
||||||
# Format:
|
|
||||||
# - entity_id: input_number.some_helper
|
|
||||||
# value: 123
|
|
||||||
#
|
|
||||||
|
|
||||||
quiet_time_off_input_number_values:
|
quiet_time_off_input_number_values:
|
||||||
- entity_id: input_number.openhasp_1_backlight_level
|
- entity_id: input_number.openhasp_1_backlight_level
|
||||||
value: 200
|
value: 200
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
# OPENHASP QUIET TIME OFF PAGE ACTION
|
|
||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# Sends the OpenHASP panel back to the main page when Quiet Time ends.
|
|
||||||
#
|
|
||||||
# Current OpenHASP MQTT command topic:
|
|
||||||
# hasp/openhasp_1/command/page
|
|
||||||
#
|
|
||||||
|
|
||||||
quiet_time_off_openhasp_page_topic: "hasp/openhasp_1/command/page"
|
quiet_time_off_openhasp_page_topic: "hasp/openhasp_1/command/page"
|
||||||
quiet_time_off_openhasp_page: 1
|
quiet_time_off_openhasp_page: 1
|
||||||
|
|
||||||
@@ -121,13 +62,6 @@ automation:
|
|||||||
|
|
||||||
actions:
|
actions:
|
||||||
- choose:
|
- choose:
|
||||||
######################################################################
|
|
||||||
# QUIET TIME ON ACTIONS
|
|
||||||
######################################################################
|
|
||||||
#
|
|
||||||
# Runs when Quiet Time starts.
|
|
||||||
#
|
|
||||||
|
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ trigger.to_state.state == 'on' }}"
|
value_template: "{{ trigger.to_state.state == 'on' }}"
|
||||||
@@ -138,47 +72,44 @@ automation:
|
|||||||
- action: homeassistant.turn_off
|
- action: homeassistant.turn_off
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ repeat.item }}"
|
entity_id: "{{ repeat.item }}"
|
||||||
|
|
||||||
- repeat:
|
- repeat:
|
||||||
for_each: "{{ quiet_time_on_turn_on_entities }}"
|
for_each: "{{ quiet_time_on_turn_on_entities }}"
|
||||||
sequence:
|
sequence:
|
||||||
- action: homeassistant.turn_on
|
- action: homeassistant.turn_on
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ repeat.item }}"
|
entity_id: "{{ repeat.item }}"
|
||||||
|
# Stop camera motion from extending presence, then fade the
|
||||||
######################################################################
|
# current session to the existing Screen Off base state.
|
||||||
# QUIET TIME OFF ACTIONS
|
- action: switch.turn_off
|
||||||
######################################################################
|
target:
|
||||||
#
|
entity_id: switch.flounder_kiosk_motion_wake
|
||||||
# Runs when Quiet Time ends.
|
- wait_template: "{{ is_state('switch.flounder_kiosk_motion_wake', 'off') }}"
|
||||||
#
|
timeout: "00:00:10"
|
||||||
|
continue_on_timeout: true
|
||||||
|
- action: mqtt.publish
|
||||||
|
data:
|
||||||
|
topic: "viewroad-commands/flounder/presence/end"
|
||||||
|
payload: "10"
|
||||||
|
retain: false
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ trigger.to_state.state == 'off' }}"
|
value_template: "{{ trigger.to_state.state == 'off' }}"
|
||||||
sequence:
|
sequence:
|
||||||
##################################################################
|
|
||||||
# Quiet Time OFF - binary/entity actions
|
|
||||||
##################################################################
|
|
||||||
|
|
||||||
- repeat:
|
- repeat:
|
||||||
for_each: "{{ quiet_time_off_turn_off_entities }}"
|
for_each: "{{ quiet_time_off_turn_off_entities }}"
|
||||||
sequence:
|
sequence:
|
||||||
- action: homeassistant.turn_off
|
- action: homeassistant.turn_off
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ repeat.item }}"
|
entity_id: "{{ repeat.item }}"
|
||||||
|
|
||||||
- repeat:
|
- repeat:
|
||||||
for_each: "{{ quiet_time_off_turn_on_entities }}"
|
for_each: "{{ quiet_time_off_turn_on_entities }}"
|
||||||
sequence:
|
sequence:
|
||||||
- action: homeassistant.turn_on
|
- action: homeassistant.turn_on
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ repeat.item }}"
|
entity_id: "{{ repeat.item }}"
|
||||||
|
- action: switch.turn_on
|
||||||
##################################################################
|
target:
|
||||||
# Quiet Time OFF - input_number set actions
|
entity_id: switch.flounder_kiosk_motion_wake
|
||||||
##################################################################
|
|
||||||
|
|
||||||
- repeat:
|
- repeat:
|
||||||
for_each: "{{ quiet_time_off_input_number_values }}"
|
for_each: "{{ quiet_time_off_input_number_values }}"
|
||||||
sequence:
|
sequence:
|
||||||
@@ -187,34 +118,8 @@ automation:
|
|||||||
entity_id: "{{ repeat.item.entity_id }}"
|
entity_id: "{{ repeat.item.entity_id }}"
|
||||||
data:
|
data:
|
||||||
value: "{{ repeat.item.value | float }}"
|
value: "{{ repeat.item.value | float }}"
|
||||||
|
|
||||||
##################################################################
|
|
||||||
# Quiet Time OFF - OpenHASP page action
|
|
||||||
##################################################################
|
|
||||||
#
|
|
||||||
# Change OpenHASP panel back to page 1 when Quiet Time ends.
|
|
||||||
#
|
|
||||||
|
|
||||||
- action: mqtt.publish
|
- action: mqtt.publish
|
||||||
data:
|
data:
|
||||||
topic: "{{ quiet_time_off_openhasp_page_topic }}"
|
topic: "{{ quiet_time_off_openhasp_page_topic }}"
|
||||||
payload: "{{ quiet_time_off_openhasp_page | int }}"
|
payload: "{{ quiet_time_off_openhasp_page | int }}"
|
||||||
retain: false
|
retain: false
|
||||||
|
|
||||||
##################################################################
|
|
||||||
# Quiet Time OFF - other custom actions
|
|
||||||
##################################################################
|
|
||||||
#
|
|
||||||
# Add any extra non-binary service calls here later.
|
|
||||||
#
|
|
||||||
# Examples:
|
|
||||||
#
|
|
||||||
# - action: script.some_script
|
|
||||||
#
|
|
||||||
# - action: select.select_option
|
|
||||||
# target:
|
|
||||||
# entity_id: select.some_select
|
|
||||||
# data:
|
|
||||||
# option: "Some Option"
|
|
||||||
#
|
|
||||||
##################################################################
|
|
||||||
|
|||||||
@@ -0,0 +1,245 @@
|
|||||||
|
################################################################################
|
||||||
|
# Quiet Time On / Off Actions Package
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# TITLE:
|
||||||
|
# Quiet Time On / Off Actions
|
||||||
|
#
|
||||||
|
# FILE:
|
||||||
|
# quiet_time_on_off_actions.yaml
|
||||||
|
#
|
||||||
|
# VERSION:
|
||||||
|
# V1.3 2026-09-04
|
||||||
|
# - Disables Flounder Motion Wake during Quiet Time and requests a one-off
|
||||||
|
# 10-second presence fade to Screen Off.
|
||||||
|
# - Restores Flounder Motion Wake when Quiet Time ends.
|
||||||
|
#
|
||||||
|
# V1.2 2026-06-20
|
||||||
|
#
|
||||||
|
# VERSION HISTORY:
|
||||||
|
# V1.2 2026-06-20
|
||||||
|
# - Added Quiet Time OFF action to change OpenHASP panel openhasp_1
|
||||||
|
# back to page 1.
|
||||||
|
#
|
||||||
|
# V1.1 2026-06-15
|
||||||
|
# - Added separate Quiet Time ON and Quiet Time OFF action sections.
|
||||||
|
# - Added support for non-binary Quiet Time OFF actions.
|
||||||
|
# - Sets input_number.openhasp_1_backlight_level to 200 when Quiet Time ends.
|
||||||
|
#
|
||||||
|
# V1.0 2026-06-15
|
||||||
|
# - Initial standalone package split out from the main Quiet Time package.
|
||||||
|
# - Turns selected entities on/off when input_boolean.quiet_time changes.
|
||||||
|
#
|
||||||
|
# PURPOSE:
|
||||||
|
# Runs local Home Assistant actions when Quiet Time is turned ON or OFF.
|
||||||
|
#
|
||||||
|
# The main Quiet Time package should continue to own:
|
||||||
|
# - input_boolean.quiet_time
|
||||||
|
# - daily reset behaviour
|
||||||
|
# - MQTT quiet_time state publishing
|
||||||
|
#
|
||||||
|
# This package only handles extra local actions that should happen when
|
||||||
|
# Quiet Time starts or ends.
|
||||||
|
#
|
||||||
|
# EDITING NOTES:
|
||||||
|
# - Add normal on/off entities to the relevant entity lists.
|
||||||
|
# - Empty lists are fine and will simply do nothing.
|
||||||
|
# - Use the "Other Quiet Time OFF Actions" section for things that are not
|
||||||
|
# simple on/off actions, such as setting input_numbers, selects, scenes,
|
||||||
|
# scripts, MQTT commands, or custom service calls.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# AUTOMATIONS
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
automation:
|
||||||
|
- id: quiet_time_state_change_actions
|
||||||
|
alias: "Quiet Time - State Change Actions"
|
||||||
|
description: "Runs configured Home Assistant actions when Quiet Time is turned on or off."
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
variables:
|
||||||
|
##########################################################################
|
||||||
|
# QUIET TIME ON ACTION LISTS
|
||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# These actions run when input_boolean.quiet_time changes to "on".
|
||||||
|
#
|
||||||
|
|
||||||
|
quiet_time_on_turn_off_entities:
|
||||||
|
- light.led_matrix_display_led_matrix_display_display
|
||||||
|
|
||||||
|
quiet_time_on_turn_on_entities: []
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# QUIET TIME OFF ACTION LISTS
|
||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# These actions run when input_boolean.quiet_time changes to "off".
|
||||||
|
#
|
||||||
|
|
||||||
|
quiet_time_off_turn_off_entities: []
|
||||||
|
|
||||||
|
quiet_time_off_turn_on_entities:
|
||||||
|
- light.led_matrix_display_led_matrix_display_display
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# OTHER QUIET TIME OFF ACTION VALUES
|
||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# Use this list for input_number helpers that should be set when Quiet Time
|
||||||
|
# ends.
|
||||||
|
#
|
||||||
|
# Format:
|
||||||
|
# - entity_id: input_number.some_helper
|
||||||
|
# value: 123
|
||||||
|
#
|
||||||
|
|
||||||
|
quiet_time_off_input_number_values:
|
||||||
|
- entity_id: input_number.openhasp_1_backlight_level
|
||||||
|
value: 200
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# OPENHASP QUIET TIME OFF PAGE ACTION
|
||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# Sends the OpenHASP panel back to the main page when Quiet Time ends.
|
||||||
|
#
|
||||||
|
# Current OpenHASP MQTT command topic:
|
||||||
|
# hasp/openhasp_1/command/page
|
||||||
|
#
|
||||||
|
|
||||||
|
quiet_time_off_openhasp_page_topic: "hasp/openhasp_1/command/page"
|
||||||
|
quiet_time_off_openhasp_page: 1
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: state
|
||||||
|
entity_id: input_boolean.quiet_time
|
||||||
|
from:
|
||||||
|
- "on"
|
||||||
|
- "off"
|
||||||
|
to:
|
||||||
|
- "on"
|
||||||
|
- "off"
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- choose:
|
||||||
|
######################################################################
|
||||||
|
# QUIET TIME ON ACTIONS
|
||||||
|
######################################################################
|
||||||
|
#
|
||||||
|
# Runs when Quiet Time starts.
|
||||||
|
#
|
||||||
|
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ trigger.to_state.state == 'on' }}"
|
||||||
|
sequence:
|
||||||
|
- repeat:
|
||||||
|
for_each: "{{ quiet_time_on_turn_off_entities }}"
|
||||||
|
sequence:
|
||||||
|
- action: homeassistant.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: "{{ repeat.item }}"
|
||||||
|
|
||||||
|
- repeat:
|
||||||
|
for_each: "{{ quiet_time_on_turn_on_entities }}"
|
||||||
|
sequence:
|
||||||
|
- action: homeassistant.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: "{{ repeat.item }}"
|
||||||
|
|
||||||
|
# Stop camera motion from extending presence, then fade the
|
||||||
|
# current session to the existing Screen Off base state.
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.flounder_kiosk_motion_wake
|
||||||
|
|
||||||
|
- wait_template: "{{ is_state('switch.flounder_kiosk_motion_wake', 'off') }}"
|
||||||
|
timeout: "00:00:10"
|
||||||
|
continue_on_timeout: true
|
||||||
|
|
||||||
|
- action: mqtt.publish
|
||||||
|
data:
|
||||||
|
topic: "viewroad-commands/flounder/presence/end"
|
||||||
|
payload: "10"
|
||||||
|
retain: false
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# QUIET TIME OFF ACTIONS
|
||||||
|
######################################################################
|
||||||
|
#
|
||||||
|
# Runs when Quiet Time ends.
|
||||||
|
#
|
||||||
|
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ trigger.to_state.state == 'off' }}"
|
||||||
|
sequence:
|
||||||
|
##################################################################
|
||||||
|
# Quiet Time OFF - binary/entity actions
|
||||||
|
##################################################################
|
||||||
|
|
||||||
|
- repeat:
|
||||||
|
for_each: "{{ quiet_time_off_turn_off_entities }}"
|
||||||
|
sequence:
|
||||||
|
- action: homeassistant.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: "{{ repeat.item }}"
|
||||||
|
|
||||||
|
- repeat:
|
||||||
|
for_each: "{{ quiet_time_off_turn_on_entities }}"
|
||||||
|
sequence:
|
||||||
|
- action: homeassistant.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: "{{ repeat.item }}"
|
||||||
|
|
||||||
|
- action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: switch.flounder_kiosk_motion_wake
|
||||||
|
|
||||||
|
##################################################################
|
||||||
|
# Quiet Time OFF - input_number set actions
|
||||||
|
##################################################################
|
||||||
|
|
||||||
|
- repeat:
|
||||||
|
for_each: "{{ quiet_time_off_input_number_values }}"
|
||||||
|
sequence:
|
||||||
|
- action: input_number.set_value
|
||||||
|
target:
|
||||||
|
entity_id: "{{ repeat.item.entity_id }}"
|
||||||
|
data:
|
||||||
|
value: "{{ repeat.item.value | float }}"
|
||||||
|
|
||||||
|
##################################################################
|
||||||
|
# Quiet Time OFF - OpenHASP page action
|
||||||
|
##################################################################
|
||||||
|
#
|
||||||
|
# Change OpenHASP panel back to page 1 when Quiet Time ends.
|
||||||
|
#
|
||||||
|
|
||||||
|
- action: mqtt.publish
|
||||||
|
data:
|
||||||
|
topic: "{{ quiet_time_off_openhasp_page_topic }}"
|
||||||
|
payload: "{{ quiet_time_off_openhasp_page | int }}"
|
||||||
|
retain: false
|
||||||
|
|
||||||
|
##################################################################
|
||||||
|
# Quiet Time OFF - other custom actions
|
||||||
|
##################################################################
|
||||||
|
#
|
||||||
|
# Add any extra non-binary service calls here later.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
#
|
||||||
|
# - action: script.some_script
|
||||||
|
#
|
||||||
|
# - action: select.select_option
|
||||||
|
# target:
|
||||||
|
# entity_id: select.some_select
|
||||||
|
# data:
|
||||||
|
# option: "Some Option"
|
||||||
|
#
|
||||||
|
##################################################################
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
#:########################################################################################:#
|
||||||
|
# View Road Smoke Alarm RF Package - V1.2.0 #
|
||||||
|
#:########################################################################################:#
|
||||||
|
# Receives normalized AJ-765 RF state from the decoder running on beaver. #
|
||||||
|
# #
|
||||||
|
# V1.2 performs early RF fingerprint classification, normally shortly after RF activity. #
|
||||||
|
# #
|
||||||
|
# Current RF fingerprints: #
|
||||||
|
# - detector_test : TEST button transmission from a detector #
|
||||||
|
# - remote_test : TEST transmission matching the remote capture #
|
||||||
|
# - remote_hush : HUSH/LOCATE button on the Goldair remote #
|
||||||
|
# - smoke_alarm : Experimental only - not yet considered authoritative #
|
||||||
|
# #
|
||||||
|
# Individual detector identity has NOT been found in the RF protocol. #
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
|
||||||
|
mqtt:
|
||||||
|
|
||||||
|
- binary_sensor:
|
||||||
|
name: "RF Interconnect"
|
||||||
|
unique_id: view_road_smoke_alarm_rf_interconnect
|
||||||
|
default_entity_id: binary_sensor.smoke_alarm_rf_interconnect
|
||||||
|
|
||||||
|
state_topic: "viewroad-status/smokealarms/rf/interconnect"
|
||||||
|
payload_on: "ON"
|
||||||
|
payload_off: "OFF"
|
||||||
|
|
||||||
|
availability_topic: "viewroad-status/smokealarms/rf/availability"
|
||||||
|
payload_available: "online"
|
||||||
|
payload_not_available: "offline"
|
||||||
|
|
||||||
|
icon: mdi:radio-tower
|
||||||
|
|
||||||
|
device:
|
||||||
|
identifiers:
|
||||||
|
- view_road_smoke_alarm_rf
|
||||||
|
name: "Smoke Alarm RF Monitor"
|
||||||
|
manufacturer: "Zorruno"
|
||||||
|
model: "AJ-765 RF Monitor"
|
||||||
|
sw_version: "1.2.0"
|
||||||
|
|
||||||
|
|
||||||
|
- event:
|
||||||
|
name: "RF Event"
|
||||||
|
unique_id: view_road_smoke_alarm_rf_event
|
||||||
|
default_entity_id: event.smoke_alarm_rf_event
|
||||||
|
|
||||||
|
state_topic: "viewroad-status/smokealarms/rf/event"
|
||||||
|
|
||||||
|
event_types:
|
||||||
|
- interconnect_start
|
||||||
|
- detector_test
|
||||||
|
- remote_test
|
||||||
|
- remote_hush
|
||||||
|
- smoke_alarm
|
||||||
|
- unknown_aj765
|
||||||
|
- interconnect_end
|
||||||
|
|
||||||
|
availability_topic: "viewroad-status/smokealarms/rf/availability"
|
||||||
|
payload_available: "online"
|
||||||
|
payload_not_available: "offline"
|
||||||
|
|
||||||
|
icon: mdi:radio-tower
|
||||||
|
|
||||||
|
device:
|
||||||
|
identifiers:
|
||||||
|
- view_road_smoke_alarm_rf
|
||||||
|
|
||||||
|
|
||||||
|
- sensor:
|
||||||
|
name: "RF Current Type"
|
||||||
|
unique_id: view_road_smoke_alarm_rf_current_type
|
||||||
|
default_entity_id: sensor.smoke_alarm_rf_current_type
|
||||||
|
|
||||||
|
state_topic: "viewroad-status/smokealarms/rf/current_type"
|
||||||
|
|
||||||
|
availability_topic: "viewroad-status/smokealarms/rf/availability"
|
||||||
|
payload_available: "online"
|
||||||
|
payload_not_available: "offline"
|
||||||
|
|
||||||
|
icon: mdi:waveform
|
||||||
|
|
||||||
|
device:
|
||||||
|
identifiers:
|
||||||
|
- view_road_smoke_alarm_rf
|
||||||
|
|
||||||
|
|
||||||
|
- sensor:
|
||||||
|
name: "RF Last Type"
|
||||||
|
unique_id: view_road_smoke_alarm_rf_last_type
|
||||||
|
default_entity_id: sensor.smoke_alarm_rf_last_type
|
||||||
|
|
||||||
|
state_topic: "viewroad-status/smokealarms/rf/last_type"
|
||||||
|
entity_category: diagnostic
|
||||||
|
|
||||||
|
availability_topic: "viewroad-status/smokealarms/rf/availability"
|
||||||
|
payload_available: "online"
|
||||||
|
payload_not_available: "offline"
|
||||||
|
|
||||||
|
icon: mdi:waveform
|
||||||
|
|
||||||
|
device:
|
||||||
|
identifiers:
|
||||||
|
- view_road_smoke_alarm_rf
|
||||||
|
|
||||||
|
|
||||||
|
- sensor:
|
||||||
|
name: "RF Last Confidence"
|
||||||
|
unique_id: view_road_smoke_alarm_rf_last_confidence
|
||||||
|
default_entity_id: sensor.smoke_alarm_rf_last_confidence
|
||||||
|
|
||||||
|
state_topic: "viewroad-status/smokealarms/rf/last_confidence"
|
||||||
|
unit_of_measurement: "%"
|
||||||
|
state_class: measurement
|
||||||
|
entity_category: diagnostic
|
||||||
|
|
||||||
|
availability_topic: "viewroad-status/smokealarms/rf/availability"
|
||||||
|
payload_available: "online"
|
||||||
|
payload_not_available: "offline"
|
||||||
|
|
||||||
|
icon: mdi:percent
|
||||||
|
|
||||||
|
device:
|
||||||
|
identifiers:
|
||||||
|
- view_road_smoke_alarm_rf
|
||||||
|
|
||||||
|
|
||||||
|
- sensor:
|
||||||
|
name: "RF Last Seen"
|
||||||
|
unique_id: view_road_smoke_alarm_rf_last_seen
|
||||||
|
default_entity_id: sensor.smoke_alarm_rf_last_seen
|
||||||
|
|
||||||
|
state_topic: "viewroad-status/smokealarms/rf/last_seen"
|
||||||
|
device_class: timestamp
|
||||||
|
entity_category: diagnostic
|
||||||
|
|
||||||
|
availability_topic: "viewroad-status/smokealarms/rf/availability"
|
||||||
|
payload_available: "online"
|
||||||
|
payload_not_available: "offline"
|
||||||
|
|
||||||
|
device:
|
||||||
|
identifiers:
|
||||||
|
- view_road_smoke_alarm_rf
|
||||||
|
|
||||||
|
|
||||||
|
- sensor:
|
||||||
|
name: "RF Last Duration"
|
||||||
|
unique_id: view_road_smoke_alarm_rf_last_duration
|
||||||
|
default_entity_id: sensor.smoke_alarm_rf_last_duration
|
||||||
|
|
||||||
|
state_topic: "viewroad-status/smokealarms/rf/last_duration"
|
||||||
|
unit_of_measurement: "s"
|
||||||
|
device_class: duration
|
||||||
|
state_class: measurement
|
||||||
|
entity_category: diagnostic
|
||||||
|
|
||||||
|
availability_topic: "viewroad-status/smokealarms/rf/availability"
|
||||||
|
payload_available: "online"
|
||||||
|
payload_not_available: "offline"
|
||||||
|
|
||||||
|
device:
|
||||||
|
identifiers:
|
||||||
|
- view_road_smoke_alarm_rf
|
||||||