MisterWil / abodepy

A thin Python wrapper for the Abode alarm API
MIT License
49 stars 17 forks source link

Philips Hue White & Color Bulb #28

Closed shred86 closed 5 years ago

shred86 commented 6 years ago

JSON for Philips Hue bulb paired to Abode gateway.

{ "actions": [ { "label": "Switch off", "value": "a=1&z=29&sw=off;" }, { "label": "Switch on", "value": "a=1&z=29&sw=on;" }, { "label": "Toggle", "value": "a=1&z=29&sw=toggle;" }, { "label": "0%", "value": "a=1&z=29&sw=0;" }, { "label": "10%", "value": "a=1&z=29&sw=10;" }, { "label": "20%", "value": "a=1&z=29&sw=20;" }, { "label": "30%", "value": "a=1&z=29&sw=30;" }, { "label": "40%", "value": "a=1&z=29&sw=40;" }, { "label": "50%", "value": "a=1&z=29&sw=50;" }, { "label": "60%", "value": "a=1&z=29&sw=60;" }, { "label": "70%", "value": "a=1&z=29&sw=70;" }, { "label": "80%", "value": "a=1&z=29&sw=80;" }, { "label": "90%", "value": "a=1&z=29&sw=90;" }, { "label": "100%", "value": "a=1&z=29&sw=99;" } ], "area": "1", "bypass": "0", "control_url": "api/v1/control/light/ZB:XXXXXX", "deep_link": null, "default_group_id": "1", "faults": { "low_battery": 0, "no_response": 0, "out_of_order": 0, "supervision": 0, "tempered": 0 }, "generic_type": "light", "group_id": "33092", "group_name": "Lights", "has_subscription": null, "icon": "assets/icons/unknown.svg", "id": "ZB:XXXXXX", "is_window": "", "name": "Bedroom Lamp", "origin": "abode", "schar_24hr": "0", "sort_id": "5", "sort_order": "", "sresp_24hr": "0", "sresp_entry_0": "0", "sresp_entry_1": "0", "sresp_entry_2": "0", "sresp_entry_3": "0", "sresp_entry_4": "0", "sresp_exit_0": "0", "sresp_exit_1": "0", "sresp_exit_2": "0", "sresp_exit_3": "0", "sresp_exit_4": "0", "sresp_mode_0": "0", "sresp_mode_1": "0", "sresp_mode_2": "0", "sresp_mode_3": "0", "sresp_mode_4": "0", "status": "Off", "statusEx": "0", "status_color": "#5cb85c", "status_ex": "", "status_icons": [], "statuses": { "color_mode": "0", "color_temp": 2695, "hue": 228, "level": "50", "saturation": 56, "switch": "0" }, "type": "RGB Dimmer", "type_tag": "device_type.hue", "uuid": "", "version": "LCT014", "zone": "29" }

Also, I noticed when using the developer view in Chrome, this is the payload that is passed when adjusting the brightness from the Abode website:

{action: "setpercent", percentage: 40}

This is different than how generic dimmers seem to work which is through changing the 'level' key value pair. However, changing the 'level' key value pair still works with these Philips bulbs.

It's also executing a POST method to this URL: Request URL: https://my.goabode.com/integrations/v1/devices/deviceidehere

shred86 commented 6 years ago

I'm working on this to get RGB support with HA. I'm able to get HA to successfully read the color settings from Abode, but the issue I'm having is setting the color via HA.

Using the Chrome developer console, it looks like to set the color via the Abode webpage, it's sending:

I created a new function (copied from the set_level function):

def set_color(self, color):
        """Set device color."""
        hue, saturation = color

        if self._json_state['control_url']:
            url = CONST.BASE_URL + 'integrations/v1/devices/' + self._json_state.get('uuid')

            color_data = {
                'action': 'setcolor',
                'hue': int(hue),
                'saturation': int(saturation)
            }

            response = self._abode.send_request(
                "post", url, data=color_data)
            response_object = json.loads(response.text)

            return True

return False

I've made changes to the light/abode.py file in Home Assistant and it's sending the correct data. I've also confirmed the request URL is correct and requested payload is formatted correctly, but when I try to change the color via HA, I get a 401 response (authentication).

When I change the colors from the Abode web app, this is the http request I'm seeing:

Request
:method: POST
:scheme: https
:authority: my.goabode.com
:path: /integrations/v1/devices/[snipped]
Content-Type: application/json
Origin: https://my.goabode.com
Host: my.goabode.com
Accept: application/json, text/plain, */*
Connection: keep-alive
Accept-Language: en-us
Accept-Encoding: br, gzip, deflate
Authorization: Bearer [snipped]
Cookie: [snipped]
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1 Safari/605.1.15
Referer: https://my.goabode.com/
Content-Length: 47
ABODE-API-KEY: [snipped]

Response
:status: 200
ETag: W/"50c-RSeRD7mZOlpP3Im7j5UA3g"
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Date: Mon, 21 May 2018 02:12:00 GMT
Content-Length: 1292

Request Data
MIME Type: application/json
Request Data: {"action":"setcolor","hue":213,"saturation":80}

Edit: Something else I noticed during login is this response is received which appears to match the 'Authorization' in the header above:

{
    "token_type": "Bearer",
    "access_token": [snip],
    "expires_in": 3600
}

Does this perhaps need to be passed in the headers with an http request from abodepy? Everything else works fine except when I try to change the color, but I'm wondering if maybe since it's a 'post' to a different URL, maybe it requires additional authentication since the RGB control is a 3rd party integration for Abode... just a wild guess.

shred86 commented 6 years ago

So I just tried turning on/off the light without sending the 'Authorization' token in the header and it works fine. However, if I try to change the color without the 'Authorization' token, it does not work (401 response), so it appears it's required for changing colors but for turning the light on/off (status) or setting the brightness (level). I guess what I need to figure out now is how I can get that 'access_token' that is sent during login to pass in the headers when 'send_request' is called.

MisterWil commented 6 years ago

https://github.com/MisterWil/abodepy/blob/master/abodepy/__init__.py#L418

Try adding this around that line: headers['Authorization'] = 'Bearer ' + self._token

Seems strange, but it might work?

shred86 commented 6 years ago

Tried that but still getting a 401 response. Something else I tried was using the token from logging in with the web browser and that seemed to work (guessing maybe because the token was still valid since I was still logged in) and with that, I was receiving a 400 response.

The token that is passed which matches the 'Authorization' in the headers is separate from the JSON login response (it's called 'claims'). I'm not sure how to access that claims response data...

Edit: Well, looks like you can just do a get request from https://my.goabode.com//api/auth2/claims after you're logged in. I'm able to successfully change the color of the lights from HA. The last piece is figuring out how to determine if the existing token is expired or not because they're only good for 60 minutes. However, this might not be an issue since I have the token being set to a variable within the login function so if there's no web-api key, it's going to call the login function anyways.

shred86 commented 6 years ago

@MisterWil - I've created two new methods in the AbodeDevice object but as I'm looking at this, it seems like it would make more sense to move set_level (existing method), set_color_temp (new method) and set_color (new method) over to the light.py file instead of the __init__.py in the devices package. Any thoughts or would you like me to move them over with my next commit?

Edit: I've made pretty good progress and everything appears to be working well. One small issue that I don't think I can fix:

{  
   "id":"ZB:[snip]",
   "type_tag":"device_type.hue",
   "type":"RGB Dimmer",
   "name":"Overhead Light",
   "area":"1",
   "zone":"30",
   "sort_order":"",
   "is_window":"",
   "bypass":"0",
   "schar_24hr":"0",
   "sresp_24hr":"0",
   "sresp_mode_0":"0",
   "sresp_entry_0":"0",
   "sresp_exit_0":"0",
   "group_name":"Ungrouped",
   "group_id":"1",
   "default_group_id":"1",
   "sort_id":"10000",
   "sresp_mode_1":"0",
   "sresp_entry_1":"0",
   "sresp_exit_1":"0",
   "sresp_mode_2":"0",
   "sresp_entry_2":"0",
   "sresp_exit_2":"0",
   "sresp_mode_3":"0",
   "uuid":"[snip]",
   "sresp_entry_3":"0",
   "sresp_exit_3":"0",
   "sresp_mode_4":"0",
   "sresp_entry_4":"0",
   "sresp_exit_4":"0",
   "version":"LST002",
   "origin":"abode",
   "has_subscription":null,
   "control_url":"api\/v1\/control\/light\/ZB:[snip]",
   "deep_link":null,
   "status_color":"#5cb85c",
   "faults":{  
      "low_battery":0,
      "tempered":0,
      "supervision":0,
      "out_of_order":0,
      "no_response":0
   },
   "status":"On",
   "statuses":{  
      "saturation":57,
      "hue":60,
      "level":"37",
      "switch":"1",
      "color_temp":6536,
      "color_mode":"2"
   },
   "status_ex":"",
   "actions":[  
      {  
         "label":"Switch off",
         "value":"a=1&z=30&sw=off;"
      },
      {  
         "label":"Switch on",
         "value":"a=1&z=30&sw=on;"
      },
      {  
         "label":"Toggle",
         "value":"a=1&z=30&sw=toggle;"
      },
      {  
         "label":"0%",
         "value":"a=1&z=30&sw=0;"
      },
      {  
         "label":"10%",
         "value":"a=1&z=30&sw=10;"
      },
      {  
         "label":"20%",
         "value":"a=1&z=30&sw=20;"
      },
      {  
         "label":"30%",
         "value":"a=1&z=30&sw=30;"
      },
      {  
         "label":"40%",
         "value":"a=1&z=30&sw=40;"
      },
      {  
         "label":"50%",
         "value":"a=1&z=30&sw=50;"
      },
      {  
         "label":"60%",
         "value":"a=1&z=30&sw=60;"
      },
      {  
         "label":"70%",
         "value":"a=1&z=30&sw=70;"
      },
      {  
         "label":"80%",
         "value":"a=1&z=30&sw=80;"
      },
      {  
         "label":"90%",
         "value":"a=1&z=30&sw=90;"
      },
      {  
         "label":"100%",
         "value":"a=1&z=30&sw=99;"
      }
   ],
   "status_icons":[  

   ],
   "statusEx":"37",
   "icon":"assets\/icons\/bulb-1.svg"
}

I've confirmed this is actually a bug with Abode because if I adjust the color temperature in one app and check it in another, same issue as described above. I think this is based on the fact I'm using Phillips Hue bulbs and this is the color temperate range they operate in, but the Abode app allows for adjustments outside of that to account for LIFX bulbs (I'm assuming they can go cooler/warmer color temps). Either way, kind of poor design on Abode's part I think for not including logic to provide a different UI depending on the bulb type.

shred86 commented 6 years ago

Just made a pull request which adds support for changing colors. I've only tested this with my Phillips Hue bulb and light strip which are paired with my Abode hub. Once the code is reviewed and good to go, could you please push a new Abodepy version so I can submit my Home Assistant changes.

shred86 commented 5 years ago

Added with Abodepy 0.14.0 and my Home Assistant pull request was merged.