Skip to content

Commit

Permalink
move to platform
Browse files Browse the repository at this point in the history
  • Loading branch information
nitaybz committed Nov 8, 2020
1 parent 36ab257 commit f615bce
Show file tree
Hide file tree
Showing 7 changed files with 967 additions and 188 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ node_modules

# homebridge-people specifics
seen.db.json

test.js
22 changes: 13 additions & 9 deletions config-sample.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
{
"accessories": [
"platforms": [
{
"accessory": "networkPresence",
"name": "my iPhone",
"mac": "cc:29:f5:3b:a2:f2"
},
{
"accessory": "networkPresence",
"name": "my iPad",
"ip": "10.0.0.142"
"platform": "networkPresence",
"devices": [
{
"name": "my iPhone",
"mac": "cc:29:f5:3b:a2:f2"
},
{
"name": "my iPad",
"ip": "10.0.0.142"
}

]
}
]
}
119 changes: 34 additions & 85 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,94 +1,43 @@
const { Accessory } = require('homebridge-plugin-helpers');
const { NetworkObserver } = require('./network');

module.exports = function (homebridge) {
networkPresenceAccessory.register(homebridge);
};
const Network = require('./lib/network')
const PLUGIN_NAME = 'homebridge-network-presence'
const PLATFORM_NAME = 'networkPresence'
module.exports = (api) => {
api.registerPlatform(PLUGIN_NAME, PLATFORM_NAME, networkPresence)
}

class networkPresenceAccessory extends Accessory {
class networkPresence {

static get pluginName() {
return "homebridge-network-presence";
}

static get accessoryName() {
return "networkPresence";
}
constructor(log, config, api) {
this.api = api
this.log = log

constructor(homebridge, log, config, api) {
super();
// Save args
this.log = log;
this.config = config;
this.api = api;
// Setup Homebridge
this.Service = homebridge.hap.Service;
this.Characteristic = homebridge.hap.Characteristic;
// Setup Service
this.isDetected = 0;
this.service = new this.Service.OccupancySensor(this.name);
this.setupCharacteristics();
this.setupDeviceObserver();
}
this.accessories = []
this.devices = []
this.PLUGIN_NAME = PLUGIN_NAME
this.PLATFORM_NAME = PLATFORM_NAME
this.name = config.name || PLATFORM_NAME
this.devicesConfig = config.devices || []
this.debug = config.debug || false

get name() {
return this.config.name;
}

// define debug method to output debug logs when enabled in the config
this.log.easyDebug = (...content) => {
if (this.debug) {
this.log(content.reduce((previous, current) => {
return previous + ' ' + current
}))
} else
this.log.debug(content.reduce((previous, current) => {
return previous + ' ' + current
}))
}

get manufacturer() {
return "network-presence";
}
this.api.on('didFinishLaunching', Network.init.bind(this))

get model() {
return "arp-network-presence";
}

get serialNumber() {
return this.config.mac || this.config.ip;
configureAccessory(accessory) {
this.log.easyDebug(`Found Cached Accessory: ${accessory.displayName} (${accessory.context.serial}) `)
this.accessories.push(accessory)
}

setupCharacteristics() {
const { Characteristic } = this;
this.service
.getCharacteristic(Characteristic.OccupancyDetected)
.on('get', (callback) => callback(null, this.isDetected));
}

setupDeviceObserver() {
const { net } = this;
const { mac, ip } = this.config;
if (mac) {
net.on(`connected:mac:${mac.toLowerCase()}`, (device) =>
this.setDetected(1)
);
net.on(`disconnected:mac:${mac}`, (device) =>
this.setDetected(0)
);
} if (ip) {
net.on(`connected:ip:${ip}`, (device) =>
this.setDetected(1)
);
net.on(`disconnected:ip:${ip}`, (device) =>
this.setDetected(0)
);
}
}

static get net() {
if (!this._net) {
this._net = new NetworkObserver();
}
return this._net;
}

get net() {
return this.constructor.net;
}

setDetected(isDetected, device) {
this.log(`${this.name} ${isDetected ? 'connected to' : 'disconnected from'} the network! (mac: ${device.mac} | ip:${device.ip})`)
this.isDetected = isDetected;
this.service.updateValue(isDetected);
}

}
}
81 changes: 81 additions & 0 deletions lib/accessory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
let Characteristic, Service

class OccupancySensor {
constructor(network, config, platform) {

Service = platform.api.hap.Service
Characteristic = platform.api.hap.Characteristic
this.network = network
this.log = platform.log
this.api = platform.api
this.mac = config.mac.toLowerCase()
this.ip = config.ip
this.name = config.name
this.model = 'ARP-network-scanner'
this.serial = this.mac.toLowerCase() || this.ip
this.manufacturer = '@nitaybz'
this.displayName = this.name


this.UUID = this.api.hap.uuid.generate(this.serial)
this.accessory = platform.accessories.find(accessory => accessory.UUID === this.UUID)

if (!this.accessory) {
this.log(`Creating New ${platform.PLATFORM_NAME} Accessory for ${this.name}`)
this.accessory = new this.api.platformAccessory(this.name, this.UUID)
this.accessory.context.serial = this.serial

platform.accessories.push(this.accessory)
// register the accessory
this.api.registerPlatformAccessories(platform.PLUGIN_NAME, platform.PLATFORM_NAME, [this.accessory])
}


this.isDetected = this.accessory.context.isDetected || 0

let informationService = this.accessory.getService(Service.AccessoryInformation)

if (!informationService)
informationService = this.accessory.addService(Service.AccessoryInformation)

informationService
.setCharacteristic(Characteristic.Manufacturer, this.manufacturer)
.setCharacteristic(Characteristic.Model, this.model)
.setCharacteristic(Characteristic.SerialNumber, this.serial)

this.addOccupancySensor()

}

addOccupancySensor() {
this.log.easyDebug(`Adding "${this.name}" Occupancy Sensor Service`)
this.OccupancySensorService = this.accessory.getService(Service.OccupancySensor)
if (!this.OccupancySensorService)
this.OccupancySensorService = this.accessory.addService(Service.OccupancySensor, this.name, 'netSensor')

this.OccupancySensorService.getCharacteristic(Characteristic.OccupancyDetected)
.on('get', (callback) => callback(null, isDetected))
.updateValue(isDetected)

const listenTo = this.mac ? `mac:${this.mac}` : `ip:${this.ip}`
this.log.easyDebug(`[${this.name}] - Listening to ${listenTo}`)

this.network.on(`connected:${listenTo}`, (device) =>
this.setDetected(1, device)
);
this.network.on(`disconnected:${listenTo}`, (device) =>
this.setDetected(0, device)
);

}

setDetected(isDetected, device) {
this.log(`[${this.name}] - ${isDetected ? 'connected to' : 'disconnected from'} the network! (mac: ${device.mac} | ip:${device.ip})`)
this.isDetected = isDetected
this.accessory.context.isDetected = isDetected
this.OccupancySensorService.updateValue(isDetected)
}
}


module.exports = OccupancySensor
51 changes: 38 additions & 13 deletions network.js → lib/network.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
const { EventEmitter } = require('events');
const ping = require("ping");
const Promise = require('bluebird');
const arpScanner = require('arpscan/promise');
const find = require('local-devices');
const Accessory = require('./accessory')

const init = function() {
removeCachedDevices.bind(this)()

this.log(`Initiating Network Scanner...`)
const net = new NetworkObserver()

net.on('err', (err) => {
this.log('ERROR OCCURRED !!')
this.log(err)
})

this.devicesConfig.forEach(device => new Accessory(net, device, this))


}

class NetworkObserver extends EventEmitter {
constructor() {
Expand All @@ -17,17 +34,9 @@ class NetworkObserver extends EventEmitter {
return 1000;
}

get table() {
return new Promise((resolve, reject) => {
arpScanner()
.then(entries => resolve(entries))
.catch(error => reject(error));
});
}

get devices() {
return this.table
.then(entries => this._parseMacAddress(entries))
return find()
// .then(entries => this._parseMacAddress(entries))
.then(entries =>
Promise.all(entries.map(entry =>
this.ping(entry.ip)
Expand Down Expand Up @@ -123,5 +132,21 @@ class NetworkObserver extends EventEmitter {
}

module.exports = {
NetworkObserver
};
NetworkObserver,
init
};


const removeCachedDevices = function() {
this.accessories.forEach(accessory => {
const deviceInConfig = this.devicesConfig.find(device => device.mac === accessory.context.serial || device.ip === accessory.context.serial)
if (deviceInConfig)
return
else {
// unregistering accessory
this.log(`Unregistering disconnected device: "${accessory.name}" (${accessory.context.serial}`)
this.api.unregisterPlatformAccessories(this.PLUGIN_NAME, this.PLATFORM_NAME, [accessory])
}

});
}
Loading

0 comments on commit f615bce

Please sign in to comment.