additional esphome devices and fixes

This commit is contained in:
root
2026-04-29 19:36:37 +12:00
parent f14bbbd23a
commit ae00e821ba
6 changed files with 632 additions and 109 deletions
+17 -2
View File
@@ -12,6 +12,8 @@
# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-bedrm1airfilter.yaml # https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-bedrm1airfilter.yaml
#:########################################################################################:# #:########################################################################################:#
# VERSIONS: # VERSIONS:
# V1.3 2026-04-29 Added restored fan speed so the selected fan speed is remembered
# and re-applied after reboot.
# V1.2 2026-04-27 Converted filter replacement logic from pulse-count based to kRevs based. # V1.2 2026-04-27 Converted filter replacement logic from pulse-count based to kRevs based.
# Added editable Replacement Threshold number in kRevs. # Added editable Replacement Threshold number in kRevs.
# Added Reset Replacement Threshold button to restore default 19000 kRevs. # Added Reset Replacement Threshold button to restore default 19000 kRevs.
@@ -81,7 +83,7 @@ substitutions:
# Project Naming # Project Naming
project_name: "Generic.D1 Mini" # Project Details project_name: "Generic.D1 Mini" # Project Details
project_version: "v1.2" # Project V denotes release of yaml file, allowing checking of deployed vs latest version project_version: "v1.3" # Project V denotes release of yaml file, allowing checking of deployed vs latest version
# Passwords and Secrets # Passwords and Secrets
api_key: !secret esp-api_key api_key: !secret esp-api_key
@@ -177,6 +179,18 @@ esphome:
# Restore Clean/Dirty state and warning LEDs. # Restore Clean/Dirty state and warning LEDs.
- script.execute: update_filter_state - script.execute: update_filter_state
# Re-apply the restored fan speed after boot.
# The template number restores its value, but this forces the actual
# MOSFET/PWM output state to match the restored Home Assistant value.
- delay: 1s
- number.set:
id: fan_speed
value: !lambda |-
if (isnan(id(fan_speed).state)) {
return 0.0f;
}
return id(fan_speed).state;
#:########################################################################################:# #:########################################################################################:#
# ESP PLATFORM AND FRAMEWORK: # ESP PLATFORM AND FRAMEWORK:
@@ -297,11 +311,12 @@ button:
number: number:
# Slider for Fan Speed 0-6, 0 = Off, 6 = Max # Slider for Fan Speed 0-6, 0 = Off, 6 = Max
- platform: template - platform: template
name: "${friendly_name} Fan Speed" name: "${friendly_name} Speed Level"
id: fan_speed id: fan_speed
icon: mdi:air-filter icon: mdi:air-filter
update_interval: never update_interval: never
optimistic: true optimistic: true
restore_value: true
min_value: 0 min_value: 0
max_value: 6 max_value: 6
initial_value: 0 initial_value: 0
+2 -2
View File
@@ -264,7 +264,7 @@ preferences:
flash_write_interval: 5min flash_write_interval: 5min
mdns: mdns:
disabled: false disabled: true
########################################################################################## ##########################################################################################
# GLOBAL VARIABLES # GLOBAL VARIABLES
@@ -696,7 +696,7 @@ text_sensor:
return std::string("At Temperature"); return std::string("At Temperature");
} }
if (id(led_standby_red).state) return std::string("Standby"); if (id(led_standby_red).state) return std::string("Standby");
return std::string("Off"); return std::string("Standby");
on_value: on_value:
- script.execute: publish_status - script.execute: publish_status
+227
View File
@@ -0,0 +1,227 @@
###############################################################################
# Bedroom 1 Ikea Air Filter Package
# File: /config/packages/bedroom_1_ikea_air_filter.yaml
# Version: 1.0
# Date: 2026-04-29
#
# Purpose:
# - Creates a dropdown helper called "Bedroom 1 Ikea Fan".
# - Auto mode controls the Bedroom 1 Ikea air filter speed by priority.
# - Manual dropdown modes set a fixed fan speed and disable auto control.
#
# Auto priority order:
# 1. Quiet time on: fan speed 2
# 2. Bedside light on: fan speed 2
# 3. Free power time, 21:00 to midnight: fan speed 5
# 4. Daytime, 09:00 to 15:00: fan speed 4
# 5. Default: fan speed 2
###############################################################################
input_select:
bedroom_1_ikea_fan:
name: "Bedroom 1 Ikea Fan"
icon: mdi:fan
options:
- "Auto"
- "Off"
- "High"
- "Medium"
- "Low"
- "Quiet"
script:
bedroom_1_ikea_air_filter_set_speed_if_needed:
alias: "Bedroom 1 Ikea Air Filter - Set Speed If Needed"
description: >
Sets the Bedroom 1 Ikea air filter speed only when the requested speed
is different from the current speed.
mode: queued
fields:
target_speed:
name: "Target speed"
description: "Fan speed level from 0 to 6."
example: 2
sequence:
- variables:
fan_speed_entity: number.bedroom_1_air_filter_bedroom_1_air_filter_speed_level
fan_current_speed: "{{ states(fan_speed_entity) | float(-1) }}"
fan_target_speed: "{{ target_speed | float }}"
- condition: template
value_template: "{{ fan_current_speed != fan_target_speed }}"
- action: number.set_value
target:
entity_id: number.bedroom_1_air_filter_bedroom_1_air_filter_speed_level
data:
value: "{{ fan_target_speed | int }}"
automation:
- id: bedroom_1_ikea_air_filter_auto_control
alias: "Bedroom 1 Ikea Air Filter - Auto Control"
description: >
Automatically controls the Bedroom 1 Ikea air filter speed when the
Bedroom 1 Ikea Fan dropdown is set to Auto.
mode: restart
triggers:
# Re-apply the correct speed after Home Assistant restarts.
- trigger: homeassistant
event: start
# Highest priority condition.
- trigger: state
entity_id: input_boolean.quiet_time
# Bedside lamp should force low speed while on.
- trigger: state
entity_id: light.master_bedroom_bedside_lamp_arlec_bulb_master_bedroom_bedside_lamp_arlec_bulb
# Main timing boundaries.
- trigger: time
at:
- "00:00:00"
- "09:00:00"
- "15:00:00"
- "21:00:00"
# Safety/re-check trigger, especially for the bedside lamp rule.
- trigger: time_pattern
minutes: "/10"
conditions:
# Manual dropdown modes disable automatic control.
- condition: state
entity_id: input_select.bedroom_1_ikea_fan
state: "Auto"
actions:
- variables:
auto_target_speed: >-
{% if is_state('input_boolean.quiet_time', 'on') %}
2
{% elif is_state('light.master_bedroom_bedside_lamp_arlec_bulb_master_bedroom_bedside_lamp_arlec_bulb', 'on') %}
2
{% elif now().hour >= 21 %}
5
{% elif now().hour >= 9 and now().hour < 15 %}
4
{% else %}
2
{% endif %}
- action: script.bedroom_1_ikea_air_filter_set_speed_if_needed
data:
target_speed: "{{ auto_target_speed | int }}"
- id: bedroom_1_ikea_air_filter_dropdown_control
alias: "Bedroom 1 Ikea Air Filter - Dropdown Control"
description: >
Handles the Bedroom 1 Ikea Fan dropdown. Auto enables the automatic
control automation. Manual modes disable automatic control and set
the requested fixed speed.
mode: restart
triggers:
# Apply the selected dropdown mode when it changes.
- trigger: state
entity_id: input_select.bedroom_1_ikea_fan
# Re-apply the selected dropdown mode after Home Assistant restarts.
- trigger: homeassistant
event: start
actions:
- choose:
- alias: "Auto mode"
conditions:
- condition: state
entity_id: input_select.bedroom_1_ikea_fan
state: "Auto"
sequence:
- action: automation.turn_on
target:
entity_id: automation.bedroom_1_ikea_air_filter_auto_control
# Auto starts at speed 2, then immediately evaluates the
# current priority rules.
- action: script.bedroom_1_ikea_air_filter_set_speed_if_needed
data:
target_speed: 2
- delay:
seconds: 1
- action: automation.trigger
target:
entity_id: automation.bedroom_1_ikea_air_filter_auto_control
data:
skip_condition: false
- alias: "Off mode"
conditions:
- condition: state
entity_id: input_select.bedroom_1_ikea_fan
state: "Off"
sequence:
- action: automation.turn_off
target:
entity_id: automation.bedroom_1_ikea_air_filter_auto_control
- action: script.bedroom_1_ikea_air_filter_set_speed_if_needed
data:
target_speed: 0
- alias: "High mode"
conditions:
- condition: state
entity_id: input_select.bedroom_1_ikea_fan
state: "High"
sequence:
- action: automation.turn_off
target:
entity_id: automation.bedroom_1_ikea_air_filter_auto_control
- action: script.bedroom_1_ikea_air_filter_set_speed_if_needed
data:
target_speed: 6
- alias: "Medium mode"
conditions:
- condition: state
entity_id: input_select.bedroom_1_ikea_fan
state: "Medium"
sequence:
- action: automation.turn_off
target:
entity_id: automation.bedroom_1_ikea_air_filter_auto_control
- action: script.bedroom_1_ikea_air_filter_set_speed_if_needed
data:
target_speed: 4
- alias: "Low mode"
conditions:
- condition: state
entity_id: input_select.bedroom_1_ikea_fan
state: "Low"
sequence:
- action: automation.turn_off
target:
entity_id: automation.bedroom_1_ikea_air_filter_auto_control
- action: script.bedroom_1_ikea_air_filter_set_speed_if_needed
data:
target_speed: 2
- alias: "Quiet mode"
conditions:
- condition: state
entity_id: input_select.bedroom_1_ikea_fan
state: "Quiet"
sequence:
- action: automation.turn_off
target:
entity_id: automation.bedroom_1_ikea_air_filter_auto_control
- action: script.bedroom_1_ikea_air_filter_set_speed_if_needed
data:
target_speed: 1
+75 -16
View File
@@ -1,6 +1,42 @@
# yaml-language-server: $schema=null # yaml-language-server: $schema=null
############################################################################### ###############################################################################
# PACKAGE: Lounge scenes (delta-only settings) + manual override # PACKAGE: Lounge scenes controller
#
# PURPOSE:
# - Provides selectable lounge lighting scenes from Home Assistant.
# - Scenes are selected via input_select.lounge_scene.
# - The selector resets back to "Select Scene:" after each scene is applied, so
# the same scene can be selected repeatedly.
# - Scenes are delta-only: only entities listed in a scene are changed.
# - Manual override can block automatic scene changes.
# - Last remembered scene is tracked so TV automations can avoid changing lights
# when the lounge was deliberately set to All Off.
#
# SUPPORTED SCENE VALUE TYPES:
# - light.*:
# 0 = turn off
# 1-100 = turn on at brightness percentage
# "on" = turn on
# "off" = turn off
# "toggle" = toggle on/off, using 100 percent when turning on
# "toggle_75" = if on, turn off; if off, turn on at 75 percent
#
# - switch.*:
# "on" = turn on
# "off" = turn off
# "toggle" = toggle on/off
#
# - number.*:
# numeric value is sent using number.set_value
#
# - input_number.*:
# numeric value is sent using input_number.set_value
# Example: input_number.openhasp_1_backlight_level: 180
#
# NOTES:
# - Keep on/off/toggle values quoted for clarity.
# - Numeric values can be left unquoted.
# - Only scenes not listed in excluded_scenes update input_text.lounge_last_scene.
############################################################################### ###############################################################################
input_select: input_select:
@@ -49,7 +85,7 @@ script:
data: data:
option: "{{ scene_name }}" option: "{{ scene_name }}"
# NEW: Wait briefly for HA to commit the new state (avoids race) # Wait briefly for HA to commit the new state before reading it.
- wait_template: "{{ states('input_select.lounge_scene') == scene_name }}" - wait_template: "{{ states('input_select.lounge_scene') == scene_name }}"
timeout: "00:00:02" timeout: "00:00:02"
continue_on_timeout: true continue_on_timeout: true
@@ -62,15 +98,19 @@ script:
sequence: sequence:
- variables: - variables:
sel: "{{ states('input_select.lounge_scene') }}" sel: "{{ states('input_select.lounge_scene') }}"
##################################################################### #####################################################################
# EXCLUDED SCENES (these are temp scenes, not remembered as last) # EXCLUDED SCENES
# These are temporary/action scenes and are not remembered as last.
##################################################################### #####################################################################
excluded_scenes: excluded_scenes:
- "Select Scene:" - "Select Scene:"
- "Reading On/Off" - "Reading On/Off"
#- "Night Light" #- "Night Light"
##################################################################### #####################################################################
# SCENE SETTINGS (delta only - only list entities you want to change) # SCENE SETTINGS
# Delta only - only list entities you want to change.
##################################################################### #####################################################################
scene_settings: scene_settings:
Bright: Bright:
@@ -91,6 +131,7 @@ script:
#switch.esp_loungenorthswitch_relay_1_main_lights: "on" #switch.esp_loungenorthswitch_relay_1_main_lights: "on"
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 100 number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 100
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 100 number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 100
input_number.openhasp_1_backlight_level: 255
TV General: TV General:
light.esp_lounge6chdimmer_couch_spots_left: 60 light.esp_lounge6chdimmer_couch_spots_left: 60
@@ -109,6 +150,7 @@ script:
#switch.esp_loungenorthswitch_relay_1_main_lights: "on" #switch.esp_loungenorthswitch_relay_1_main_lights: "on"
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 60 number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 60
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 60 number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 60
input_number.openhasp_1_backlight_level: 120
Movie: Movie:
light.esp_lounge6chdimmer_couch_spots_left: 20 light.esp_lounge6chdimmer_couch_spots_left: 20
@@ -127,6 +169,7 @@ script:
#switch.esp_loungenorthswitch_relay_1_main_lights: "on" #switch.esp_loungenorthswitch_relay_1_main_lights: "on"
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 40 number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 40
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 40 number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 40
input_number.openhasp_1_backlight_level: 15
Reading On/Off: Reading On/Off:
light.esp_lounge6chdimmer_couch_spots_left: "toggle_75" light.esp_lounge6chdimmer_couch_spots_left: "toggle_75"
@@ -154,6 +197,7 @@ script:
#switch.esp_loungenorthswitch_relay_1_main_lights: "on" #switch.esp_loungenorthswitch_relay_1_main_lights: "on"
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 5 number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 5
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 5 number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 5
input_number.openhasp_1_backlight_level: 8
Warm Cozy: Warm Cozy:
light.esp_lounge6chdimmer_couch_spots_left: 20 light.esp_lounge6chdimmer_couch_spots_left: 20
@@ -170,6 +214,7 @@ script:
#switch.esp_loungenorthswitch_relay_1_main_lights: "on" #switch.esp_loungenorthswitch_relay_1_main_lights: "on"
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 20 number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 20
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 20 number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 20
input_number.openhasp_1_backlight_level: 12
All Off: All Off:
light.esp_lounge6chdimmer_couch_spots_left: 0 light.esp_lounge6chdimmer_couch_spots_left: 0
@@ -188,12 +233,11 @@ script:
#switch.esp_loungenorthswitch_relay_1_main_lights: "on" #switch.esp_loungenorthswitch_relay_1_main_lights: "on"
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 0 number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 0
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 0 number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 0
#input_number.openhasp_1_backlight_level: 100
##################################################################### #########################################################################
##################################################################### # REMEMBER LAST SCENE
##################################################################### #########################################################################
# Only remember scenes that are not excluded
- choose: - choose:
- conditions: "{{ sel not in excluded_scenes }}" - conditions: "{{ sel not in excluded_scenes }}"
sequence: sequence:
@@ -202,6 +246,9 @@ script:
data: data:
value: "{{ sel }}" value: "{{ sel }}"
#########################################################################
# APPLY SELECTED SCENE
#########################################################################
- repeat: - repeat:
for_each: "{{ (scene_settings.get(sel, {})).keys() | list }}" for_each: "{{ (scene_settings.get(sel, {})).keys() | list }}"
sequence: sequence:
@@ -210,23 +257,32 @@ script:
val: "{{ (scene_settings.get(sel, {}))[ent] }}" val: "{{ (scene_settings.get(sel, {}))[ent] }}"
is_light: "{{ ent.startswith('light.') }}" is_light: "{{ ent.startswith('light.') }}"
is_switch: "{{ ent.startswith('switch.') }}" is_switch: "{{ ent.startswith('switch.') }}"
is_number_ent: "{{ ent.startswith('number.') }}"
is_input_number_ent: "{{ ent.startswith('input_number.') }}"
is_num: "{{ val is number }}" is_num: "{{ val is number }}"
vstr: "{{ (val|string) if not is_num else '' }}" vstr: "{{ (val|string) if not is_num else '' }}"
is_toggle: "{{ (not is_num) and (vstr|lower).startswith('toggle') }}" is_toggle: "{{ (not is_num) and (vstr|lower).startswith('toggle') }}"
toggle_pct: "{{ (vstr.split('_')|last)|int if ('_' in vstr) else 100 }}" toggle_pct: "{{ (vstr.split('_')|last)|int if ('_' in vstr) else 100 }}"
currently_on: "{{ is_state(ent, 'on') }}" currently_on: "{{ is_state(ent, 'on') }}"
is_number_ent: "{{ ent.startswith('number.') }}" # 🔹 NEW
- choose: - choose:
# 0) Numbers: set numeric value (e.g. 0..100) # 0a) Numbers: set numeric value
- conditions: "{{ is_number_ent and is_num }}" # 🔹 NEW - conditions: "{{ is_number_ent and is_num }}"
sequence: sequence:
- service: number.set_value - service: number.set_value
data: data:
entity_id: "{{ ent }}" entity_id: "{{ ent }}"
value: "{{ val|float }}" value: "{{ val|float }}"
# 1) Lights: toggle[_NN] -> if on turn off, else turn on to NN (default 100) # 0b) Input numbers: set numeric value
- conditions: "{{ is_input_number_ent and is_num }}"
sequence:
- service: input_number.set_value
data:
entity_id: "{{ ent }}"
value: "{{ val|float }}"
# 1) Lights: toggle[_NN] -> if on turn off, else turn on to NN
- conditions: "{{ is_light and is_toggle }}" - conditions: "{{ is_light and is_toggle }}"
sequence: sequence:
- choose: - choose:
@@ -248,13 +304,14 @@ script:
data: data:
entity_id: "{{ ent }}" entity_id: "{{ ent }}"
# 3) Lights: numeric brightness (0 = off) # 3) Lights: numeric brightness, where 0 = off
- conditions: "{{ is_light and is_num and (val|int) > 0 }}" - conditions: "{{ is_light and is_num and (val|int) > 0 }}"
sequence: sequence:
- service: light.turn_on - service: light.turn_on
data: data:
entity_id: "{{ ent }}" entity_id: "{{ ent }}"
brightness_pct: "{{ val|int }}" brightness_pct: "{{ val|int }}"
- conditions: "{{ is_light and is_num and (val|int) == 0 }}" - conditions: "{{ is_light and is_num and (val|int) == 0 }}"
sequence: sequence:
- service: light.turn_off - service: light.turn_off
@@ -267,6 +324,7 @@ script:
- service: light.turn_on - service: light.turn_on
data: data:
entity_id: "{{ ent }}" entity_id: "{{ ent }}"
- conditions: "{{ is_light and not is_num and (val in [false, 'off', 'Off', 'OFF']) }}" - conditions: "{{ is_light and not is_num and (val in [false, 'off', 'Off', 'OFF']) }}"
sequence: sequence:
- service: light.turn_off - service: light.turn_off
@@ -279,6 +337,7 @@ script:
- service: switch.turn_on - service: switch.turn_on
data: data:
entity_id: "{{ ent }}" entity_id: "{{ ent }}"
- conditions: "{{ is_switch and (val in [false, 'off', 'Off', 'OFF']) }}" - conditions: "{{ is_switch and (val in [false, 'off', 'Off', 'OFF']) }}"
sequence: sequence:
- service: switch.turn_off - service: switch.turn_off
@@ -322,7 +381,7 @@ automation:
- platform: state - platform: state
entity_id: remote.lounge_tv entity_id: remote.lounge_tv
to: "on" to: "on"
for: "00:00:02" #small debounce for: "00:00:02"
condition: condition:
- condition: state - condition: state
entity_id: input_boolean.lounge_manual_override entity_id: input_boolean.lounge_manual_override
@@ -340,7 +399,7 @@ automation:
- platform: state - platform: state
entity_id: remote.lounge_tv entity_id: remote.lounge_tv
to: "off" to: "off"
for: "00:00:02" #small debounce for: "00:00:02"
condition: condition:
- condition: state - condition: state
entity_id: input_boolean.lounge_manual_override entity_id: input_boolean.lounge_manual_override
+108 -85
View File
@@ -4,41 +4,17 @@
# #
# PAGE OBJECTS USED # PAGE OBJECTS USED
# - p1b1 = main temperature display # - p1b1 = main temperature display
# - p1b2 = alternating Setpoint / Humidity display # - p1b2 = setpoint display
# - p1b3 = setpoint down # - p1b3 = setpoint down
# - p1b4 = setpoint up # - p1b4 = setpoint up
# - p1b5 = heater status text # - p1b5 = heater status text
# - p1b6 = heater operation / flame button # - p1b6 = heater operation / flame button
# - p1b7 = humidity display
############################################################################### ###############################################################################
############################################################################### ###############################################################################
# HELPERS # HELPERS
############################################################################### ###############################################################################
input_boolean:
hasp_setpoint_hold_active:
name: HASP Setpoint Hold Active
initial: false
input_number:
# How long Setpoint and Humidity are each shown before rotating
hasp_setpoint_humidity_cycle_seconds:
name: HASP Setpoint Humidity Cycle Seconds
min: 1
max: 60
step: 1
mode: box
unit_of_measurement: s
initial: 10
# After the setpoint changes, hold the setpoint screen for this long
hasp_setpoint_hold_seconds:
name: HASP Setpoint Hold Seconds
min: 1
max: 60
step: 1
mode: box
unit_of_measurement: s
initial: 15
############################################################################### ###############################################################################
# MQTT ENTITIES # MQTT ENTITIES
@@ -48,6 +24,14 @@ mqtt:
- name: "Lounge Environment Humidity MQTT" - name: "Lounge Environment Humidity MQTT"
unique_id: "lounge_environment_humidity_mqtt" unique_id: "lounge_environment_humidity_mqtt"
state_topic: "viewroad-status/lounge-environment/humidity" state_topic: "viewroad-status/lounge-environment/humidity"
value_template: >
{% set raw = value | trim %}
{% if raw.startswith('{') %}
{% set j = raw | from_json %}
{{ j.humidity | default(j.value | default(raw)) }}
{% else %}
{{ raw | replace('%', '') | trim }}
{% endif %}
############################################################################### ###############################################################################
# AUTOMATIONS # AUTOMATIONS
@@ -99,35 +83,53 @@ automation:
{{ s if s not in ['unknown', 'unavailable', ''] else 'HEATER --' }} {{ s if s not in ['unknown', 'unavailable', ''] else 'HEATER --' }}
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# When setpoint changes: # Setpoint display on left side of centre row
# - immediately show Setpoint # - Strips any existing units so only one °C is shown
# - hold it for hold_seconds
# - then allow normal Setpoint/Humidity rotation again
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
- id: hasp_setpoint_changed_hold_display - id: hasp_setpoint_to_btn_text
alias: "HASP: show setpoint immediately and hold" alias: "HASP: update setpoint (p1b2.text)"
mode: restart mode: queued
trigger: trigger:
- platform: state - platform: state
entity_id: sensor.rinnai_neo_gas_heater_setpoint_text entity_id: sensor.rinnai_neo_gas_heater_setpoint_text
action: action:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.hasp_setpoint_hold_active
- service: mqtt.publish - service: mqtt.publish
data: data:
topic: "hasp/openhasp_1/command/p1b2.text" topic: "hasp/openhasp_1/command/p1b2.text"
payload: > payload: >
{% set s = states('sensor.rinnai_neo_gas_heater_setpoint_text') %} {% set raw = states('sensor.rinnai_neo_gas_heater_setpoint_text') %}
{{ 'Setpoint: ' ~ (s if s not in ['unknown', 'unavailable', ''] else '--') }} {% set cleaned = raw
| replace('°C', '')
| replace('° C', '')
| replace('C', '')
| trim %}
{% if cleaned not in ['unknown', 'unavailable', '', 'none', 'None'] %}
Set: {{ cleaned | float(0) | round(1) }}°C
{% else %}
Set: -- °C
{% endif %}
- delay: # -------------------------------------------------------------------------
seconds: "{{ states('input_number.hasp_setpoint_hold_seconds') | int(15) }}" # Humidity display on right side of centre row
# -------------------------------------------------------------------------
- service: input_boolean.turn_off - id: hasp_humidity_to_btn_text
target: alias: "HASP: update humidity (p1b7.text)"
entity_id: input_boolean.hasp_setpoint_hold_active mode: queued
trigger:
- platform: state
entity_id: sensor.lounge_environment_humidity_mqtt
action:
- service: mqtt.publish
data:
topic: "hasp/openhasp_1/command/p1b7.text"
payload: >
{% set raw = states('sensor.lounge_environment_humidity_mqtt') %}
{% set cleaned = raw | replace('%', '') | trim %}
{% if cleaned in ['unknown', 'unavailable', '', 'none', 'None'] %}
Hum: Unknown
{% else %}
Hum: {{ cleaned }}%
{% endif %}
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# Up / Down buttons on the HASP plate # Up / Down buttons on the HASP plate
@@ -298,9 +300,6 @@ automation:
event: start event: start
action: action:
- service: script.hasp_push_static_texts - service: script.hasp_push_static_texts
- service: script.turn_on
target:
entity_id: script.hasp_rotate_setpoint_humidity
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# Re-push screen state when panel comes online # Re-push screen state when panel comes online
@@ -316,9 +315,6 @@ automation:
action: action:
- delay: "00:00:05" - delay: "00:00:05"
- service: script.hasp_push_static_texts - service: script.hasp_push_static_texts
- service: script.turn_on
target:
entity_id: script.hasp_rotate_setpoint_humidity
############################################################################### ###############################################################################
# SCRIPTS # SCRIPTS
@@ -332,6 +328,9 @@ script:
alias: "HASP: push static texts" alias: "HASP: push static texts"
mode: queued mode: queued
sequence: sequence:
# Push Set/Hum display styling first, so the centre row is not blue
- service: script.hasp_style_center_info_buttons
- service: mqtt.publish - service: mqtt.publish
data: data:
topic: "hasp/openhasp_1/command/p1b1.text" topic: "hasp/openhasp_1/command/p1b1.text"
@@ -359,8 +358,29 @@ script:
data: data:
topic: "hasp/openhasp_1/command/p1b2.text" topic: "hasp/openhasp_1/command/p1b2.text"
payload: > payload: >
{% set s = states('sensor.rinnai_neo_gas_heater_setpoint_text') %} {% set raw = states('sensor.rinnai_neo_gas_heater_setpoint_text') %}
{{ 'Setpoint: ' ~ (s if s not in ['unknown', 'unavailable', ''] else '--') }} {% set cleaned = raw
| replace('°C', '')
| replace('° C', '')
| replace('C', '')
| trim %}
{% if cleaned not in ['unknown', 'unavailable', '', 'none', 'None'] %}
Set: {{ cleaned | float(0) | round(1) }}°C
{% else %}
Set: -- °C
{% endif %}
- service: mqtt.publish
data:
topic: "hasp/openhasp_1/command/p1b7.text"
payload: >
{% set raw = states('sensor.lounge_environment_humidity_mqtt') %}
{% set cleaned = raw | replace('%', '') | trim %}
{% if cleaned in ['unknown', 'unavailable', '', 'none', 'None'] %}
Hum: Unknown
{% else %}
Hum: {{ cleaned }}%
{% endif %}
# Push middle flame button state # Push middle flame button state
- service: mqtt.publish - service: mqtt.publish
@@ -445,42 +465,45 @@ script:
payload: "#0095D9" payload: "#0095D9"
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# Rotate the middle information line between Setpoint and Humidity # Style centre row info buttons as text panels
# Pauses humidity display while the setpoint hold flag is active # - p1b2 = setpoint
# - p1b7 = humidity
# This removes the default blue button styling from these display-only fields.
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
hasp_rotate_setpoint_humidity: hasp_style_center_info_buttons:
alias: "HASP: rotate setpoint and humidity" alias: "HASP: style centre info buttons"
mode: restart mode: queued
sequence:
- repeat:
while:
- condition: template
value_template: "{{ true }}"
sequence: sequence:
- service: mqtt.publish - service: mqtt.publish
data: data:
topic: "hasp/openhasp_1/command/p1b2.text" topic: "hasp/openhasp_1/command/p1b2.text_color"
payload: > payload: "#FFFFFF"
{% set s = states('sensor.rinnai_neo_gas_heater_setpoint_text') %} - service: mqtt.publish
{{ 'Setpoint: ' ~ (s if s not in ['unknown', 'unavailable', ''] else '--') }} data:
topic: "hasp/openhasp_1/command/p1b2.bg_color"
- delay: payload: "#000000"
seconds: "{{ states('input_number.hasp_setpoint_humidity_cycle_seconds') | int(10) }}" - service: mqtt.publish
data:
- condition: state topic: "hasp/openhasp_1/command/p1b2.bg_grad_color"
entity_id: input_boolean.hasp_setpoint_hold_active payload: "#000000"
state: "off" - service: mqtt.publish
data:
topic: "hasp/openhasp_1/command/p1b2.border_color"
payload: "#000000"
- service: mqtt.publish - service: mqtt.publish
data: data:
topic: "hasp/openhasp_1/command/p1b2.text" topic: "hasp/openhasp_1/command/p1b7.text_color"
payload: > payload: "#FFFFFF"
{% set h = states('sensor.lounge_environment_humidity_mqtt') %} - service: mqtt.publish
{% if h in ['unknown', 'unavailable', ''] %} data:
Humidity: Unknown topic: "hasp/openhasp_1/command/p1b7.bg_color"
{% else %} payload: "#000000"
Humidity: {{ h }}% - service: mqtt.publish
{% endif %} data:
topic: "hasp/openhasp_1/command/p1b7.bg_grad_color"
- delay: payload: "#000000"
seconds: "{{ states('input_number.hasp_setpoint_humidity_cycle_seconds') | int(10) }}" - service: mqtt.publish
data:
topic: "hasp/openhasp_1/command/p1b7.border_color"
payload: "#000000"
@@ -0,0 +1,199 @@
###############################################################################
# PACKAGE: OpenHASP Lounge 1 Wall Plate Backlight Control
# NODE/TOPIC ROOT: hasp/openhasp_1/
#
# INTENT:
# - Keep backlight control separate from the thermostat/heater UI package.
# - Avoid using brightness 0 as the main OFF method.
# - Wake the panel with "idle off" before applying brightness.
#
# OPENHASP NOTES:
# - backlight brightness range is 1..255
# - backlight off is a state, not a brightness level
# - idle off clears idle/sleep state and behaves like a wake-up
###############################################################################
###############################################################################
# HELPERS
###############################################################################
input_boolean:
openhasp_1_backlight_enable:
name: OpenHASP 1 Backlight Enable
icon: mdi:television-ambient-light
initial: true
input_number:
openhasp_1_backlight_level:
name: OpenHASP 1 Backlight Level
min: 1
max: 255
step: 1
mode: slider
initial: 255
###############################################################################
# AUTOMATIONS
###############################################################################
automation:
# -------------------------------------------------------------------------
# Backlight enable helper changed
# - ON -> wake panel and apply current brightness level
# - OFF -> tell openHASP to switch the backlight off
# -------------------------------------------------------------------------
- id: openhasp_1_backlight_enable_changed
alias: "OpenHASP 1: backlight enable changed"
mode: restart
trigger:
- platform: state
entity_id: input_boolean.openhasp_1_backlight_enable
action:
- choose:
- conditions:
- condition: state
entity_id: input_boolean.openhasp_1_backlight_enable
state: "on"
sequence:
- service: script.openhasp_1_backlight_apply
default:
- service: script.openhasp_1_backlight_off
# -------------------------------------------------------------------------
# Backlight level helper changed
# - If backlight is enabled, apply the new level immediately
# - If disabled, just store the new level for next time
# -------------------------------------------------------------------------
- id: openhasp_1_backlight_level_changed
alias: "OpenHASP 1: backlight level changed"
mode: restart
trigger:
- platform: state
entity_id: input_number.openhasp_1_backlight_level
condition:
- condition: state
entity_id: input_boolean.openhasp_1_backlight_enable
state: "on"
action:
- service: script.openhasp_1_backlight_apply
# -------------------------------------------------------------------------
# Re-apply requested backlight state when Home Assistant starts
# -------------------------------------------------------------------------
- id: openhasp_1_backlight_on_ha_start
alias: "OpenHASP 1: apply backlight on HA start"
mode: queued
trigger:
- platform: homeassistant
event: start
action:
- delay: "00:00:10"
- service: script.openhasp_1_backlight_apply_requested_state
# -------------------------------------------------------------------------
# Re-apply requested backlight state when the panel reconnects
# -------------------------------------------------------------------------
- id: openhasp_1_backlight_on_panel_online
alias: "OpenHASP 1: apply backlight on panel online"
mode: queued
trigger:
- platform: mqtt
topic: "hasp/openhasp_1/LWT"
condition:
- condition: template
value_template: "{{ trigger.payload == 'online' }}"
action:
- delay: "00:00:05"
- service: script.openhasp_1_backlight_apply_requested_state
# -------------------------------------------------------------------------
# If openHASP enters idle while HA says the backlight should be enabled,
# wake it and re-apply the requested brightness.
#
# This is intended to stop the "black until touched" behaviour when the
# plate's own idle state has blanked the display.
# -------------------------------------------------------------------------
- id: openhasp_1_backlight_recover_from_idle
alias: "OpenHASP 1: recover backlight from idle"
mode: restart
trigger:
- platform: mqtt
topic: "hasp/openhasp_1/state/idle"
condition:
- condition: state
entity_id: input_boolean.openhasp_1_backlight_enable
state: "on"
- condition: template
value_template: "{{ trigger.payload | lower != 'off' }}"
action:
- delay: "00:00:01"
- service: script.openhasp_1_backlight_apply
###############################################################################
# SCRIPTS
###############################################################################
script:
# -------------------------------------------------------------------------
# Apply current requested brightness.
#
# Important:
# - Send idle off first so the panel is awake.
# - Then send a JSON backlight command with state ON and brightness 1..255.
# -------------------------------------------------------------------------
openhasp_1_backlight_apply:
alias: "OpenHASP 1: apply backlight level"
mode: restart
sequence:
- service: mqtt.publish
data:
topic: "hasp/openhasp_1/command"
payload: "idle off"
- delay: "00:00:00.25"
- service: mqtt.publish
data:
topic: "hasp/openhasp_1/command"
payload: >
backlight {"state":"on","brightness":{{ states('input_number.openhasp_1_backlight_level') | int(255) }}}
# Send once more shortly after. This helps with panels that miss the
# brightness change while coming out of idle.
- delay: "00:00:00.75"
- service: mqtt.publish
data:
topic: "hasp/openhasp_1/command"
payload: >
backlight {"state":"on","brightness":{{ states('input_number.openhasp_1_backlight_level') | int(255) }}}
# -------------------------------------------------------------------------
# Turn the backlight off using the openHASP backlight OFF state.
# Do not set brightness to 0.
# -------------------------------------------------------------------------
openhasp_1_backlight_off:
alias: "OpenHASP 1: backlight off"
mode: restart
sequence:
- service: mqtt.publish
data:
topic: "hasp/openhasp_1/command"
payload: "backlight off"
# -------------------------------------------------------------------------
# Apply either ON/current-level or OFF according to helper state.
# Used on HA startup and panel reconnect.
# -------------------------------------------------------------------------
openhasp_1_backlight_apply_requested_state:
alias: "OpenHASP 1: apply requested backlight state"
mode: restart
sequence:
- choose:
- conditions:
- condition: state
entity_id: input_boolean.openhasp_1_backlight_enable
state: "on"
sequence:
- service: script.openhasp_1_backlight_apply
default:
- service: script.openhasp_1_backlight_off