Lay-Z-Spa Hot Tub wi-fi pump automation

Hey all,

today I installed the Bestway HACS plugin and everything worked absolutely smoothly.
What I don’t get is how to automate that the filter is e.g. being turned off every day at 8pm.

I can’t find any suitable action which allows me to switch “switch.spa_filter” from “on” to “off” based on a timer.

Anyone any idea?

You’re probably looking for something like this:

The action at the bottom is a Device action.

1 Like

Exactly. Unfortunately, it doesn’t list any of the switches of the spa when adding a Device action in the Actions area:

Although its being listed in the entities:

is there anything new about the HydroJet models?

Greetings, Adrian

1 Like

Hi! Since yesterday im having issues im affraid.
The Bestway App stil works and returns correct values, yet all of my API calls from postman or in HA return values from the same hour yesterday evening at which it stopped working.

Once i figured this out i’ll post what ive got!

Edit: I deleted the spa from the bestway app and connected it again. After this my postman command’s and HA started working as it should. I’m new to the whole github thing tho Adrian, so i will post a quick guide to get you started so you can setup something like what ive got, probably within a day.

The following works for my Lay Z Spa San Francisco model using the Bestway App, ive done the minimum to get it working, once i find the time to make it decent i will post here again. (No error codes,… at this time) Modify the api links depending on if you registerd in EU or USA, if one does not work, try the other. (Im using usapi while im in EU, somehow)

Bruce’s Scripts that ive used & modified with the needed input for the HydroJet models, you can find the codes for login in here since that part is all the same:

Before we start, create the map ‘packages’ and open configuration.yaml. Enter:

homeassistant:
 packages: !include_dir_named packages

Now you can download & place the needed pieces of code in the packages directory.

  • Start with this one: secrets.yaml.example, enter your login information and rename to secrets.yaml, token & did will be aquired in the following steps.
  • Next is: sensor_rest_hottub_bestway_initial_login.yaml.disabled, rename to sensor_rest_hottub_bestway_initial_login.yaml and restart HA.
  • Add an entities card inside HA using this sensor, this will return your bestway token. Replace {your token} inside secrets.yaml with the received token.
  • Next: sensor_rest_hottub_bindings.yaml.disabled, rename to sensor_rest_hottub_bindings.yaml and restart HA.
  • Add an entities card inside HA using this sensor. This will return your did and some other information. Go to secrets.yaml and update this with your did.
  • This is the login part done, now you can create the following file: sensor_rest_hottub_status.yaml
sensor:
  - platform: rest
    name: hottub_status
    scan_interval: 30
    timeout: 20    
    resource: !secret bestway_status_url
    device_class: timestamp
    headers:
      Content-Type: application/json
      X-Gizwits-Application-Id: 98754e684ec045528b073876c34c7348
    method: GET
    value_template: "{{ value_json.updated_at | timestamp_custom ('%Y-%m-%dT%H:%M:%S+01:00') }}"
    json_attributes_path: "$.attr"
    json_attributes:
      - Tnow              # Temperature of Water in Pump
      - Tset              # Target Temperature
      - power             # Power - 1:On, 0:Off
      - filter            # Power - 1:On, 0:Off  
      - heat              # Heater - 1:On, 0:Off
      - wave              # Bubbles - 1:On, 0:Off
      - jet               # Jet Status
# https://support.bestwayaftersales.co.uk/faq/get-help-with-your-lay-z-spa-pump/

Now, restart HA again and when you add this sensor to an entity card you should be able to see the configured values under ‘Attributes’.

If this works, you dont need sensor_rest_hottub_bestway_initial_login.yaml & sensor_rest_hottub_bindings.yaml anymore so you can rename them back to *.disabled.

With the following codes under packages you then should be able to configure it like ive got:

sensor_rest_hottub_temperature.yaml

sensor:
  - platform: template
    sensors:
      hottub_temperature:
        friendly_name: "Hot Tub Temperature"
        value_template: "{{ state_attr('sensor.hottub_status', 'Tnow') }}"
        unit_of_measurement: "\u00B0C"

rest_command_hottub_command.yaml

rest_command:
  hottub_command: 
    method: POST
    headers:
      content_type: "application/json"
      X-Gizwits-Application-Id: "98754e684ec045528b073876c34c7348"
      X-Gizwits-User-token: !secret bestway_token    
    url: !secret bestway_control_url
    payload: "{{hottub_command}}"

sensor_template_hottub_jets.yaml

switch:
  - platform: template
    switches:
      hottub_jets:
        availability_template: "{{ states('binary_sensor.hottub_online') }}"
        unique_id: hottub_jets
        friendly_name: Jets 
        value_template: "{% if state_attr('sensor.hottub_status', 'jet') == 1 %}on{% else %}off{% endif %}"
        turn_on:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"jet": 1} }   
          - delay: 00:00:05
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status
        turn_off:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"jet": 0} }   
          - delay: 00:00:05
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status

switch_template_hottub_bubbles_high.yaml

switch:
  - platform: template
    switches:
      hottub_bubbles_high:
        availability_template: "{{ states('binary_sensor.hottub_online') }}"
        unique_id: hottub_bubbles_high
        friendly_name: Bubbles
        value_template: "{% if state_attr('sensor.hottub_status', 'wave') == 100 %}on{% else %}off{% endif %}"
        turn_on:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"wave": 100} }   
          - delay: 00:00:05
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status
        turn_off:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"wave": 0} }   
          - delay: 00:00:05
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status

switch_template_hottub_bubbles_medium.yaml

switch:
  - platform: template
    switches:
      hottub_bubbles_medium:
        availability_template: "{{ states('binary_sensor.hottub_online') }}"
        unique_id: hottub_bubbles_medium
        friendly_name: Bubbles
        value_template: "{% if state_attr('sensor.hottub_status', 'wave') == 40 %}on{% else %}off{% endif %}"
        turn_on:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"wave": 40} }   
          - delay: 00:00:05
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status
        turn_off:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"wave": 0} }   
          - delay: 00:00:05
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status

switch_template_hottub_filter.yaml

switch:
  - platform: template
    switches:
      hottub_filter:
        availability_template: "{{ states('binary_sensor.hottub_online') }}"
        unique_id: hottub_filter
        friendly_name: Filter  
        value_template: "{% if state_attr('sensor.hottub_status', 'filter') == 2 %}on{% else %}off{% endif %}"
        turn_on:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"filter": 2} }   
          - delay: 00:00:05
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status
        turn_off:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"filter": 0} }   
          - delay: 00:00:05
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status

switch_template_hottub_heat.yaml

switch:
  - platform: template
    switches:
      hottub_heat:
        availability_template: "{{ states('binary_sensor.hottub_online') }}"
        unique_id: Heater
        friendly_name: Heater      
        value_template: "{% if state_attr('sensor.hottub_status', 'heat') != 0 %}on{% else %}off{% endif %}"
        turn_on:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"heat": 1} }   
          - delay: 00:00:05
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status
        turn_off:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"heat": 0} }   
          - delay: 00:00:03
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status

switch_template_hottub_power.yaml

switch:
  - platform: template
    switches:
      hottub_power:
        availability_template: "{{ states('binary_sensor.hottub_online') }}"
        friendly_name: Power
        unique_id: hottub_power
        value_template: "{% if state_attr('sensor.hottub_status', 'power') == 1 %}on{% else %}off{% endif %}"
        turn_on:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"power": 1} }   
          - delay: 00:00:05
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status
        turn_off:
          - service: rest_command.hottub_command
            data_template: 
              hottub_command: >
                {"attrs": {"power": 0} }  
          - delay: 00:00:05
          - service: homeassistant.update_entity
            entity_id: sensor.hottub_status

That should be it, if you ran into any issues let me know, ill try to help as good as i can.

Hello Tomnesia,

the device has worked so far, but I can’t use anything at the moment


I can see a temperature so i guess its connecting and passing values. To make sure of this, when you go to entities and open hottub_status do you see all the values under attributes? (and are they correct with the values the bestway app tell you?)

should look like this:image

Hi I’m also trying to work out what’s changed (clearly the API!!) and found the following, also trying to get this working in PostMan first.

https://usapi.gizwits.com/app/login
https://euapi.gizwits.com/app/login

Here’s the cURL…

curl --location ‘https://usapi.gizwits.com/app/login
–header ‘X-Gizwits-Application-Id: 98754e684ec045528b073876c34c7348’
–header ‘Content-Type: application/json’
–data-raw '{
“username”: “[email protected]”,
“password”: “my password”

However I keep getting user not know (400 response), the app works OK.

I’d be interested if this works for you?

Hi Rob,

It does work for me, only difference i see is language in the data, might be worth a shot to add the following behind your password:
, “lang”: “en” }

If this does not work, seems you might have the same issue i had 2 days ago. Remove youre spa from the bestway app and re-add it.

Hi All

I thought you may be interested in my experiences with this API, there have been changes recently (as people have noted), but they aren’t as drastic as is being suggested in recent topics.

Firstly a little background, I first bought one of these a couple of years ago and the first thing I did was to hook it into HA to create automations that for example use excess solar to heat the tub. The pump broke down in April and I went back to a manual pump - having go fed up of manually running it I decided to replace the wifi pump with a new one - which I installed yesterday, only to find the HA integration no longer worked…

I followed the chain of recent comments and tested the fixes, unfortunately I could not get any calls to work via postman on these URLs, I always received user not found responses (I see this has been successful for some of you).

https://usapi.gizwits.com/app/login
https://euapi.gizwits.com/app/login

The iOS app was working successfully so I decided to create a reverse proxy to trap and look at the traffic from the App to their servers.

The App (in the UK) is making calls to https://mobileapi.lay-z-spa.co.uk/v1/auth/login to get an auth token, which is exactly as it always was in my integration.

curl --location ‘https://mobileapi.lay-z-spa.co.uk/v1/auth/login
–header ‘Content-Type: application/x-www-form-urlencoded’
–data-urlencode ‘[email protected]
–data-urlencode ‘password=myPwd’

I have also found that the token has become short lived (not sure yet on TTL) but when you log into the app - a new token is generated for my account and the stored HA token is invalidated. This took a while to work out, one minute working, the next not.

So I’ve had to create a dynamic store for this token in HA which can be referenced by the further APIs and also a refresh - just in case it is invalidated and needed immediately (before the REST refresh).

The other URLs use the API token in the body as below, but it’s potentially dynamic now, so I have to use a stored and inject it at execution, meaning I had to move the calls to command line (as payloads in Rest sensors can’t be dynamic… please fix this).

curl --location ‘https://mobileapi.lay-z-spa.co.uk/v1/gizwits/is_online
–header ‘Content-Type: application/x-www-form-urlencoded’
–data-urlencode ‘did=myDid’
–data-urlencode ‘api_token=myToken’

The final change is that the response to the /status API has changed

curl --location ‘https://mobileapi.lay-z-spa.co.uk/v1/gizwits/status
–header ‘Content-Type: application/x-www-form-urlencoded’
–data-urlencode ‘did=myDid’
–data-urlencode ‘api_token=myToken’

I also had to move this to a command line sensor, and manage the response differently.

If it’s of use to anyone reading this, these are the command line sensors I needed to create.

  • sensor:
    command: “curl -L POST ‘https://mobileapi.lay-z-spa.co.uk/v1/gizwits/is_online’ -H ‘Content-Type: application/x-www-form-urlencoded’ -d ‘did=myDid’ -d ‘api_token={{ states(‘sensor.hottub_login’) }}’”
    name: hottub_online_cmd
    scan_interval: 90
    value_template: “{{ value_json.data }}”
  • sensor:
    command: “curl -L POST ‘https://mobileapi.lay-z-spa.co.uk/v1/gizwits/status’ -H ‘Content-Type: application/x-www-form-urlencoded’ -d ‘did=myDid’ -d ‘api_token={{ states(‘sensor.hottub_login’) }}’”
    name: hottub_status_cmd
    scan_interval: 90
    value_template: “{% if value_json.data.temp_now > 0 %}online{% else %}offline{% endif %}”
    json_attributes:
    - data

The “data” attribute contains all the attributes of the current state of the tub. So to use it you must use the following notation (this is my sensor for the pump temperature) to use the status values.

  hottub_pump_temp:
    availability_template: "{{ states('sensor.hottub_online_cmd') }}"
    friendly_name: "HotTub Pump Temperature"
    unit_of_measurement: '°C'
    value_template: "{{ state_attr('sensor.hottub_status_cmd', 'data')['temp_now'] | int(0) }}"  

I hope this is of use to someone and saves you some of the pain I had to work out the changes in the API from lay-z-spa.

1 Like

Hi Rob,

Good that you got yours running again!

I can still switch between the Bestway App and HA without any issues, are you using the lay z spa app by any chance or is that irrelevant? Im also using a HydroJet model that is new from this year if im correct, so those changes might still come to me?

My apologies for the questions, still kind off new to HA and API’s in general, trying to understand it as good as i can.

Hi All, I have got this working really well using node-red.
As we have solar, battery and grid power here I have got it automated from our Solax system

I hope this helps and keep this updated as I use it constantly.
Happy to answer any questions.
A big thanks to the original creators of the Lay-z-spa and Solax on HACS who help us all here.
I will be doing a YouTube video showing how it all works at some point.

Dave

Hello Tom,

Yes, I can see the values, and they also match the APP

Hey @cdpuk

thanks for your reply and the screenshot. However, Device action doesn’t list any suitable linked device from the Spa, hence can’t select the switch.

In the entities its being listed:

However, trying to make use of this, it doesn’t show up in the Automations → “Device action”:
image

Oddly, I can find it when configuring it in my Dashboard:
image

So, why does the Automation can’t see the device/entity?

You need to find “Lay-Z-Spa” in the “Device” field. In HA terms the integration typically exposes one device which has multiple entities (the filter switch being one of them).

Once that “Device” field is set correctly, actions for the related entities will be displayed like my screenshot.

I think you are missing the binary_sensor_template_hottub_online.yaml file.
Since this is a precondition for the switches to work, it must be present.
I had the same problem, setting up the file solved the problem.

Is anyone using a newer spa pump with v01 on the side? I had an airjet pump and it was working in HA. I got a new hot tub this week and it’s still an airjet, but “v01” is printed on the side of it. I specifically had to select that version in the app to get it work. The app is working fine and I can pull it into HA, but when I do I can only pull spa statuses, there are no settings, toggles, etc. I assume the entity naming is different on the new version, but not sure what to do to get it working. Any suggestions?

1 Like

getting unavailable today

Logger: custom_components.bestway.coordinator
Source: helpers/update_coordinator.py:233
Integration: Bestway (documentation, issues)
First occurred: September 28, 2023 at 4:08:47 PM (3 occurrences)
Last logged: 11:00:32 AM

Error fetching Bestway API data: Error communicating with API:
Error fetching Bestway API data: Error communicating with API: 500, message=‘INTERNAL SERVER ERROR’, url=URL(‘https://usapi.gizwits.com/app/bindings’)

tried in postman and seems to be working here, getting this response:
URL: https://usapi.gizwits.com/app/bindings

{“devices”: [{“protoc”: 3, “ws_port”: 8080, “port_s”: 8883, “gw_did”: null, “host”: “usm2m.gizwits.com”,
“sleep_duration”: 3600, “port”: 1883, “mcu_soft_version”: “P182D102”, “product_key”: “REDACTED”,
“state_last_timestamp”: 1695979943, “role”: “owner”, “is_sandbox”: false, “type”: “normal”, “product_name”: “Airjet”,
“is_disabled”: false, “mcu_hard_version”: “P180D100”, “wifi_soft_version”: “0402003A”, “dev_alias”: “SPA”, “mesh_id”:
null, “is_online”: true, “dev_label”: [], “wss_port”: 8880, “remark”: “21”, “did”: “REDACTED”, “mac”:
“REDACTED”, “passcode”: “REDACTED”, “wifi_hard_version”: “00ESP826”, “is_low_power”: false}]}

had the same problem and once updated again all came right