homebridge-arlo
Advanced tools
Comparing version 0.0.2 to 0.0.3
326
index.js
@@ -6,2 +6,4 @@ 'use strict'; | ||
const DEFAULT_SUBSCRIBE_TIME = 60000; | ||
let Accessory, PlatformAccessory, Characteristic, Service, StreamController, UUIDGen; | ||
@@ -57,3 +59,3 @@ | ||
let accessory = new PlatformAccessory(deviceName, UUIDGen.generate(device.id), Accessory.Categories.CAMERA); | ||
let accessory = new PlatformAccessory(device.id, UUIDGen.generate(device.id), Accessory.Categories.CAMERA); | ||
@@ -87,2 +89,35 @@ let service = accessory.getService(Service.AccessoryInformation); | ||
} | ||
else if (deviceType === Arlo.Q) { | ||
this.log("Found: Camera - %s [%s]", device.id, device.id); | ||
let accessory = new PlatformAccessory(device.id, UUIDGen.generate(device.id), Accessory.Categories.CAMERA); | ||
let service = accessory.getService(Service.AccessoryInformation); | ||
service.setCharacteristic(Characteristic.Manufacturer, "Arlo") | ||
.setCharacteristic(Characteristic.Model, deviceModel); | ||
service.getCharacteristic(Characteristic.FirmwareRevision); | ||
service.getCharacteristic(Characteristic.HardwareRevision); | ||
accessory.addService(Service.MotionSensor, deviceName); | ||
service = accessory.addService(Service.CameraControl, deviceName); | ||
service.addCharacteristic(Characteristic.NightVision); | ||
service.addCharacteristic(Characteristic.ImageMirroring); | ||
service.addCharacteristic(Characteristic.ImageRotation) | ||
.setProps({ | ||
maxValue: 180, | ||
minValue: 0, | ||
minStep: 180 | ||
}); | ||
accessory.configureCameraSource(new ArloCameraSource(this.log, accessory, device)); | ||
accessory.addService(Service.SecuritySystem, deviceName); | ||
this.accessories[accessory.UUID] = new ArloQAccessory(this.log, this.config, accessory, device); | ||
this.api.publishCameraAccessories("homebridge-arlo", [accessory]); | ||
} | ||
} | ||
@@ -110,4 +145,9 @@ | ||
else if(device.getType() === Arlo.CAMERA) { | ||
this.accessories[uuid] = new ArloCameraAccessory(this.log, (accessory instanceof ArloBaseStationAccessory ? accessory.accessory : accessory), device); | ||
this.log("Online: Camera %s [%s]", accessory.displayName, device.id); | ||
this.accessories[uuid] = new ArloCameraAccessory(this.log, (accessory instanceof ArloCameraAccessory ? accessory.accessory : accessory), device); | ||
} | ||
else if(device.getType() === Arlo.Q) { | ||
this.log("Online: Camera %s [%s]", accessory.displayName, device.id); | ||
this.accessories[uuid] = new ArloQAccessory(this.log, this.config, (accessory instanceof ArloQAccessory ? accessory.accessory : accessory), device); | ||
} | ||
}.bind(this)); | ||
@@ -130,2 +170,3 @@ | ||
this.NIGHT_ARM = config.night_arm || Arlo.ARMED; | ||
this.interval = config.interval || DEFAULT_SUBSCRIBE_TIME; | ||
@@ -203,3 +244,3 @@ this.accessory | ||
}.bind(this), | ||
60000 | ||
(this.interval) | ||
); | ||
@@ -465,7 +506,6 @@ } | ||
handleSnapshotRequest(request, callback) { | ||
// todo - remove this | ||
let now = Date.now(); | ||
if (this.lastSnapshot && now < this.lastSnapshot + 300000) { | ||
this.log('Camera %s [%s] - Next snapshot in %d secs', this.accessory.displayName, this.device.id, parseInt((this.lastSnapshot + 300000 - now) / 1000)); | ||
this.log('Snapshot skipped: Camera %s [%s] - Next in %d secs', this.accessory.displayName, this.device.id, parseInt((this.lastSnapshot + 300000 - now) / 1000)); | ||
callback(); | ||
@@ -475,8 +515,4 @@ return; | ||
this.log("Camera %s [%s] - Snapshot request", this.accessory.displayName, this.device.id); | ||
this.log("Snapshot request: Camera %s [%s]", this.accessory.displayName, this.device.id); | ||
//this.once('snapshot', function(data) { | ||
// callback(undefined,data); | ||
//}); | ||
this.device.getSnapshot(function(error, data) { | ||
@@ -491,8 +527,7 @@ if (error) { | ||
this.log("Camera %s [%s] - Snapshot confirmed", this.accessory.displayName, this.device.id); | ||
this.log(data); | ||
this.log("Snapshot confirmed: Camera %s [%s]", this.accessory.displayName, this.device.id); | ||
this.device.once('fullFrameSnapshotAvailable', function(url) { | ||
this.device.once(Arlo.FF_SNAPSHOT, function(url) { | ||
this.device.downloadSnapshot(url, function (data) { | ||
this.log("Camera %s [%s] - Snapshot downloaded", this.accessory.displayName, this.device.id); | ||
this.log("Snapshot downloaded: Camera %s [%s]", this.accessory.displayName, this.device.id); | ||
callback(undefined, data); | ||
@@ -520,3 +555,3 @@ }.bind(this)); | ||
_createStreamControllers(options) { | ||
this.log("_createStreamControllers"); | ||
//this.log("_createStreamControllers"); | ||
let streamController = new StreamController(1, options, this); | ||
@@ -528,1 +563,262 @@ | ||
} | ||
class ArloQAccessory { | ||
constructor(log, config, accessory, device) { | ||
this.accessory = accessory; | ||
this.device = device; | ||
this.log = log; | ||
config = config || {}; | ||
this.STAY_ARM = config.stay_arm || Arlo.ARMED; | ||
this.NIGHT_ARM = config.night_arm || Arlo.ARMED; | ||
this.interval = config.interval || DEFAULT_SUBSCRIBE_TIME; | ||
this.accessory | ||
.getService(Service.AccessoryInformation) | ||
.setCharacteristic(Characteristic.Model, device.getModel()) | ||
.setCharacteristic(Characteristic.SerialNumber, device.getSerialNumber()); | ||
this.setupListeners(); | ||
} | ||
setupListeners() { | ||
this.accessory | ||
.getService(Service.SecuritySystem) | ||
.getCharacteristic(Characteristic.SecuritySystemTargetState) | ||
.on('set', this.setTargetState.bind(this)); | ||
this.device.on(Arlo.ARMED, function() { | ||
this.accessory | ||
.getService(Service.SecuritySystem) | ||
.getCharacteristic(Characteristic.SecuritySystemTargetState) | ||
.updateValue(Characteristic.SecuritySystemTargetState.AWAY_ARM); | ||
this.accessory | ||
.getService(Service.SecuritySystem) | ||
.getCharacteristic(Characteristic.SecuritySystemCurrentState) | ||
.updateValue(Characteristic.SecuritySystemCurrentState.AWAY_ARM); | ||
}.bind(this)); | ||
this.device.on(Arlo.DISARMED, function() { | ||
this.accessory | ||
.getService(Service.SecuritySystem) | ||
.getCharacteristic(Characteristic.SecuritySystemTargetState) | ||
.updateValue(Characteristic.SecuritySystemTargetState.DISARM); | ||
this.accessory | ||
.getService(Service.SecuritySystem) | ||
.getCharacteristic(Characteristic.SecuritySystemCurrentState) | ||
.updateValue(Characteristic.SecuritySystemCurrentState.DISARMED); | ||
}.bind(this)); | ||
if (this.STAY_ARM !== Arlo.ARMED) { | ||
this.device.on(this.STAY_ARM, function() { | ||
this.accessory | ||
.getService(Service.SecuritySystem) | ||
.getCharacteristic(Characteristic.SecuritySystemTargetState) | ||
.updateValue(Characteristic.SecuritySystemTargetState.STAY_ARM); | ||
this.accessory | ||
.getService(Service.SecuritySystem) | ||
.getCharacteristic(Characteristic.SecuritySystemCurrentState) | ||
.updateValue(Characteristic.SecuritySystemCurrentState.STAY_ARM); | ||
}.bind(this)); | ||
} | ||
if (this.NIGHT_ARM !== Arlo.ARMED) { | ||
this.device.on(this.NIGHT_ARM, function() { | ||
this.accessory | ||
.getService(Service.SecuritySystem) | ||
.getCharacteristic(Characteristic.SecuritySystemTargetState) | ||
.updateValue(Characteristic.SecuritySystemTargetState.NIGHT_ARM); | ||
this.accessory | ||
.getService(Service.SecuritySystem) | ||
.getCharacteristic(Characteristic.SecuritySystemCurrentState) | ||
.updateValue(Characteristic.SecuritySystemCurrentState.NIGHT_ARM); | ||
}.bind(this)); | ||
} | ||
this.accessory | ||
.getService(Service.CameraControl) | ||
.getCharacteristic(Characteristic.On) | ||
.on('set', this.setPrivacyActive.bind(this)); | ||
this.accessory | ||
.getService(Service.CameraControl) | ||
.getCharacteristic(Characteristic.ImageMirroring) | ||
.on('set', this.setImageMirroring.bind(this)); | ||
this.accessory | ||
.getService(Service.CameraControl) | ||
.getCharacteristic(Characteristic.ImageRotation) | ||
.on('set', this.setImageRotation.bind(this)); | ||
this.accessory | ||
.getService(Service.MotionSensor) | ||
.getCharacteristic(Characteristic.MotionDetected) | ||
.on('get', this.get.bind(this)); | ||
this.device.on(Arlo.MOTION, this.updateMotionDetected.bind(this)); | ||
this.device.on(Arlo.UPDATE, function(info) { | ||
this.updateInfo(info); | ||
this.updateConnectionState(info.connectionState); | ||
this.updateImageMirroring(info.mirror); | ||
this.updateImageRotation(info.flip); | ||
this.updateNightVision(info.nightVisionMode); | ||
this.updatePrivacyActive(info.privacyActive); | ||
}.bind(this)); | ||
setInterval( | ||
function() { | ||
this.device.subscribe(); | ||
}.bind(this), | ||
(this.interval) | ||
); | ||
} | ||
get(callback) { | ||
if (this.device) { | ||
this.device.get(); | ||
} | ||
callback(null, null) | ||
} | ||
setImageMirroring(value, callback) { | ||
this.device.set({mirror: value}, function() { | ||
callback(null); | ||
}) | ||
} | ||
setImageRotation(value, callback) { | ||
this.device.set({flip: (value > 0 ? true : false)}, function() { | ||
callback(null); | ||
}) | ||
} | ||
setPrivacyActive(value, callback) { | ||
this.device.set({privacyActive: value == false}, function() { | ||
callback(null); | ||
}) | ||
} | ||
setTargetState(state, callback) { | ||
switch(state) { | ||
case Characteristic.SecuritySystemTargetState.AWAY_ARM: | ||
this.device.arm(function() { | ||
callback(null); | ||
this.device.emit(Arlo.ARMED); | ||
}.bind(this)); | ||
break; | ||
case Characteristic.SecuritySystemTargetState.DISARM: | ||
this.device.disarm(function() { | ||
callback(null); | ||
this.device.emit(Arlo.DISARMED); | ||
}.bind(this)); | ||
break; | ||
case Characteristic.SecuritySystemTargetState.STAY_ARM: | ||
this.device.setMode(this.STAY_ARM, function() { | ||
callback(null); | ||
this.device.emit(this.STAY_ARM); | ||
}.bind(this)); | ||
break; | ||
case Characteristic.SecuritySystemTargetState.NIGHT_ARM: | ||
this.device.setMode(this.NIGHT_ARM, function() { | ||
callback(null); | ||
this.device.emit(this.NIGHT_ARM); | ||
}.bind(this)); | ||
break; | ||
} | ||
} | ||
updateInfo(info) { | ||
if (info === undefined) { | ||
return; | ||
} | ||
let service = this.accessory.getService(Service.AccessoryInformation); | ||
if (info.modelId) { | ||
service.getCharacteristic(Characteristic.Model).updateValue(info.modelId); | ||
} | ||
if (info.serialNumber) { | ||
service.getCharacteristic(Characteristic.SerialNumber).updateValue(info.serialNumber); | ||
} | ||
if (info.swVersion) { | ||
service.getCharacteristic(Characteristic.FirmwareRevision).updateValue(info.swVersion); | ||
} | ||
if (info.hwVersion) { | ||
service.getCharacteristic(Characteristic.HardwareRevision).updateValue(info.hwVersion); | ||
} | ||
} | ||
updateConnectionState(connectionState) { | ||
if (connectionState === undefined) { | ||
return; | ||
} | ||
let online = connectionState === 'available'; | ||
this.log("%s: Camera %s [%s]", (online ? 'Online' : 'Offline'), this.accessory.displayName, this.device.id); | ||
} | ||
updateMotionDetected(motionDetected) { | ||
if (motionDetected === undefined) { | ||
return; | ||
} | ||
this.accessory | ||
.getService(Service.MotionSensor) | ||
.getCharacteristic(Characteristic.MotionDetected) | ||
.updateValue(motionDetected); | ||
} | ||
updateImageMirroring(mirror) { | ||
if (mirror === undefined) { | ||
return; | ||
} | ||
this.accessory | ||
.getService(Service.CameraControl) | ||
.getCharacteristic(Characteristic.ImageMirroring) | ||
.updateValue(mirror); | ||
} | ||
updateImageRotation(flip) { | ||
if (flip === undefined) { | ||
return; | ||
} | ||
this.accessory | ||
.getService(Service.CameraControl) | ||
.getCharacteristic(Characteristic.ImageRotation) | ||
.updateValue(flip === true ? 180 : 0); | ||
} | ||
updateNightVision(nightVisionMode) { | ||
if (nightVisionMode === undefined) { | ||
return; | ||
} | ||
this.accessory | ||
.getService(Service.CameraControl) | ||
.getCharacteristic(Characteristic.NightVision) | ||
.updateValue(nightVisionMode === 1); | ||
} | ||
updatePrivacyActive(privacyActive) { | ||
if (privacyActive === undefined) { | ||
return; | ||
} | ||
this.accessory | ||
.getService(Service.CameraControl) | ||
.getCharacteristic(Characteristic.On) | ||
.updateValue(privacyActive == false); | ||
} | ||
} |
{ | ||
"name": "homebridge-arlo", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"author": "David Parry <npm@introversion.com.au>", | ||
@@ -19,4 +19,4 @@ "description": "Arlo platform plugin for homebridge", | ||
"dependencies": { | ||
"node-arlo": ">=0.0.5" | ||
"node-arlo": ">=0.0.7" | ||
} | ||
} |
@@ -5,4 +5,3 @@ # homebridge-arlo | ||
[![NPM Version](https://img.shields.io/npm/v/homebridge-arlo.svg)](https://www.npmjs.com/package/homebridge-arlo) | ||
[![Dependency Status](https://img.shields.io/versioneye/d/nodejs/arlo.svg)](https://www.versioneye.com/nodejs/homebridge-arlo/) | ||
[![donate](https://img.shields.io/badge/%24-Buy%20me%20a%20coffee-ff69b4.svg)](https://www.buymeacoffee.com/devbobo) | ||
[![Slack Channel](https://img.shields.io/badge/slack-homebridge--arlo-e01563.svg)](https://homebridgeteam.slack.com/messages/C5C0Z6XPW) | ||
@@ -20,11 +19,15 @@ | ||
- npm update -g homebridge-arlo | ||
- `npm update -g homebridge-arlo` | ||
# Setup | ||
Arlo only allows a single login to each account at a time, as a result, if you are running Homebridge and the Arlo on the same account...logging in on your iPhone to view cameras will log out homebridge's Arlo access. | ||
Arlo only allows a single login to each account at a time, as a result, if you | ||
are running Homebridge and the Arlo on the same account... logging in on your | ||
iPhone to view cameras will log out homebridge's Arlo access. | ||
Therefore, I **highly recommend** creating an additional account in Arlo, just for homebridge access. | ||
Therefore, I **highly recommend** creating an additional account in Arlo, just | ||
for homebridge access. | ||
# Limitations | ||
This plugin currently only support Base Stations, not cameras. This is mainly because I haven't gotten video streaming to work yet. | ||
This plugin currently only support Base Stations, not cameras. This is mainly | ||
because I haven't gotten video streaming to work yet. | ||
@@ -40,2 +43,3 @@ # Configuration | ||
"password": "<insert arlo account password>" | ||
"interval": 6000 | ||
} | ||
@@ -45,12 +49,31 @@ ] | ||
``` | ||
NOTE: interval time is in milliseconds - e.g. 6000 ms are 10 sec | ||
## Optional parameters | ||
By default, Arlo only provides two modes (**armed** and **disarmed**). Since HomeKit allows a security system to have 4 statees (**away**, **home**, **night** and **off**), we provide two config parameters to enable support for the additional 2 states. If these configuration parameters aren't provided setting the state to **home** or **night** will result in the state being set to **away**. | ||
By default, Arlo only provides two modes (**armed** and **disarmed**). Since | ||
HomeKit allows a security system to have 4 states (**away**, **home**, | ||
**night** and **off**), we provide two config parameters to enable support for | ||
the additional 2 states. If these configuration parameters aren't provided | ||
setting the state to **home** or **night** will result in the state being set | ||
to **away**, i.e. **armed**. | ||
`stay_arm` - The string label for the mode created in Arlo for the **home** or **stay** state. | ||
Arlo uses the string `modeX` to identify each mode, with `mode0` used for the | ||
default **disarmed** state and `mode1` used for the default **armed** state. | ||
To determine the correct `modeX` string for your custom state, login to the | ||
[Arlo web console](https://arlo.netgear.com) and click the "Edit Mode" button. | ||
The URL will show the ` modeX` string for that custom state, e.g. | ||
https\://arlo.netgear.com/#/modes/`<USER_ID>`/edit/**mode2** | ||
`night_arm` - The string label for the mode created in Arlo for the **night** state. | ||
Once you've determined the `modeX` string of your custom mode(s), you can | ||
configure `homebridge-arlo` to use those for the additional modes available | ||
via HomeKit: | ||
Sample Configuration | ||
* `stay_arm` - The `modeX` label for the custom mode created in Arlo for the | ||
**home** or **stay** state. | ||
* `night_arm` - The `modeX` label for the custom mode created in Arlo for the | ||
**night** state. | ||
### Sample Configuration with Optional Parameters | ||
```javascript | ||
@@ -67,18 +90,1 @@ "platforms": [ | ||
] | ||
``` | ||
# Siri commands | ||
**Arming - Away Mode**<br/> | ||
_Set the security system to armed/away_ | ||
**Disarming - Off Mode**<br/> | ||
_Set the security system to disarmed/off_ | ||
**Arming - Home Mode**<br/> | ||
_Set the security system to stay_ | ||
**Arming - Night Mode**<br/> | ||
_Set the security system to night_ | ||
32194
663
86
Updatednode-arlo@>=0.0.7