Skip to content

Commit

Permalink
Allow subscription to Abode gateway.timeline events
Browse files Browse the repository at this point in the history
Add attribute gatewayTimeline for event subscription to Abode gateway timeline events
Add attribute lastResult for event subscription to Abode portal results
Move the driver into drivers/ directory, to allow both drivers and apps in this repo
Test inconsistent fields in websocket message json to avoid null references
  • Loading branch information
jorhett committed Apr 5, 2020
1 parent 3b30cd3 commit 817ad06
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 31 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)

This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html)

## 2020-04-04 Beta Release 0.7.0

### Added

- New attribute gatewayTimeline allows event subscription to Abode gateway timeline events
- New attribute lastResult allows event subscription to Abode portal interactions

### Changed

- Moved the driver into drivers/ directory, to allow both drivers and apps in this repo

### Fixed

- Inconsistent fields in websocket messages sometimes caused attempts to dereference null fields

## 2020-03-31 Beta Release 0.6.3

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Follow Hubitat's instructions for adding new driver code:
[https://docs.hubitat.com/index.php?title=How_to_Install_Custom_Drivers](https://docs.hubitat.com/index.php?title=How_to_Install_Custom_Drivers)

Import the driver from following URL:
[https://raw.githubusercontent.com/jorhett/hubitat-abode/master/AbodeAlarm.groovy](https://github.com/jorhett/hubitat-abode/blob/master/AbodeAlarm.groovy)
[https://raw.githubusercontent.com/jorhett/hubitat-abode/v0/drivers/AbodeAlarm.groovy](https://github.com/jorhett/hubitat-abode/blob/v0/drivers/AbodeAlarm.groovy)

## Requirements

Expand Down
65 changes: 35 additions & 30 deletions AbodeAlarm.groovy → drivers/AbodeAlarm.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
name: 'Abode Alarm',
namespace: 'jorhett',
author: 'Jo Rhett',
importUrl: 'https://raw.githubusercontent.com/jorhett/hubitat-abode/v0/AbodeAlarm.groovy',
importUrl: 'https://raw.githubusercontent.com/jorhett/hubitat-abode/v0/drivers/AbodeAlarm.groovy',
) {
capability 'Actuator'
capability 'Refresh'
Expand All @@ -24,7 +24,7 @@
command 'logout'
attribute 'isLoggedIn', 'String'
attribute 'gatewayMode', 'String'
attribute 'abodeTimeline', 'String'
attribute 'gatewayTimeline', 'String'
attribute 'lastResult', 'String'
}

Expand Down Expand Up @@ -139,7 +139,7 @@ private baseURL() {
}

private driverUserAgent() {
return 'AbodeAlarm/0.4.0 Hubitat Elevation driver'
return 'AbodeAlarm/0.7.0 Hubitat Elevation driver'
}

private login() {
Expand Down Expand Up @@ -232,11 +232,11 @@ private updateMode(String new_mode) {
state.remove('localModeChange')
} else {
if (targetModeAway && new_mode == 'away') {
log.info 'Changing Hubitat mode to ' + new_mode
log.info 'Changing Hubitat mode to ' + targetModeAway
location.setMode(targetModeAway)
}
else if (targetModeHome) {
log.info 'Changing Hubitat mode to ' + new_mode
log.info 'Changing Hubitat mode to ' + targetModeHome
location.setMode(targetModeHome)
}
}
Expand Down Expand Up @@ -448,6 +448,7 @@ private eventsToIgnore() {
return [
// Internal alarm tracking events used by Abode responders
'alarm.add',
'alarm.ignore',
'alarm.del',
// Nest integration events
'nest.refresh.true',
Expand Down Expand Up @@ -492,25 +493,29 @@ def sendEnabledEvents(
// User choice to log
case ~/.* Contact/: // or event code 5100 open, 5101 closed, 5110 unlocked, 5111 locked
if (saveContacts)
sendEvent(name: 'abodeTimeline', value: alert_value, descriptionText: message, type: alert_type)
sendEvent(name: 'gatewayTimeline', value: alert_value, descriptionText: message, type: alert_type)
break

case ~/CUE Automation/: // or event code 520x
if (saveAutomation)
sendEvent(name: 'abodeTimeline', value: alert_value, descriptionText: message, type: alert_type)
sendEvent(name: 'gatewayTimeline', value: alert_value, descriptionText: message, type: alert_type)
break

default:
sendEvent(name: 'abodeTimeline', value: alert_value, descriptionText: message, type: alert_type)
sendEvent(name: 'gatewayTimeline', value: alert_value, descriptionText: message, type: alert_type)
break
}
}

def parseEvent(String event_text) {
twovalue = event_text =~ /^\["com\.goabode\.([\w+\.]+)",(.*)\]$/
if (twovalue.find()) {
event_type = twovalue[0][1]
event_class = twovalue[0][1]
event_data = twovalue[0][2]

if (eventsToIgnore().contains(event_class))
return

switch(event_data) {
// Quoted text
case ~/^".*"$/:
Expand All @@ -525,58 +530,58 @@ def parseEvent(String event_text) {
// JSON format
case ~/^\{.*\}$/:
details = parseJson(event_data)
message = details.event_name

// These may or may not exist on any given event
user_info = formatEventUser(details)
message = details.event_name ?: details.message ?: ''
device_type = details.device_type ?: ''
event_type = details.event_type ?: ''
alert_value = [
details.device_name,
details.event_type
event_type
].findAll { it.isEmpty() == false }.join(' ')

if (details.event_type == 'Automation') {
if (event_type == 'Automation') {
alert_type = 'CUE Automation'
// Automation puts the rule name in device_name, which is backwards for our purposes
alert_value = details.device_name
}
else if (user_info)
else if (user_info.isEmpty() == false)
alert_type = user_info
else if (device_type != '')
else if (device_type.isEmpty() == false)
alert_type = device_type
else
alert_type = ''
break

default:
log.warn "Event ${event_type} has unknown data format: ${event_data}"
log.warn "Event ${event_class} has unknown data format: ${event_data}"
message = event_data
break
}
switch(event_type) {
case eventsToIgnore:
break

switch(event_class) {
case 'gateway.mode':
updateMode(message)
break

case ~/^gateway\.timeline.*/:
if (logDebug) log.debug "${event_type} -${device_type} ${message}"
if (logDebug) log.debug "${event_class} -${device_type} ${message}"

// Devices we ignore events for
if (! devicesToIgnore().contains(details.device_name)) {
if (syncArming) syncArmingEvents(details.event_type)
if (syncArming) syncArmingEvents(event_type)
sendEnabledEvents(alert_value, message, alert_type)
}
break

// Presence/Geofence updates
case ~/fence.update.*/:
if (saveGeofence)
sendEvent(name: 'abodeTimeline', value: details.location, descriptionText: details.message, type: 'Geofence')
sendEvent(name: 'gatewayTimeline', value: details.location, descriptionText: details.message, type: 'Geofence')
break

default:
if (logDebug) log.debug "Ignoring Event ${event_type} ${message}"
if (logDebug) log.debug "Ignoring Event ${event_class} ${message}"
break
}
} else {
Expand All @@ -590,14 +595,14 @@ def parse(String message) {
if (logTrace) log.trace 'webSocket event raw: ' + message

// First character is the event type
event_type = message.substring(0,1)
packet_type = message.substring(0,1)
// remainder is the data (optional)
event_data = message.substring(1)
packet_data = message.substring(1)

switch(event_type) {
switch(packet_type) {
case '0':
log.debug 'webSocket session open received'
jsondata = parseJson(event_data)
jsondata = parseJson(packet_data)
if (jsondata.containsKey('pingInterval')) state.webSocketPingInterval = jsondata['pingInterval']
if (jsondata.containsKey('pingTimeout')) state.webSocketPingTimeout = jsondata['pingTimeout']
if (jsondata.containsKey('sid')) state.webSocketSid = jsondata['sid']
Expand All @@ -620,8 +625,8 @@ def parse(String message) {

case '4':
// First character of the message indicates purpose
message_type = event_data.substring(0,1)
message_data = event_data.substring(1)
message_type = packet_data.substring(0,1)
message_data = packet_data.substring(1)
switch(message_type) {
case '0':
log.info 'webSocket message = Event socket connected'
Expand Down Expand Up @@ -656,7 +661,7 @@ def parse(String message) {
break

default:
log.warn "Unknown webSocket event (${event_type}) received: " + event_data
log.warn "Unknown webSocket event (${packet_type}) received: " + packet_data
break
}
}
Expand Down
Binary file modified images/events.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 817ad06

Please sign in to comment.