core icon indicating copy to clipboard operation
core copied to clipboard

SleepIQ Footwarmers not being added after update

Open jmwaldrip opened this issue 1 year ago • 20 comments

The problem

I have a Climate360 split king. It includes foot warmers and climate.

I updated my HA to 2024.1.1, and the new foot warmer entities are not being added for the SleepIQ integration.

I have deleted the device and added it again, I have deleted the device, rebooted my HA server and went through the flow to add it again and no success.

What version of Home Assistant Core has the issue?

2024.1.1

What was the last working version of Home Assistant Core?

No response

What type of installation are you running?

Home Assistant Container

Integration causing the issue

SleepIQ

Link to integration documentation on our website

https://www.home-assistant.io/integrations/sleepiq/

Diagnostics information

Not available in the UI

Example YAML snippet

No response

Anything in the logs that might be useful for us?

No response

Additional information

No response

jmwaldrip avatar Jan 06 '24 05:01 jmwaldrip

Hey there @mfugate1, @kbickar, mind taking a look at this issue as it has been labeled with an integration (sleepiq) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of sleepiq can trigger bot actions by commenting:

  • @home-assistant close Closes the issue.
  • @home-assistant rename Awesome new title Renames the issue.
  • @home-assistant reopen Reopen the issue.
  • @home-assistant unassign sleepiq Removes the current integration label and assignees on the issue, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component) to the issue.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component) on the issue.

(message by CodeOwnersMention)


sleepiq documentation sleepiq source (message by IssueLinks)

home-assistant[bot] avatar Jan 06 '24 05:01 home-assistant[bot]

The climate360 line uses a pretty different API. Someone will need to find the codes to send to control them.

kbickar avatar Jan 12 '24 16:01 kbickar

How would I do that? Any guides? Or is it just do a MITM and try to capture the commands?

jmwaldrip avatar Jan 12 '24 22:01 jmwaldrip

@ClayBenson94 figured it out for the rest of the commands. I think he did it by decompiling the app.

Here's the initial discussion: https://github.com/kbickar/asyncsleepiq/issues/12

kbickar avatar Jan 12 '24 22:01 kbickar

Ahh okay. What are next steps?

jmwaldrip avatar Jan 12 '24 22:01 jmwaldrip

There are a few codes that might be of interest:
FWPG = "GetFootwarmingPresence" FWTS = "SetFootwarmingSettings" FWTG = "GetFootwarmingSettings"

I need to know the json payload sent and the response from those.

kbickar avatar Jan 12 '24 22:01 kbickar

Here is what I found after doing a MITM.

FWPG was not present in the 60+ calls the app made.

FWTG

Request

{    "sourceApplication": "iOS Consumer Mobile App",    "key": "FWTG",    "args": "right"}

Response

{    "cdcResponse": "PASS:low 120 120"}

FWTS

Request

{    "args": "right low 120",    "sourceApplication": "iOS Consumer Mobile App",    "key": "FWTS"}

Response

{    "cdcResponse": "PASS:"}

jmwaldrip avatar Jan 13 '24 07:01 jmwaldrip

I'm guessing the 360 might behave differently from some others because it not only has foot heating but also core heating and core cooling options, so they might represent the options a bit differently.

I can confirm though, that I don't see the door warming stuff in HA with the newest update -- let me know if I can help gathering responses from the app! It's been a while since I set it up but I can take a swing

ClayBenson94 avatar Jan 13 '24 09:01 ClayBenson94

I did more tracing and did a bit of data mapping.

This includes setting the footwarmer and the climate for the bed.

Let me know what else I can provide. climate_360_requests.csv

jmwaldrip avatar Jan 13 '24 22:01 jmwaldrip

This is very helpful! Are you able to see if the GetSystemConfiguration returns something relating to foot warming? Need to know if it's supported on a bed

kbickar avatar Jan 13 '24 22:01 kbickar

Sure thing.

This call was not made by the app, so I replicated the calls in Postman and changed the code to test the code SYCG for GetSystemConfiguration.

Here are the results

URL: https://prod-api.sleepiq.sleepnumber.com/rest/sn/v1/accounts/<account-id>/beds/<bed-id>/bamkey

Request Body: {"sourceApplication":"iOS Consumer Mobile App","args":"","key":"SYCG"}

Response Body: {"cdcResponse": "PASS:dual yes yes yes yes heat_cool yes yes yes yes yes yes yes yes yes yes"}

jmwaldrip avatar Jan 14 '24 16:01 jmwaldrip

Since I was just grabbing requests from my iphone to test your earlier ask about codes, I decided to test the one I couldnt find earlier.

Note: The arguments requires left or right. If you don't pass the arguments it will fail.

FWPG

URL: https://prod-api.sleepiq.sleepnumber.com/rest/sn/v1/accounts//beds//bamkey

Request Body: {"sourceApplication":"iOS Consumer Mobile App","args":"right","key":"FWPG"}

Response Body: {"cdcResponse": "PASS:1"}

jmwaldrip avatar Jan 14 '24 16:01 jmwaldrip

I update the library on this branch: https://github.com/kbickar/asyncsleepiq/tree/fuzion-foot

Are you able to test if that works to set the foot warmer?

kbickar avatar Jan 14 '24 19:01 kbickar

Happy to try, how should I test? (Meaning, how do I test your branch?)

jmwaldrip avatar Jan 14 '24 19:01 jmwaldrip

Take the example code and add to the end of the main() function:

        print(f"Foot Warmers: {bed.foundation.foot_warmers}")
        await bed.foundation.foot_warmers[0].set_foot_warming(FootWarmingTemps.HIGH, 20)

This should print out the foot warmer info and then set it to high for 20 seconds

kbickar avatar Jan 14 '24 19:01 kbickar

Ignore this, I realized I forgot to import the FootWarmerTemps class. Testing again.

~~Here is the error output~~

Logging in as <my-email>...
Initializing bed data...
Beds:
SleepIQBed(<bed name>, model=CLIMATE360, id=<bed-id>) [SleepIQSleeper[Side.LEFT](<wifes-name>, in_bed=False, sn=70), SleepIQSleeper[Side.RIGHT](<my-name>, in_bed=False, sn=75)] SleepIQFoundation[](lights: 1, features: 23, actuators: 4, presets: 2)
Pause mode: False
New Pause mode: True
Calibrating...
Stopping pump...
Foot Warmers: [SleepIQFootWarmer[Side.LEFT]: Off, 0, OFF, SleepIQFootWarmer[Side.RIGHT]: Off, 0, OFF]
Traceback (most recent call last):
  File "C:\Users\<my-username>\downloads\asyncsleepiq-fuzion-foot\main.py", line 38, in <module>
    asyncio.get_event_loop().run_until_complete(main())
  File "C:\Python311\Lib\asyncio\base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "C:\Users\<my-username>\downloads\asyncsleepiq-fuzion-foot\main.py", line 36, in main
    await bed.foundation.foot_warmers[0].set_foot_warming(FootWarmingTemps.HIGH, 20)
                                                          ^^^^^^^^^^^^^^^^
NameError: name 'FootWarmingTemps' is not defined
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x0000027894D84E50>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x00000278956BDFD0>, 96867.39)]', '[(<aiohttp.client_proto.ResponseHandler object at 0x00000278956BCF30>, 96878.437)]']
connector: <aiohttp.connector.TCPConnector object at 0x0000027894D84E90>``

jmwaldrip avatar Jan 14 '24 21:01 jmwaldrip

Add from asyncsleepiq import AsyncSleepIQ, LOGIN_KEY, FootWarmingTemps at the top

kbickar avatar Jan 14 '24 21:01 kbickar

Thanks! I noticed that and was already testing again.

TLDR: It worked!

There was another bug in the API call that I put a quick fix in to get around to test the full flow.

asyncsleepiq\fuzion\foot_warmer.py

Line: 18

Original Code: args = [SIDES_FULL[self.side].lower(), temperature.name.lower(), time]

My Quick Fix Code: args = [str(SIDES_FULL[self.side].lower()), str(temperature.name.lower()), str(time)]

The string join complained that there was an int when it was expecting a string. So I just did a cast to string on everything to work around it. I haven't written much in python in a while, so I am not sure what the right permanent fix should be.

Here is the output from the error of the string join.

Logging in as <my-username>...
Initializing bed data...
Beds:
SleepIQBed(<bed-name>, model=CLIMATE360, id=<bed-id>) [SleepIQSleeper[Side.LEFT](<wife's name>, in_bed=False, sn=70), SleepIQSleeper[Side.RIGHT](<my-name>, in_bed=False, sn=75)] SleepIQFoundation[](lights: 1, features: 23, actuators: 4, presets: 2)
Pause mode: True
New Pause mode: False
Calibrating...
Stopping pump...
Foot Warmers: [SleepIQFootWarmer[Side.LEFT]: Off, 0, OFF, SleepIQFootWarmer[Side.RIGHT]: Off, 0, OFF]
Traceback (most recent call last):
  File "C:\Users\<username>\downloads\asyncsleepiq-fuzion-foot\main.py", line 38, in <module>
    asyncio.get_event_loop().run_until_complete(main())
  File "C:\Python311\Lib\asyncio\base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "C:\Users\<username>\downloads\asyncsleepiq-fuzion-foot\main.py", line 36, in main
    await bed.foundation.foot_warmers[0].set_foot_warming(FootWarmingTemps.HIGH, 20)
  File "C:\Users\<username>\downloads\asyncsleepiq-fuzion-foot\asyncsleepiq-fuzion-foot\asyncsleepiq\fuzion\foot_warmer.py", line 19, in set_foot_warming
    await self._api.bamkey(self.bed_id, "SetFootwarmingSettings", args)
  File "C:\Users\<username>\downloads\asyncsleepiq-fuzion-foot\asyncsleepiq-fuzion-foot\asyncsleepiq\api.py", line 172, in bamkey
    "args": " ".join(args),
            ^^^^^^^^^^^^^^
TypeError: sequence item 2: expected str instance, int found
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x0000022BECD4D250>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x0000022BECD45B70>, 97166.296)]', '[(<aiohttp.client_proto.ResponseHandler object at 0x0000022BECD451D0>, 97175.593)]']
connector: <aiohttp.connector.TCPConnector object at 0x0000022BECD4CC50>

Log output of working test after fixing the string join. (I confirmed it showed up in the app too)

Logging in as <username>...
Initializing bed data...
Beds:
SleepIQBed(<bedname>, model=CLIMATE360, id=<bed-id>) [SleepIQSleeper[Side.LEFT](<wife's-name>, in_bed=False, sn=70), SleepIQSleeper[Side.RIGHT](<my-name>, in_bed=False, sn=75)] SleepIQFoundation[](lights: 1, features: 23, actuators: 4, presets: 2)
Pause mode: True
New Pause mode: False
Calibrating...
Stopping pump...
Foot Warmers: [SleepIQFootWarmer[Side.LEFT]: Off, 0, OFF, SleepIQFootWarmer[Side.RIGHT]: Off, 0, OFF]
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x0000018A64E1D250>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x0000018A64E15B00>, 97708.562)]', '[(<aiohttp.client_proto.ResponseHandler object at 0x0000018A64E15160>, 97719.187)]']
connector: <aiohttp.connector.TCPConnector object at 0x0000018A64E1CC50>

jmwaldrip avatar Jan 14 '24 21:01 jmwaldrip

This is probably a different issue that is a feature request.

I would be willing to spend some time testing/developing adding support for the climate (bed heating/cooling) functionality of my bed. Would that be something you're open to adding to the library as well?

jmwaldrip avatar Jan 14 '24 21:01 jmwaldrip

Great! I'll make the fix and publish a new release of the library.

For other climate controls that would be a new feature. If you'd like to help we could start a new issue for it: https://github.com/kbickar/asyncsleepiq/issues

kbickar avatar Jan 14 '24 21:01 kbickar