homebridge-openwrt-control 0.0.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +436 -0
- package/LICENSE +21 -0
- package/README.md +2 -0
- package/config.schema.json +463 -0
- package/index.js +143 -0
- package/package.json +53 -0
- package/src/apdevice.js +247 -0
- package/src/constants.js +6 -0
- package/src/functions.js +81 -0
- package/src/impulsegenerator.js +41 -0
- package/src/openwrt.js +173 -0
- package/src/swdevice.js +247 -0
package/src/swdevice.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import EventEmitter from 'events';
|
|
2
|
+
let Accessory, Characteristic, Service, Categories, AccessoryUUID;
|
|
3
|
+
|
|
4
|
+
class SwitchDevice extends EventEmitter {
|
|
5
|
+
constructor(api, config, openWrt, openWrtInfo) {
|
|
6
|
+
super();
|
|
7
|
+
|
|
8
|
+
Accessory = api.platformAccessory;
|
|
9
|
+
Characteristic = api.hap.Characteristic;
|
|
10
|
+
Service = api.hap.Service;
|
|
11
|
+
Categories = api.hap.Categories;
|
|
12
|
+
AccessoryUUID = api.hap.uuid;
|
|
13
|
+
|
|
14
|
+
//config
|
|
15
|
+
this.name = config.name;
|
|
16
|
+
this.switch = config.switch;
|
|
17
|
+
this.logInfo = config.log?.info || false;
|
|
18
|
+
this.logDebug = config.log?.debug || false;
|
|
19
|
+
|
|
20
|
+
//external integration
|
|
21
|
+
this.restFul = config.restFul || {};
|
|
22
|
+
this.restFulConnected = false;
|
|
23
|
+
this.mqtt = config.mqtt || {};
|
|
24
|
+
this.mqttConnected = false;
|
|
25
|
+
|
|
26
|
+
//openwrt
|
|
27
|
+
this.openWrt = openWrt;
|
|
28
|
+
this.openWrtInfo = openWrtInfo;
|
|
29
|
+
this.ssids = openWrtInfo.ssids;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
async externalIntegrations() {
|
|
33
|
+
//RESTFul server
|
|
34
|
+
const restFulEnabled = this.restFul.enable || false;
|
|
35
|
+
if (restFulEnabled) {
|
|
36
|
+
try {
|
|
37
|
+
this.restFul1 = new RestFul({
|
|
38
|
+
port: this.restFul.port || 3000,
|
|
39
|
+
logWarn: this.logWarn,
|
|
40
|
+
logDebug: this.logDebug
|
|
41
|
+
})
|
|
42
|
+
.on('connected', (message) => {
|
|
43
|
+
this.emit('success', message);
|
|
44
|
+
this.restFulConnected = true;
|
|
45
|
+
})
|
|
46
|
+
.on('set', async (key, value) => {
|
|
47
|
+
try {
|
|
48
|
+
await this.setOverExternalIntegration('RESTFul', key, value);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
this.emit('warn', `RESTFul set error: ${error}`);
|
|
51
|
+
};
|
|
52
|
+
})
|
|
53
|
+
.on('debug', (debug) => this.emit('debug', debug))
|
|
54
|
+
.on('warn', (warn) => this.emit('warn', warn))
|
|
55
|
+
.on('error', (error) => this.emit('error', error));
|
|
56
|
+
} catch (error) {
|
|
57
|
+
this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//mqtt client
|
|
62
|
+
const mqttEnabled = this.mqtt.enable || false;
|
|
63
|
+
if (mqttEnabled) {
|
|
64
|
+
try {
|
|
65
|
+
this.mqtt1 = new Mqtt({
|
|
66
|
+
host: this.mqtt.host,
|
|
67
|
+
port: this.mqtt.port || 1883,
|
|
68
|
+
clientId: this.mqtt.clientId ? `${this.savedInfo.manufacturer}_${this.mqtt.clientId}_${Math.random().toString(16).slice(3)}` : `${this.savedInfo.manufacturer}_${Math.random().toString(16).slice(3)}`,
|
|
69
|
+
prefix: this.mqtt.prefix ? `${this.savedInfo.manufacturer}/${this.mqtt.prefix}/${this.name}` : `${this.savedInfo.manufacturer}/${this.name}`,
|
|
70
|
+
user: this.mqtt.auth?.user,
|
|
71
|
+
passwd: this.mqtt.auth?.passwd,
|
|
72
|
+
logWarn: this.logWarn,
|
|
73
|
+
logDebug: this.logDebug
|
|
74
|
+
})
|
|
75
|
+
.on('connected', (message) => {
|
|
76
|
+
this.emit('success', message);
|
|
77
|
+
this.mqttConnected = true;
|
|
78
|
+
})
|
|
79
|
+
.on('subscribed', (message) => {
|
|
80
|
+
this.emit('success', message);
|
|
81
|
+
})
|
|
82
|
+
.on('set', async (key, value) => {
|
|
83
|
+
try {
|
|
84
|
+
await this.setOverExternalIntegration('MQTT', key, value);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
this.emit('warn', `MQTT set error: ${error}`);
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
.on('debug', (debug) => this.emit('debug', debug))
|
|
90
|
+
.on('warn', (warn) => this.emit('warn', warn))
|
|
91
|
+
.on('error', (error) => this.emit('error', error));
|
|
92
|
+
} catch (error) {
|
|
93
|
+
this.emit('warn', `MQTT integration start error: ${error}`);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async setOverExternalIntegration(integration, key, value) {
|
|
101
|
+
try {
|
|
102
|
+
let set = false
|
|
103
|
+
switch (key) {
|
|
104
|
+
case 'Power':
|
|
105
|
+
const powerState = value ? 'ON' : 'OFF';
|
|
106
|
+
set = await this.openWrt.send('Power', powerState);
|
|
107
|
+
break;
|
|
108
|
+
default:
|
|
109
|
+
this.emit('warn', `${integration}, received key: ${key}, value: ${value}`);
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
return set;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
throw new Error(`${integration} set key: ${key}, value: ${value}, error: ${error}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
//prepare accessory
|
|
119
|
+
async prepareAccessory() {
|
|
120
|
+
try {
|
|
121
|
+
//prepare accessory
|
|
122
|
+
if (this.logDebug) this.emit('debug', `prepare accessory`);
|
|
123
|
+
const accessoryName = this.name;
|
|
124
|
+
const accessoryUUID = AccessoryUUID.generate(this.deviceUuid);
|
|
125
|
+
const accessoryCategory = Categories.AIRPORT;
|
|
126
|
+
const accessory = new Accessory(accessoryName, accessoryUUID, accessoryCategory);
|
|
127
|
+
|
|
128
|
+
//prepare information service
|
|
129
|
+
if (this.logDebug) this.emit('debug', `prepare information service`);
|
|
130
|
+
accessory.getService(Service.AccessoryInformation)
|
|
131
|
+
.setCharacteristic(Characteristic.Manufacturer, 'OpenWrt')
|
|
132
|
+
.setCharacteristic(Characteristic.Model, accessoryName)
|
|
133
|
+
.setCharacteristic(Characteristic.SerialNumber, this.networkId)
|
|
134
|
+
.setCharacteristic(Characteristic.FirmwareRevision, this.organizationId)
|
|
135
|
+
.setCharacteristic(Characteristic.ConfiguredName, accessoryName);
|
|
136
|
+
|
|
137
|
+
if (this.logDebug) this.emit('debug', `prepare service`);
|
|
138
|
+
|
|
139
|
+
//device
|
|
140
|
+
this.services = [];
|
|
141
|
+
for (const ssid of this.ssids) {
|
|
142
|
+
const ssidName = ssid.name;
|
|
143
|
+
if (this.logDebug) this.emit('debug', `prepare ssid: ${ssidName} service`);
|
|
144
|
+
|
|
145
|
+
const serviceName = this.accessPoint.namePrefix ? `${this.name} ${ssidName}` : ssidName;
|
|
146
|
+
const service = accessory.addService(Service.Switch, serviceName, `service${ssidName}`);
|
|
147
|
+
service.addOptionalCharacteristic(Characteristic.ConfiguredName);
|
|
148
|
+
service.setCharacteristic(Characteristic.ConfiguredName, serviceName);
|
|
149
|
+
service.getCharacteristic(Characteristic.On)
|
|
150
|
+
.onGet(async () => {
|
|
151
|
+
const state = ssid.state;
|
|
152
|
+
if (this.logInfo) this.emit('message', `SSID: ${ssidName}, state: ${state ? 'Enabled' : 'Disabled'}`);
|
|
153
|
+
return state;
|
|
154
|
+
})
|
|
155
|
+
.onSet(async (state) => {
|
|
156
|
+
try {
|
|
157
|
+
state = state ? true : false;
|
|
158
|
+
await this.openWrt.send('ssid', ssidName, state);
|
|
159
|
+
if (this.logInfo) this.emit('message', `SSID: ${ssidName}, set State: ${state ? 'Enabled' : 'Disabled'}`);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
this.emit('warn', `SSID: ${ssidName}, set state error: ${error}`);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
this.services.push(service);
|
|
165
|
+
|
|
166
|
+
if (this.accessPoint.sensor) {
|
|
167
|
+
if (this.logDebug) this.emit('debug', `prepare ssid: ${ssidName} sensor service`);
|
|
168
|
+
|
|
169
|
+
this.sensorServices = [];
|
|
170
|
+
const sensorService = accessory.addService(Service.ContactSensor, ssidName, `sensorService${ssidName}`);
|
|
171
|
+
sensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
|
|
172
|
+
sensorService.setCharacteristic(Characteristic.ConfiguredName, ssidName);
|
|
173
|
+
sensorService.getCharacteristic(Characteristic.ContactSensorState)
|
|
174
|
+
.onGet(async () => {
|
|
175
|
+
const state = ssid.state;
|
|
176
|
+
return state;
|
|
177
|
+
});
|
|
178
|
+
this.sensorServices.push(sensorService);
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
return accessory;
|
|
183
|
+
} catch (error) {
|
|
184
|
+
throw new Error(error);
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
//start
|
|
189
|
+
async start() {
|
|
190
|
+
try {
|
|
191
|
+
//start external integrations
|
|
192
|
+
if (this.restFul.enable || this.mqtt.enable) await this.externalIntegrations();
|
|
193
|
+
|
|
194
|
+
this.emit('devInfo', `-------- Switch ${this.name} --------`);
|
|
195
|
+
this.emit('devInfo', `Name: ${this.openWrtInfo.systemInfo.hostname}`);
|
|
196
|
+
this.emit('devInfo', `Model: ${this.openWrtInfo.systemInfo.model}`);
|
|
197
|
+
this.emit('devInfo', `System: ${this.openWrtInfo.systemInfo.system}`);
|
|
198
|
+
this.emit('devInfo', `Release: ${this.openWrtInfo.systemInfo.release?.description}`);
|
|
199
|
+
this.emit('devInfo', `----------------------------------`);
|
|
200
|
+
|
|
201
|
+
//denon client
|
|
202
|
+
this.openWrt.on('systemInfo', (info) => {
|
|
203
|
+
this.informationService?.updateCharacteristic(Characteristic.FirmwareRevision, info.release?.version);
|
|
204
|
+
})
|
|
205
|
+
.on('wirelessStatus', async (status) => {
|
|
206
|
+
})
|
|
207
|
+
.on('wirelessRadios', async (radios) => {
|
|
208
|
+
})
|
|
209
|
+
.on('ssids', async (ssids) => {
|
|
210
|
+
// sensors
|
|
211
|
+
for (let i = 0; i < ssids.length; i++) {
|
|
212
|
+
const ssid = ssids[i];
|
|
213
|
+
|
|
214
|
+
const name = ssid[i].name;
|
|
215
|
+
const state = ssid[i].state;
|
|
216
|
+
const serviceName = this.accessPoint.namePrefix ? `${this.name} ${name}` : name;
|
|
217
|
+
this.services?.[i]
|
|
218
|
+
?.setCharacteristic(Characteristic.ConfiguredName, serviceName)
|
|
219
|
+
.updateCharacteristic(Characteristic.On, state);
|
|
220
|
+
|
|
221
|
+
this.sensorServices?.[i]
|
|
222
|
+
?.setCharacteristic(Characteristic.ConfiguredName, name)
|
|
223
|
+
.updateCharacteristic(Characteristic.ContactSensorState, state ? 0 : 1);
|
|
224
|
+
|
|
225
|
+
if (this.logInfo) {
|
|
226
|
+
this.emit('info', `SSID name: ${ssid.name}`);
|
|
227
|
+
this.emit('info', `Name: ${ssid.state}`);
|
|
228
|
+
this.emit('info', `Mode: ${ssid.mode}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
.on('restFul', (path, data) => {
|
|
233
|
+
if (this.restFulConnected) this.restFul1.update(path, data);
|
|
234
|
+
})
|
|
235
|
+
.on('mqtt', (topic, message) => {
|
|
236
|
+
if (this.mqttConnected) this.mqtt1.emit('publish', topic, message);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
//prepare accessory
|
|
240
|
+
const accessory = await this.prepareAccessory();
|
|
241
|
+
return accessory;
|
|
242
|
+
} catch (error) {
|
|
243
|
+
throw new Error(`Start error: ${error}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
export default SwitchDevice;
|