Integration of HUUM UKU Wifi

Hello,
I plan the Integration of my Sauna. BleBox-Sauna is a nice approach, but doesnt work with „bio-Sauna“-setups (extra Steam-Modul). HUUM UKU is a very famous Sauna Producer with a very interesting Remote Control via APP and WIFI. I search for an Integration into HA - any ideas? THX in advance!

3 Likes

I would also like to integrate HUMM into HA, even just the current temperature might be a good start. I might look at how to create an integration for it. Being able to turn it on/off using HA UI buttons would also be cool.

this is my actual approach and works well … sorry for the German “words” …

#HUUM

  • platform: rest
    resource: https://api.huum.eu/action/home/status
    username: USERNAME
    password: PASSWORD
    authentication: basic
    scan_interval: 60
    name: sauna_status
    value_template: “OK”
    json_attributes:
    • “door”
    • “temperature”
    • “targetTemperature”
    • “statusCode”
  • platform: template
    sensors:
    sauna_temperature:
    value_template: “{{ state_attr(‘sensor.sauna_status’, ‘temperature’) }}”
    device_class: temperature
    unit_of_measurement: “°C”
    sauna_target_temperature:
    value_template: “{{ state_attr(‘sensor.sauna_status’, ‘targetTemperature’) }}”
    device_class: temperature
    unit_of_measurement: “°C”
    sauna_door:
    value_template: >-
    {% set state = state_attr(‘sensor.sauna_status’, ‘door’) %}
    {% if state == “true” %}Geschlossen
    {% elif state == “false” %}Offen
    {% else %}Unbekannt{% endif %}
    sauna_statuscode:
    value_template: >-
    {% set state = state_attr(‘sensor.sauna_status’, ‘statusCode’) %}
    {% if state == 230 %}Offline
    {% elif state == 231 %}OnlineHeating
    {% elif state == 232 %}OnlineNotHeating
    {% elif state == 233 %}Blocked
    {% elif state == 240 %}Emergency
    {% else %}Unbekannt{% endif %}
2 Likes

Huge thanks @Quellweg I got this working today perfectly. I had to edit the quote characters to get it formatted properly but that’s no problem.

I have just also come across some docs for the the API which means additional integrations such as switches could also now be done. I haven’t thought of a reason to yet though!

2 Likes

I’ve also been able to add config to configuration.yaml to toggle the light and sauna on and off now:

The commands below are then linked to a button that just calls a service (the commands are in the service list).

shell_command:
  sauna_light_toggle: 'curl "https://test%40test.com:[email protected]/action/home/light"'
  sauna_off: 'curl -X POST "https://test%40test.com:[email protected]/action/home/stop"'

rest_command:
  sauna_on:
    url: https://api.huum.eu/action/home/start
    username: [email protected]
    password: password
    payload: '{"targetTemperature":"90"}'
    verify_ssl: true
    content_type: application/json
    method: post
1 Like

Trying to achieve the same thing, got the first part formatted correctly but keep strugling with the value_templates.

Checking config keeps loading and cant get it restarted, anybody can point me the error ?

Edit: found it. Added the working formatted code.

  - platform: rest
    resource: https://api.huum.eu/action/home/status
    username: SECRET
    password: SECRET
    authentication: basic
    scan_interval: 60
    name: sauna_status
    value_template: "OK"
    json_attributes:
      - door
      - temperature
      - targetTemperature
      - statusCode

  - platform: template
    sensors:
      sauna_temperature:
        value_template: "{{ state_attr('sensor.sauna_status', 'temperature') }}"
        device_class: temperature
        unit_of_measurement: °C

      sauna_target_temperature:
        value_template: "{{ state_attr('sensor.sauna_status', 'targetTemperature') }}"
        device_class: temperature
        unit_of_measurement: °C

      sauna_door:
        value_template: >-
          {% set state = state_attr('sensor.sauna_status', 'door') %}
          {% if state == true %}Gesloten
          {% elif state == false %}Open
          {% else %}Unbekannt{% endif %}

    name: sauna_status
    value_template: "OK"
    json_attributes:
      - door
      - temperature
      - targetTemperature
      - statusCode

  - platform: template
    sensors:
      sauna_temperature:
        value_template: "{{ state_attr('sensor.sauna_status', 'temperature') }}"
        device_class: temperature
        unit_of_measurement: °C

      sauna_target_temperature:
        value_template: "{{ state_attr('sensor.sauna_status', 'targetTemperature') }}"
        device_class: temperature
        unit_of_measurement: °C

      sauna_door:
        value_template: >-
          {% set state = state_attr('sensor.sauna_status', 'door') %}
          {% if state == true %}Gesloten
          {% elif state == false %}Open
          {% else %}Unbekannt{% endif %}

      sauna_statuscode:
        value_template: >-
          {% set state = state_attr('sensor.sauna_status', 'statusCode') %}
          {% if state == 230 %}Offline
          {% elif state == 231 %}OnlineHeating
          {% elif state == 232 %}OnlineNotHeating
          {% elif state == 233 %}Blocked
          {% elif state == 240 %}Emergency
          {% else %}Unbekannt{% endif %}```

Looking great! Thank you for sharing. Really valuable to get started.

Did anyone manage to control the HUUM as well or only reading current data and statuses?

See the code posted by Deejbee, add this to your configuration.yaml

You can then create scripts to run these commands. (Light toggle, sauna on and sauna off).

Using an input slider you can easily add a custom desired temperature. And you can use template switches to combine the status and action to create switches to toggle the light and sauna.

Btw. All the credits to Quellweg and Deejbee for sharing their code.

2 Likes

Thanks! Nice. I managed to add the sensor values and the services.

But could you kindly guide on how to use the services to create the scripts need and how to then use them to create the beautiful dashboard card you showed?

Here is my config, sorry for not the most organised code/script names. I created a input_boolean to use as state switch for the light and the sauna. Script runs the commands and update this boolean, using the template switch i combine the state of the boolean and the switch so it gives a toggle option without the delay. Every 5 minutes a automation checks if the status of the boolean matches the online-status and updates is accordingly if for any reason these wouldn’t match.

Also there is the input_number.temperatuursauna which is being used to run the rest_command to use the desired temperature as set temperature.

Works here flawless. Maybe others do have better options.

Make sure in config.yaml you put te relevant code in appropriate places; ie. sensor, switch, light etc.

And i also changes some parts of the original code earlier in this topic like status commands etc so be aware of this (if you dont update this not everything will work).

configuration.yaml

################ HUUM #############
shell_command:
  sauna_light_toggle: 'curl "https://<EMAIL>%40gmail.com:<PASSWORD>@api.huum.eu/action/home/light"'
  sauna_off: curl -X POST https://<EMAIL>%40gmail.com:<PASSWORD>@api.huum.eu/action/home/stop

rest_command:
  sauna_on:
    url: https://api.huum.eu/action/home/start
    username: <EMAIL>
    password: <PASSWORD>
    payload: '{"targetTemperature":{{ states("input_number.temperatuursauna")|int }} }'
    verify_ssl: true
    content_type: application/json
    method: post

sensor:

  - platform: rest
    resource: https://api.huum.eu/action/home/status
    username: <SECRET>
    password: <SECRET>
    authentication: basic
    scan_interval: 60
    name: sauna_status
    value_template: "OK"
    json_attributes:
      - door
      - temperature
      - targetTemperature
      - statusCode
      - light


  - platform: template
    sensors:
      sauna_temperature:
        value_template: "{{ state_attr('sensor.sauna_status', 'temperature') }}"
        device_class: temperature
        unit_of_measurement: °C
    
      sauna_target_temperature:
        value_template: "{{ state_attr('sensor.sauna_status', 'targetTemperature') }}"
        device_class: temperature
        unit_of_measurement: °C
    
      sauna_door:
        value_template: >-
          {% set state = state_attr('sensor.sauna_status', 'door') %}
          {% if state == true %}Gesloten
          {% elif state == false %}Open
          {% else %}Unbekannt{% endif %}
    
      sauna_light:
        value_template: >-
          {% set state = state_attr('sensor.sauna_status', 'light') %}
          {% if state == 0 %}off
          {% elif state == 1 %}on
          {% else %}Onbekend{% endif %}

      sauna_statuscode:
        value_template: >-
          {% set state = state_attr('sensor.sauna_status', 'statusCode') %}
          {% if state == 230 %}Offline
          {% elif state == 231 %}on
          {% elif state == 232 %}off
          {% elif state == 233 %}Blocked
          {% elif state == 240 %}Emergency       
          {% else %}Unknown{% endif %}

light:
  - platform: template
    lights:
      sauna:
        friendly_name: "Sauna Lampen"
        value_template: "{{ states('input_boolean.sauna_lightstate') }}"
        turn_on: 
          service: script.sauna_lampen_aan
        turn_off:
          service: script.sauna_lampen_uit_dupliceer

switch:
  - platform: template
    switches:
      sauna:
        friendly_name: "Sauna"
        value_template: "{{ states('input_boolean.sauna_state') }}"
        turn_on:
          service: script.sauna_aan
        turn_off:
          service: script.sauna_uit

input_number:
  temperatuursauna:
    name: Sauna Temperatuur
    initial: 75
    min: 41
    max: 108
    step: 1

input_boolean:
  sauna_state:
    name: Status Sauna
  sauna_lightstate:
    name: Status Sauna Lampen

scripts.yaml

sauna_licht_toggle:
  alias: '[SAUNA] Licht toggle'
  sequence:
  - service: shell_command.sauna_light_toggle
  mode: single
sauna:
  alias: '[SAUNA] Sauna Uit'
  sequence:
  - service: shell_command.sauna_off
  mode: single
sauna_sauna_aan_75graden:
  alias: '[SAUNA] Sauna aan 75graden'
  sequence:
  - service: rest_command.sauna_on
  mode: single
sauna_aan:
  alias: sauna aan
  sequence:
  - service: script.sauna_sauna_aan_75graden
  - service: input_boolean.turn_on
    target:
      entity_id: input_boolean.sauna_state
  - delay:
      hours: 0
      minutes: 1
      seconds: 0
      milliseconds: 0
  - choose:
    - conditions:
      - condition: state
        entity_id: sensor.sauna_statuscode
        state: 'on'
      sequence:
      - service: input_boolean.turn_on
        target:
          entity_id: input_boolean.sauna_state
    - conditions:
      - condition: state
        entity_id: sensor.sauna_statuscode
        state: 'off'
      sequence:
      - service: input_boolean.turn_off
        target:
          entity_id: input_boolean.sauna_state
    default: []
  mode: single
sauna_uit:
  alias: sauna uit
  sequence:
  - service: script.sauna
  - service: input_boolean.turn_off
    target:
      entity_id: input_boolean.sauna_state
  - delay:
      hours: 0
      minutes: 1
      seconds: 0
      milliseconds: 0
  - choose:
    - conditions:
      - condition: state
        entity_id: sensor.sauna_statuscode
        state: 'on'
      sequence:
      - service: input_boolean.turn_on
        target:
          entity_id: input_boolean.sauna_state
    - conditions:
      - condition: state
        entity_id: sensor.sauna_statuscode
        state: 'off'
      sequence:
      - service: input_boolean.turn_off
        target:
          entity_id: input_boolean.sauna_state
    default: []
  mode: single
sauna_lampen_uit_dupliceer:
  alias: 'sauna lampen uit '
  sequence:
  - service: script.sauna_licht_toggle
  - service: input_boolean.turn_off
    target:
      entity_id: input_boolean.sauna_lightstate
  - delay:
      hours: 0
      minutes: 1
      seconds: 0
      milliseconds: 0
  - choose:
    - conditions:
      - condition: state
        entity_id: sensor.sauna_light
        state: 'on'
      sequence:
      - service: input_boolean.turn_on
        target:
          entity_id: input_boolean.sauna_lightstate
    - conditions:
      - condition: state
        entity_id: sensor.sauna_light
        state: 'off'
      sequence:
      - service: input_boolean.turn_off
        target:
          entity_id: input_boolean.sauna_lightstate
    default: []
  mode: single
sauna_lampen_aan:
  alias: sauna lampen aan
  sequence:
  - service: script.sauna_licht_toggle
  - service: input_boolean.turn_on
    target:
      entity_id: input_boolean.sauna_lightstate
  - delay:
      hours: 0
      minutes: 1
      seconds: 0
      milliseconds: 0
  - choose:
    - conditions:
      - condition: state
        entity_id: sensor.sauna_light
        state: 'on'
      sequence:
      - service: input_boolean.turn_on
        target:
          entity_id: input_boolean.sauna_lightstate
    - conditions:
      - condition: state
        entity_id: sensor.sauna_light
        state: 'off'
      sequence:
      - service: input_boolean.turn_off
        target:
          entity_id: input_boolean.sauna_lightstate
    default: []
  mode: single

automations.yaml

- id: '1640475808847'
  alias: Sauna Status Update
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.sauna_statuscode
  - platform: time_pattern
    minutes: '5'
  condition: []
  action:
  - choose:
    - conditions:
      - condition: state
        entity_id: sensor.sauna_statuscode
        state: 'on'
      sequence:
      - service: input_boolean.turn_on
        target:
          entity_id: input_boolean.sauna_state
    - conditions:
      - condition: state
        entity_id: sensor.sauna_statuscode
        state: 'off'
      sequence:
      - service: input_boolean.turn_off
        target:
          entity_id: input_boolean.sauna_state
    default: []
  mode: single
- id: '1640476303582'
  alias: Sauna Lampen Update
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.sauna_light
  - platform: time_pattern
    minutes: '5'
  condition: []
  action:
  - choose:
    - conditions:
      - condition: state
        entity_id: sensor.sauna_light
        state: 'on'
      sequence:
      - service: input_boolean.turn_on
        target:
          entity_id: input_boolean.sauna_lightstate
    - conditions:
      - condition: state
        entity_id: sensor.sauna_light
        state: 'off'
      sequence:
      - service: input_boolean.turn_off
        target:
          entity_id: input_boolean.sauna_lightstate
    default: []
  mode: single

lovelace frontend:

type: entities
show_header_toggle: false
entities:
  - entity: sensor.sauna_door
    name: Deur
  - entity: sensor.sauna_statuscode
    name: Status
  - entity: sensor.sauna_temperature
    name: Huidige temperatuur
  - type: conditional
    conditions:
      - entity: sensor.sauna_target_temperature
        state_not: unknown
    row:
      entity: sensor.sauna_target_temperature
      name: Ingestelde temperatuur
  - entity: light.sauna
  - entity: switch.sauna
    icon: mdi:radiator
  - entity: input_number.temperatuursauna
  - entity: media_player.sauna
    type: custom:mini-media-player
    toggle_power: true
    shortcuts:
      buttons:
        - name: ClassicFM
          type: service
          id: squeezebox.call_method
          data:
            entity_id: media_player.sauna
            command: playlist
            parameters:
              - play
              - classicfm
        - name: Skyradio
          type: service
          id: squeezebox.call_method
          data:
            entity_id: media_player.sauna
            command: playlist
            parameters:
              - play
              - >-
                http://opml.radiotime.com/Tune.ashx?id=s224032&formats=aac,ogg,mp3,wmpro,wma,wmvoice&partnerId=16&serial=7a068b625989fd18b463b262fd7dd78f
        - name: 100.5 Das Hitradio
          type: service
          id: squeezebox.call_method
          data:
            entity_id: media_player.sauna
            command: playlist
            parameters:
              - play
              - >-
                http://opml.radiotime.com/Tune.ashx?id=s2730&formats=aac,ogg,mp3,wmpro,wma,wmvoice&partnerId=16&serial=7a068b625989fd18b463b262fd7dd78f
        - name: X-Mas Hits
          type: service
          id: squeezebox.call_method
          data:
            entity_id: media_player.sauna
            command: playlist
            parameters:
              - play
              - >-
                https://stream06.dotpoint.nl:8006/stream?DIST=TuneIn&TGT=TuneIn&maxServers=2&partnertok=eyJhbGciOiJIUzI1NiIsImtpZCI6InR1bmVpbiIsInR5cCI6IkpXVCJ9.eyJ0cnVzdGVkX3BhcnRuZXIiOnRydWUsImlhdCI6MTY0MDE5ODY2OSwiaXNzIjoidGlzcnYifQ.c0w2YmufQO-tadk_CrRWQgeSNnFGD0ywrPwwlaiM49s
title: Sauna
2 Likes

Thank you so much for generously sharing. I am struggling with learning how Home Assistant works and these real case examples really help.

Could it be that the
- platform: rest
part should be included in the
sensor:
section instead of
rest_command:?

I get errors in my configuration.yaml while adding it the way you did above.

You are correct, sorry my bad copy paste mistake!

No problem, best way to get known with Hass is implementing en editing examples you find here!

1 Like

sub’d… just purchased a huum drop 4.5 w/wifi, so this will be a nice addition to HA for me.
hopefully an integration comes to light from all this work to date!?

Hi Jon_S,

I also copied the code above and it doesn’t work.

Can you please post what the correct one looks like?

I’m an absolute newbie to Hass.io and come from FHEM :wink:

Thx,
ANdi

anyone have a good conversion of C to F?

I tried this… which kinda works, but when I try to set a temp and activate the sauna, it still seems to want “C” instead. Its odd because the UKU is set to use/display F and in the app also. Guessing the API only uses C instead of F.

Suppose for now I will use C until more knowledge is learned…

  ## HUUM Template
      sauna_temperature:
        #value_template: "{{ state_attr('sensor.sauna_status', 'temperature') }}"
        value_template: >-
          {% set temp = state_attr('sensor.sauna_status', 'temperature') | float %}
          {{((temp)*9/5)+32}}
        device_class: temperature
        unit_of_measurement: "F"

      sauna_target_temperature:
        #value_template: "{{ state_attr('sensor.sauna_status', 'targetTemperature') }}"
        value_template: >-
          {% set targtemp = state_attr('sensor.sauna_status', 'targetTemperature') | float %}
          {{((targtemp)*9/5)+32}}
        device_class: temperature
        unit_of_measurement: "F"

Here is the JSON output from the API, does seem to be reporting only in C (sauna off)
image

and sauna on

1 Like

made a couple/few updates to my implementation…
these might have room for improvements also

Created sensor w/icon for the door sensor based on position of door… noticed the current door sensor is not binary, so made a new sensor to wrap the one pulled in from the REST lookup

      huum_temperature:
        friendly_name: 'HUUM Temperature'
        unit_of_measurement: F
        device_class: temperature
        value_template: "{{ ((states('sensor.sauna_temperature') | float) * 9 / 5) + 32 }}"

      huum_target_temperature:
        friendly_name: 'HUUM Target Temperature'
        unit_of_measurement: F
        device_class: temperature
        value_template: "{{ ((states('sensor.sauna_target_temperature') | float) * 9 / 5) + 32 }}"

      huum_sauna_door:
        friendly_name: 'HUUM Door Sensor'
        value_template: >
          {% set state = states.sensor.sauna_door.state %}
          {% if state == 'Open' %}Open
          {% elif state == 'Closed' %}Closed
          {% endif %}

        icon_template: >
          {% set state = states.sensor.sauna_door.state %}
          {% if state == 'Open' %}mdi:door-open
          {% elif state == 'Closed' %}mdi:door-closed
          {% endif %}

I also incorporated 2 other sensors to convert C to F and pulled these into the flex-horseshoe-card to help on my translation of the temperatures… I might look more into creating a set of Preset buttons since everyone in the house has they own preferred temperature.
image

Lastly, one of the features that drew me to the UKU was the child lockout function on the dial… So to give that function into HA, I am using the restriction-card to require a PIN and give a Message to the user before starting operation. This card will show a lock icon also. Only downside I am not liking is the PIN is in plaintext instead of **** as you type it.

type: custom:restriction-card
action: double_tap
restriction-regular-lock-color: red
restriction-success-lock-color: green
restrictions:
  pin:
    code: 1234
    text: >-
      Before confirming the PIN, Please ensure the Sauna is Safe and Ready! 
      Dont burn my house down!!.. Oh, and enjoy your session.
    retry_delay: 10

This screenshot shows the new door sensor with icons based on door (open/closed)
image

** Still working on an automation to notify.notify when Current Temp == Target Temp

Oh, also changed the Temperature selection icon to “mdi:gauge”
image

There is a python library already out there on github but i have struggle to implement a custom integration as i have no idea on how python works. Maybe someone of you is able to do so?

2 Likes

Thanks for sharing your configuration with us.
I used it for my HUUM UKU Wifi and most of it works just fine. The only thing (and maybe the most important one) not working is to stop the heating.
I can see that the scripts work as they should, but it seems that the shell command is not working.

After checking that my mail and password is correct I tried to just open the link in browser which leads to an 404 error {“state”:{“code”:404,“message”:“Error 404. Page not found.”}}

Would it maybe better to do this with an rest_command too, or do you have any other idea?

Hi @weidi!

The package that you linked to will be the package used for creating the actual integration. Sorry for the confusion. I will try to finish up the integration next week and create a PR for HA and hopefully you will have a real HUUM integration in the near future :slight_smile:

3 Likes

This is my shell_command in my config that turns the heat off, if that helps? I couldn’t get it working with rest_command, perhaps because the POST payload is empty in this case.

shell_command:

  sauna_off: 'curl -X POST "https://<<user>>:<<password>>@api.huum.eu/action/home/stop"'