############################################################################### # PACKAGE: OpenHASP Thermostat / Gas Heater Control # VERSION: v1.1 (2026-06-18) # NODE/TOPIC ROOT: hasp/openhasp_1/ # # PAGE OBJECTS USED # - p1b1 = main temperature display # - p1b2 = setpoint icon/value display # - p1b3 = setpoint down # - p1b4 = setpoint up # - p1b5 = heater status text # - p1b6 = heater operation / flame button # - p1b7 = humidity icon/value display # # NOTES: # - The HASP flame button toggles the ESPHome Heater Operation switch. # - Heater Operation ON = ESPHome Mode AUTO. # - Heater Operation OFF = ESPHome Mode OFF. # - BYPASS (Remote Only) is only shown when that ESPHome mode is selected. # - p1b2 and p1b7 include their icons in the MQTT text payload so HA updates # do not overwrite the icons loaded from pages.jsonl. ############################################################################### ############################################################################### # HELPERS ############################################################################### ############################################################################### # MQTT ENTITIES ############################################################################### mqtt: sensor: - name: "Lounge Environment Humidity MQTT" unique_id: "lounge_environment_humidity_mqtt" 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 ############################################################################### automation: # ------------------------------------------------------------------------- # Main temperature display # - Shows normal lounge temperature # - Normalises values so we do not get duplicated °C or long float strings # - No space is used before °C # ------------------------------------------------------------------------- - id: hasp_temp_to_btn_text alias: "HASP: update temp (p1b1.text)" mode: queued trigger: - platform: state entity_id: sensor.lounge_environment_lounge_environment_temperature action: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b1.text" payload: > {% set raw = states('sensor.lounge_environment_lounge_environment_temperature') %} {% set cleaned = raw | replace('°C', '') | replace('° C', '') | replace('C', '') | trim %} {% if cleaned not in ['unknown', 'unavailable', '', 'none', 'None'] %} {{ cleaned | float(0) | round(1) }}°C {% else %} --°C {% endif %} # ------------------------------------------------------------------------- # Heater status text at bottom of screen # - Shows OFF when ESPHome Mode is OFF # - Shows BYPASS only when ESPHome Mode is BYPASS (Remote Only) # - Otherwise mirrors the ESPHome status text, now normally Auto (...) # ------------------------------------------------------------------------- - id: hasp_heater_status_to_btn_text alias: "HASP: update heater status (p1b5.text)" mode: queued trigger: - platform: state entity_id: - sensor.rinnai_neo_gas_heater_rinnai_neo_gas_heater_status_text - select.rinnai_neo_gas_heater_mode action: - service: script.hasp_publish_heater_status_text # ------------------------------------------------------------------------- # Setpoint display on left side of centre row # - Strips any existing units so only one °C is shown # - Includes thermometer icon so HA updates do not remove it # ------------------------------------------------------------------------- - id: hasp_setpoint_to_btn_text alias: "HASP: update setpoint (p1b2.text)" mode: queued trigger: - platform: state entity_id: sensor.rinnai_neo_gas_heater_setpoint_text action: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b2.text" payload: > {% set raw = states('sensor.rinnai_neo_gas_heater_setpoint_text') %} {% set cleaned = raw | replace('°C', '') | replace('° C', '') | replace('C', '') | trim %} {% if cleaned not in ['unknown', 'unavailable', '', 'none', 'None'] %} {{ '\uE50F' }} {{ cleaned | float(0) | round(1) }}°C {% else %} {{ '\uE50F' }} --°C {% endif %} # ------------------------------------------------------------------------- # Humidity display on right side of centre row # - Includes water/drop icon so HA updates do not remove it # ------------------------------------------------------------------------- - id: hasp_humidity_to_btn_text alias: "HASP: update humidity (p1b7.text)" 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'] %} {{ '\uE58C' }} --% {% else %} {{ '\uE58C' }} {{ cleaned }}% {% endif %} # ------------------------------------------------------------------------- # Up / Down buttons on the HASP plate # These call the existing HA button entities # ------------------------------------------------------------------------- - id: hasp_btn_up_press alias: "HASP: p1b4 up -> heater setpoint UP" mode: queued trigger: - platform: mqtt topic: "hasp/openhasp_1/state/p1b4" condition: - condition: template value_template: "{{ trigger.payload_json.event | default('') == 'up' }}" action: - service: button.press target: entity_id: button.rinnai_neo_gas_heater_rinnai_neo_gas_heater_setpoint_up - id: hasp_btn_down_press alias: "HASP: p1b3 up -> heater setpoint DOWN" mode: queued trigger: - platform: mqtt topic: "hasp/openhasp_1/state/p1b3" condition: - condition: template value_template: "{{ trigger.payload_json.event | default('') == 'up' }}" action: - service: button.press target: entity_id: button.rinnai_neo_gas_heater_rinnai_neo_gas_heater_setpoint_down # ------------------------------------------------------------------------- # Middle flame button # - Tap toggles Heater Operation, which maps AUTO <-> OFF in ESPHome # - If Mode is BYPASS (Remote Only), tapping this will turn Heater Operation ON # and therefore return the ESPHome controller to AUTO. # ------------------------------------------------------------------------- - id: hasp_btn_heat_toggle alias: "HASP: p1b6 up -> heater operation toggle" mode: queued trigger: - platform: mqtt topic: "hasp/openhasp_1/state/p1b6" condition: - condition: template value_template: "{{ trigger.payload_json.event | default('') == 'up' }}" action: - service: switch.toggle target: entity_id: switch.rinnai_neo_gas_heater_heater_operation # ------------------------------------------------------------------------- # Flame button appearance # - OFF: dark grey background, light grey flame # - BYPASS: dark grey background, amber flame # - AUTO, flame OFF: theme blue background, white flame # - AUTO, flame ON: theme blue background, solid red flame # ------------------------------------------------------------------------- - id: hasp_heat_button_state alias: "HASP: update heat button state (p1b6)" mode: restart trigger: - platform: state entity_id: - select.rinnai_neo_gas_heater_mode - switch.rinnai_neo_gas_heater_heater_operation - switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_activate_flame action: - service: script.hasp_apply_heat_button_state # ------------------------------------------------------------------------- # Start / restart display when HA starts # ------------------------------------------------------------------------- - id: hasp_start_on_ha_start alias: "HASP: start display loop on HA start" trigger: - platform: homeassistant event: start action: - service: script.hasp_push_static_texts # ------------------------------------------------------------------------- # Re-push screen state when panel comes online # ------------------------------------------------------------------------- - id: hasp_start_on_panel_online alias: "HASP: start display loop when panel goes online" trigger: - platform: mqtt topic: "hasp/openhasp_1/LWT" condition: - condition: template value_template: "{{ trigger.payload == 'online' }}" action: - delay: "00:00:05" - service: script.hasp_push_static_texts ############################################################################### # SCRIPTS ############################################################################### script: # ------------------------------------------------------------------------- # Push all current values / colours to the panel # Useful on HA startup and panel reconnect # ------------------------------------------------------------------------- hasp_push_static_texts: alias: "HASP: push static texts" mode: queued sequence: # Push Set/Hum display styling first, so the centre row is not blue - service: script.hasp_style_center_info_buttons - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b1.text" payload: > {% set raw = states('sensor.lounge_environment_lounge_environment_temperature') %} {% set cleaned = raw | replace('°C', '') | replace('° C', '') | replace('C', '') | trim %} {% if cleaned not in ['unknown', 'unavailable', '', 'none', 'None'] %} {{ cleaned | float(0) | round(1) }}°C {% else %} --°C {% endif %} - service: script.hasp_publish_heater_status_text - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b2.text" payload: > {% set raw = states('sensor.rinnai_neo_gas_heater_setpoint_text') %} {% set cleaned = raw | replace('°C', '') | replace('° C', '') | replace('C', '') | trim %} {% if cleaned not in ['unknown', 'unavailable', '', 'none', 'None'] %} {{ '\uE50F' }} {{ cleaned | float(0) | round(1) }}°C {% else %} {{ '\uE50F' }} --°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'] %} {{ '\uE58C' }} --% {% else %} {{ '\uE58C' }} {{ cleaned }}% {% endif %} - service: script.hasp_apply_heat_button_state # ------------------------------------------------------------------------- # Publish heater status text to p1b5 # Keeps OFF/BYPASS display based on ESPHome Mode, not just the operation switch. # # Display behaviour: # - OFF -> Off # - BYPASS (Remote Only) -> Bypass (Remote Only) # - Auto but flame OFF -> Auto (Up to Temp) # - Auto (Level 1) -> Auto 🔥 # - Auto (Level 2) -> Auto 🔥🔥 # - Auto (Level 3) -> Auto 🔥🔥🔥 # - Auto (Level 4) -> Auto 🔥🔥🔥🔥 # # The flame is the openHASP/Material icon \uE238, not an emoji. # ------------------------------------------------------------------------- hasp_publish_heater_status_text: alias: "HASP: publish heater status text" mode: queued sequence: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b5.text" payload: > {% set mode = states('select.rinnai_neo_gas_heater_mode') %} {% set op = states('switch.rinnai_neo_gas_heater_heater_operation') %} {% set flame_on = is_state('switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_activate_flame', 'on') %} {% set s = states('sensor.rinnai_neo_gas_heater_rinnai_neo_gas_heater_status_text') %} {% set flame = '\uE238' %} {% if mode == 'OFF' %} Off {% elif mode == 'BYPASS (Remote Only)' %} Bypass (Remote Only) {% elif op == 'on' and not flame_on %} Auto {% elif s not in ['unknown', 'unavailable', '', 'none', 'None'] %} {% set matches = s | regex_findall('Level ([0-9]+)', ignorecase=True) %} {% set level = matches[0] | int(0) if matches | count > 0 else 0 %} {% if level > 0 %} Auto {{ flame * level }} {% else %} {{ s }} {% endif %} {% elif mode not in ['unknown', 'unavailable', '', 'none', 'None'] %} {{ mode }} {% else %} HEATER -- {% endif %} # ------------------------------------------------------------------------- # Publish middle flame button icon and colours to p1b6 # ------------------------------------------------------------------------- hasp_apply_heat_button_state: alias: "HASP: apply heat button state" mode: queued sequence: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.text" payload: "\uE238" - choose: # BYPASS (Remote Only) -> dark button, amber flame so it is visibly different # from ordinary OFF, but still looks inactive. - conditions: - condition: state entity_id: select.rinnai_neo_gas_heater_mode state: "BYPASS (Remote Only)" sequence: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.text_color" payload: "#FFB000" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_color" payload: "#2F3240" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_grad_color" payload: "#2F3240" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.border_color" payload: "#2F3240" # OFF -> dark grey button, light grey flame - conditions: - condition: state entity_id: select.rinnai_neo_gas_heater_mode state: "OFF" sequence: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.text_color" payload: "#C0C0C0" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_color" payload: "#2F3240" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_grad_color" payload: "#2F3240" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.border_color" payload: "#2F3240" # AUTO, flame ON -> blue button, red flame - conditions: - condition: state entity_id: switch.rinnai_neo_gas_heater_heater_operation state: "on" - condition: state entity_id: switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_activate_flame state: "on" sequence: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.text_color" payload: "#FF3030" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_color" payload: "#0095D9" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_grad_color" payload: "#00B6FF" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.border_color" payload: "#0095D9" # AUTO, flame OFF -> blue button, white flame - conditions: - condition: state entity_id: switch.rinnai_neo_gas_heater_heater_operation state: "on" - condition: state entity_id: switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_activate_flame state: "off" sequence: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.text_color" payload: "#FFFFFF" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_color" payload: "#0095D9" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_grad_color" payload: "#00B6FF" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.border_color" payload: "#0095D9" default: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.text_color" payload: "#C0C0C0" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_color" payload: "#2F3240" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_grad_color" payload: "#2F3240" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.border_color" payload: "#2F3240" # ------------------------------------------------------------------------- # Style centre row info buttons as text panels # - p1b2 = setpoint # - p1b7 = humidity # This removes the default blue button styling from these display-only fields. # ------------------------------------------------------------------------- hasp_style_center_info_buttons: alias: "HASP: style centre info buttons" mode: queued sequence: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b2.text_color" payload: "#FFFFFF" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b2.bg_color" payload: "#000000" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b2.bg_grad_color" payload: "#000000" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b2.border_color" payload: "#000000" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b7.text_color" payload: "#FFFFFF" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b7.bg_color" payload: "#000000" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b7.bg_grad_color" payload: "#000000" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b7.border_color" payload: "#000000"