Skip to content
Snippets Groups Projects
Commit 3d88d32c authored by Erick Hitter's avatar Erick Hitter
Browse files

Merge branch 'develop' into 'master'

Add support for "double-click" and "hold" click types

Closes #1

See merge request !2
parents b7bc4b1f 54fd6ba1
No related branches found
No related tags found
No related merge requests found
...@@ -30,11 +30,11 @@ If `flicd` and this script are not run from the same device, ensure that `flicd` ...@@ -30,11 +30,11 @@ If `flicd` and this script are not run from the same device, ensure that `flicd`
**Can I run `flicd` as a daemon/at startup?** **Can I run `flicd` as a daemon/at startup?**
Yes. See https://ethtiter.com/ for a `systemd` service file. Yes. See https://ethitter.com/p/9738/ for a `systemd` service file.
**How is the `buttons` property of `config.json` structured?** **How is the `buttons` property of `config.json` structured?**
Each object within the `buttons` property is structured according to how the button should respond to the entity's current state. For example, if the light is off, what should a button press do. Each object within the `buttons` property is structured according what effect the click should have on an entity in its current state. For example, if the light is off, what should a single-click do.
"mac": { "mac": {
"mac": "mac", "mac": "mac",
...@@ -42,15 +42,17 @@ Each object within the `buttons` property is structured according to how the but ...@@ -42,15 +42,17 @@ Each object within the `buttons` property is structured according to how the but
"status": { "status": {
"entity_id": "switch.lamp" "entity_id": "switch.lamp"
}, },
"off": { "single": {
"entity": "switch", "on": {
"entity_id": "switch.lamp", "entity": "switch",
"entity_action": "turn_on" "entity_id": "switch.lamp",
}, "entity_action": "turn_off"
"on": { },
"entity": "switch", "off": {
"entity_id": "switch.lamp", "entity": "switch",
"entity_action": "turn_off" "entity_id": "switch.lamp",
"entity_action": "turn_on"
}
} }
} }
...@@ -62,21 +64,71 @@ The above example simply switches a light on and off, depending on its current s ...@@ -62,21 +64,71 @@ The above example simply switches a light on and off, depending on its current s
"status": { "status": {
"entity_id": "alarm_control_panel.shm" "entity_id": "alarm_control_panel.shm"
}, },
"disarmed": { "single": {
"entity": "alarm_control_panel", "disarmed": {
"entity_id": "alarm_control_panel.shm", "entity": "alarm_control_panel",
"entity_action": "alarm_arm_home" "entity_id": "alarm_control_panel.shm",
"entity_action": "alarm_arm_home"
},
"armed_home": {
"entity": "alarm_control_panel",
"entity_id": "alarm_control_panel.shm",
"entity_action": "alarm_disarm"
},
"armed_away": {
"entity": "switch",
"entity_id": "switch.lamp",
"entity_action": "turn_on"
}
}
}
In this example, if the alarm isn't active, or is set to the "armed home" state, its Flic button will toggle between those states. If, however, one tried to use the button to disable the alarm when no one is home (motion sensors are active, among other changes), the button will simply turn on a light; it won't disarm the alarm, as that's something I only allow for those who have access to Home Assistant or SmartThings directly.
As three click types--`single`, `double`, and `hold`--are supported, adding responses to the new click types is a matter of updating `config.json` to define how those clicks are handled.
"mac": {
"mac": "mac",
"label": "Lamp",
"status": {
"entity_id": "switch.lamp"
},
"single": {
"on": {
"entity": "switch",
"entity_id": "switch.lamp",
"entity_action": "turn_off"
},
"off": {
"entity": "switch",
"entity_id": "switch.lamp",
"entity_action": "turn_on"
}
}, },
"armed_home": { "double": {
"entity": "alarm_control_panel", "on": {
"entity_id": "alarm_control_panel.shm", "entity": "switch",
"entity_action": "alarm_disarm" "entity_id": "switch.lamp",
"entity_action": "turn_off"
},
"off": {
"entity": "switch",
"entity_id": "switch.lamp",
"entity_action": "turn_on"
}
}, },
"armed_away": { "hold": {
"entity": "switch", "on": {
"entity_id": "switch.lamp", "entity": "switch",
"entity_action": "turn_on" "entity_id": "switch.lamp",
"entity_action": "turn_off"
},
"off": {
"entity": "switch",
"entity_id": "switch.lamp",
"entity_action": "turn_on"
}
} }
} }
In this example, if the alarm isn't active, or is set to the "armed home" state, its Flic button will toggle between those states. If, however, one tried to use the button to disable the alarm when no one is home (motion sensors are active, among other changes), the button will simply turn on a light; it won't disarm the alarm, as that's something I only allow for those who have access to Home Assistant or SmartThings directly. This isn't a particularly interesting example, as all three click types perform the same action, but it demonstrates what's possible.
...@@ -12,17 +12,43 @@ ...@@ -12,17 +12,43 @@
"status": { "status": {
"entity_id": "" "entity_id": ""
}, },
"on": { "single": {
"entity": "", "on": {
"entity_id": "", "entity": "",
"entity_action": "" "entity_id": "",
"entity_action": ""
},
"off": {
"entity": "",
"entity_id": "",
"entity_action": ""
}
}, },
"off": { "double": {
"entity": "", "on": {
"entity_id": "", "entity": "",
"entity_action": "" "entity_id": "",
"entity_action": ""
},
"off": {
"entity": "",
"entity_id": "",
"entity_action": ""
}
},
"hold": {
"on": {
"entity": "",
"entity_id": "",
"entity_action": ""
},
"off": {
"entity": "",
"entity_id": "",
"entity_action": ""
}
} }
} }
}, },
"config_version": 2 "config_version": 3
} }
...@@ -13,8 +13,8 @@ var request = require( 'request' ); ...@@ -13,8 +13,8 @@ var request = require( 'request' );
*/ */
var config = require( './config.json' ); var config = require( './config.json' );
if ( 'undefined' === typeof config.config_version || config.config_version < 2 ) { if ( 'undefined' === typeof config.config_version || config.config_version < 3 ) {
console.error( 'Configuration is for v0.1.0 and must be updated to work with this release. Exiting!' ); console.error( 'Configuration is for a release prior to v0.2.5 and must be updated to work with this release. Exiting!' );
process.exit(); process.exit();
} }
...@@ -40,24 +40,53 @@ client.on( 'newVerifiedButton', function( bdAddr ) { ...@@ -40,24 +40,53 @@ client.on( 'newVerifiedButton', function( bdAddr ) {
* BUTTON REACTIONS * BUTTON REACTIONS
*/ */
function listenToButton( bdAddr ) { function listenToButton( bdAddr ) {
// Not much to do if the button isn't configured
if ( "object" !== typeof config.buttons[bdAddr] ) { if ( "object" !== typeof config.buttons[bdAddr] ) {
console.error( 'No configuration for button ' + bdAddr ); console.error( 'No configuration for button ' + bdAddr );
return; return;
} }
// Establish button connection
var cc = new FlicConnectionChannel( bdAddr ); var cc = new FlicConnectionChannel( bdAddr );
client.addConnectionChannel( cc ); client.addConnectionChannel( cc );
cc.on( 'buttonUpOrDown', function( clickType, wasQueued, timeDiff ) { // Bind to our desired click type; see ProtocolDocumentation.md in fliclib-linux-hci
if ( 'ButtonDown' !== clickType ) { cc.on( 'buttonSingleOrDoubleClickOrHold', function( clickType, wasQueued, timeDiff ) {
// Don't handle long-queued events, to avoid excessive toggling of HA entities
if ( wasQueued && timeDiff > 2 ) {
return; return;
} }
if ( wasQueued && timeDiff > 2 ) { // Convert the verbose click name to something convenient
// Also validates click type
var parsedClickType = '';
switch ( clickType ) {
case 'ButtonSingleClick':
parsedClickType = 'single';
break;
case 'ButtonDoubleClick':
parsedClickType = 'double';
break;
case 'ButtonHold':
parsedClickType = 'hold';
break;
default:
// Do nothing, this type isn't supported
break;
}
// Click type is unsupported
if ( 0 === parsedClickType.length ) {
console.error( 'Unsupported click type ' + clickType );
return; return;
} }
buttonActivated( bdAddr ); // Time to pass the click to HA
buttonActivated( bdAddr, parsedClickType );
} ); } );
} }
...@@ -68,9 +97,24 @@ function listenToButton( bdAddr ) { ...@@ -68,9 +97,24 @@ function listenToButton( bdAddr ) {
/** /**
* Make HTTP(s) requests to Home Assistant to toggle status of device assigned to pushed button * Make HTTP(s) requests to Home Assistant to toggle status of device assigned to pushed button
*/ */
function buttonActivated( mac ) { function buttonActivated( mac, clickType ) {
var buttonConfig = config.buttons[mac]; // Check for a button config
if ( 'undefined' === typeof config.buttons[ mac ] ) {
console.error( 'No configuration for button ' + mac );
return;
}
var buttonConfig = config.buttons[ mac ];
// Check for a config for this click type
if ( 'undefined' === typeof buttonConfig[ clickType ] ) {
console.error( 'No configuration for click type `' + clickType + '` on button "' + buttonConfig.label + '"' );
return;
}
var buttonClickConfig = buttonConfig[ clickType ];
// Check current state of button's entity
var req = { var req = {
url: homeAssistantApiBase + 'states/' + buttonConfig.status.entity_id, url: homeAssistantApiBase + 'states/' + buttonConfig.status.entity_id,
headers: { headers: {
...@@ -95,12 +139,13 @@ function buttonActivated( mac ) { ...@@ -95,12 +139,13 @@ function buttonActivated( mac ) {
// HA only deals with JSON // HA only deals with JSON
body = JSON.parse( body ); body = JSON.parse( body );
// Use entity's current state to determine new state, per config
var service = 'services/', var service = 'services/',
postBody = {}; postBody = {};
if ( 'object' === typeof buttonConfig[ body.state ] ) { if ( 'object' === typeof buttonClickConfig[ body.state ] ) {
service += buttonConfig[ body.state ].entity + '/' + buttonConfig[ body.state ].entity_action; service += buttonClickConfig[ body.state ].entity + '/' + buttonClickConfig[ body.state ].entity_action;
postBody.entity_id = buttonConfig[ body.state ].entity_id; postBody.entity_id = buttonClickConfig[ body.state ].entity_id;
} else { } else {
console.error( 'Unhandled state: ' + body.state ); console.error( 'Unhandled state: ' + body.state );
return; return;
...@@ -111,7 +156,7 @@ function buttonActivated( mac ) { ...@@ -111,7 +156,7 @@ function buttonActivated( mac ) {
req.method = 'POST'; req.method = 'POST';
req.body = JSON.stringify( postBody ); req.body = JSON.stringify( postBody );
// Make request to change alarm status // Make request to update entity status
request( req, function( err, res, body ) { request( req, function( err, res, body ) {
// Handle error states // Handle error states
if ( err ) { if ( err ) {
......
{ {
"name": "flic-button-home-assistant-controller", "name": "flic-button-home-assistant-controller",
"version": "0.2.0", "version": "0.2.5",
"description": "Control Home Assistant entities with Flic buttons", "description": "Control Home Assistant entities with Flic buttons",
"author": "Erick Hitter <contact@ethitter.com>", "author": "Erick Hitter <contact@ethitter.com>",
"license": "GPL-2.0+", "license": "GPL-2.0+",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment