This repository has been archived by the owner on May 29, 2022. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
index.js
156 lines (133 loc) · 6.12 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
'use strict';
const UnifiEvents = require('unifi-events')
const manifest = require('./package.json');
const url = require('url');
var Service, Characteristic;
module.exports = function (homebridge) {
Service = homebridge.hap.Service;
Characteristic = homebridge.hap.Characteristic;
homebridge.registerAccessory('homebridge-unifi-occupancy-sensor',
'UniFi Occupancy Sensor', OccupancySensor)
};
class OccupancySensor {
constructor(log, config) {
this.log = log;
this.name = config.name;
this.occupancyService = new Service.OccupancySensor(this.name);
this.watch = config.monitor || [];
if (config.watch) {
for (const watched of config.watch) {
if (typeof watched === 'string' || watched instanceof String) {
this.watch.push({ "device": watched, "ap": undefined });
} else {
this.watch.push(watched);
}
}
}
this.watchGuests = config.watchGuests;
this.mode = config.mode || 'any';
this.interval = config.interval || 1800;
this.controller = url.parse(config.unifi.controller);
this.unifi = new UnifiEvents({
host: this.controller.hostname,
port: this.controller.port || 443,
username: config.unifi.username,
password: config.unifi.password,
site: config.unifi.site || 'default',
insecure: !config.unifi.secure || true,
unifios: config.unifi.unifios || false,
listen: true
});
this.unifi.on('*.connected', (data) => {
this.log.debug(`Device Connected Event Received from UniFi Controller: ${data.msg}`);
return this.checkOccupancy()
});
this.unifi.on('*.disconnected', (data) => {
this.log.debug(`Device Disconnected Event Received from UniFi Controller: ${data.msg}`);
return this.checkOccupancy()
});
this.occupancyDetected = Characteristic.OccupancyDetected.OCCUPANCY_NOT_DETECTED;
this.checkOccupancy();
setInterval(this.checkOccupancy.bind(this), this.interval * 1000)
}
checkGuest(isGuest, mac) {
if (this.watchGuests && isGuest) {
this.log.debug(`Device [${mac}] is connected to a guest network and guest network monitoring is enabled.`);
return true
} else if (!this.watchGuests && isGuest) {
this.log.debug(`Device [${mac}] is connected to a guest network but guest network monitoring is NOT enabled.`);
return false
} else {
this.log.debug(`Device [${mac}] is NOT connected to a guest network.`);
return true
}
}
isInWatchlist(device) {
return this.watch.some(watchedDevice => (
watchedDevice.device === device.mac && (watchedDevice.ap === undefined || watchedDevice.ap === device.ap_mac))
);
}
checkOccupancy() {
this.log.debug('Getting list of connected clients from UniFi Controller...');
return this.unifi.get('stat/sta')
.then((res) => {
this.log.debug(`${res.data.length} devices are currently connected to the UniFi network, checking each one to see if any are on the watch list...`);
let activeDevices = res.data.filter((device) => {
this.log.debug(`Device [${device.mac}, ${device.ap_mac}] HOSTNAME: "${device.hostname}" , GUEST: "${device.is_guest}", SSID: "${device.essid}"`);
if (this.isInWatchlist(device) && this.checkGuest(device.is_guest, device.mac)) {
this.log.debug(`Device [${device.mac}, ${device.ap_mac}] Device is on the watch list. Going to trigger occupancy.`);
return true
} else {
this.log.debug(`Device [${device.mac}] Ignoring. Not on the watch list.`);
return false
}
});
this.log.debug(`Monitored devices found:`, activeDevices.map(x => x.mac));
if (this.mode === 'none') {
if (activeDevices.length > 0) {
this.log(`${activeDevices.length} monitored device(s) found. Accessory is in mode "none" so NOT triggering occupancy.`);
this.occupancyDetected = Characteristic.OccupancyDetected.OCCUPANCY_NOT_DETECTED
} else {
this.log(`${activeDevices.length} monitored device(s) found. Accessory is in mode "none" so triggering occupancy.`);
this.occupancyDetected = Characteristic.OccupancyDetected.OCCUPANCY_DETECTED
}
} else if (this.mode === 'all') {
if (activeDevices.length === this.watch.length) {
this.log(`${activeDevices.length} monitored device(s) found. Accessory is in mode "all" and all watched devices are connected so triggering occupancy.`);
this.occupancyDetected = Characteristic.OccupancyDetected.OCCUPANCY_DETECTED
} else {
this.log(`${activeDevices.length} monitored device(s) found. Accessory is in mode "all" and not all watched devices are connected so NOT triggering occupancy.`);
this.occupancyDetected = Characteristic.OccupancyDetected.OCCUPANCY_NOT_DETECTED
}
} else {
if (activeDevices.length > 0) {
this.log(`${activeDevices.length} monitored device(s) found. Accessory is in mode "any" so triggering occupancy.`);
this.occupancyDetected = Characteristic.OccupancyDetected.OCCUPANCY_DETECTED
} else {
this.log(`${activeDevices.length} monitored device(s) found. Accessory is in mode "any" so NOT triggering occupancy.`);
this.occupancyDetected = Characteristic.OccupancyDetected.OCCUPANCY_NOT_DETECTED
}
}
this.setOccupancyDetected(this.occupancyDetected)
})
.catch((err) => {
this.log(`ERROR: Failed to check occupancy: ${err.message}`)
})
}
getOccupancyDetected(callback) {
return callback(null, this.occupancyDetected)
}
setOccupancyDetected(value) {
return this.occupancyService.setCharacteristic(Characteristic.OccupancyDetected, value)
}
getServices() {
var informationService = new Service.AccessoryInformation()
.setCharacteristic(Characteristic.Manufacturer, 'oznu')
.setCharacteristic(Characteristic.Model, 'unifi-occupancy')
.setCharacteristic(Characteristic.SerialNumber, manifest.version);
this.occupancyService
.getCharacteristic(Characteristic.OccupancyDetected)
.on('get', this.getOccupancyDetected.bind(this));
return [informationService, this.occupancyService]
}
}