cdpuk / ha-bestway

Home Assistant integration for Bestway / Lay-Z-Spa hot tubs
MIT License
59 stars 15 forks source link

Airjet_V01 Support #41

Closed dloveall closed 5 months ago

dloveall commented 9 months ago

It appears that I have a different version of the AirJet, identified as "Airjet_V01". The status values are different, but it appears that I have most(all?) of the values defined in BestwaySpaDeviceStatus. Is there a preferred method of adding support? I can try to add a new BestwayDeviceType.AIRJET_V01_SPA and do a pull request. Or I can provide a proposed mapping of values to function names (turn on feature, observe change, turn off feature, repeat)? Another method, somewhere in between?

Thank you for writing this integration! It appears well setup to abstract to an additional type.

The log message is: Status for unknown device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 0, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 792, "word4": 0, "word7": 34, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 792, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 93, "option7": 10260, "option4": 0, "option5": 27182, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 1, "heat": 3, "Tunit": 0, "wave": 0, "word3": 0, "Tset": 104, "filter": 2, "E28": 0, "bit6": 1, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}

My guess on some of the mappings (untested & not methodical, just looking at the names to start) is: spa_power: power temp_now: Tnow temp_set: Tset temp_set_unit: Tunit heat_power: heat heat_temp_reach: filter_power: filter wave_power: wave locked: errors: earth_fault:

mccleved commented 8 months ago

Did you ever get this worked out? I have the same model and would like to get it connected.

jazzmonger commented 7 months ago

@dloveall I have the same problem/model here...

jazzmonger commented 7 months ago

I tried modifying model.py with this:

class BestwayDeviceType(Enum):
    """Bestway device types."""

    AIRJET_V01 = "Airjet_V01"
    AIRJET_SPA = "Airjet"
    POOL_FILTER = "Pool Filter"
    UNKNOWN = "Unknown"

    @staticmethod
    def from_api_product_name(product_name: str) -> BestwayDeviceType:
        """Get the enum value based on the 'product_name' field in the API response."""

        if product_name == "Airjet_V01":
            return BestwayDeviceType.AIRJET_V01
        if product_name == "Airjet":
            return BestwayDeviceType.AIRJET_SPA        
        if product_name == "泳池过滤器":
            # Chinese translates to "pool filter"
            return BestwayDeviceType.POOL_FILTER
        return BestwayDeviceType.UNKNOWN

and the api.py file with this:

try:
                if device_info.device_type == BestwayDeviceType.AIRJET_V01:
                    errors = []
                    for err_num in range(1, 10):
                        if device_attrs[f"system_err{err_num}"] == 1:
                            errors.append(err_num)

                    spa_status = BestwaySpaDeviceStatus(
                        latest_data["updated_at"],
                        device_attrs["power"],
                        device_attrs["Tnow"],
                        device_attrs["Tset"],
                        (
                            TemperatureUnit.CELSIUS
                            if device_attrs["temp_set_unit"]
                            == "摄氏"  # Chinese translates to "Celsius"
                            else TemperatureUnit.FAHRENHEIT
                        ),
                        device_attrs["heat_power"] == 1,
                        device_attrs["heat_temp_reach"] == 1,
                        device_attrs["filter_power"] == 1,
                        device_attrs["wave_power"] == 1,
                        device_attrs["locked"] == 1,
                        errors,
                        device_attrs["earth"] == 1,
                    )

                    self._spa_state_cache[did] = spa_status
#next try
                elif device_info.device_type == BestwayDeviceType.AIRJET_SPA:
                    errors = []

but it throws an error:

2023-11-22 12:17:42.446 ERROR (MainThread) [custom_components.bestway.coordinator] Data update failed
Traceback (most recent call last):
  File "/config/custom_components/bestway/coordinator.py", line 37, in _async_update_data
    return await self.api.fetch_data()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/bestway/bestway/api.py", line 200, in fetch_data
    if device_info.device_type == BestwayDeviceType.Airjet_V01:
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/enum.py", line 784, in __getattr__
    raise AttributeError(name) from None
AttributeError: Airjet_V01

2023-11-22 12:17:47.564 INFO (MainThread) [custom_components.bestway] Reusing existing access token
2023-11-22 12:17:47.979 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device Ykbs11pev7SBKLMDijT1De
2023-11-22 12:17:47.979 ERROR (MainThread) [custom_components.bestway.coordinator] Data update failed
Traceback (most recent call last):
  File "/config/custom_components/bestway/coordinator.py", line 37, in _async_update_data
    return await self.api.fetch_data()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/bestway/bestway/api.py", line 200, in fetch_data
    if device_info.device_type == BestwayDeviceType.Airjet_V01:
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/enum.py", line 784, in __getattr__
    raise AttributeError(name) from None
AttributeError: Airjet_V01
2023-11-22 12:17:47.984 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.420 seconds (success: False)

@cdpuk We'll need your help on this...

jazzmonger commented 7 months ago

After a couple of reboots and restart of the hottub, I got past the errors and it now shows the correct Model number, but no controls:

image
jazzmonger commented 7 months ago

I'm getting further... not sure how to handle Unexpected missing key ''system_err1''

full error log:

2023-11-23 10:13:22.571 INFO (MainThread) [custom_components.bestway] Reusing existing access token
2023-11-23 10:13:22.954 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device Ykbs11pev7SBKLMDijT1De
2023-11-23 10:13:22.955 ERROR (MainThread) [custom_components.bestway.bestway.api] Unexpected missing key ''system_err1'' while decoding device attributes {"E19": 0, "E18": 0, "E32": 0, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 0, "word4": 0, "word7": 32, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 0, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 90, "option7": 10260, "option4": 0, "option5": 27186, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 0, "heat": 0, "Tunit": 0, "wave": 0, "word3": 0, "Tset": 104, "filter": 0, "E28": 0, "bit6": 0, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}
2023-11-23 10:13:22.955 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.384 seconds (success: True)
2023-11-23 10:13:22.955 INFO (MainThread) [homeassistant.components.binary_sensor] Setting up binary_sensor.bestway
2023-11-23 10:13:22.956 INFO (MainThread) [homeassistant.components.climate] Setting up climate.bestway
2023-11-23 10:13:22.956 INFO (MainThread) [homeassistant.components.number] Setting up number.bestway
2023-11-23 10:13:22.957 INFO (MainThread) [homeassistant.components.sensor] Setting up sensor.bestway
2023-11-23 10:13:22.957 INFO (MainThread) [homeassistant.components.switch] Setting up switch.bestway
2023-11-23 10:13:22.959 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new sensor.bestway entity: sensor.bestway_protocol_version
2023-11-23 10:13:22.960 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new sensor.bestway entity: sensor.bestway_mcu_software_version
2023-11-23 10:13:22.962 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new sensor.bestway entity: sensor.bestway_mcu_hardware_version
2023-11-23 10:13:22.963 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new sensor.bestway entity: sensor.bestway_wi_fi_software_version
2023-11-23 10:13:22.967 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new sensor.bestway entity: sensor.bestway_wi_fi_hardware_version

So, in brute for manner, I hard coded system_err1 and TemperatureUnit.FAHRENHEIT, but it looks like each of these attributes need to be mapped if we're going to get anywhere:

                        device_attrs["temp_set_unit"]
                        device_attrs["heat_power"] == 1,
                        device_attrs["heat_temp_reach"] == 1,
                        device_attrs["filter_power"] == 1,
                        device_attrs["wave_power"] == 1,
                        device_attrs["locked"] == 1,
                        errors,
                        device_attrs["earth"] == 1,

I've come to that conclusion after getting this error once I hard coded those 2 other values. each attribute that isnt mapped will throw an error:

ERROR (MainThread) [custom_components.bestway.bestway.api] Unexpected missing key ''temp_set_unit'' while 
decoding device attributes {"E19": 0, "E18": 0, "E32": 0, "E31": 0, "E30": 0, "E11": 0, "E10": 0, 
"E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 4, "word4": 0, "word7": 34, "word6": 0, "word1": 0, 
"word0": 0, "E29": 0, "word2": 4, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 91, 
"option7": 10260, "option4": 0, "option5": 27186, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 
0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, 
"E03": 0, "E01": 0, "bit7": 1, "heat": 3, "Tunit": 0, "wave": 0, "word3": 0, "Tset": 104, "filter": 2, "E28": 0, "bit6": 1, "bit5": 
0, "bit4": 0, "bit3": 0, "bit2": 0}

The problem is I don't see any obvious mappings for these in the list of key-value pairs.

jazzmonger commented 7 months ago

As the "I never give up" kind of guy I am, I took my best stab at mapping those attributes and now I get this! Temps are right and I can turn the power on /off, but thats about it. Thermostat controls don't work, bubble/filter sw don't work. So, I'm clearly on the right track. But, there's a Turkey that needs to be cooked, and it's calling my name.... it's Thanksgiving day here in the US. Hopefully I can poke around more soon and find the right combination.

image

And I'm now able to see how this thing heats without having to put a probe in the damn thing. And since the wifi "connected" sensor now works, I can automate an alert when it disconnects from Wifi. This happens sometimes and there's nothing worse than going outside cold and naked only to find the damn thing hasn't heated starting at 3AM!:

image

These are the changes I made to api.py at line 199:

           try:
                if device_info.device_type == BestwayDeviceType.AIRJET_V01:
                    errors = []
                    # for err_num in range(1, 10):
                    #     if device_attrs[f"system_err{err_num}"] == 1:
                    #         errors.append(err_num)
                    errors.append(1)

                    spa_status = BestwaySpaDeviceStatus(
                        latest_data["updated_at"],
                        device_attrs["power"],
                        device_attrs["Tnow"],
                        device_attrs["Tset"],
                        # (
                        #     TemperatureUnit.CELSIUS
                        #     if device_attrs["temp_set_unit"]
                        #     == "摄氏"  # Chinese translates to "Celsius"
                        #     else TemperatureUnit.FAHRENHEIT
                        # ),
                        TemperatureUnit.FAHRENHEIT,
                        device_attrs["heat"] == 1,
                        device_attrs["word3"] == 1,
                        device_attrs["filter"] == 1,
                        device_attrs["wave"] == 1,
                        device_attrs["bit6"] == 1,
                        errors,
                        device_attrs["bit5"] == 1,
                    )

                    self._spa_state_cache[did] = spa_status

and model.py at line 20:

    @staticmethod
    def from_api_product_name(product_name: str) -> BestwayDeviceType:
        """Get the enum value based on the 'product_name' field in the API response."""

        if product_name == "Airjet_V01":
            return BestwayDeviceType.AIRJET_V01
        if product_name == "Airjet":
            return BestwayDeviceType.AIRJET_SPA        
        if product_name == "泳池过滤器":
            # Chinese translates to "pool filter"
            return BestwayDeviceType.POOL_FILTER
        return BestwayDeviceType.UNKNOWN

After this little experiment, I'm convinced that these attributes hold the key (but I could be wrong...):

"bit7": 1, "heat": 3, "Tunit": 0, "wave": 0, "word3": 0, "Tset": 104, "filter": 2, "E28": 0, "bit6": 1, "bit5": 
0, "bit4": 0, "bit3": 0, "bit2": 0}
jazzmonger commented 7 months ago

@cdpuk It would be helpful if there was a way to see the value of each changed attribute-value pair as I change something on the remote app. Is there a way to expose that??? otherwise is a guessing game and there are too many variables to consider.

I added this to the api.py section so each time I load and unload the integration I can view the log:

                    attr_dump = json.dumps(device_attrs)
                    _LOGGER.warning(
                        "Status for DEBUGGING device '%s' returned: %s",
                        device_info.product_name,
                        attr_dump,
                    )
                    self._unknown_states[did] = attr_dump    

when I turn the heater on on - "heat": 3 off - "heat": 0

I'll try and figure out what the other controls change via this process.

mrtlhfr commented 6 months ago

@jazzmonger nice work -- I got this to work on my end. I made a few updates (unit, heat, filter). Haven't tested the bubbles yet, will do so this weekend and update. I get error messages (400 bad request) when changing anything in HA - is this working for someone else?

These are my changes to api.py line 199: (on top of your changes to model.py)

            try:
                if device_info.device_type == BestwayDeviceType.AIRJET_V01:
                    errors = []
                    # for err_num in range(1, 10):
                    #     if device_attrs[f"system_err{err_num}"] == 1:
                    #         errors.append(err_num)
                    #errors.append(1)

                    spa_status = BestwaySpaDeviceStatus(
                        latest_data["updated_at"],
                        device_attrs["power"],
                        device_attrs["Tnow"],
                        device_attrs["Tset"],
                        (
                            TemperatureUnit.CELSIUS
                            if device_attrs["Tunit"] 
                            == 1
                            else TemperatureUnit.FAHRENHEIT
                        ),
                        # heat = 3 on, heat = 0 off
                        device_attrs["heat"] == 3,
                        device_attrs["word3"] == 1,
                        # filter is always on when heating
                        device_attrs["heat"] == 3 or device_attrs["filter"]==2,
                        device_attrs["wave"] == 1,
                        device_attrs["bit6"] == 1,
                        errors,
                        device_attrs["bit5"] == 1,
                    )

                    #attr_dump = json.dumps(device_attrs)
                    #_LOGGER.warning(
                    #    "Status for DEBUGGING device '%s' returned: %s",
                    #    device_info.product_name,
                    #    attr_dump,
                    #)
                    #self._unknown_states[did] = attr_dump 
                    self._spa_state_cache[did] = spa_status
jazzmonger commented 6 months ago

Yes, I also get bad request when trying to update anything from HA, except on/off does work, so there's hope...

cdpuk commented 6 months ago

There is now v1.4.0-alpha1 published as a beta release via HACS. This groups together a bunch of tasks around device support, and should add support for any Airjet_V01 or Hydrojet devices. The data to get this working has been scraped together from a number of different sources and combined with a bit of guesswork.

I'd very much appreciate some testing against real devices to confirm what's working, in particular:

Debug logging has also been extended to print out those attribute collections for known devices (previous this only happened for unrecognised devices). If anything doesn't work as expected, capturing these messages before and after device state changes will be essential.

jazzmonger commented 6 months ago

Ok, I updated to your alpha code. Turning the filter AND the SPA on/off toggles I get Failed to call service switch/turn_off. 400, message='BAD REQUEST', url=URL('https://usapi.gizwits.com/app/control/Ykbs11pev7SBKLMDijT1De')

2024-01-06 08:49:40.347 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [139736619893056] 400, message='BAD REQUEST', url=URL('https://usapi.gizwits.com/app/control/Ykbs11pev7SBKLMDijT1De')
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 238, in handle_call_service
    response = await hass.services.async_call(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2067, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2104, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/homeassistant/__init__.py", line 138, in async_handle_turn_service
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/core.py", line 2067, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2104, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 272, in handle_service
    return await service.entity_service_call(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 903, in entity_service_call
    raise result from None
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1233, in async_request_call
    return await coro
           ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 948, in _handle_entity_call
    result = await task
             ^^^^^^^^^^
  File "/config/custom_components/bestway/switch.py", line 205, in async_turn_on
    await self.entity_description.turn_on_fn(self.coordinator.api, self.device_id)
  File "/config/custom_components/bestway/bestway/api.py", line 312, in hydrojet_spa_set_filter
    await self._do_control_post(device_id, filter_power=1 if filtering else 0)
  File "/config/custom_components/bestway/bestway/api.py", line 411, in _do_control_post
    return await self._do_post(
           ^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/bestway/bestway/api.py", line 422, in _do_post
    await _raise_for_status(response)
  File "/config/custom_components/bestway/bestway/api.py", line 86, in _raise_for_status
    response.raise_for_status()
  File "/usr/local/lib/python3.11/site-packages/aiohttp/client_reqrep.py", line 1059, in raise_for_status
    raise ClientResponseError(
aiohttp.client_exceptions.ClientResponseError: 400, message='BAD REQUEST', url=URL('https://usapi.gizwits.com/app/control/Ykbs11pev7SBKLMDijT1De')

The switch labeled "Power" turns the spa control on & off successfully and I can change the temp now, so that's a win. Where is debug logging output? I only see the above error msg in the logs.

cdpuk commented 6 months ago

Found something obviously wrong for the filter control, so give v1.4.0-alpha2 a go to see if that improves things.

Debug logs should be possible via Settings > Devices & Services > Bestway, then "Enable Debug Logging" for a bit, and then "Disable Debug Logging" should trigger a log download.

isaacfinnegan commented 6 months ago

I just tried 1.4.0-alpha2. Everything except bubbles and spa lock are working. On/off, temp control's and mode (heat) are all working for me.

cdpuk commented 6 months ago

I've just published v1.4.0-alpha3. This hopefully fixes the bubbles control. It looks like a lock switch wasn't being provided for you in alpha2? Worth another look in alpha3 as I've tweaked a few things.

isaacfinnegan commented 6 months ago

I've just published v1.4.0-alpha3. This hopefully fixes the bubbles control. It looks like a lock switch wasn't being provided for you in alpha2? Worth another look in alpha3 as I've tweaked a few things.

I can confirm bubbles works with alpha3! Nice!!

cdpuk commented 6 months ago

Great. Was there any progress on the lock switch with the alpha3 release?

jazzmonger commented 6 months ago

It's almost fully working. Lock sw doesn't seem to do anything though, I never use it.
The filter switch doesn't follow what's in the Bestway app. when I hit the flame icon, Heater tuns ON bit the filter sw in HA turns OFF. it should turn ON!

IMG_2661 IMG_2662

isaacfinnegan commented 6 months ago

So, on alpha3:

cdpuk commented 6 months ago

Next up: v1.4.0-alpha4

The lock switch has been removed, as it seems it never worked and isn't widely used.

The heater switch should now update the filter status (as reported by @jazzmonger).

@isaacfinnegan can the disabled bubbles switch be deleted? Something probably got renamed by me and it's caused a duplicate.

Rodman101 commented 5 months ago

Would it be possible to have "Spa Bubbles" switch between the 2 levels of bubbles? Right now it's an on-off button for the lower level of bubbles (at least that's how it's showing up in the Bestway app).

cdpuk commented 5 months ago

Would it be possible to have "Spa Bubbles" switch between the 2 levels of bubbles? Right now it's an on-off button for the lower level of bubbles (at least that's how it's showing up in the Bestway app).

That's the first I've heard about multiple levels of bubbles on these devices. If you're able to capture the debug logs while changing the settings via the Bestway app, it should be possible to identify the correct values. Be sure to wait a minute between each setting so that the integration picks up the new value.

Can anyone else confirm they also have multiple levels?

isaacfinnegan commented 5 months ago

Yes, the new wifi enabled Airjet_V01 has 2 bubbles settings, a high and low (and off).

I tried to get debug logs and changed from the different levels:

|
`2024-01-10 13:29:19.752 ERROR (SyncWorker_4) [homeassistant.components.plex.server] Resource connection failed to plex.tv: TV 2020
2024-01-10 13:29:33.930 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device QPaCIG8eSt5gBwkQMLeolf
2024-01-10 13:29:33.931 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 1, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 1829, "word4": 0, "word7": 39, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 1829, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 102, "option7": 10260, "option4": 0, "option5": 27186, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 1, "heat": 6, "Tunit": 0, "wave": 0, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 1, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}
2024-01-10 13:29:33.931 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.722 seconds (success: True)
2024-01-10 13:29:55.784 ERROR (Thread-2 (_start_tcp_client)) [custom_components.cync_lights.cync_hub] KeyError: '1761577687'
2024-01-10 13:29:56.100 ERROR (Thread-2 (_start_tcp_client)) [custom_components.cync_lights.cync_hub] KeyError: '1761577687'
2024-01-10 13:29:57.673 ERROR (Thread-2 (_start_tcp_client)) [custom_components.cync_lights.cync_hub] IndexError: list index out of range
2024-01-10 13:30:05.043 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device QPaCIG8eSt5gBwkQMLeolf
2024-01-10 13:30:05.043 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 1, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 1830, "word4": 0, "word7": 39, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 1830, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 102, "option7": 10260, "option4": 0, "option5": 27186, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 1, "heat": 5, "Tunit": 0, "wave": 50, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 1, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}
2024-01-10 13:30:05.043 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.831 seconds (success: True)
2024-01-10 13:30:35.889 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device QPaCIG8eSt5gBwkQMLeolf
2024-01-10 13:30:35.889 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 1, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 1830, "word4": 0, "word7": 39, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 1830, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 102, "option7": 10260, "option4": 0, "option5": 27186, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 1, "heat": 5, "Tunit": 0, "wave": 0, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 1, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}
2024-01-10 13:30:35.889 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.678 seconds (success: True)
2024-01-10 13:30:59.682 INFO (MainThread) [custom_components.bestway] Reusing existing access token
2024-01-10 13:31:00.358 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device QPaCIG8eSt5gBwkQMLeolf
2024-01-10 13:31:00.359 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 1, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 1831, "word4": 0, "word7": 39, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 1831, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 102, "option7": 10260, "option4": 0, "option5": 27186, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 1, "heat": 6, "Tunit": 0, "wave": 0, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 1, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}
2024-01-10 13:31:00.359 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.677 seconds (success: True)
2024-01-10 13:31:31.832 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device QPaCIG8eSt5gBwkQMLeolf
2024-01-10 13:31:31.832 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 1, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 1831, "word4": 0, "word7": 39, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 1831, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 102, "option7": 10260, "option4": 0, "option5": 27186, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 1, "heat": 5, "Tunit": 0, "wave": 100, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 1, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}
2024-01-10 13:31:31.833 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 1.765 seconds (success: True)
`
jarrettgilliam commented 5 months ago

I can confirm. The Airjet_V01 I bought a couple months ago has 2 bubble settings:

image

jarrettgilliam commented 5 months ago

I've been testing this out a bit. Looks like the "wave" property in the returned status json is showing the the bubble level as a percentage. 0 is off, 51 is low, and 100 is high. Full log attached.

2024-01-10 19:33:48.287 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device 0NS20ZT1Grb2hvDkmvBKbm
2024-01-10 19:33:48.287 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 0, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 5, "word4": 0, "word7": 38, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 5, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 100, "option7": 10260, "option4": 0, "option5": 27187, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 0, "heat": 3, "Tunit": 0, "wave": 0, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 0, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}
2024-01-10 19:33:48.287 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.445 seconds (success: True)
2024-01-10 19:34:18.218 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device 0NS20ZT1Grb2hvDkmvBKbm
2024-01-10 19:34:18.218 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 0, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 5, "word4": 0, "word7": 38, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 5, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 100, "option7": 10260, "option4": 0, "option5": 27187, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 0, "heat": 2, "Tunit": 0, "wave": 51, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 0, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}
2024-01-10 19:34:18.218 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.377 seconds (success: True)
2024-01-10 19:34:48.242 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device 0NS20ZT1Grb2hvDkmvBKbm
2024-01-10 19:34:48.243 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 0, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 6, "word4": 0, "word7": 38, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 6, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 100, "option7": 10260, "option4": 0, "option5": 27187, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 0, "heat": 2, "Tunit": 0, "wave": 100, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 0, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}
2024-01-10 19:34:48.243 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.402 seconds (success: True)
2024-01-10 19:39:25.361 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device 0NS20ZT1Grb2hvDkmvBKbm
2024-01-10 19:39:25.362 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 0, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 11, "word4": 0, "word7": 38, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 11, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 100, "option7": 10260, "option4": 0, "option5": 27187, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 1, "heat": 2, "Tunit": 0, "wave": 0, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 1, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}
2024-01-10 19:39:25.362 INFO (MainThread) [custom_components.bestway.coordinator] Fetching Bestway API data recovered
2024-01-10 19:39:25.362 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.520 seconds (success: True)

I also noticed a "Data update failed" exception in the log as well. It may be nothing:

2024-01-10 19:38:54.845 ERROR (MainThread) [custom_components.bestway.coordinator] Data update failed
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/aiohttp/connector.py", line 1173, in _create_direct_connection
    hosts = await asyncio.shield(host_resolved)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/connector.py", line 884, in _resolve_host
    addrs = await self._resolver.resolve(host, port, family=self._family)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/resolver.py", line 33, in resolve
    infos = await self._loop.getaddrinfo(
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/asyncio/base_events.py", line 867, in getaddrinfo
    return await self.run_in_executor(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/socket.py", line 962, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
socket.gaierror: [Errno -3] Try again

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/config/custom_components/bestway/coordinator.py", line 36, in _async_update_data
    await self.api.refresh_bindings()
  File "/config/custom_components/bestway/bestway/api.py", line 136, in refresh_bindings
    device.device_id: device for device in await self._get_devices()
                                           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/bestway/bestway/api.py", line 141, in _get_devices
    api_data = await self._do_get(f"{self._api_root}/app/bindings")
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/bestway/bestway/api.py", line 404, in _do_get
    response = await self._session.get(url, headers=headers)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/client.py", line 574, in _request
    conn = await self._connector.connect(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/connector.py", line 544, in connect
    proto = await self._create_connection(req, traces, timeout)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/connector.py", line 911, in _create_connection
    _, proto = await self._create_direct_connection(req, traces, timeout)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/connector.py", line 1187, in _create_direct_connection
    raise ClientConnectorError(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host usapi.gizwits.com:443 ssl:default [Try again]
2024-01-10 19:38:54.849 ERROR (MainThread) [custom_components.bestway.coordinator] Error fetching Bestway API data: Error communicating with API: Cannot connect to host usapi.gizwits.com:443 ssl:default [Try again]
2024-01-10 19:38:54.849 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 5.008 seconds (success: False)

home-assistant.log

jazzmonger commented 5 months ago

Ok, this is odd. I can turn the controls on/off from HA and they arent reflected in Bestway app.

But if I use Bestway app to turn heater/filter on/off, nothing is updated in HA.

whats also odd is if I change temp in Bestway, HA temp chnges, so comms are sort of working.

filter follows heater now which is correct.

cdpuk commented 5 months ago

The bubbles thing is a bit odd.

I'm going to have to pick one of these unless someone can work out why the 50/51 values differ.

I suspect that Cannot connect to host usapi.gizwits.com:443 error is just a temporary thing.

As for the behaviour described by @jazzmonger, it's not really clear what's going on there. Due to the way the API works, changes from the device or Bestway app can take a little while to appear in HA. When changing things in HA, other places normally update instantly.

jarrettgilliam commented 5 months ago

I checked again this morning to make sure, and I'm getting the same result (51 for low). I've got a couple of ideas though.

  1. Pick either 50 or 51 and have us report back whether the bestway app shows a "low" bubble setting when set from HA.
  2. Try exposing the wave property as a slider in HA, sort of like dimmable lights. I'm curious if the hardware and api supports any wave value, but the app limits the options to just two.
cdpuk commented 5 months ago

v1.4.0-alpha5 is now available for testing this. It's using a value of 50 to represent "MEDIUM" bubbles. If there are any glitches, it'd be useful to know:

jarrettgilliam commented 5 months ago

What happens when setting the MEDIUM level from HA? Does it achieve MEDIUM on the device and Bestway app?

Yes. Both the device and the Bestway app show MEDIUM when set to MEDIUM in HA.

2024-01-22 12:24:57.802 DEBUG (MainThread) [custom_components.bestway.bestway.api] Setting bubbles mode to 40
2024-01-22 12:25:09.283 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device 0NS20ZT1Grb2hvDkmvBKbm
2024-01-22 12:25:09.284 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 0, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 12617, "word4": 0, "word7": 36, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 14144, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 97, "option7": 10260, "option4": 0, "option5": 27187, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 1, "heat": 2, "Tunit": 0, "wave": 51, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 1, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 1}
2024-01-22 12:25:09.284 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.243 seconds (success: True)
2024-01-22 12:25:09.284 WARNING (MainThread) [custom_components.bestway.bestway.model] Unexpected API value 51 - assuming OFF

What happens when setting the MEDIUM level from the device? Does HA show this correctly? Bear in mind it could take a minute to update. What do the debug logs show? It should produce a warning if an unknown value is seen.

HA showed OFF when settings the level to MEDIUM from the device. The logs reported an unexpected value:

2024-01-22 12:26:09.483 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device 0NS20ZT1Grb2hvDkmvBKbm
2024-01-22 12:26:09.483 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 0, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 12618, "word4": 0, "word7": 36, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 14145, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 97, "option7": 10260, "option4": 0, "option5": 27187, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 1, "heat": 2, "Tunit": 0, "wave": 51, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 1, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 0}
2024-01-22 12:26:09.483 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.442 seconds (success: True)
2024-01-22 12:26:09.483 WARNING (MainThread) [custom_components.bestway.bestway.model] Unexpected API value 51 - assuming OFF

What happens when setting the MEDIUM level from the app? As above, but I'm curious whether the device and app set different values. Perhaps one is setting 50 and the other sets 51?

Just like above. HA showed OFF when settings the level to MEDIUM from the Bestway app.

2024-01-22 12:31:40.491 DEBUG (MainThread) [custom_components.bestway.bestway.api] New data received for device 0NS20ZT1Grb2hvDkmvBKbm
2024-01-22 12:31:40.491 DEBUG (MainThread) [custom_components.bestway.bestway.api] Status for device type 'Airjet_V01' returned: {"E19": 0, "E18": 0, "E32": 0, "E31": 0, "E30": 0, "E11": 0, "E10": 0, "E13": 0, "E12": 0, "E15": 0, "E14": 0, "E17": 0, "E16": 0, "word5": 12623, "word4": 0, "word7": 36, "word6": 0, "word1": 0, "word0": 0, "E29": 0, "word2": 14150, "option6": 10244, "ver": 1174, "E22": 0, "jet": 0, "E23": 0, "power": 1, "Tnow": 97, "option7": 10260, "option4": 0, "option5": 27187, "option2": 0, "option3": 30, "option0": 59940, "option1": 59940, "E24": 0, "E25": 0, "E26": 0, "E27": 0, "E20": 0, "E21": 0, "E08": 0, "E09": 0, "E06": 0, "E07": 0, "E04": 0, "E05": 0, "E02": 0, "E03": 0, "E01": 0, "bit7": 1, "heat": 2, "Tunit": 0, "wave": 51, "word3": 0, "Tset": 102, "filter": 2, "E28": 0, "bit6": 1, "bit5": 0, "bit4": 0, "bit3": 0, "bit2": 0}
2024-01-22 12:31:40.491 DEBUG (MainThread) [custom_components.bestway.coordinator] Finished fetching Bestway API data in 0.451 seconds (success: True)
2024-01-22 12:31:40.491 WARNING (MainThread) [custom_components.bestway.bestway.model] Unexpected API value 51 - assuming OFF

Full log: home-assistant.log

cdpuk commented 5 months ago

Thanks. Looks about as expected since your device is using 51 as the magic number. I've made some further changes to allow wither 50 or 51 to map to MEDIUM in HA. I'm going to wrap this up in a final 1.4.0 release, and treat any further issues separately.