misterwil / abodepy Goto Github PK
View Code? Open in Web Editor NEWA thin Python wrapper for the Abode alarm API
License: MIT License
A thin Python wrapper for the Abode alarm API
License: MIT License
Any chance you've managed to get the api info for system settings?
Specifically i'm trying to work it so that I can easily (via a script) turn off arming sounds in the morning so that I don't wake up anyone else.
I'd love to run a script that
This way I can leave and arm the house with no one else waking up.
Thanks for what you've already done!
{
"id": "RF:008ffeb0",
"type_tag": "device_type.siren",
"type": "Siren",
"name": "Basement Siren",
"area": "1",
"zone": "8",
"sort_order": null,
"is_window": "",
"bypass": "0",
"schar_24hr": "0",
"sresp_mode_0": "5",
"sresp_entry_0": "5",
"sresp_exit_0": "5",
"sresp_mode_1": "5",
"sresp_entry_1": "5",
"sresp_exit_1": "5",
"sresp_mode_2": "5",
"sresp_entry_2": "5",
"sresp_exit_2": "5",
"sresp_mode_3": "5",
"sresp_entry_3": "5",
"sresp_exit_3": "5",
"version": "",
"origin": "abode",
"has_subscription": null,
"control_url": "",
"deep_link": null,
"status_color": "#5cb85c",
"faults": {
"low_battery": 0,
"tempered": 0,
"supervision": 0,
"out_of_order": 0,
"no_response": 0
},
"status": "Online",
"statuses": {
"hvac_mode": ""
},
"status_ex": "",
"actions": [],
"status_icons": [],
"siren_default": "7405",
"siren_default_ext2": "",
"icon": "assets/icons/indoor-siren.svg"
}
Below is an incomplete and possibly duplicated list of devices that are supported by Abode but that are not currently supported by this library because I do not have the device json responses of.
If these devices are to be added to this library then I need the json values of the devices. This can be done by inspecting the network activity on the Abode webapp and pulling the data from the devices request.
abodepy -u USERNAME -p PASSWORD --devices
to get a list of devicesabodepy -u USERNAME -p PASSWORD --json DEVICE_ID
with the device ID of the device you'd like to shareIn case this helps
No motion
[{
"id": "ZB:5f2401",
"type_tag": "device_type.povs",
"type": "Occupancy",
"name": "Garage Occupancy",
"area": "1",
"zone": "10",
"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": "be29d39bfa7ea4e0add232c2d5fe5ebc",
"sresp_entry_3": "0",
"sresp_exit_3": "0",
"sresp_mode_4": "0",
"sresp_entry_4": "0",
"sresp_exit_4": "0",
"version": "POVS_00.00.03.18TC",
"origin": "abode",
"has_subscription": null,
"control_url": "",
"deep_link": null,
"status_color": "#5cb85c",
"faults": {
"low_battery": 0,
"tempered": 0,
"supervision": 0,
"out_of_order": 0,
"no_response": 0
},
"status": "Online",
"statuses": {
"motion": "0"
},
"status_ex": "",
"actions": [],
"status_icons": [],
"sresp_trigger": "0",
"sresp_restore": "0",
"occupancy_timer": "30",
"sensitivity": "4",
"model": "L1",
"icon": "assets\/icons\/occupancy-sensor.svg"
}]
Motion detected
[{
"id": "ZB:5f2401",
"type_tag": "device_type.povs",
"type": "Occupancy",
"name": "Garage Occupancy",
"area": "1",
"zone": "10",
"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": "be29d39bfa7ea4e0add232c2d5fe5ebc",
"sresp_entry_3": "0",
"sresp_exit_3": "0",
"sresp_mode_4": "0",
"sresp_entry_4": "0",
"sresp_exit_4": "0",
"version": "POVS_00.00.03.18TC",
"origin": "abode",
"has_subscription": null,
"control_url": "",
"deep_link": null,
"status_color": "#5cb85c",
"faults": {
"low_battery": 0,
"tempered": 0,
"supervision": 0,
"out_of_order": 0,
"no_response": 0
},
"status": "Motion Detected!",
"statuses": {
"motion": "1"
},
"status_ex": "",
"actions": [],
"status_icons": [],
"sresp_trigger": "0",
"sresp_restore": "0",
"occupancy_timer": "30",
"sensitivity": "4",
"model": "L1",
"icon": "assets\/icons\/occupancy-sensor.svg"
}]
It is a rather large security problem to have user/password be on the command line, since any other user on the same machine can potentially see the login credentials simply with ps
.
The user/password should be able to be specified via a config file of some kind. This also makes using command line functionality easier since the user and password don't have to be specified every time.
abodepy/abodepy/devices/__init__.py
Line 90 in 6f84bb4
@MisterWil - Not really an issue but just noticed the methods set color_temp
and set_color
are still in init.py. If I remember correctly, they were there originally then moved over to the lights.py module. Not sure if these methods are being used for anything but perhaps worth deleting.
Is there any way to hide the following messages from my Home Assistant logs without hiding all warning messages?
2018-02-20 18:56:53 WARNING (SocketIOThread) [abodepy.event_controller] Got device update for unknown device: XXX
They are coming from my Nest devices that are integrated with Abode but I don't want integrated with Home Assistant.
I'm working on adding the MFA config flow for the Abode integration and I noticed something that we should maybe change.
Right now, AbodeEventController
is being instantiated towards the beginning of initializing the Abode
class.
This results in is each time we try to log into Abode by instantiating the Abode class from HA, it creates an instance of AbodeEventController
even if the login fails (i.e. invalid credentials). Each time AbodeEventController
is instantiated, a bunch of callbacks are added:
2020-11-25 18:11:15 DEBUG (SyncWorker_6) [abodepy.socketio] Adding callback for event name: started
2020-11-25 18:11:15 DEBUG (SyncWorker_6) [abodepy.socketio] Adding callback for event name: connected
2020-11-25 18:11:15 DEBUG (SyncWorker_6) [abodepy.socketio] Adding callback for event name: disconnected
2020-11-25 18:11:15 DEBUG (SyncWorker_6) [abodepy.socketio] Adding callback for event name: com.goabode.device.update
2020-11-25 18:11:15 DEBUG (SyncWorker_6) [abodepy.socketio] Adding callback for event name: com.goabode.gateway.mode
2020-11-25 18:11:15 DEBUG (SyncWorker_6) [abodepy.socketio] Adding callback for event name: com.goabode.gateway.timeline
2020-11-25 18:11:15 DEBUG (SyncWorker_6) [abodepy.socketio] Adding callback for event name: com.goabode.automation
I'm not sure if this is really that big of an issue but it seems like this is something that should occur after a valid connection is established or confirmed. An easy solution would be to move this after the self.login()
method here. However, if you were able to create an instance of Abode
and pass in auto_login=False
, then it would self._event_controller
would never be set. That being said, I'm not even sure if that's a valid use case.
Thoughts?
{
"id": "ZB:6b1301",
"type_tag": "device_type.lm",
"type": "LM",
"name": "Freezer",
"area": "1",
"zone": "17",
"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": "Sensors",
"group_id": "<snip>",
"default_group_id": "1",
"sort_id": "1",
"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": "LMHT_00.00.03.06TC",
"origin": "abode",
"has_subscription": null,
"control_url": "",
"deep_link": null,
"status_color": "#5cb85c",
"faults": {
"low_battery": 0,
"tempered": 0,
"supervision": 0,
"out_of_order": 0,
"no_response": 0
},
"status": "-5 \u00b0F",
"statuses": {
"temperature": "-5 \u00b0F",
"temp": "-20.65",
"lux": "0 lx",
"humidity": "0 %"
},
"status_ex": "",
"actions": [
{ "label": "High Temperature Alarm", "value": "a=1&z=17&trigger=TSH;" },
{ "label": "Low Temperature Alarm", "value": "a=1&z=17&trigger=TSL;" },
{ "label": "High Humidity Alarm", "value": "a=1&z=17&trigger=HMH;" },
{ "label": "Low Humidity Alarm", "value": "a=1&z=17&trigger=HML;" }
],
"status_icons": [],
"statusEx": "0",
"icon": "assets/icons/occupancy-sensor.svg"
}
Is it possible to programmatically trigger a panic or silent duress alarm with abodepy? Maybe I'm just missing it somewhere. I saw that timeline.py can identify those events but I'm not seeing where they can be triggered. I'm trying to use a physical button as a panic button without needing a keypad or a key fob.
{
"id": "RF:00416b00",
"type_tag": "device_type.remote_controller",
"type": "Remote Controller",
"name": "Remote",
"area": "1",
"zone": "4",
"sort_order": null,
"is_window": "",
"bypass": "0",
"schar_24hr": "0",
"sresp_mode_0": "0",
"sresp_entry_0": "0",
"sresp_exit_0": "0",
"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",
"sresp_entry_3": "0",
"sresp_exit_3": "0",
"version": "",
"origin": "abode",
"has_subscription": null,
"control_url": "",
"deep_link": null,
"status_color": "#5cb85c",
"faults": {
"low_battery": 0,
"tempered": 0,
"supervision": 0,
"out_of_order": 0,
"no_response": 0
},
"status": "Online",
"statuses": {
"hvac_mode": null
},
"status_ex": "",
"actions": [],
"status_icons": [],
"icon": "assets/icons/key-fob.svg"
}
#70 When the --quiet option is used no output is returned for the options -- device or --device device_id
Expected behavior is to output the JSON or the list of devices only
I've noticed this occurring in the logs anywhere from every 1-3 days which causes for a lot of entries in the Home Assistant logs. My only guess is the session is expiring resulting in the "Not Authorized", but I don't know much about how sockets work (still trying to learn).
2019-09-30 02:55:35 WARNING (SocketIOThread) [lomond] disconnecting websocket
2019-09-30 02:55:35 WARNING (SocketIOThread) [abodepy.socketio] SocketIO Error: "Not Authorized"
2019-09-30 02:55:35 WARNING (SocketIOThread) [abodepy.socketio] Waiting 5.717237 seconds before reconnecting...
Abodepy is working great for me. However, I'm looking for the socketIO URL. I want to ensure that SSL is being used and my username and password are not being passed unencrypted. Thanks.
The past week or so (sorry that I don't have more details on when exactly) I noticed that my Home Assistant was showing Abode as unavailable. I restarted the HA server and Abode came back. It happened again a day or so later, so I went ahead and updated to 113.1. It appears to fix it for a bit, but the same thing has happened again today. I have looked at the logs, but this is all I really found. I'm not sure if there are any other logs with more detail by default, but I'm going to try to increase the logging level to see if i can get some debug info for you.
2020-07-31 18:02:20 WARNING (SocketIOThread) [abodepy.socketio] Captured exception during SocketIO event callback: Expecting value: line 1 column 1 (char 0)
2020-07-31 18:02:20 WARNING (SocketIOThread) [abodepy.socketio] SocketIO Server Ping Timeout
2020-07-31 18:03:26 WARNING (SocketIOThread) [abodepy.socketio] Captured exception during SocketIO event callback: Expecting value: line 1 column 1 (char 0)
2020-07-31 18:04:26 WARNING (SocketIOThread) [abodepy.socketio] Captured exception during SocketIO event callback: Expecting value: line 1 column 1 (char 0)
2020-07-31 18:04:26 WARNING (SocketIOThread) [abodepy.socketio] SocketIO Server Ping Timeout
2020-07-31 18:05:26 WARNING (SocketIOThread) [abodepy.socketio] Captured exception during SocketIO event callback: Expecting value: line 1 column 1 (char 0)
2020-07-31 18:05:26 WARNING (SocketIOThread) [abodepy.socketio] SocketIO Server Ping Timeout
2020-07-31 18:05:32 WARNING (SocketIOThread) [abodepy.socketio] Captured exception during SocketIO event callback: Expecting value: line 1 column 1 (char 0)
Add the ability to download and trigger photos for motion cameras.
Thanks for your support of Home Assistant!
Trying to use the --listen
argument to listen to Abode events, but it gives unexpected status code
error. Here are the complete logs.
arsaboo@aloknuc:~$ python3 /home/arsaboo/abodepy/abodecl.py --username USERNAME --password PASSWORD --listen
No devices specified, adding all devices to listener...
Listening for device updates...
DEBUG:urllib3.connectionpool:https://my.goabode.com:443 "GET /api/v1/panel HTTP/1.1" 200 739
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): my.goabode.com
DEBUG:urllib3.connectionpool:https://my.goabode.com:443 "GET /socket.io/?EIO=3&t=1503009522268-0&transport=polling HTTP/1.1" 403 None
WARNING:socketIO-client:my.goabode.com:443/socket.io [engine.io waiting for connection] unexpected status code (403 {"code":4,"message":"origin not allowed"})
DEBUG:urllib3.connectionpool:https://my.goabode.com:443 "GET /socket.io/?EIO=3&t=1503009523619-0&transport=polling HTTP/1.1" 403 None
DEBUG:urllib3.connectionpool:https://my.goabode.com:443 "GET /socket.io/?EIO=3&t=1503009524704-0&transport=polling HTTP/1.1" 403 None
DEBUG:urllib3.connectionpool:https://my.goabode.com:443 "GET /socket.io/?EIO=3&t=1503009525792-0&transport=polling HTTP/1.1" 403 None
DEBUG:urllib3.connectionpool:https://my.goabode.com:443 "GET /socket.io/?EIO=3&t=1503009526878-0&transport=polling HTTP/1.1" 403 None
Not sure what am I missing here. Also, marking @amelchio so that he can be updated on the progress.
If you try to use abodepy with Python 3.7, it breaks the lomond web listener. Here's the error in Home Assistant:
Traceback (most recent call last):
File "/Users/shred/venv/homeassistant/lib/python3.7/site-packages/lomond/session.py", line 414, in run
for event in self.websocket.feed(data):
File "/Users/shred/venv/homeassistant/lib/python3.7/site-packages/lomond/websocket.py", line 263, in feed
for message in self.stream.feed(data):
RuntimeError: generator raised StopIteration
2018-09-09 10:02:06 INFO (SocketIOThread) [abodepy.socketio] Websocket Disconnected
^C2018-09-09 10:02:07 INFO (MainThread) [homeassistant.core] Bus:Handling <Event homeassistant_stop[L]>
2018-09-09 10:02:07 INFO (SyncWorker_6) [abodepy.socketio] Stopping SocketIO thread...
2018-09-09 10:02:07 DEBUG (SyncWorker_6) [abodepy] Logout Response: {"code":200,"message":"Logout successful."}
2018-09-09 10:02:07 INFO (SyncWorker_6) [abodepy] Logout successful
2018-09-09 10:02:07 INFO (SyncWorker_6) [homeassistant.components.abode] Logged out of Abode
2018-09-09 10:02:07 INFO (MainThread) [homeassistant.core] Bus:Handling <Event homeassistant_close[L]>
Works fine with Python 3.6.5.
The camera.py module's capture method no longer works. When trying to call the capture
method, I get:
2019-11-04 18:27:11 WARNING (SyncWorker_8) [abodepy.devices.camera] Failed to capture image: Request failed
I believe PR #47 is what caused it to stop working. When I view the request using developers tool while logged into the Abode web app, I see the following when requesting an image with the Iota camera:
:method: PUT
:scheme: https
:authority: my.goabode.com
:path: /api/v1/cams/XF:b0c5caxxxxxx/capture
Which is what CAMS_ID_CAPTURE_URL
use to be. However, with PR #47, it changed capture
to snapshot
.
@milad-soufastai Where did you see the path change to capture
? I'm wondering if maybe the put request path is different depending on the type of camera you have.
This was brought up in an issue over on the Home Assistant repo: home-assistant/core#29895
There was a previous issue where requesting a camera snapshot for Iota (and possibly the "newer" circular Abode streaming cameras) was broken. The solution was changing the last word for CAMS_ID_CAPTURE_URL
in constants.py from snapshot
to capture
. It appears the older streaming camera still uses snapshot
thus breaking this functionality when using the older streaming camera.
I only have the Iota streaming camera but I'll need someone to provide the JSON data for the older (square) 720p streaming camera and newer (round) 1080p streaming camera. We need a way to check the type of camera when the capture
method is being called in cameras.py.
Edit: I think I have a simple and more robust fix for this in cameras.py
. Currently, the url
variable in the capture
method is being defined by:
url = str.replace(CONST.CAMS_ID_CAPTURE_URL, '$DEVID$', self.device_id)
Instead, we can change this to:
url = CONST.BASE_URL + self._json_state["control_url_snapshot"]
The JSON data for the Iota camera has a key called control_url_snapshot
which specifics the URL for the snapshot feature which we can use. Two obvious benefits:
This will pull the correct "control url" for whichever camera is being used. This assumes all Abode cameras have the key control_url_snapshot
in their JSON data. I need someone to confirm this for the older 720p camera and newer 1080p camera (standalone cameras).
If Abode ever updates the control URL, it won't break this capture
method.
Add the ability to list automation's and activate/deactivate them.
The Wide Angle Motion Camera is only registered as camera
for snapshots, but it is also a motion detector but it's not register as binary_sensor
. Ideally both entities should be available for different uses.
Thanks.
There is no class created in the devices folder or CONST values for smoke detectors. I got something hacked together last night that got at minimum will recognize the device to test it but doesn’t create the any of the methods or attributes for the class. If it’s ok with you I’ll put together a more proper solution and submit it to you so we can get those devices working in apps like home assistant.
Occasionally, but not always, on connection to the Abode SocketIO server a packet is received:
b'2:401:3'
This packet results in a stack trace from the socketIO_client:
ValueError: invalid literal for int() with base 10: '2:401'
This is due to a minor logic bug in socketIO_client/parsers.py where in _read_packet_length() the logic needs to be that packet_length_string starts at the start index and not 0:
def _read_packet_length(content, content_index):
indx = content_index
while content.decode()[content_index] != ':':
content_index += 1
packet_length_string = content.decode()[indx:content_index]
return content_index, int(packet_length_string)
However, when the bug is fixed the socketIO_client seems to get stuck in some sort of reconnect loop. Further debugging is required.
Thanks for your excellent work. I installed abodeby using
pip3 install abodepy
on my Ubunto box, but python abodecl.py --username USERNAME --password PASSWORD --mode
gives me the error: python: can't open file 'abodecl.py': [Errno 2] No such file or directory
.
Manually searching the file find / abodecl.py
also returns find: ‘abodecl.py’: No such file or directory
.
Any thoughts?
Add an argument to output the device._json_state to simplify the process of obtaining device json data for future development. Write a section in the readme to describe how to use this functionality to add an issue to request the addition of the device.
Line 96 in 86ee391
This is what I'm currently running to fix the login validation issue with Abode:
import uuid
abode_uuid = str(uuid.uuid1()).replace('-', '')
login_data = {
'id': self._username,
'password': self._password,
'uuid': abode_uuid
}
I’ve noticed this for a while but figured I’d post this here for reference. Every now and then I’ll see these errors in my Home Assistant logs that’s pointing to abodepy. This must be coming from my Abode multi-sensor but it doesn’t appear to have any issues in Home Assistant.
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 284, in async_update_ha_state
self._async_write_ha_state()
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 330, in _async_write_ha_state
unit_of_measurement = self.unit_of_measurement
File "/usr/src/homeassistant/homeassistant/components/abode/sensor.py", line 83, in unit_of_measurement
return self._device.humidity_unit
File "/usr/local/lib/python3.7/site-packages/abodepy/devices/sensor.py", line 46, in humidity_unit
if CONST.UNIT_PERCENT in self._get_status(CONST.HUMI_STATUS_KEY):
TypeError: argument of type 'NoneType' is not iterable
Error doing job: Task exception was never retrieved
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 284, in async_update_ha_state
self._async_write_ha_state()
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 330, in _async_write_ha_state
unit_of_measurement = self.unit_of_measurement
File "/usr/src/homeassistant/homeassistant/components/abode/sensor.py", line 85, in unit_of_measurement
return self._device.lux_unit
File "/usr/local/lib/python3.7/site-packages/abodepy/devices/sensor.py", line 58, in lux_unit
if CONST.UNIT_LUX in self._get_status(CONST.LUX_STATUS_KEY):
TypeError: argument of type 'NoneType' is not iterable
When trying to install a local editable version (checked out directly from github):
pip install -e abodepy/
It fails with the following error:
Obtaining file:///[obscured]/abodepy
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "[obscured]/abodepy/setup.py", line 4, in <module>
from abodepy.helpers.constants import (__version__, PROJECT_PACKAGE_NAME,
File "abodepy/__init__.py", line 29, in <module>
from abodepy.automation import AbodeAutomation
File "abodepy/automation.py", line 6, in <module>
import abodepy.helpers.constants as CONST
File "abodepy/helpers/constants.py", line 202
SyntaxError: Non-ASCII character '\xc2' in file abodepy/helpers/constants.py on line 202, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in [obscured]/abodepy/
Add the ability to list the available quick actions and trigger them.
A big problem with the Event Listener is that the socketio client libraries for Python all basically suck. I did, however, find a Websocket library that doesn't suck... so I've written a very light weight EngineIO/SocketIO client that sits on top of this Websocket library. Below are the notes I've compiled for this EngineIO/SocketIO code:
The SocketIO protocol is in fact two protocols. The "transport" is EngineIO and the messaging protocol is SocketIO.
EngineIO Protocol
<packet type id>[<data>]
Ex: 0{"sid":"kOeJt3LgKj2im3UVAFiO","upgrades":[],"pingInterval":25000,"pingTimeout":60000}
Ex: 2probe
Ex: 3probe
Ex: 2
Ex: 3
Ex: 40
Ex: 42["com.goabode.device.update","ZW:00000005"]
Packet Types:
0 open
Sent from the server when a new transport is opened with JSON-encoded handshake data:
sid session ID
upgrades possible transport upgrades
pingTimeout server configured ping timeout - Time to wait for pong response from server before disconnecting
pingInterval server configured ping interval - Time between client sends ping packets
1 close
Request to close the polling interface since polling will open and close sockets regularly. Not required for websockets but will still react to just in case.
2 ping
Sent by the client to the server. Should be sent every pingInterval.
3 pong
Sent by the server to the client to respond to a ping. Should be received within pingTimeout after the last ping.
4 message
Messages to or from the server. We only care about recieving data.
5 upgrade
Upgrade test from one transport to another. Since we're only using websockets we can ignore this.
6 noop
A "no op" packet. Ignored.
Ping Timeouts
The client must send a ping packet every pingInteveral. The client will consider the server unresponsive after not recieving a
reply from the server for pingTimeout. Since the two values are shared between the server and the client, the server
will also be able to detect whether the client becomes unresponsive when it does not receive any data within pingTimeout + pingInterval
SocketIO Protocol
The data portion of an EngineIO packet type 4 will utilize the SocketIO protocol.
Ex: 40
Ex: 42["com.goabode.device.update","ZW:00000005"]
Ex: 42["com.goabode.gateway.timeline",{"mac":"B0:C5:CA:30:0A:C8","id":213014558,"date":"04/03/2018","time":"01:15 PM","event_utc":1522786544,"event_cid":"","event_code":"5125","device_id":"ZW:00000005","device_type_id":"66","device_type":"Dimmer","nest_has_motion":"","nest_has_sound":"","nest_has_person":"","device_name":"Kitchen Lights","file_path":"","deep_link":"","file_name":"","file_size":"","file_count":"","file_is_del":0,"event_type":"On","severity":"8","pos":"l","color":"
000000","is_alarm":"0","icon":"assets/email/lightbulb-on.png","user_id":"","user_name":"","mobile_name":"","parent_tid":"","app_type":"","viewed_by_uid":"","verified_by_tid":"","event_name":"Kitchen Lights On","event_by":""}]
In the above examples the first '4' is the EngineIO message type and everything after it is the SocketIO message type.
The SocketIO message itself if some sort of format like: [data] (ex: 42/chat,[“join”,”{room:1}”])
where optional namespace is "/chat", defaulting to /, and ID is used for the ack. The data portion is essentially a json array where the first index is a string for the event name
and the second index onward can be a string or json object.
We will dumb this down: When we receive an event we will parse out only the [data] portion and parse it as json into a dict, pull out the event_name, and then pass that along with
the event data through to an on_event method.
Message Types:
0 connect Confirms SocketIO Message Connection
1 disconnect Transmitted before SocketIO Disconnect? Not sure where this is used but will similarly react.
2 event Event message - What We've Done This For
3 ack Acknowledge an event - Ignored
4 error Error message (for example, authentication failure).
5 binary event Binary data event - Ignored for our purposes currently
6 binary ack Acknowledge a binary event - Ignored
https://github.com/wildfoundry/dataplicity-lomond/
https://www.willmcgugan.com/blog/tech/post/announcing-lomond/
http://lomond.readthedocs.io/en/latest/
https://github.com/socketio/engine.io-protocol
https://github.com/socketio/socket.io-protocol
Seems that there exists an edge case where if the cache exists but is corrupted in some way (failure to write due to disk full or incorrect permissions), logins will fail to work.
Possible solutions are perhaps to verify the integrity of the data.
If the username and password are given then confirm that these values match the cached values?
See this stack overflow for how to append a checksum to the end of a pickle file to verify integrity: https://stackoverflow.com/questions/1653897/if-pickling-was-interrupted-will-unpickling-necessarily-always-fail-python
Looks like the Occupancy Sensor and the Temperature,Humidity, and Light sensor are considered the same so I see an error in my HA logs on every restart since the Occupancy Sensor doesn't provide Humidity information.
Error doing job: Task exception was never retrieved Traceback (most recent call last): File "/usr/src/app/homeassistant/helpers/entity_platform.py", line 352, in _async_add_entity await entity.async_update_ha_state() File "/usr/src/app/homeassistant/helpers/entity.py", line 244, in async_update_ha_state unit_of_measurement = self.unit_of_measurement File "/usr/src/app/homeassistant/components/abode/sensor.py", line 76, in unit_of_measurement return self._device.humidity_unit File "/usr/local/lib/python3.7/site-packages/abodepy/devices/sensor.py", line 44, in humidity_unit if CONST.UNIT_PERCENT in self._get_status(CONST.HUMI_STATUS_KEY): TypeError: argument of type 'NoneType' is not iterable
Are the new CUE Automations built in such a way that it would be possible to list and activate/deactivate them similar to how legacy automations work? Or are they not accessible via API?
I noticed a few days ago that the alarm panel state in abodepy no longer syncs with the actual gateway state. I added some logging in socketio.py and discovered that it's not getting any gateway mode events. It still gets device update events interestingly, just not mode change events. Not sure if this is just me or are other people seeing this as well.
Abode now supports 2FA. This ties in to issue #30 which requires a UUID for login requests now. I assume this UUID is to allow Abode to keep track of which 'devices' have logged in previously and used 2FA to complete the process.
I'll need to enable 2FA on my account and then I'll note the new packets that are used to complete this login process. I'll also need to save this UUID somewhere - probably the new config file option as per #20.
I was testing some home assistant automations today and noticed that the abode_alarm_end event was not fired when I deactivated the alarm. It looks like abodepy groups the alarm end event by code 3100 to 3199. I checked my abode timeline and the "Alarm Disabled" event fired after I deactivated the alarm has code 4001. I think Abode might have changed the code of this event.
Not sure if opening an Issue was the correct way to ask this question, but I didn't see a better way to ask the question. I'm assuming that using the --listen flag is what I would want to use to tie in my Home Automation system (Homeseer) to immediately react to changes in Abode state. I'm interested to know if there are any concerns, perhaps around load on the Abode servers, or other potential issues, with using this for the long haul? If I were to script something to open a listening connection to Abode, it would be 24/7/365 (and reconnect anytime a disconnect happens). Has anyone been doing this or should I avoid it?
If I should avoid it, then I'll need to see if I can find some way to have Abode trigger an external event when states change.
thanks!
Paul
{
"id": "RF:001d2730",
"type_tag": "device_type.pir",
"type": "IR",
"name": "Foyer Motion",
"area": "1",
"zone": "13",
"sort_order": null,
"is_window": "",
"bypass": "0",
"schar_24hr": "0",
"sresp_mode_0": "0",
"sresp_entry_0": "0",
"sresp_exit_0": "0",
"sresp_mode_1": "5",
"sresp_entry_1": "4",
"sresp_exit_1": "0",
"sresp_mode_2": "0",
"sresp_entry_2": "4",
"sresp_exit_2": "0",
"sresp_mode_3": "0",
"sresp_entry_3": "0",
"sresp_exit_3": "0",
"version": "",
"origin": "abode",
"has_subscription": null,
"control_url": "",
"deep_link": null,
"status_color": "#5cb85c",
"faults": {
"low_battery": 0,
"tempered": 0,
"supervision": 0,
"out_of_order": 0,
"no_response": 0
},
"status": "Online",
"statuses": {
"hvac_mode": null
},
"status_ex": "",
"actions": [],
"status_icons": [],
"model": "L1",
"icon": "assets/icons/motioncamera-a.svg"
}
This is the JSON for a Z-Wave dimmer (GE Z-Wave Plus In-Wall Smart Dimmer) connected through Abode.
I am able to control the on/off state through HASS currently (the dimmer shows up as a light), but not the dimmer percentage.
{
"id": "ZW:0000000b",
"type_tag": "device_type.dimmer",
"type": "Dimmer",
"name": "West Deck Light",
"area": "1",
"zone": "10",
"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": "Lights",
"group_id": "<snip>",
"default_group_id": "1",
"sort_id": "1",
"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": "",
"origin": "abode",
"has_subscription": null,
"control_url": "api/v1/control/light/ZW:0000000b",
"deep_link": null,
"status_color": "#5cb85c",
"faults": {
"low_battery": 0,
"tempered": 0,
"supervision": 0,
"out_of_order": 0,
"no_response": 0
},
"status": "Off",
"statuses": {
"saturation": "N/A",
"hue": "N/A",
"level": "0",
"switch": "0",
"color_temp": "N/A",
"color_mode": "N/A"
},
"status_ex": "",
"actions": [
{ "label": "Switch off", "value": "a=1&z=10&sw=off;" },
{ "label": "Switch on", "value": "a=1&z=10&sw=on;" },
{ "label": "Toggle", "value": "a=1&z=10&sw=toggle;" },
{ "label": "0%", "value": "a=1&z=10&sw=0;" },
{ "label": "10%", "value": "a=1&z=10&sw=10;" },
{ "label": "20%", "value": "a=1&z=10&sw=20;" },
{ "label": "30%", "value": "a=1&z=10&sw=30;" },
{ "label": "40%", "value": "a=1&z=10&sw=40;" },
{ "label": "50%", "value": "a=1&z=10&sw=50;" },
{ "label": "60%", "value": "a=1&z=10&sw=60;" },
{ "label": "70%", "value": "a=1&z=10&sw=70;" },
{ "label": "80%", "value": "a=1&z=10&sw=80;" },
{ "label": "90%", "value": "a=1&z=10&sw=90;" },
{ "label": "100%", "value": "a=1&z=10&sw=99;" }
],
"status_icons": [],
"statusEx": "0",
"icon": "assets/icons/bulb-1.svg"
}
Capture when an alarm is triggered and report it through the event interface.
I was curious why I was not getting an abode_panel_fault
event triggered in Home Assistant when arming the system with a fault. I set the integration to show debug logs, and I think what I'm seeing is that the fault codes are no longer in the 13xx range, at least for my configuration (I have no delay timer on setting "Home" but I have a 30-second delay on setting "Away"), but rather in the 60xx range. The relevant portions of the debug log are below.
2020-06-26 10:28:11 DEBUG (SyncWorker_28) [abodepy.devices.alarm] Set Alarm Home Response: {"area":"1","mode":"home"}
2020-06-26 10:28:11 INFO (SyncWorker_28) [abodepy.devices.alarm] Set alarm area_1 mode to: home
2020-06-26 10:28:12 DEBUG (SocketIOThread) [abodepy.event_controller] Timeline event received: Gateway Armed w/ Faults(s) - Home - Armed w/ Faults(s) - Home (6077)
2020-06-26 10:28:12 DEBUG (SocketIOThread) [abodepy.event_controller] Alarm mode change event to: home
2020-06-26 10:28:48 DEBUG (SyncWorker_7) [abodepy.devices.alarm] Set Alarm Home Response: {"area":"1","mode":"away"}
2020-06-26 10:28:48 INFO (SyncWorker_7) [abodepy.devices.alarm] Set alarm area_1 mode to: away
2020-06-26 10:28:49 DEBUG (SocketIOThread) [abodepy.event_controller] Timeline event received: Gateway Arming w/ Fault(s) - Away (Exit Timer Started) - Arming w/ Fault(s) - Away (Exit Timer Started) (6055)
2020-06-26 10:29:20 DEBUG (SocketIOThread) [abodepy.event_controller] Timeline event received: Gateway Armed w/ Faults(s) - Away - Armed w/ Faults(s) - Away (6071)
2020-06-26 10:29:20 DEBUG (SocketIOThread) [abodepy.event_controller] Alarm mode change event to: away
Is anyone still seeing fault codes in the 13xx range, or is there something unique to my configuration? Abode did just recently (the last month or so?) release a new version of their app and web interface, so perhaps a minor update to the API/events was made.
Let me know if I can provide any other helpful debug information.
I have a fresh install from today install using:
pip3 install abodepy
seems to be a success:
Installing collected packages: colorlog, six, lomond, certifi, urllib3, idna, chardet, requests, abodepy
Successfully installed abodepy-1.2.0 certifi-2020.12.5 chardet-3.0.4 colorlog-4.6.2 idna-2.10 lomond-0.3.3 requests-2.25.0 six-1.15.0 urllib3-1.26.2
But from command line I get
$ abodepy --help
abodepy: command not found
Is there some additional step needed between pip3 install and running it from command line?
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
AttributeError: 'NoneType' object has no attribute 'lower'
AttributeError: 'AbodeDevice' object has no attribute 'is_on'
I think these may be related to Nest items integrating with abode.
{
"id": "RF:0059b180",
"type_tag": "device_type.glass",
"type": "GLASS",
"name": "Back door",
"area": "1",
"zone": "2",
"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": "5",
"sresp_entry_1": "5",
"sresp_exit_1": "0",
"sresp_mode_2": "5",
"sresp_entry_2": "5",
"sresp_exit_2": "0",
"sresp_mode_3": "5",
"uuid": "xxxx",
"sresp_entry_3": "5",
"sresp_exit_3": "0",
"sresp_mode_4": "5",
"sresp_entry_4": "5",
"sresp_exit_4": "0",
"version": "",
"origin": "abode",
"has_subscription": null,
"control_url": "",
"deep_link": null,
"status_color": "#5cb85c",
"faults": {
"low_battery": 0,
"tempered": 0,
"supervision": 0,
"out_of_order": 0,
"no_response": 0
},
"status": "Online",
"statuses": [],
"status_ex": "",
"actions": [],
"status_icons": [],
"icon": "assets/icons/acoustic-sensor.svg"
}
Is there any way to set the alarm state to "triggered" when the alarm is activated? I noticed it's being reported in the Home Assistant debug message:
2019-05-25 17:19:25 DEBUG (SocketIOThread) [abodepy.event_controller] Timeline event received: Front Door Interior Alarm Activated - Interior Alarm Activated (1132)
Here is the json data when the alarm is triggered:
[{
"id": "743443290",
"event_utc": "1558831901",
"date": "05\/25\/2019",
"time": "05:51 PM",
"event_cid": "",
"viewed_by_uid": "0",
"verified_by_tid": "743443663",
"event_code": "1132",
"event_type": "Interior Alarm Activated",
"color": "#cc3f44",
"user_id": "",
"user_name": "",
"mobile_name": "",
"parent_tid": "",
"app_type": "",
"device_id": "SR:PIR",
"device_type_id": "9",
"icon": "assets\/email\/alarm-activated.png",
"device_name": "Living Room Motion",
"event_name": "Living Room Motion Interior Alarm Activated"
}, {
"id": "743443285",
"event_utc": "1558831900",
"date": "05\/25\/2019",
"time": "05:51 PM",
"event_cid": "",
"viewed_by_uid": "0",
"verified_by_tid": "743443663",
"event_code": "1132",
"event_type": "Interior Alarm Activated",
"color": "#cc3f44",
"user_id": "",
"user_name": "",
"mobile_name": "",
"parent_tid": "",
"app_type": "",
"device_id": "RF:XXXXXX",
"device_type_id": "4",
"icon": "assets\/email\/alarm-activated.png",
"device_name": "Front Door",
"event_name": "Front Door Interior Alarm Activated"
}]
Unsure if it is desired to pull these devices or not - Home Assistant already offers components for them so it seems silly to duplicate that work. Perhaps if someone wants to use the command line they might want this functionality? I've attached the json for these devices for future reference.
Add support of and tests for the attached power switch meter device.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.