homebridge-openwrt-control 0.0.2-beta.5 → 0.0.2-beta.50

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.
@@ -4,7 +4,7 @@
4
4
  "singular": true,
5
5
  "fixArrays": true,
6
6
  "strictValidation": true,
7
- "headerDisplay": "This plugin works with OpenWrt Devices based on Dashboard API. Devices are exposed to HomeKit as separate accessories and each needs to be manually paired.",
7
+ "headerDisplay": "This plugin works with OpenWrt flashed devices. Devices are exposed to HomeKit as separate accessories and each needs to be manually paired.",
8
8
  "footerDisplay": "For documentation please see [GitHub repository](https://github.com/grzegorz914/homebridge-openwrt-control).",
9
9
  "schema": {
10
10
  "type": "object",
@@ -13,7 +13,7 @@
13
13
  "type": "array",
14
14
  "items": {
15
15
  "type": "object",
16
- "title": "Network",
16
+ "title": "Device",
17
17
  "properties": {
18
18
  "name": {
19
19
  "title": "Name",
package/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { join } from 'path';
2
2
  import { mkdirSync, existsSync, writeFileSync } from 'fs';
3
3
  import OpenWrt from './src/openwrt.js';
4
- import AccessPoint from './src/apdevice.js';
5
- import Switch from './src/swdevice.js';
4
+ import AccessPoint from './src/accesspoint.js';
5
+ import Switch from './src/switch.js';
6
6
  import ImpulseGenerator from './src/impulsegenerator.js';
7
7
  import { PluginName, PlatformName } from './src/constants.js';
8
8
 
@@ -14,7 +14,6 @@ class OpenWrtPlatform {
14
14
  return;
15
15
  }
16
16
  this.accessories = [];
17
- this.devices = [];
18
17
 
19
18
  //check if prefs directory exist
20
19
  const prefDir = join(api.user.storagePath(), 'openWrt');
@@ -27,9 +26,9 @@ class OpenWrtPlatform {
27
26
 
28
27
  api.on('didFinishLaunching', async () => {
29
28
  for (const deviceConfig of config.devices) {
30
- const { name, host, port, displayType } =deviceConfig;
29
+ const { name, host, displayType } = deviceConfig;
31
30
  if (!name || !host || !displayType) {
32
- log.warn(`Device: ${host || 'host missing'}, ${name || 'name missing'}, ${!displayType ? ', disply type disabled' : ''} in config, will not be published in the Home app`);
31
+ log.warn(`Device: ${host || 'host missing'}, ${name || 'name missing'}, ${!displayType ? ', display type disabled' : ''} in config, will not be published in the Home app`);
33
32
  continue;
34
33
  }
35
34
 
@@ -61,43 +60,46 @@ class OpenWrtPlatform {
61
60
  log.info(`Device: ${host} ${name}, Config: ${JSON.stringify(safeConfig, null, 2)}`);
62
61
  }
63
62
 
64
- const refreshInterval = (deviceConfig.refreshInterval ?? 5) * 1000;
65
- if (deviceConfig.accessPoint?.enable) this.devices.push('accessPoint');
66
- if (deviceConfig.switch?.enable) this.devices.push('switch');
63
+ try {
67
64
 
68
- if (this.devices.length === 0) return;
65
+ // create impulse generator for every device
66
+ const impulseGenerator = new ImpulseGenerator()
67
+ .on('start', async () => {
68
+ try {
69
+
70
+ let openWrt = new OpenWrt(deviceConfig)
71
+ .on('success', msg => logLevel.success && log.success(`Device: ${host}, ${msg}`))
72
+ .on('info', msg => log.info(`Device: ${host} ${name}, ${msg}`))
73
+ .on('debug', msg => log.info(`Device: ${host} ${name}, debug: ${msg}`))
74
+ .on('warn', msg => log.warn(`Device: ${host} ${name}, ${msg}`))
75
+ .on('error', msg => log.error(`Device: ${host} ${name}, ${msg}`))
76
+
77
+ const openWrtInfo = await openWrt.connect();
78
+ if (!openWrtInfo.state) {
79
+ if (logLevel.warn) log.warn(`Device: ${host} ${name}, no data received`);
80
+ return;
81
+ }
69
82
 
70
- const openWrt = new OpenWrt(deviceConfig)
71
- .on('success', msg => logLevel.success && log.success(`Device: ${host}, ${msg}`))
72
- .on('info', msg => log.info(`Device: ${host}, ${msg}`))
73
- .on('debug', msg => log.info(`Device: ${host}, debug: ${msg}`))
74
- .on('warn', msg => log.warn(`Device: ${host}, ${msg}`))
75
- .on('error', msg => log.error(`Device: ${host}, ${msg}`))
83
+ // start openwrt impulse generator
84
+ const refreshInterval = (deviceConfig.refreshInterval ?? 5) * 1000;
85
+ await openWrt.impulseGenerator.state(true, [{ name: 'connect', sampling: refreshInterval }], false);
76
86
 
77
- const openWrtInfo = await openWrt.connect();
78
- if (!openWrtInfo.state) {
79
- if (logLevel.warn) log.warn(`Device: ${host} ${name}, no data received`);
80
- return;
81
- }
87
+ const configuredDevices = [];
88
+ if (deviceConfig.accessPoint?.enable) configuredDevices.push('accessPoint');
89
+ if (deviceConfig.switch?.enable) configuredDevices.push('switch');
90
+ if (configuredDevices.length === 0) return;
82
91
 
83
- try {
84
- for (const device of this.devices) {
85
- // create impulse generator
86
- const impulseGenerator = new ImpulseGenerator()
87
- .on('start', async () => {
88
- try {
89
-
90
- // create device instance
91
- let type;
92
- switch (device) {
93
- case 'accessPoint': type = new AccessPoint(api, deviceConfig, openWrt, openWrtInfo); break;
94
- case 'switch': type = new Switch(api, deviceConfig, openWrt, openWrtInfo); break;
95
- default:
96
- if (logLevel.warn) log.warn(`Device: ${host} ${name}, unknown device: ${device}`);
97
- return;
92
+ for (const device of configuredDevices) {
93
+ // create device clases
94
+ const DeviceClasses = { accessPoint: AccessPoint, switch: Switch };
95
+ const DeviceClass = DeviceClasses[device];
96
+
97
+ if (!DeviceClass) {
98
+ if (logLevel.warn) log.warn(`Device: ${host} ${name}, class not found for: ${device}`);
99
+ continue;
98
100
  }
99
101
 
100
- type
102
+ const type = new DeviceClass(api, deviceConfig, openWrt, openWrtInfo)
101
103
  .on('devInfo', msg => logLevel.devInfo && log.info(msg))
102
104
  .on('success', msg => logLevel.success && log.success(`Device: ${host} ${name}, ${msg}`))
103
105
  .on('info', msg => log.info(`Device: ${host} ${name}, ${msg}`))
@@ -110,23 +112,21 @@ class OpenWrtPlatform {
110
112
  api.publishExternalAccessories(PluginName, [accessory]);
111
113
  if (logLevel.success) log.success(`Device: ${host} ${name}, Published as external accessory.`);
112
114
  }
113
-
114
- // stop master impulse generator
115
- await impulseGenerator.state(false);
116
- } catch (error) {
117
- if (logLevel.error) log.error(`Device: ${host} ${name}, Start impulse generator error: ${error.message ?? error}, trying again.`);
118
115
  }
119
- })
120
- .on('state', (state) => {
121
- if (logLevel.debug) log.info(`Device: ${host} ${name}, Start impulse generator ${state ? 'started' : 'stopped'}.`);
122
- });
123
116
 
124
- // start impulse generator
125
- await impulseGenerator.state(true, [{ name: 'start', sampling: 120000 }]);
126
- }
117
+ // stop accessory impulse generator
118
+ await impulseGenerator.state(false);
119
+ } catch (error) {
120
+ if (logLevel.error) log.error(`Device: ${host} ${name}, Start impulse generator error: ${error.message ?? error}, trying again.`);
121
+ }
122
+ })
123
+ .on('state', (state) => {
124
+ if (logLevel.debug) log.info(`Device: ${host} ${name}, Start impulse generator ${state ? 'started' : 'stopped'}.`);
125
+ });
126
+
127
+ // start accessory impulse generator
128
+ await impulseGenerator.state(true, [{ name: 'start', sampling: 120000 }]);
127
129
 
128
- // start openwrt impulse generator
129
- await openWrt.impulseGenerator.state(true, [{ name: 'connect', sampling: refreshInterval }], false);
130
130
  } catch (error) {
131
131
  if (logLevel.error) log.error(`Device: ${host} ${name}, Did finish launching error: ${error.message ?? error}`);
132
132
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "OpenWrt Control",
3
3
  "name": "homebridge-openwrt-control",
4
- "version": "0.0.2-beta.5",
4
+ "version": "0.0.2-beta.50",
5
5
  "description": "Homebridge plugin to control OpenWrt flashed devices.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
@@ -1,7 +1,7 @@
1
1
  import EventEmitter from 'events';
2
2
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
3
3
 
4
- class AccessPointDevice extends EventEmitter {
4
+ class AccessPoint extends EventEmitter {
5
5
  constructor(api, config, openWrt, openWrtInfo) {
6
6
  super();
7
7
 
@@ -12,8 +12,10 @@ class AccessPointDevice extends EventEmitter {
12
12
  AccessoryUUID = api.hap.uuid;
13
13
 
14
14
  //config
15
- this.name = config.accessPoint.name || openWrtInfo.systemInfo.hostname;
16
- this.accessPoint = config.accessPoint;
15
+ this.host = config.host;
16
+ this.name = config.accessPoint?.name || openWrtInfo.systemInfo.hostname;
17
+ this.namePrefix = config.accessPoint?.namePrefix || false;
18
+ this.sensorsEnabled = config.accessPoint?.sensor || false
17
19
  this.logInfo = config.log?.info || false;
18
20
  this.logDebug = config.log?.debug || false;
19
21
 
@@ -27,6 +29,48 @@ class AccessPointDevice extends EventEmitter {
27
29
  this.openWrt = openWrt;
28
30
  this.openWrtInfo = openWrtInfo;
29
31
  this.ssids = openWrtInfo.ssids;
32
+
33
+ //openwrt client
34
+ this.openWrt.on('systemInfo', (info) => {
35
+ this.informationService?.updateCharacteristic(Characteristic.FirmwareRevision, info.release?.version);
36
+ })
37
+ .on('networkInfo', async (info) => {
38
+ })
39
+ .on('wirelessStatus', async (status) => {
40
+ })
41
+ .on('wirelessRadios', async (radios) => {
42
+ })
43
+ .on('ssids', async (ssids) => {
44
+ this.ssids = ssids;
45
+
46
+ // sensors
47
+ for (let i = 0; i < ssids.length; i++) {
48
+ const ssid = ssids[i];
49
+ const name = ssid.name;
50
+ const state = ssid.state;
51
+ const serviceName = this.namePrefix ? `${this.name} ${name}` : name;
52
+ this.services?.[i]
53
+ ?.setCharacteristic(Characteristic.ConfiguredName, serviceName)
54
+ .updateCharacteristic(Characteristic.On, state);
55
+
56
+ this.sensorServices?.[i]
57
+ ?.setCharacteristic(Characteristic.ConfiguredName, serviceName)
58
+ .updateCharacteristic(Characteristic.ContactSensorState, !state);
59
+
60
+ if (this.logInfo) {
61
+ this.emit('info', `Name: ${ssid.name}`);
62
+ this.emit('info', `State: ${ssid.state}`);
63
+ this.emit('info', `Mode: ${ssid.mode}`);
64
+ }
65
+ }
66
+ })
67
+ .on('restFul', (path, data) => {
68
+ if (this.restFulConnected) this.restFul1.update(path, data);
69
+ })
70
+ .on('mqtt', (topic, message) => {
71
+ if (this.mqttConnected) this.mqtt1.emit('publish', topic, message);
72
+ });
73
+
30
74
  };
31
75
 
32
76
  async externalIntegrations() {
@@ -65,8 +109,8 @@ class AccessPointDevice extends EventEmitter {
65
109
  this.mqtt1 = new Mqtt({
66
110
  host: this.mqtt.host,
67
111
  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}`,
112
+ clientId: this.mqtt.clientId ? `${this.openWrtInfo.systemInfo.release.distribution || 'OpenWrt'}_${this.mqtt.clientId}_${Math.random().toString(16).slice(3)}` : `${this.openWrtInfo.systemInfo.release.distribution || 'OpenWrt'}_${Math.random().toString(16).slice(3)}`,
113
+ prefix: this.mqtt.prefix ? `${this.openWrtInfo.systemInfo.release.distribution || 'OpenWrt'}/${this.mqtt.prefix}/${this.name}` : `${this.openWrtInfo.systemInfo.release.distribution || 'OpenWrt'}/${this.name}`,
70
114
  user: this.mqtt.auth?.user,
71
115
  passwd: this.mqtt.auth?.passwd,
72
116
  logWarn: this.logWarn,
@@ -121,28 +165,28 @@ class AccessPointDevice extends EventEmitter {
121
165
  //prepare accessory
122
166
  if (this.logDebug) this.emit('debug', `prepare accessory`);
123
167
  const accessoryName = this.name;
124
- const accessoryUUID = AccessoryUUID.generate(this.openWrtInfo.systemInfo.hostname);
168
+ const accessoryUUID = AccessoryUUID.generate(this.host + this.openWrtInfo.systemInfo.system);
125
169
  const accessoryCategory = Categories.AIRPORT;
126
170
  const accessory = new Accessory(accessoryName, accessoryUUID, accessoryCategory);
127
171
 
128
172
  //prepare information service
129
173
  if (this.logDebug) this.emit('debug', `prepare information service`);
130
- accessory.getService(Service.AccessoryInformation)
131
- .setCharacteristic(Characteristic.Manufacturer, 'OpenWrt')
174
+ this.informationService = accessory.getService(Service.AccessoryInformation)
175
+ .setCharacteristic(Characteristic.Manufacturer, this.openWrtInfo.systemInfo.release.distribution || 'OpenWrt')
132
176
  .setCharacteristic(Characteristic.Model, this.openWrtInfo.systemInfo.model)
133
177
  .setCharacteristic(Characteristic.SerialNumber, this.openWrtInfo.systemInfo.system)
134
- .setCharacteristic(Characteristic.FirmwareRevision, this.openWrtInfo.systemInfo.release?.description)
135
- .setCharacteristic(Characteristic.ConfiguredName, accessoryName);
178
+ .setCharacteristic(Characteristic.FirmwareRevision, this.openWrtInfo.systemInfo.release?.version);
136
179
 
137
180
  if (this.logDebug) this.emit('debug', `prepare service`);
138
181
 
139
- //device
182
+ //services
140
183
  this.services = [];
184
+ this.sensorServices = [];
141
185
  for (const ssid of this.ssids) {
142
186
  const name = ssid.name;
143
187
  if (this.logDebug) this.emit('debug', `prepare ssid: ${name} service`);
144
188
 
145
- const serviceName = this.accessPoint.namePrefix ? `${accessoryName} ${name}` : name;
189
+ const serviceName = this.namePrefix ? `${accessoryName} ${name}` : name;
146
190
  const service = accessory.addService(Service.Switch, serviceName, `service${name}`);
147
191
  service.addOptionalCharacteristic(Characteristic.ConfiguredName);
148
192
  service.setCharacteristic(Characteristic.ConfiguredName, serviceName);
@@ -163,10 +207,8 @@ class AccessPointDevice extends EventEmitter {
163
207
  });
164
208
  this.services.push(service);
165
209
 
166
- if (this.accessPoint.sensor) {
210
+ if (this.sensorsEnabled) {
167
211
  if (this.logDebug) this.emit('debug', `prepare ssid: ${name} sensor service`);
168
-
169
- this.sensorServices = [];
170
212
  const sensorService = accessory.addService(Service.ContactSensor, serviceName, `sensorService${name}`);
171
213
  sensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
172
214
  sensorService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
@@ -192,50 +234,14 @@ class AccessPointDevice extends EventEmitter {
192
234
  if (this.restFul.enable || this.mqtt.enable) await this.externalIntegrations();
193
235
 
194
236
  this.emit('devInfo', `-------- Access Point ${this.name} --------`);
195
- this.emit('devInfo', `Name: ${this.openWrtInfo.systemInfo.hostname}`);
196
- this.emit('devInfo', `Model: ${this.openWrtInfo.systemInfo.model}`);
237
+ this.emit('devInfo', `Model: ${this.openWrtInfo.systemInfo.model || this.openWrtInfo.systemInfo.board_name}`);
197
238
  this.emit('devInfo', `System: ${this.openWrtInfo.systemInfo.system}`);
239
+ this.emit('devInfo', `Kernel: ${this.openWrtInfo.systemInfo.kernel}`);
198
240
  this.emit('devInfo', `Firmware: ${this.openWrtInfo.systemInfo.release?.description}`);
241
+ this.emit('devInfo', `Target: ${this.openWrtInfo.systemInfo.release?.target}`);
242
+ this.emit('devInfo', `SSIDs: ${this.ssids.length}`);
199
243
  this.emit('devInfo', `----------------------------------`);
200
244
 
201
- //openwrt client
202
- this.openWrt.on('systemInfo', (info) => {
203
- this.informationService?.updateCharacteristic(Characteristic.FirmwareRevision, info.release?.description);
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
245
  //prepare accessory
240
246
  const accessory = await this.prepareAccessory();
241
247
  return accessory;
@@ -244,4 +250,4 @@ class AccessPointDevice extends EventEmitter {
244
250
  }
245
251
  }
246
252
  };
247
- export default AccessPointDevice;
253
+ export default AccessPoint;
package/src/openwrt.js CHANGED
@@ -1,16 +1,14 @@
1
- import EventEmitter from "events";
2
- import axios from "axios";
1
+ import EventEmitter from 'events';
2
+ import axios from 'axios';
3
3
  import Functions from './functions.js';
4
- import ImpulseGenerator from "./impulsegenerator.js";
4
+ import ImpulseGenerator from './impulsegenerator.js';
5
5
 
6
6
  class OpenWrt extends EventEmitter {
7
7
  constructor(config) {
8
8
  super();
9
9
 
10
- this.name = config.name;
11
- this.host = config.host;
12
- this.user = config.user;
13
- this.passwd = config.passwd;
10
+ this.user = config.auth?.user || 'root';
11
+ this.passwd = config.auth?.passwd;
14
12
  this.logError = config.log?.error;
15
13
  this.logDebug = config.log?.debug;
16
14
 
@@ -26,7 +24,7 @@ class OpenWrt extends EventEmitter {
26
24
 
27
25
  this.functions = new Functions();
28
26
  this.axiosInstance = axios.create({
29
- baseURL: `${config.host}/ubus`,
27
+ baseURL: `http://${config.host}/ubus`,
30
28
  timeout: 5000,
31
29
  headers: {
32
30
  "Content-Type": "application/json"
@@ -34,11 +32,11 @@ class OpenWrt extends EventEmitter {
34
32
  });
35
33
 
36
34
  this.impulseGenerator = new ImpulseGenerator()
37
- .on("connect", () => this.handleWithLock(async () => {
35
+ .on('connect', () => this.handleWithLock(async () => {
38
36
  await this.connect();
39
37
  }))
40
- .on("state", (state) => {
41
- this.emit(state ? "success" : "warn", `Impulse generator ${state ? "started" : "stopped"}`);
38
+ .on('state', (state) => {
39
+ this.emit(state ? 'success' : 'warn', `Impulse generator ${state ? 'started' : 'stopped'}`);
42
40
  });
43
41
  }
44
42
 
@@ -49,8 +47,7 @@ class OpenWrt extends EventEmitter {
49
47
  try {
50
48
  await fn();
51
49
  } catch (error) {
52
- this.emit("error", `Impulse generator error: ${error.message}`
53
- );
50
+ this.emit('error', `Impulse generator error: ${error.message}`);
54
51
  } finally {
55
52
  this.lock = false;
56
53
  }
@@ -62,83 +59,98 @@ class OpenWrt extends EventEmitter {
62
59
  return this.sessionId;
63
60
  }
64
61
 
65
- const response = await this.axiosInstance.post("", {
66
- jsonrpc: "2.0",
62
+ const response = await this.axiosInstance.post('', {
63
+ jsonrpc: '2.0',
67
64
  id: 1,
68
- method: "call",
69
- params: ["00000000000000000000000000000000", "session", "login", { username: this.user, password: this.passwd }]
65
+ method: 'call',
66
+ params: ['00000000000000000000000000000000', 'session', 'login', { username: this.user, password: this.passwd }]
70
67
  });
71
68
 
72
69
  const result = response.data?.result?.[1];
73
- if (!result?.ubus_rpc_session) {
74
- throw new Error("ubus login failed");
75
- }
70
+ if (!result?.ubus_rpc_session) throw new Error('Ubus login failed');
76
71
 
77
72
  this.sessionId = result.ubus_rpc_session;
78
73
  this.sessionExpiresAt = now + 240_000;
79
74
 
80
- if (this.logDebug) this.emit("debug", `Ubus login OK`);
75
+ if (this.logDebug) this.emit('debug', `Ubus login OK`);
81
76
  return this.sessionId;
82
77
  }
83
78
 
84
79
  async ubusCall(service, method, params = {}) {
85
80
  const session = await this.login();
86
-
87
- const response = await this.axiosInstance.post("", {
88
- jsonrpc: "2.0",
81
+ const response = await this.axiosInstance.post('', {
82
+ jsonrpc: '2.0',
89
83
  id: 2,
90
- method: "call",
84
+ method: 'call',
91
85
  params: [session, service, method, params]
92
86
  });
93
87
 
94
- if (response.data?.error) {
95
- throw new Error(response.data.error.message || "ubus call error");
96
- }
88
+ if (response.data?.error) throw new Error(response.data.error.message || 'Ubus call error');
97
89
 
98
90
  return response.data.result[1];
99
91
  }
100
92
 
101
93
  async connect() {
102
- try {
103
- const openWrtInfo = { state: false, systemInfo: {}, wirelessStatus: {}, wirelessRadios: [], ssids: [] }
104
- const systemInfo = await this.ubusCall("system", "board");
105
- if (this.logDebug) this.emit("debug", `System info data: ${JSON.stringify(systemInfo, null, 2)}`);
106
-
107
- const wirelessStatus = await this.ubusCall("network.wireless", "status");
108
- if (this.logDebug) this.emit("debug", `Wireless status data: ${JSON.stringify(wirelessStatus, null, 2)}`);
109
-
110
- const wirelessRadios = Object.values(status.radios).map(radio => ({
111
- name: radio.name,
112
- state: radio.up === true,
113
- interfaces: Object.values(radio.interfaces).map(i => ({
114
- name: i.ssid,
115
- state: i.up === true,
116
- mode: i.mode
117
- }))
118
- }));
119
-
120
- const ssids = wirelessRadios.flatMap(radio => radio.interfaces);
121
- this.emit("systemInfo", systemInfo);
122
- this.emit("wirelessStatus", wirelessStatus);
123
- this.emit("wirelessRadios", wirelessRadios);
124
- this.emit("ssids", ssids);
94
+ const openWrtInfo = { state: false, systemInfo: {}, networkInfo: {}, wirelessStatus: {}, wirelessRadios: [], ssids: [] }
125
95
 
126
- if (this.firstRun) {
127
- this.emit("success", `Connect success`);
128
- this.firstRun = false;
129
- }
96
+ try {
97
+ const systemInfo = await this.ubusCall('system', 'board');
98
+ if (this.logDebug) this.emit('debug', `System info data: ${JSON.stringify(systemInfo, null, 2)}`);
99
+
100
+ //const networkInfo = await this.ubusCall('network.device', 'status', '{ "name": "eth0" }');
101
+ //const networkInfo = await this.ubusCall('file', 'read', { path: '/sys/class/net/eth0/address' });
102
+ //if (this.logDebug) this.emit('debug', `Network info data: ${networkInfo}`);
103
+
104
+ //const wirelessStatus = await this.ubusCall('network.wireless', 'status');
105
+ const wirelessStatus = await this.ubusCall('uci', 'get', { config: 'wireless' });
106
+ if (this.logDebug) this.emit('debug', `Wireless status data: ${JSON.stringify(wirelessStatus, null, 2)}`);
107
+
108
+ //const wirelessRadios = Object.values(wirelessStatus.radios).map(radio => ({
109
+ //name: radio.name,
110
+ //state: radio.up === true,
111
+ //interfaces: Object.values(radio.interfaces).map(i => ({
112
+ //name: i.ssid,
113
+ //state: i.up === true,
114
+ //mode: i.mode
115
+ //}))
116
+ //}));
117
+
118
+ //const ssids = wirelessRadios.flatMap(radio => radio.interfaces);
119
+ const ssids = Object.entries(wirelessStatus.values || {}).flatMap(([key, data]) => {
120
+ if (!key.startsWith('wifinet')) return [];
121
+ return [{
122
+ ifname: data['.name'] || key,
123
+ name: data.ssid || null,
124
+ device: data.device || null,
125
+ mode: data.mode || null,
126
+ hidden: data.hidden === '1' || data.hidden === true,
127
+ state: true
128
+ }];
129
+ });
130
130
 
131
131
  openWrtInfo.state = true;
132
132
  openWrtInfo.systemInfo = systemInfo;
133
+ //openWrtInfo.networkInfo = networkInfo;
133
134
  openWrtInfo.wirelessStatus = wirelessStatus;
134
- openWrtInfo.wirelessRadios = wirelessRadios;
135
+ //openWrtInfo.wirelessRadios = wirelessRadios;
135
136
  openWrtInfo.ssids = ssids;
136
137
 
137
- if (this.logDebug) this.emit("debug", `OpenWrt Data: ${JSON.stringify(openWrtInfo, null, 2)}`);
138
+ if (this.firstRun) {
139
+ this.emit('success', `Connect success`);
140
+ this.firstRun = false;
141
+ }
142
+
143
+ // emit data
144
+ this.emit('systemInfo', systemInfo);
145
+ //this.emit('networkInfo', networkInfo);
146
+ this.emit('wirelessStatus', wirelessStatus);
147
+ //this.emit('wirelessRadios', wirelessRadios);
148
+ this.emit('ssids', ssids);
149
+
138
150
  return openWrtInfo;
139
151
  } catch (error) {
140
- if (this.logError) this.emit("error", `Connect error: ${error.message}`);
141
- return null;
152
+ if (this.logError) this.emit('error', `Connect error: ${error.message}`);
153
+ return openWrtInfo;
142
154
  }
143
155
  }
144
156
 
@@ -146,29 +158,29 @@ class OpenWrt extends EventEmitter {
146
158
  switch (type) {
147
159
  case 'ssid':
148
160
  await this.handleWithLock(async () => {
149
- if (this.logDebug) this.emit("debug", `${state ? "Enabling" : "Disabling"} SSID ${ssidName}`);
161
+ if (this.logDebug) this.emit('debug', `${state ? 'Enabling' : 'Disabling'} SSID ${ssidName}`);
150
162
 
151
- const status = await this.ubusCall("network.wireless", "status");
163
+ const status = await this.ubusCall('network.wireless', 'status');
152
164
  const iface = await this.functions.findIfaceBySsid(status, ssidName);
153
165
  if (!iface) throw new Error(`SSID ${ssidName} not found`);
154
166
 
155
167
  const section = iface.section;
156
168
  if (!section) throw new Error(`No UCI section for SSID ${ssidName}`);
157
169
 
158
- await this.ubusCall("uci", "set",
170
+ await this.ubusCall('uci', 'set',
159
171
  {
160
- config: "wireless",
172
+ config: 'wireless',
161
173
  section: section,
162
174
  values: {
163
- disabled: state ? "0" : "1"
175
+ disabled: state ? '0' : '1'
164
176
  }
165
177
  }
166
178
  );
167
179
 
168
- await this.ubusCall("uci", "commit", { config: "wireless" });
169
- await this.ubusCall("network.wireless", "reload", {});
180
+ await this.ubusCall('uci', 'commit', { config: 'wireless' });
181
+ await this.ubusCall('network.wireless', 'reload', {});
170
182
 
171
- if (this.logDebug) this.emit("debug", `Send SSID ${ssidName} ${state ? "enabled" : "disabled"}`);
183
+ if (this.logDebug) this.emit('debug', `Send SSID ${ssidName} ${state ? 'enabled' : 'disabled'}`);
172
184
  });
173
185
  break;
174
186
  case 'switch':
@@ -177,5 +189,4 @@ class OpenWrt extends EventEmitter {
177
189
  }
178
190
  }
179
191
 
180
- export default OpenWrt;
181
-
192
+ export default OpenWrt;
@@ -1,7 +1,7 @@
1
1
  import EventEmitter from 'events';
2
2
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
3
3
 
4
- class SwitchDevice extends EventEmitter {
4
+ class Switch extends EventEmitter {
5
5
  constructor(api, config, openWrt, openWrtInfo) {
6
6
  super();
7
7
 
@@ -12,8 +12,10 @@ class SwitchDevice extends EventEmitter {
12
12
  AccessoryUUID = api.hap.uuid;
13
13
 
14
14
  //config
15
- this.name = config.switch.name || openWrtInfo.systemInfo.hostname;
16
- this.switch = config.switch;
15
+ this.host = config.host;
16
+ this.name = config.accessPoint.name || openWrtInfo.systemInfo.hostname;
17
+ this.namePrefix = config.accessPoint?.namePrefix || false;
18
+ this.sensorsEnabled = config.accessPoint?.sensor || false
17
19
  this.logInfo = config.log?.info || false;
18
20
  this.logDebug = config.log?.debug || false;
19
21
 
@@ -27,6 +29,43 @@ class SwitchDevice extends EventEmitter {
27
29
  this.openWrt = openWrt;
28
30
  this.openWrtInfo = openWrtInfo;
29
31
  this.ssids = openWrtInfo.ssids;
32
+
33
+ //openwrt client
34
+ this.openWrt.on('systemInfo', (info) => {
35
+ this.informationService?.updateCharacteristic(Characteristic.FirmwareRevision, info.release?.version);
36
+ })
37
+ .on('networkInfo', async (info) => {
38
+ })
39
+ .on('ports', async (ports) => {
40
+ this.ports = ports;
41
+
42
+ // sensors
43
+ for (let i = 0; i < ports.length; i++) {
44
+ const port = ports[i];
45
+ const name = port.name;
46
+ const state = port.state;
47
+ const serviceName = this.namePrefix ? `${this.name} ${name}` : name;
48
+ this.services?.[i]
49
+ ?.setCharacteristic(Characteristic.ConfiguredName, serviceName)
50
+ .updateCharacteristic(Characteristic.On, state);
51
+
52
+ this.sensorServices?.[i]
53
+ ?.setCharacteristic(Characteristic.ConfiguredName, serviceName)
54
+ .updateCharacteristic(Characteristic.ContactSensorState, !state);
55
+
56
+ if (this.logInfo) {
57
+ this.emit('info', `Name: ${ports.name}`);
58
+ this.emit('info', `State: ${ports.state}`);
59
+ this.emit('info', `Mode: ${ports.mode}`);
60
+ }
61
+ }
62
+ })
63
+ .on('restFul', (path, data) => {
64
+ if (this.restFulConnected) this.restFul1.update(path, data);
65
+ })
66
+ .on('mqtt', (topic, message) => {
67
+ if (this.mqttConnected) this.mqtt1.emit('publish', topic, message);
68
+ });
30
69
  };
31
70
 
32
71
  async externalIntegrations() {
@@ -65,8 +104,8 @@ class SwitchDevice extends EventEmitter {
65
104
  this.mqtt1 = new Mqtt({
66
105
  host: this.mqtt.host,
67
106
  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}`,
107
+ clientId: this.mqtt.clientId ? `${this.openWrtInfo.systemInfo.release.distribution || 'OpenWrt'}_${this.mqtt.clientId}_${Math.random().toString(16).slice(3)}` : `${this.openWrtInfo.systemInfo.release.distribution || 'OpenWrt'}_${Math.random().toString(16).slice(3)}`,
108
+ prefix: this.mqtt.prefix ? `${this.openWrtInfo.systemInfo.release.distribution || 'OpenWrt'}/${this.mqtt.prefix}/${this.name}` : `${this.openWrtInfo.systemInfo.release.distribution || 'OpenWrt'}/${this.name}`,
70
109
  user: this.mqtt.auth?.user,
71
110
  passwd: this.mqtt.auth?.passwd,
72
111
  logWarn: this.logWarn,
@@ -121,29 +160,30 @@ class SwitchDevice extends EventEmitter {
121
160
  //prepare accessory
122
161
  if (this.logDebug) this.emit('debug', `prepare accessory`);
123
162
  const accessoryName = this.name;
124
- const accessoryUUID = AccessoryUUID.generate(this.openWrtInfo.systemInfo.hostname);
125
- const accessoryCategory = Categories.ROUTER;
163
+ const accessoryUUID = AccessoryUUID.generate(this.host + this.openWrtInfo.systemInfo.system);
164
+ const accessoryCategory = Categories.AIRPORT;
126
165
  const accessory = new Accessory(accessoryName, accessoryUUID, accessoryCategory);
127
166
 
128
167
  //prepare information service
129
168
  if (this.logDebug) this.emit('debug', `prepare information service`);
130
169
  accessory.getService(Service.AccessoryInformation)
131
- .setCharacteristic(Characteristic.Manufacturer, 'OpenWrt')
170
+ .setCharacteristic(Characteristic.Manufacturer, this.openWrtInfo.systemInfo.release.distribution || 'OpenWrt')
132
171
  .setCharacteristic(Characteristic.Model, this.openWrtInfo.systemInfo.model)
133
172
  .setCharacteristic(Characteristic.SerialNumber, this.openWrtInfo.systemInfo.system)
134
- .setCharacteristic(Characteristic.FirmwareRevision, this.openWrtInfo.systemInfo.release?.description)
173
+ .setCharacteristic(Characteristic.FirmwareRevision, this.openWrtInfo.systemInfo.release?.version)
135
174
  .setCharacteristic(Characteristic.ConfiguredName, accessoryName);
136
175
 
137
176
  if (this.logDebug) this.emit('debug', `prepare service`);
138
177
 
139
- //device
178
+ //services
140
179
  this.services = [];
180
+ this.sensorServices = [];
141
181
  for (const port of this.ports) {
142
182
  const name = port.name;
143
183
  if (this.logDebug) this.emit('debug', `prepare port: ${name} service`);
144
184
 
145
- const serviceName = this.accessPoint.namePrefix ? `${accessoryName} ${ssidName}` : ssidName;
146
- const service = accessory.addService(Service.Switch, serviceName, `service${ssidName}`);
185
+ const serviceName = this.namePrefix ? `${accessoryName} ${name}` : name;
186
+ const service = accessory.addService(Service.Switch, serviceName, `service${name}`);
147
187
  service.addOptionalCharacteristic(Characteristic.ConfiguredName);
148
188
  service.setCharacteristic(Characteristic.ConfiguredName, serviceName);
149
189
  service.getCharacteristic(Characteristic.On)
@@ -163,10 +203,9 @@ class SwitchDevice extends EventEmitter {
163
203
  });
164
204
  this.services.push(service);
165
205
 
166
- if (this.accessPoint.sensor) {
206
+ if (this.sensorsEnabled) {
167
207
  if (this.logDebug) this.emit('debug', `prepare port: ${name} sensor service`);
168
208
 
169
- this.sensorServices = [];
170
209
  const sensorService = accessory.addService(Service.ContactSensor, serviceName, `sensorService${name}`);
171
210
  sensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
172
211
  sensorService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
@@ -191,49 +230,15 @@ class SwitchDevice extends EventEmitter {
191
230
  //start external integrations
192
231
  if (this.restFul.enable || this.mqtt.enable) await this.externalIntegrations();
193
232
 
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}`);
233
+ this.emit('devInfo', `-------- Access Point ${this.name} --------`);
234
+ this.emit('devInfo', `Model: ${this.openWrtInfo.systemInfo.model || this.openWrtInfo.systemInfo.board_name}`);
197
235
  this.emit('devInfo', `System: ${this.openWrtInfo.systemInfo.system}`);
236
+ this.emit('devInfo', `Kernel: ${this.openWrtInfo.systemInfo.kernel}`);
198
237
  this.emit('devInfo', `Firmware: ${this.openWrtInfo.systemInfo.release?.description}`);
238
+ this.emit('devInfo', `Target: ${this.openWrtInfo.systemInfo.release?.target}`);
239
+ this.emit('devInfo', `Ports: ${this.ports.length}`);
199
240
  this.emit('devInfo', `----------------------------------`);
200
241
 
201
- //openwrt client
202
- this.openWrt.on('systemInfo', (info) => {
203
- this.informationService?.updateCharacteristic(Characteristic.FirmwareRevision, info.release?.description);
204
- })
205
- .on('switchStatus', async (status) => {
206
- })
207
- .on('switchPorts', async (ports) => {
208
- // sensors
209
- for (let i = 0; i < ports.length; i++) {
210
- const port = ports[i];
211
-
212
- const name = port[i].name;
213
- const state = port[i].state;
214
- const serviceName = this.accessPoint.namePrefix ? `${this.name} ${name}` : name;
215
- this.services?.[i]
216
- ?.setCharacteristic(Characteristic.ConfiguredName, serviceName)
217
- .updateCharacteristic(Characteristic.On, state);
218
-
219
- this.sensorServices?.[i]
220
- ?.setCharacteristic(Characteristic.ConfiguredName, name)
221
- .updateCharacteristic(Characteristic.ContactSensorState, state ? 0 : 1);
222
-
223
- if (this.logInfo) {
224
- this.emit('info', `Port name: ${port.name}`);
225
- this.emit('info', `Name: ${port.state}`);
226
- this.emit('info', `Mode: ${port.mode}`);
227
- }
228
- }
229
- })
230
- .on('restFul', (path, data) => {
231
- if (this.restFulConnected) this.restFul1.update(path, data);
232
- })
233
- .on('mqtt', (topic, message) => {
234
- if (this.mqttConnected) this.mqtt1.emit('publish', topic, message);
235
- });
236
-
237
242
  //prepare accessory
238
243
  const accessory = await this.prepareAccessory();
239
244
  return accessory;
@@ -242,4 +247,4 @@ class SwitchDevice extends EventEmitter {
242
247
  }
243
248
  }
244
249
  };
245
- export default SwitchDevice;
250
+ export default Switch;