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.
@@ -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;