Balboa Hot Tub/Spa Automation and Power Savings

Do you mind sharing the yaml for this dashboard?

Mostly i’ve used a combination of mushroom cards and a mini graph card. The only special is I’ve created a sensor to calculate the time to target temperature (You have to fine tune it to to your setup).

Sensor:

  - platform: template
    sensors:
      hot_tub_heat_time:
        friendly_name: "Hot Tub Heat Time"
        unit_of_measurement: "hours"
        value_template: >-
          {% set initial_temp = states('sensor.bwa_link_hot_tub_current_water_temperature')|float %}
          {% set final_temp = states('number.bwa_link_hot_tub_target_water_temperature')|float %}
          {% set water_mass = 920 %}
          {% set heating_power = 3000 %}
          {% set efficiency = 0.9 %}
          {% set delta_t = final_temp - initial_temp %}
          {% set heat_energy = water_mass * 4184 * delta_t %}
          {% set heat_time_hours = heat_energy / (heating_power * efficiency * 3600) %}
          {{ heat_time_hours|round(2) }}


Dashboard:

type: vertical-stack
cards:
  - square: false
    type: grid
    cards:
      - type: custom:mushroom-entity-card
        entity: binary_sensor.bwa_link_hot_tub_heating
        name: Heater
        secondary_info: none
        fill_container: false
        icon_color: red
        layout: vertical
      - type: custom:mushroom-entity-card
        entity: switch.bwa_link_hot_tub_pump
        name: Pump
        icon: mdi:pump
        secondary_info: none
        tap_action:
          action: call-service
          service: switch.toggle
          target:
            entity_id: switch.bwa_link_hot_tub_pump
          data: {}
        icon_color: green
        layout: vertical
      - type: custom:mushroom-light-card
        entity: light.bwa_link_hot_tub_lights
        name: Lights
        secondary_info: none
        layout: vertical
        icon_color: amber
        tap_action:
          action: call-service
          service: light.toggle
          target:
            entity_id: light.bwa_link_hot_tub_lights
          data: {}
    columns: 3
  - square: false
    type: grid
    cards:
      - type: vertical-stack
        cards:
          - type: custom:mushroom-number-card
            entity: number.bwa_link_hot_tub_target_water_temperature
            secondary_info: none
            display_mode: buttons
            primary_info: state
            icon_type: icon
            layout: vertical
            icon_color: '#00BFFF'
          - type: custom:mushroom-select-card
            entity: select.bwa_link_hot_tub_temperature_range
            name: Temp Mode
            icon_type: none
            layout: horizontal
            primary_info: none
            secondary_info: none
      - type: custom:mini-graph-card
        name: Hot Tub Temp
        entities:
          - entity: sensor.bwa_link_hot_tub_current_water_temperature
            name: Current
            color: '#FF1493'
            hours_to_show: 12
          - entity: number.bwa_link_hot_tub_target_water_temperature
            name: Target
            color: '#00BFFF'
            hours_to_show: 12
    columns: 2
  - square: false
    type: grid
    cards:
      - type: custom:mushroom-entity-card
        entity: sensor.hot_tub_heat_time
        name: To Target
        icon: mdi:target
        icon_color: disabled
      - type: custom:mushroom-template-card
        primary: Clean Filter
        secondary: >
          {% set time_left = state_attr('timer.hot_tub_filter_clean',
          'remaining') %} {% if time_left is not none %}
            {% set total_seconds = (time_left | as_timedelta).total_seconds() %}
            {% set days = total_seconds // 86400 %}
            {% if days == 1 %}
              1 day left
            {% else %}
              {{ days | int }} days left
            {% endif %}
          {% else %}

          {{ states('timer.hot_tub_filter_clean') }}

          {% endif %}
        icon: mdi:air-filter
        icon_color: ''
        tap_action:
          action: call-service
          service: timer.start
          target:
            entity_id: timer.hot_tub_filter_clean
          data: {}
        hold_action:
          action: call-service
          service: timer.cancel
          target:
            entity_id: timer.hot_tub_filter_clean
          data: {}
    columns: 2
  - type: custom:scheduler-card
    include:
      - select.bwa_link_hot_tub_temperature_range
    exclude: []
    title: true
    discover_existing: false
    show_header_toggle: false
    display_options:
      primary_info: default
      secondary_info:
        - relative-time
        - additional-tasks
      icon: action
    sort_by:
      - state
      - relative-time
    time_step: 30

2 Likes

I have the same problem here. Unable to start the service Where do I start to look?

░░ The job identifier is 3728 and the job result is done.
Jun 10 13:36:01 jacuzzi systemd[1318]: bwa_mqtt_bridge.service: Failed to determine user credentials: No such process
Jun 10 13:36:01 jacuzzi systemd[1]: Starting Balboa Spa MQTT Bridge...
░░ Subject: A start job for unit bwa_mqtt_bridge.service has begun execution
░░ Defined-By: systemd
░░ Support: https://www.debian.org/support
░░
░░ A start job for unit bwa_mqtt_bridge.service has begun execution.
░░
░░ The job identifier is 3728.
Jun 10 13:36:01 jacuzzi systemd[1318]: bwa_mqtt_bridge.service: Failed at step USER spawning /usr/local/bin/bwa_mqtt_bridge: No such process
░░ Subject: Process /usr/local/bin/bwa_mqtt_bridge could not be executed
░░ Defined-By: systemd
░░ Support: https://www.debian.org/support
░░
░░ The process /usr/local/bin/bwa_mqtt_bridge could not be executed and failed.
░░
░░ The error number returned by this process is ERRNO.
Jun 10 13:36:01 jacuzzi systemd[1]: bwa_mqtt_bridge.service: Main process exited, code=exited, status=217/USER
░░ Subject: Unit process exited
░░ Defined-By: systemd
░░ Support: https://www.debian.org/support
░░
░░ An ExecStart= process belonging to unit bwa_mqtt_bridge.service has exited.
░░
░░ The process' exit code is 'exited' and its exit status is 217.
Jun 10 13:36:01 jacuzzi systemd[1]: bwa_mqtt_bridge.service: Failed with result 'exit-code'.
░░ Subject: Unit failed
░░ Defined-By: systemd
░░ Support: https://www.debian.org/support
░░
░░ The unit bwa_mqtt_bridge.service has entered the 'failed' state with result 'exit-code'.
Jun 10 13:36:01 jacuzzi systemd[1]: Failed to start Balboa Spa MQTT Bridge.
░░ Subject: A start job for unit bwa_mqtt_bridge.service has failed
░░ Defined-By: systemd
░░ Support: https://www.debian.org/support
░░
░░ A start job for unit bwa_mqtt_bridge.service has finished with a failure.
░░
░░ The job identifier is 3728 and the job result is failed.

Just for information, it was recently discovered that the bwa-mqtt-bridge code that this is based on seems to support native communication with a non-Balboa RS485-Wifi adapter (like the $15 Elfin-EW11). This greatly simplifies the communication process by removing socat from the equation.

I’ve packaged this solution up as a Home Assistant Add-On (local install required for now).

Steps:

  1. Follow @jshank 's guide for connecting the Elfin device GitHub - jshank/bwalink: Automate your Balboa Spa! A docker container with socat and ccutrer/balboa_worldwide_app that supports a remote serial to IP device or host running ser2net, socat or ESPEasy serial server
    Stop at the end of this section, do not do the ‘BWA Link Docker Setup’
  2. Follow the instrutions here to setup the HA Add-on Installation & Run · supersebbo/bwa-mqtt-bridge-addon Wiki · GitHub

Notes:

  1. This is only intended to work for TCP based RS485-Wifi adapters
  2. It’s only been tested with an Elfin-EW11/EW11A so far
  3. It only works with an internal MQTT broker (e.g. the official Mosquitto add-on from HA)

Any feedback, please leave it here: Initial Testing and Feedback · Issue #1 · supersebbo/bwa-mqtt-bridge-addon · GitHub

So since an add-on is essentially a docker container that the HA Supervisor configured to link to HA, how would one go about setting this up in their own docker container environment? I run HA Container, so I have to play the role of supervisor. I do not have the option to install add-ons.

That is what @jshank original docker container is for - just follow his instructions and edit the docker-entrypoint.sh file to remove the socat line and put your RS485 bridge’s TCP URI instead of /dev/hottub

like:

#!/bin/sh

set -e

#Launch the bwa_mqtt_bridge 
/usr/local/bundle/bin/bwa_mqtt_bridge ${MQTT_URI} tcp://my.ip.address:my_port/
1 Like

That’s what I was looking for, the edits that needed to be made to the docker image to remove socat. I’ve been running this docker container for a while but have had some issues with delayed communications.

Glad I could help. I believe @jshank is going to rework his code to include this after some burn-in testing. Any feedback you have would be appreciated, mine has been rock-solid for about a week now.

Release bwalink 2023.06 · jshank/bwalink · GitHub is pushed to the repository with socat deprecated. No issues in a week so we’ll call that successful. Awesome research @supersebbo !

Just updated my docker to the latest version. So far so good. I’m getting data and status for everything and the “discarding invalid data prior to message” message that I would get once every second has stopped. I plan to test out some controls and automations later this week and can report back.

I’m completely new to HA but stumbled across this thread and wanted to build this out so I’ve installed the Elfin module and completed it’s setup. After this I’m confused by the next steps to follow. I believe I’m installing HA with MQTT broker on a Raspberry Pi that will solely be used for this spa project (in my case). Could I follow @supersebbo post from there? If so, is there anything specific about the installation on the Pi I should take note of to make this work. Sorry for the noob questions but thank you for the help!

I have full control of the hot tub and very fast response and status update. Previously I could send maybe 2-3 commands then all communication would just freeze. I even experienced a situation where the lights kept turning on and off by themselves because a light toggle command got stuck in a loop, but the light entity status never updated. But all of that is gone now and it’s very nice and easy to control. Nice work! Now to find a nice Lovelace card or way to display everything.

1 Like

If you’re doing HA Supervised or HAOS on the Pi then the add-on is the way to go. If you’re running HA on your own server OS then use the docker container.

1 Like

@jshank I’m seeing warnings in my HA logs about MQTT not generating unique IDs for this device. Whenever the docker container starts and connects to MQTT I see these errors. It doesn’t seem to affect anything though:

2023-07-10 09:27:05.399 ERROR (MainThread) [homeassistant.components.switch] Platform mqtt does not generate unique IDs. ID bwa_spa_hold already exists - ignoring switch.bwa_link_hot_tub_hold
2023-07-10 09:27:05.406 ERROR (MainThread) [homeassistant.components.switch] Platform mqtt does not generate unique IDs. ID bwa_spa_twenty-four-hour-time already exists - ignoring switch.bwa_link_hot_tub_24_hour_time
2023-07-10 09:27:05.408 ERROR (MainThread) [homeassistant.components.switch] Platform mqtt does not generate unique IDs. ID bwa_filter-cycle2_enabled already exists - ignoring switch.bwa_link_filter_cycle_2_enabled
2023-07-10 09:27:05.410 ERROR (MainThread) [homeassistant.components.binary_sensor] Platform mqtt does not generate unique IDs. ID bwa_spa_priming already exists - ignoring binary_sensor.bwa_link_hot_tub_priming
2023-07-10 09:27:05.411 ERROR (MainThread) [homeassistant.components.binary_sensor] Platform mqtt does not generate unique IDs. ID bwa_spa_heating already exists - ignoring binary_sensor.bwa_link_hot_tub_heating
2023-07-10 09:27:05.413 ERROR (MainThread) [homeassistant.components.binary_sensor] Platform mqtt does not generate unique IDs. ID bwa_spa_circulation-pump already exists - ignoring binary_sensor.bwa_link_hot_tub_circulation_pump_running
2023-07-10 09:27:05.414 ERROR (MainThread) [homeassistant.components.binary_sensor] Platform mqtt does not generate unique IDs. ID bwa_filter-cycle1_running already exists - ignoring binary_sensor.bwa_link_filter_cycle_1_running
2023-07-10 09:27:05.416 ERROR (MainThread) [homeassistant.components.binary_sensor] Platform mqtt does not generate unique IDs. ID bwa_filter-cycle2_running already exists - ignoring binary_sensor.bwa_link_filter_cycle_2_running
2023-07-10 09:27:05.417 ERROR (MainThread) [homeassistant.components.select] Platform mqtt does not generate unique IDs. ID bwa_spa_heating-mode already exists - ignoring select.bwa_link_hot_tub_heating_mode
2023-07-10 09:27:05.419 ERROR (MainThread) [homeassistant.components.select] Platform mqtt does not generate unique IDs. ID bwa_spa_temperature-scale already exists - ignoring select.bwa_link_hot_tub_temperature_scale
2023-07-10 09:27:05.421 ERROR (MainThread) [homeassistant.components.select] Platform mqtt does not generate unique IDs. ID bwa_spa_temperature-range already exists - ignoring select.bwa_link_hot_tub_temperature_range
2023-07-10 09:27:05.422 ERROR (MainThread) [homeassistant.components.sensor] Platform mqtt does not generate unique IDs. ID bwa_spa_current-temperature already exists - ignoring sensor.bwa_link_hot_tub_current_water_temperature
2023-07-10 09:27:05.424 ERROR (MainThread) [homeassistant.components.number] Platform mqtt does not generate unique IDs. ID bwa_spa_target-temperature already exists - ignoring number.bwa_link_hot_tub_target_water_temperature
2023-07-10 09:27:05.425 ERROR (MainThread) [homeassistant.components.number] Platform mqtt does not generate unique IDs. ID bwa_spa_pump1 already exists - ignoring number.bwa_link_hot_tub_pump_1
2023-07-10 09:27:05.427 ERROR (MainThread) [homeassistant.components.number] Platform mqtt does not generate unique IDs. ID bwa_spa_pump2 already exists - ignoring number.bwa_link_hot_tub_pump_2
2023-07-10 09:27:05.428 ERROR (MainThread) [homeassistant.components.number] Platform mqtt does not generate unique IDs. ID bwa_filter-cycle1_start-hour already exists - ignoring number.bwa_link_filter_cycle_1_start_hour
2023-07-10 09:27:05.432 ERROR (MainThread) [homeassistant.components.number] Platform mqtt does not generate unique IDs. ID bwa_filter-cycle1_start-minute already exists - ignoring number.bwa_link_filter_cycle_1_start_minute
2023-07-10 09:27:05.433 ERROR (MainThread) [homeassistant.components.number] Platform mqtt does not generate unique IDs. ID bwa_filter-cycle1_duration already exists - ignoring number.bwa_link_filter_cycle_1_duration
2023-07-10 09:27:05.434 ERROR (MainThread) [homeassistant.components.number] Platform mqtt does not generate unique IDs. ID bwa_filter-cycle2_start-hour already exists - ignoring number.bwa_link_filter_cycle_2_start_hour
2023-07-10 09:27:05.435 ERROR (MainThread) [homeassistant.components.number] Platform mqtt does not generate unique IDs. ID bwa_filter-cycle2_start-minute already exists - ignoring number.bwa_link_filter_cycle_2_start_minute
2023-07-10 09:27:05.436 ERROR (MainThread) [homeassistant.components.number] Platform mqtt does not generate unique IDs. ID bwa_filter-cycle2_duration already exists - ignoring number.bwa_link_filter_cycle_2_duration
2023-07-10 09:27:05.437 ERROR (MainThread) [homeassistant.components.light] Platform mqtt does not generate unique IDs. ID bwa_spa_light1 already exists - ignoring light.bwa_link_hot_tub_lights

The specific error says:

Logger: homeassistant.components.light
Source: helpers/entity_platform.py:607
Integration: Light (documentation, issues)
First occurred: 9:27:05 AM (2 occurrences)
Last logged: 9:37:16 AM

Platform mqtt does not generate unique IDs. ID bwa_spa_light1 already exists - ignoring light.bwa_link_hot_tub_lights

Also, every once in a while I will go to change a setting on the hot tub like the lights on/off or temperature, or pump speed and the entities go unavailable. Come to find out the docker container has crashed. This is the log from the docker container. You’ll see it crashed at 14:37:06 UTC and I restarted the container about 9 seconds later.

2023-07-10 14:37:06	stdout	I,   to spa: #<BWA::Messages::ToggleItem 4>
2023-07-10 14:37:06	stdout	D, wrote: 7e 07 0a bf 11 04 00 85 7e
2023-07-10 14:37:06	stderr	/usr/local/bundle/gems/balboa_worldwide_app-2.1.4/lib/bwa/client.rb:74:in `readpartial': Connection reset by peer (Errno::ECONNRESET)
2023-07-10 14:37:06	stderr	from /usr/local/bundle/gems/balboa_worldwide_app-2.1.4/lib/bwa/client.rb:74:in `block in poll'
2023-07-10 14:37:06	stderr	from /usr/local/bundle/gems/balboa_worldwide_app-2.1.4/lib/bwa/client.rb:64:in `loop'
2023-07-10 14:37:06	stderr	from /usr/local/bundle/gems/balboa_worldwide_app-2.1.4/lib/bwa/client.rb:64:in `poll'
2023-07-10 14:37:06	stderr	from /usr/local/bundle/gems/balboa_worldwide_app-2.1.4/exe/bwa_mqtt_bridge:59:in `block in initialize'
2023-07-10 14:37:06	stderr	from /usr/local/bundle/gems/balboa_worldwide_app-2.1.4/exe/bwa_mqtt_bridge:58:in `loop'
2023-07-10 14:37:06	stderr	from /usr/local/bundle/gems/balboa_worldwide_app-2.1.4/exe/bwa_mqtt_bridge:58:in `initialize'
2023-07-10 14:37:06	stderr	from /usr/local/bundle/gems/balboa_worldwide_app-2.1.4/exe/bwa_mqtt_bridge:421:in `new'
2023-07-10 14:37:06	stderr	from /usr/local/bundle/gems/balboa_worldwide_app-2.1.4/exe/bwa_mqtt_bridge:421:in `<top (required)>'
2023-07-10 14:37:06	stderr	from /usr/local/bundle/bin/bwa_mqtt_bridge:25:in `load'
2023-07-10 14:37:06	stderr	from /usr/local/bundle/bin/bwa_mqtt_bridge:25:in `<main>'
2023-07-10 14:37:15	stdout	I,   to spa: #<BWA::Messages::ConfigurationRequest>
2023-07-10 14:37:15	stdout	D, wrote: 7e 05 0a bf 04 77 7e
2023-07-10 14:37:15	stdout	D, discarding invalid data prior to message ff af 13 00 00 62 09 24 00 00 01 00 02 04 00 00 00 00 00 00 00 00 00 5c 00 00 00 78 00 00 c3 7e
2023-07-10 14:37:15	stdout	D, discarding invalid data prior to message 7e 05 10 bf ff
2023-07-10 14:37:15	stdout	D,  read: 7e 0d 0a bf 23 01 00 06 00 8d 00 04 00 25 7e
2023-07-10 14:37:15	stdout	I, from spa: #<BWA::Messages::FilterCycles cycle1 6:00@01:00 cycle2(enabled) 4:00@13:00>
2023-07-10 14:37:16	stdout	D,  read: 7e 1a 0a bf 24 64 dc 2b 00 4d 58 42 50 32 30 20 20 0c 10 47 d6 0a 01 0a 04 00 0c 7e
2023-07-10 14:37:16	stdout	I, from spa: #<BWA::Messages::ControlConfiguration MXBP20 V43.0>
2023-07-10 14:37:16	stdout	D, discarding invalid data prior to message 7e 05 10 bf 07 5b fe
2023-07-10 14:37:16	stdout	D,  read: 7e 0d 0a bf 23 01 00 06 00 8d 00 04 00 25 7e
2023-07-10 14:37:16	stdout	I, from spa: #<BWA::Messages::FilterCycles cycle1 6:00@01:00 cycle2(enabled) 4:00@13:00>
2023-07-10 14:37:16	stdout	D,  read: 7e 0b 0a bf 2e 0a 00 01 50 00 00 bf 7e
2023-07-10 14:37:16	stdout	I, from spa: #<BWA::Messages::ControlConfiguration2 pumps=[2, 2, 0, 0, 0, 0] lights=[true, false] circulation_pump aux=[false, false]>
2023-07-10 14:37:16	stdout	W, Balboa MQTT Bridge running (version 2.1.4)
2023-07-10 14:37:16	stdout	D,  read: 7e 0b 0a bf 2e 0a 00 01 50 00 00 bf 7e
2023-07-10 14:37:16	stdout	I, from spa: #<BWA::Messages::ControlConfiguration2 pumps=[2, 2, 0, 0, 0, 0] lights=[true, false] circulation_pump aux=[false, false]>

If you have the older GL Series (GL2000 or GL2001) my project now pretty much has feature parity wth the original project posted

1 Like

I don’t think you need to worry about those warnings. For the balboa_worldwide_app error, it’s worth opening an issue in the parent repo so Cody can take a look.

1 Like

i can’t connect, any help?

pictures:
https://aijaa.com/OYGysN
https://aijaa.com/2i36Bd

https://aijaa.com/L4hEEA
https://aijaa.com/xiz1Pb

https://aijaa.com/3bhVeC

The IP address of your serial to wifi bridge is not 10.10.100.254. Go to the status page and in the first section (System State) it will show what the IP address is for the device. Try connecting to that IP address.

Also, make sure your DNS is correct. You have it set at 223.5.5.5. If you have a simple home network, this should be set to whatever is hosting DNS services, or just the IP address of your gateway (router, ie: 192.168.1.1).