visualapproach / WiFi-remote-for-Bestway-Lay-Z-SPA

Hack - ESP8266 as WiFi remote control for Bestway Lay-Z spa Helsinki
GNU General Public License v3.0
304 stars 74 forks source link

Home Assistant Intergration - Sample #96

Closed denxhun closed 1 year ago

denxhun commented 3 years ago

I really love this project, a real gap filler. I've seen in the description that integration to Home Assistant is possible via the MQTT interface.

Could you please share sample integrations to HA? I'm curious about the UI and the automation part as well.

PS: I'm happily contribute but no experience with this project yet.

visualapproach commented 3 years ago

Thank you. Yes I will do that when I have time to do so. I use nodered to catch the MQTT messages, and HACS nodered integration to make sensors available outside nodered. Then I can use the standard lovelace cards.

RGarrett93 commented 3 years ago

Yes please, if you can publish an example for Home Assistant, I've got it working nicely on Node-Red with MQTT and have integrated that with Smart NORA (Google) but I'm fairly new to HA and cant seem to get HACS node red integration to show the states correctly.

visualapproach commented 3 years ago

I've updated the nodered flows folder now (development branch)

RGarrett93 commented 3 years ago

Thank you very much @visualapproach, its working great with your example.

I particularly like the push notification to the HA app, I've got an issue with the bubbles randomly turning on and I cant work out what's causing it on my end, so now I'll get a notification for when they trigger and hopefully find the issue on the debug.

visualapproach commented 3 years ago

Good 😊 Here is my HA card image

markbellkosel commented 2 years ago

I wish I was able to do this! This is exactly what I have been wanting to accomplish.

dwoosnam commented 2 years ago

I just wanted to thank @visualapproach again for this excellent project. I have just upgraded to the latest version after running happily for a long time. All the extra features/sensors that drop right into home assistant are amazing!

For anyone interested, this is my current hot tub page on HomeAssistant

HomeAssistant

If anyone was interested in the code, it's here, just add a new card, select manual and paste in - you will need to have Mushroom cards Mini Graph Card and installed from HACS.

type: vertical-stack
cards:
  - square: false
    columns: 2
    type: grid
    cards:
      - type: custom:mushroom-entity-card
        entity: sensor.nodered_bdc8d8e3_805f28
        name: Hot Tub Display
        icon: mdi:fit-to-screen
        icon_color: disabled
        layout: horizontal
        fill_container: true
        tap_action:
          action: none
        hold_action:
          action: none
        double_tap_action:
          action: none
      - type: custom:mushroom-template-card
        primary: Hot Tub Ready
        secondary: >-
          {%- if is_state('binary_sensor.layzspa_ready', 'off') %} {{
          states('sensor.layzspa_time_to_target') | round(1) }} Hours to target 
          {% else %} Time for a dip {{ user }} {% endif %}
        icon: >-
          {%- if is_state('binary_sensor.layzspa_ready', 'off') %}
          mdi:thumb-down{% else %}mdi:thumb-up{% endif %}
        layout: horizontal
        entity: binary_sensor.layzspa_ready
        icon_color: >-
          {%- if is_state('binary_sensor.layzspa_ready', 'off') %} red {% else
          %} green {% endif %}
        tap_action:
          action: none
        hold_action:
          action: none
        double_tap_action:
          action: none
  - square: false
    columns: 3
    type: grid
    cards:
      - type: custom:mushroom-entity-card
        entity: switch.layzspa_pump
        secondary_info: none
        name: Pump
        fill_container: true
        layout: vertical
        tap_action:
          action: toggle
      - type: custom:mushroom-entity-card
        entity: switch.layzspa_heat_regulation
        secondary_info: none
        layout: vertical
        fill_container: true
        tap_action:
          action: toggle
        name: Heater
      - type: custom:mushroom-entity-card
        entity: switch.layzspa_airbubbles
        secondary_info: none
        layout: vertical
        tap_action:
          action: toggle
        name: Bubbles
        fill_container: true
  - square: false
    columns: 2
    type: grid
    cards:
      - type: custom:mushroom-template-card
        primary: Filter Reset
        secondary: 'Age: {{ states(''sensor.layzspa_filter_age'') | round(1) }} days'
        icon: >-
          {%- if states('sensor.layzspa_filter_age') | int > 10 %} mdi:sync {%
          else %} mdi:air-filter {% endif %}
        layout: horizontal
        entity: button.layzspa_reset_filter_timer
        hold_action:
          action: toggle
        tap_action:
          action: none
        fill_container: false
        icon_color: >-
          {%- if states('sensor.layzspa_filter_age') | int > 10 %} red {% else
          %} disabled {% endif %}
      - type: custom:mushroom-template-card
        primary: Chlorine Reset
        secondary: 'Age: {{ states(''sensor.layzspa_chlorine_age'') | round (1) }} days'
        icon: >-
          {%- if states('sensor.layzspa_chlorine_age') | int > 10 %} mdi:sync {%
          else %} mdi:test-tube {% endif %}
        entity: button.layzspa_reset_chlorine_timer
        layout: horizontal
        tap_action:
          action: none
        hold_action:
          action: toggle
        icon_color: >-
          {%- if states('sensor.layzspa_chlorine_age') | int > 10 %} red {% else
          %} disabled {% endif %}
  - square: true
    columns: 2
    type: grid
    cards:
      - type: thermostat
        entity: climate.layzspa_temperature_control
        name: Hot Tub
      - type: vertical-stack
        cards:
          - type: custom:mini-graph-card
            name: Hot Tub Temperature
            entities:
              - entity: sensor.layzspa_temperature
                name: Current
                color: '#FF1493'
                hours_to_show: 12
              - entity: sensor.layzspa_target_temperature
                name: Target
                color: '#00BFFF'
                hours_to_show: 12
          - type: custom:mushroom-entity-card
            entity: sensor.layzspa_time_to_target
            layout: horizontal
            name: Time to Target Temp
            fill_container: false
            icon_color: disabled
            tap_action:
              action: none
            hold_action:
              action: none
            double_tap_action:
              action: none
            icon: mdi:target

This is also the Node-Red flow I use to get the "Spa Display" sensor. I haven't put the time into converting it into home assistant.

[{"id":"b8225bf8.ace218","type":"mqtt in","z":"91dd6e92.2e71f","name":"","topic":"layzspa/message","qos":"2","datatype":"json","broker":"c66cc937.7b3028","nl":false,"rap":false,"inputs":0,"x":180,"y":180,"wires":[["949a9f5a.fa11"]]},{"id":"949a9f5a.fa11","type":"function","z":"91dd6e92.2e71f","name":"","func":"var display = String.fromCharCode(msg.payload.CH1,msg.payload.CH2,msg.payload.CH3);\n\nmsg.payload.disp=display;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":160,"wires":[["bdc8d8e3.805f28"]]},{"id":"bdc8d8e3.805f28","type":"ha-entity","z":"91dd6e92.2e71f","name":"Spa Display","server":"35db33f1.06bbbc","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Spa Display"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"payload.disp","stateType":"msg","attributes":[{"property":"","value":"","valueType":"str"}],"resend":true,"outputLocation":"payload.disp","outputLocationType":"msg","inputOverride":"allow","x":890,"y":140,"wires":[["9ec37d36.a781f"]]},{"id":"9ec37d36.a781f","type":"switch","z":"91dd6e92.2e71f","name":"Errors?","property":"payload.disp.state","propertyType":"msg","rules":[{"t":"cont","v":"e","vt":"str"},{"t":"empty"}],"checkall":"true","repair":false,"outputs":2,"x":1080,"y":120,"wires":[["4157f28d.0849dc"],[]]},{"id":"4157f28d.0849dc","type":"trigger","z":"91dd6e92.2e71f","name":"","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"2","extend":false,"overrideDelay":true,"units":"hr","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":1190,"y":40,"wires":[["316b9013.9379a"]]},{"id":"316b9013.9379a","type":"api-call-service","z":"91dd6e92.2e71f","name":"Notify Dan","server":"35db33f1.06bbbc","version":1,"debugenabled":true,"service_domain":"notify","service":"mobile_app_phone_dan","entityId":"","data":"{\"title\":\"Hot Tub\",\"message\":\"The hot tub has experienced an {{ payload.disp.state }} error\"}","dataType":"json","mergecontext":"","output_location":"payload","output_location_type":"msg","mustacheAltTags":false,"x":1350,"y":140,"wires":[[]]},{"id":"c66cc937.7b3028","type":"mqtt-broker","name":"HomeAssistant-Mosquitto","broker":"localhost","port":"1883","clientid":"","autoConnect":true,"usetls":false,"compatmode":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""},{"id":"35db33f1.06bbbc","type":"server","name":"DW : Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]

mattburns commented 1 year ago

Thanks for this 👌 It took a while, but I got most of this working. I had to rename some entities in your card config because I have extra prefix (eg sensor.layzspa_wifi_controller_layzspa_temp_c). I also noticed that everything was in farenheit so had to change that too. Happy to help anyone else attempting the same.

image

I'm just stuck with the temperature controller still being in farenheit :

image
visualapproach commented 1 year ago

Hi there, the climate card is converting everything thrown at it to the unit set in HA general settings. So go to HA settings-system-general and set C Thx

mattburns commented 1 year ago

Huzzah, that did it, thanks 💯

patatman commented 1 month ago

For anyone else not running NodeRed and just wanting a copy paste solution: Huge credit to @dwoosnam for doing all the work, I'm just copy pasting his findings across different issues/topics. 1) setup custom display MQTT sensor:

mqtt:
  discovery_prefix: homeassistant
  sensor:
    - name: "Layzspa Display"
      unique_id: "layzspa_display"
      state_topic: "layzspa/message"
      icon: mdi:fit-to-screen
      value_template: >-
        {% set ASCII = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx !x#$%&'()*+`-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz" %}
        {% set ch1=ASCII[value_json.CH1] %}
        {% set ch2=ASCII[value_json.CH2] %}
        {% set ch3=ASCII[value_json.CH3] %}
        {{ch1}}{{ch2}}{{ch3}}
      availability_topic: "layzspa/Status"
      payload_available: "Alive"
      payload_not_available: "Dead"

2) Adapt yaml to use new values (be mindful of the difference sensors for C or F, adapt to your own need):

type: vertical-stack
cards:
  - square: false
    columns: 2
    type: grid
    cards:
      - type: custom:mushroom-entity-card
        entity: sensor.layzspa_display
        name: Hot Tub Display
        icon: mdi:fit-to-screen
        icon_color: disabled
        layout: horizontal
        fill_container: true
        tap_action:
          action: none
        hold_action:
          action: none
        double_tap_action:
          action: none
      - type: custom:mushroom-template-card
        primary: Hot Tub Ready
        secondary: >-
          {%- if is_state('binary_sensor.layzspa_ready', 'off') %} {{
          states('sensor.layzspa_time_to_target') | round(1) }} Hours to target 
          {% else %} Time for a dip {{ user }} {% endif %}
        icon: >-
          {%- if is_state('binary_sensor.layzspa_ready', 'off') %}
          mdi:thumb-down{% else %}mdi:thumb-up{% endif %}
        layout: horizontal
        entity: binary_sensor.layzspa_ready
        icon_color: >-
          {%- if is_state('binary_sensor.layzspa_ready', 'off') %} red {% else
          %} green {% endif %}
        tap_action:
          action: none
        hold_action:
          action: none
        double_tap_action:
          action: none
  - square: false
    columns: 3
    type: grid
    cards:
      - type: custom:mushroom-entity-card
        entity: switch.layzspa_pump
        secondary_info: none
        name: Pump
        fill_container: true
        layout: vertical
        tap_action:
          action: toggle
      - type: custom:mushroom-entity-card
        entity: switch.layzspa_heat_regulation
        secondary_info: none
        layout: vertical
        fill_container: true
        tap_action:
          action: toggle
        name: Heater
      - type: custom:mushroom-entity-card
        entity: switch.layzspa_airbubbles
        secondary_info: none
        layout: vertical
        tap_action:
          action: toggle
        name: Bubbles
        fill_container: true
  - square: false
    columns: 2
    type: grid
    cards:
      - type: custom:mushroom-template-card
        primary: Filter Reset
        secondary: "Age: {{ states('sensor.layzspa_filter_age') | round(1) }} days"
        icon: >-
          {%- if states('sensor.layzspa_filter_age') | int > 10 %} mdi:sync {%
          else %} mdi:air-filter {% endif %}
        layout: horizontal
        entity: button.layzspa_reset_filter_timer
        hold_action:
          action: toggle
        tap_action:
          action: none
        fill_container: false
        icon_color: >-
          {%- if states('sensor.layzspa_filter_age') | int > 10 %} red {% else
          %} disabled {% endif %}
      - type: custom:mushroom-template-card
        primary: Chlorine Reset
        secondary: "Age: {{ states('sensor.layzspa_chlorine_age') | round (1) }} days"
        icon: >-
          {%- if states('sensor.layzspa_chlorine_age') | int > 10 %} mdi:sync {%
          else %} mdi:test-tube {% endif %}
        entity: button.layzspa_reset_chlorine_timer
        layout: horizontal
        tap_action:
          action: none
        hold_action:
          action: toggle
        icon_color: >-
          {%- if states('sensor.layzspa_chlorine_age') | int > 10 %} red {% else
          %} disabled {% endif %}
  - square: true
    columns: 2
    type: grid
    cards:
      - type: thermostat
        entity: climate.layzspa_temperature_control
        name: Hot Tub
      - type: vertical-stack
        cards:
          - type: custom:mini-graph-card
            name: Hot Tub Temperature
            entities:
              - entity: sensor.layzspa_temp_c
                name: Current
                color: "#FF1493"
                hours_to_show: 12
              - entity: sensor.layzspa_target_temp_c
                name: Target
                color: "#00BFFF"
                hours_to_show: 12
          - type: custom:mushroom-entity-card
            entity: sensor.layzspa_time_to_ready
            layout: horizontal
            name: Time to Target Temp
            fill_container: false
            icon_color: disabled
            tap_action:
              action: none
            hold_action:
              action: none
            double_tap_action:
              action: none
            icon: mdi:target

3): Enjoy the dashboard

image