homebridge-openwrt-control 0.0.2-beta.2 → 0.0.2-beta.20

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",
@@ -111,7 +111,7 @@
111
111
  "placeholder": "Name",
112
112
  "description": "Here set the Name to be displayed in Homebridge/HomeKit for this access point.",
113
113
  "condition": {
114
- "functionBody": "return model.devices[arrayIndices[0]].accessPoint.enable === true;"
114
+ "functionBody": "return model.devices[arrayIndices].accessPoint.enable === true;"
115
115
  }
116
116
  },
117
117
  "namePrefix": {
@@ -119,13 +119,13 @@
119
119
  "type": "boolean",
120
120
  "description": "Here enable/disable the accessory name as a prefix for the access point name.",
121
121
  "condition": {
122
- "functionBody": "return model.devices[arrayIndices[0]].accessPoint.enable === true;"
122
+ "functionBody": "return model.devices[arrayIndices].accessPoint.enable === true;"
123
123
  }
124
124
  },
125
125
  "sensor": {
126
- "title": "Enable",
126
+ "title": "Sensor",
127
127
  "type": "boolean",
128
- "description": "Here Enable/Disable sensor for every ssid.",
128
+ "description": "Here Enable/Disable sensor for every SSID.",
129
129
  "condition": {
130
130
  "functionBody": "return model.devices[arrayIndices].accessPoint.enable === true;"
131
131
  }
package/index.js CHANGED
@@ -26,34 +26,34 @@ class OpenWrtPlatform {
26
26
  }
27
27
 
28
28
  api.on('didFinishLaunching', async () => {
29
- for (const config of config.devices) {
30
- const { name, host, port, displayType } = config;
31
- if (!name || !host || !port || !displayType) {
32
- log.warn(`Device: ${host || 'host missing'}, ${name || 'name missing'}, ${port || 'port missing'}${!displayType ? ', disply type disabled' : ''} in config, will not be published in the Home app`);
29
+ for (const deviceConfig of config.devices) {
30
+ const { name, host, displayType } = deviceConfig;
31
+ 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`);
33
33
  continue;
34
34
  }
35
35
 
36
36
  //log config
37
37
  const logLevel = {
38
- devInfo: config.log?.deviceInfo,
39
- success: config.log?.success,
40
- info: config.log?.info,
41
- warn: config.log?.warn,
42
- error: config.log?.error,
43
- debug: config.log?.debug
38
+ devInfo: deviceConfig.log?.deviceInfo,
39
+ success: deviceConfig.log?.success,
40
+ info: deviceConfig.log?.info,
41
+ warn: deviceConfig.log?.warn,
42
+ error: deviceConfig.log?.error,
43
+ debug: deviceConfig.log?.debug
44
44
  };
45
45
 
46
46
  if (logLevel.debug) {
47
47
  log.info(`Device: ${host} ${name}, did finish launching.`);
48
48
  const safeConfig = {
49
- ...config,
49
+ ...deviceConfig,
50
50
  auth: {
51
- ...config.auth,
51
+ ...deviceConfig.auth,
52
52
  passwd: 'removed',
53
53
  },
54
54
  mqtt: {
55
55
  auth: {
56
- ...config.mqtt?.auth,
56
+ ...deviceConfig.mqtt?.auth,
57
57
  passwd: 'removed',
58
58
  }
59
59
  },
@@ -61,13 +61,13 @@ class OpenWrtPlatform {
61
61
  log.info(`Device: ${host} ${name}, Config: ${JSON.stringify(safeConfig, null, 2)}`);
62
62
  }
63
63
 
64
- const refreshInterval = (config.refreshInterval ?? 5) * 1000;
65
- if (config.accessPoint?.enable) this.devices.push('accessPoint');
66
- if (config.switch?.enable) this.devices.push('switch');
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');
67
67
 
68
68
  if (this.devices.length === 0) return;
69
69
 
70
- const openWrt = new OpenWrt(config)
70
+ const openWrt = new OpenWrt(deviceConfig)
71
71
  .on('success', msg => logLevel.success && log.success(`Device: ${host}, ${msg}`))
72
72
  .on('info', msg => log.info(`Device: ${host}, ${msg}`))
73
73
  .on('debug', msg => log.info(`Device: ${host}, debug: ${msg}`))
@@ -90,8 +90,8 @@ class OpenWrtPlatform {
90
90
  // create device instance
91
91
  let type;
92
92
  switch (device) {
93
- case 'accessPoint': type = new AccessPoint(api, config, openWrt, openWrtInfo); break;
94
- case 'switch': type = new Switch(api, config, openWrt, openWrtInfo); break;
93
+ case 'accessPoint': type = new AccessPoint(api, deviceConfig, openWrt, openWrtInfo); break;
94
+ case 'switch': type = new Switch(api, deviceConfig, openWrt, openWrtInfo); break;
95
95
  default:
96
96
  if (logLevel.warn) log.warn(`Device: ${host} ${name}, unknown device: ${device}`);
97
97
  return;
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.2",
4
+ "version": "0.0.2-beta.20",
5
5
  "description": "Homebridge plugin to control OpenWrt flashed devices.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
package/src/functions.js CHANGED
@@ -1,6 +1,4 @@
1
1
  import { promises as fsPromises } from 'fs';
2
- import { DiacriticsMap } from './constants.js';
3
-
4
2
  class Functions {
5
3
  constructor() {
6
4
  }
@@ -45,28 +43,6 @@ class Functions {
45
43
  }
46
44
  }
47
45
 
48
- async sanitizeString(str) {
49
- if (!str) return '';
50
-
51
- // Replace diacritics using map
52
- str = str.replace(/[^\u0000-\u007E]/g, ch => DiacriticsMap[ch] || ch);
53
-
54
- // Replace separators between words with space
55
- str = str.replace(/(\w)[.:;+\-\/]+(\w)/g, '$1 $2');
56
-
57
- // Replace remaining standalone separators with space
58
- str = str.replace(/[.:;+\-\/]/g, ' ');
59
-
60
- // Remove remaining invalid characters (keep letters, digits, space, apostrophe)
61
- str = str.replace(/[^A-Za-z0-9 ']/g, ' ');
62
-
63
- // Collapse multiple spaces
64
- str = str.replace(/\s+/g, ' ');
65
-
66
- // Trim
67
- return str.trim();
68
- }
69
-
70
46
  async findIfaceBySsid(status, targetSsid) {
71
47
  for (const radio of Object.values(status.radios)) {
72
48
  for (const iface of Object.values(radio.interfaces)) {
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,52 +59,54 @@ 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
+ this.emit('debug', `Login: ${this.user} ${this.passwd}`)
63
+ const response = await this.axiosInstance.post('', {
64
+ jsonrpc: '2.0',
67
65
  id: 1,
68
- method: "call",
69
- params: ["00000000000000000000000000000000", "session", "login", { username: this.user, password: this.passwd }]
66
+ method: 'call',
67
+ params: ['00000000000000000000000000000000', 'session', 'login', { username: this.user, password: this.passwd }]
70
68
  });
71
69
 
72
70
  const result = response.data?.result?.[1];
73
71
  if (!result?.ubus_rpc_session) {
74
- throw new Error("ubus login failed");
72
+ throw new Error('ubus login failed');
75
73
  }
76
74
 
77
75
  this.sessionId = result.ubus_rpc_session;
78
76
  this.sessionExpiresAt = now + 240_000;
79
77
 
80
- if (this.logDebug) this.emit("debug", `Ubus login OK`);
78
+ if (this.logDebug) this.emit('debug', `Ubus login OK`);
81
79
  return this.sessionId;
82
80
  }
83
81
 
84
82
  async ubusCall(service, method, params = {}) {
85
83
  const session = await this.login();
86
84
 
87
- const response = await this.axiosInstance.post("", {
88
- jsonrpc: "2.0",
85
+ const response = await this.axiosInstance.post('', {
86
+ jsonrpc: '2.0',
89
87
  id: 2,
90
- method: "call",
88
+ method: 'call',
91
89
  params: [session, service, method, params]
92
90
  });
93
91
 
94
92
  if (response.data?.error) {
95
- throw new Error(response.data.error.message || "ubus call error");
93
+ throw new Error(response.data.error.message || 'ubus call error');
96
94
  }
97
95
 
98
96
  return response.data.result[1];
99
97
  }
100
98
 
101
99
  async connect() {
100
+ const openWrtInfo = { state: false, systemInfo: {}, wirelessStatus: {}, wirelessRadios: [], ssids: [] }
101
+
102
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)}`);
103
+ const systemInfo = await this.ubusCall('system', 'board');
104
+ if (this.logDebug) this.emit('debug', `System info data: ${JSON.stringify(systemInfo, null, 2)}`);
106
105
 
107
- const wirelessStatus = await this.ubusCall("network.wireless", "status");
108
- if (this.logDebug) this.emit("debug", `Wireless status data: ${JSON.stringify(wirelessStatus, null, 2)}`);
106
+ const wirelessStatus = await this.ubusCall('network.wireless', 'status');
107
+ if (this.logDebug) this.emit('debug', `Wireless status data: ${JSON.stringify(wirelessStatus, null, 2)}`);
109
108
 
110
- const wirelessRadios = Object.values(status.radios).map(radio => ({
109
+ const wirelessRadios = Object.values(wirelessStatus.radios).map(radio => ({
111
110
  name: radio.name,
112
111
  state: radio.up === true,
113
112
  interfaces: Object.values(radio.interfaces).map(i => ({
@@ -118,13 +117,13 @@ class OpenWrt extends EventEmitter {
118
117
  }));
119
118
 
120
119
  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);
120
+ this.emit('systemInfo', systemInfo);
121
+ this.emit('wirelessStatus', wirelessStatus);
122
+ this.emit('wirelessRadios', wirelessRadios);
123
+ this.emit('ssids', ssids);
125
124
 
126
125
  if (this.firstRun) {
127
- this.emit("success", `Connect success`);
126
+ this.emit('success', `Connect success`);
128
127
  this.firstRun = false;
129
128
  }
130
129
 
@@ -134,11 +133,11 @@ class OpenWrt extends EventEmitter {
134
133
  openWrtInfo.wirelessRadios = wirelessRadios;
135
134
  openWrtInfo.ssids = ssids;
136
135
 
137
- if (this.logDebug) this.emit("debug", `OpenWrt Data: ${JSON.stringify(openWrtInfo, null, 2)}`);
136
+ if (this.logDebug) this.emit('debug', `OpenWrt Data: ${JSON.stringify(openWrtInfo, null, 2)}`);
138
137
  return openWrtInfo;
139
138
  } catch (error) {
140
- if (this.logError) this.emit("error", `Connect error: ${error.message}`);
141
- return null;
139
+ if (this.logError) this.emit('error', `Connect error: ${error.message}`);
140
+ return openWrtInfo;
142
141
  }
143
142
  }
144
143
 
@@ -146,29 +145,29 @@ class OpenWrt extends EventEmitter {
146
145
  switch (type) {
147
146
  case 'ssid':
148
147
  await this.handleWithLock(async () => {
149
- if (this.logDebug) this.emit("debug", `${state ? "Enabling" : "Disabling"} SSID ${ssidName}`);
148
+ if (this.logDebug) this.emit('debug', `${state ? 'Enabling' : 'Disabling'} SSID ${ssidName}`);
150
149
 
151
- const status = await this.ubusCall("network.wireless", "status");
150
+ const status = await this.ubusCall('network.wireless', 'status');
152
151
  const iface = await this.functions.findIfaceBySsid(status, ssidName);
153
152
  if (!iface) throw new Error(`SSID ${ssidName} not found`);
154
153
 
155
154
  const section = iface.section;
156
155
  if (!section) throw new Error(`No UCI section for SSID ${ssidName}`);
157
156
 
158
- await this.ubusCall("uci", "set",
157
+ await this.ubusCall('uci', 'set',
159
158
  {
160
- config: "wireless",
159
+ config: 'wireless',
161
160
  section: section,
162
161
  values: {
163
- disabled: state ? "0" : "1"
162
+ disabled: state ? '0' : '1'
164
163
  }
165
164
  }
166
165
  );
167
166
 
168
- await this.ubusCall("uci", "commit", { config: "wireless" });
169
- await this.ubusCall("network.wireless", "reload", {});
167
+ await this.ubusCall('uci', 'commit', { config: 'wireless' });
168
+ await this.ubusCall('network.wireless', 'reload', {});
170
169
 
171
- if (this.logDebug) this.emit("debug", `Send SSID ${ssidName} ${state ? "enabled" : "disabled"}`);
170
+ if (this.logDebug) this.emit('debug', `Send SSID ${ssidName} ${state ? 'enabled' : 'disabled'}`);
172
171
  });
173
172
  break;
174
173
  case 'switch':