mezz64 / pyEight

Python library to interface with the Eight Sleep API
MIT License
59 stars 15 forks source link

Some API reversing discoveries: #38

Open andrew-kennedy opened 1 year ago

andrew-kennedy commented 1 year ago

I captured a bunch of traffic to the eight sleep api from the iOS app and figured I'd document it here, as there isn't a discussion area for this project.

Setting Temperature:

Temperature setting URL: https://client-api.8slp.net/v1/users/<user_id>/temperature Guest temperature setting URL: https://client-api.8slp.net/v1/users/guest-<device_id>-<left|right>/temperature Method: PUT Request body to set smart schedule or weekly schedules, where heating level is an integer from -100 to 100:

{
  "settings": {
    "scheduleType": "smart",
    "timeBased": {
      "level": 0,
      "durationSeconds": 0
    },
    "smart": {
      "bedTimeLevel": <heating_level>,
      "initialSleepLevel": <heating_level>,
      "finalSleepLevel": <heating_level>
    },
    "schedules": []
  }
}

Request body to set heating/cooling level:

{
  "currentLevel": 91
}

Request body to turn power on or off, possible values are "off" or "smart". Potentially more values are supported as when the smart mode is started and in the bedtime state, the actual value returned for currentState is "smart:bedtime", so you can track which smart "phase" you are in that way.:

{
  "currentState": {
    "type": "<off|smart>"
  }
}

Changing sides/taking over bed

Change sides URL: https://client-api.8slp.net/v1/users/<user_id> Method: PUT Request body to change sides:

{
  "currentDevice": {
    "id": "<device_id>",
    "side": "<right | left | solo>"
  }
}

I don't have a linked partner account, as my partner doesn't like to use the app and just sets and forgets the guest account through my app. The way guests accounts work seems to be as follows:

Both sides of the bed always have a unique user ID, which follow the following template: guest-<device_id>-<left|right>. You can always use the same /temperature api for guests, but they are only enabled or have any effect when you user is set to the other side of the bed. So if you are set to the left side, all left guest settings will persist but have no effect, etc.

When the side is set to solo, neither guest temp setting endpoints have any effect.

Away mode

Away mode api url: https://app-api.8slp.net/v1/users/<user_id>/away-mode Method: PUT Request body to start away mode:

{
  "awayPeriod": {
    "start": "2023-06-14T03:01:00.000Z"
  }
}

Request body to end away mode:

{
  "awayPeriod": {
    "end": "2023-06-14T03:06:00.000Z"
  }
}

From my exploration I learned that the timestamps you send must be valid timestamps or else you get a validation error, but they are immediately ignored, sending any start timestamp seems to immediately start away mode and the returned awayPeriod start time is always just the time the request was received. Same goes for sending the request to end away mode, timestamp must be valid but is ignored and away mode is ended immediately with the end time set to the time the request was received.

lukas-clarke commented 1 year ago

Have you tried this recently? I just tried it and was getting a 401 error when trying to set the temperature.

kylemurray2 commented 1 year ago

I'm also still getting a 401 after changing the api address.

mezz64 commented 1 year ago

It's not that simple unfortunately. The alternate api URL uses OAuth authentication and there is no published way to obtain the proper keys beyond what you can obtain by sniffing app traffic. I'm afraid if they push everything to the new endpoint this library will become EOL.

andrew-kennedy commented 1 year ago

This guy https://www.reddit.com/user/ThrowawayUsernameRE seems to be working on reverse engineering the Constrained Application Protocol that the eight sleep pod uses to communicate with their servers, I'm hoping he can figure out how it works so we can enable pyEight to do direct local communication.