homebridge-openwrt-control 0.0.2-beta.10 → 0.0.2-beta.13
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/config.schema.json +1 -1
- package/package.json +1 -1
- package/src/openwrt.js +92 -56
package/config.schema.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"singular": true,
|
|
5
5
|
"fixArrays": true,
|
|
6
6
|
"strictValidation": true,
|
|
7
|
-
"headerDisplay": "This plugin works with OpenWrt
|
|
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",
|
package/package.json
CHANGED
package/src/openwrt.js
CHANGED
|
@@ -1,76 +1,110 @@
|
|
|
1
|
-
import EventEmitter from
|
|
2
|
-
import
|
|
3
|
-
import Functions from
|
|
4
|
-
import ImpulseGenerator from
|
|
1
|
+
import EventEmitter from 'events';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import Functions from './functions.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.
|
|
11
|
-
this.
|
|
12
|
-
this.passwd = config.auth?.passwd || "";
|
|
13
|
-
|
|
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
|
|
|
15
|
+
//external integration
|
|
16
|
+
this.restFulEnabled = config.restFul?.enable || false;
|
|
17
|
+
this.mqttEnabled = config.mqtt?.enable || false;
|
|
18
|
+
|
|
17
19
|
this.firstRun = true;
|
|
18
20
|
this.lock = false;
|
|
19
21
|
|
|
22
|
+
this.sessionId = null;
|
|
23
|
+
this.sessionExpiresAt = 0;
|
|
24
|
+
|
|
20
25
|
this.functions = new Functions();
|
|
26
|
+
this.axiosInstance = axios.create({
|
|
27
|
+
baseURL: `http://${config.host}/ubus`,
|
|
28
|
+
timeout: 5000,
|
|
29
|
+
headers: {
|
|
30
|
+
"Content-Type": "application/json"
|
|
31
|
+
}
|
|
32
|
+
});
|
|
21
33
|
|
|
22
34
|
this.impulseGenerator = new ImpulseGenerator()
|
|
23
|
-
.on(
|
|
35
|
+
.on('connect', () => this.handleWithLock(async () => {
|
|
24
36
|
await this.connect();
|
|
25
37
|
}))
|
|
26
|
-
.on(
|
|
27
|
-
this.emit(state ?
|
|
38
|
+
.on('state', (state) => {
|
|
39
|
+
this.emit(state ? 'success' : 'warn', `Impulse generator ${state ? 'started' : 'stopped'}`);
|
|
28
40
|
});
|
|
29
41
|
}
|
|
30
42
|
|
|
31
43
|
async handleWithLock(fn) {
|
|
32
44
|
if (this.lock) return;
|
|
33
45
|
this.lock = true;
|
|
46
|
+
|
|
34
47
|
try {
|
|
35
48
|
await fn();
|
|
36
49
|
} catch (error) {
|
|
37
|
-
this.emit(
|
|
50
|
+
this.emit('error', `Impulse generator error: ${error.message}`
|
|
51
|
+
);
|
|
38
52
|
} finally {
|
|
39
53
|
this.lock = false;
|
|
40
54
|
}
|
|
41
55
|
}
|
|
42
56
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
});
|
|
57
|
+
async login() {
|
|
58
|
+
const now = Date.now();
|
|
59
|
+
if (this.sessionId && now < this.sessionExpiresAt) {
|
|
60
|
+
return this.sessionId;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const response = await this.axiosInstance.post('', {
|
|
64
|
+
jsonrpc: '2.0',
|
|
65
|
+
id: 1,
|
|
66
|
+
method: 'call',
|
|
67
|
+
params: ['00000000000000000000000000000000', 'session', 'login', { 'username': this.user, 'password': this.passwd }]
|
|
56
68
|
});
|
|
69
|
+
|
|
70
|
+
const result = response.data?.result?.[1];
|
|
71
|
+
if (!result?.ubus_rpc_session) {
|
|
72
|
+
throw new Error('ubus login failed');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.sessionId = result.ubus_rpc_session;
|
|
76
|
+
this.sessionExpiresAt = now + 240_000;
|
|
77
|
+
|
|
78
|
+
if (this.logDebug) this.emit('debug', `Ubus login OK`);
|
|
79
|
+
return this.sessionId;
|
|
57
80
|
}
|
|
58
81
|
|
|
59
|
-
// --- ubus call przez SSH ---
|
|
60
82
|
async ubusCall(service, method, params = {}) {
|
|
61
|
-
const
|
|
62
|
-
|
|
83
|
+
const session = await this.login();
|
|
84
|
+
|
|
85
|
+
const response = await this.axiosInstance.post('', {
|
|
86
|
+
jsonrpc: '2.0',
|
|
87
|
+
id: 2,
|
|
88
|
+
method: 'call',
|
|
89
|
+
params: [session, service, method, params]
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (response.data?.error) {
|
|
93
|
+
throw new Error(response.data.error.message || 'ubus call error');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return response.data.result[1];
|
|
63
97
|
}
|
|
64
98
|
|
|
65
|
-
// --- Pobranie info i statusu ---
|
|
66
99
|
async connect() {
|
|
67
|
-
const openWrtInfo = { state: false, systemInfo: {}, wirelessStatus: {}, wirelessRadios: [], ssids: [] }
|
|
100
|
+
const openWrtInfo = { state: false, systemInfo: {}, wirelessStatus: {}, wirelessRadios: [], ssids: [] }
|
|
101
|
+
|
|
68
102
|
try {
|
|
69
|
-
const systemInfo = await this.ubusCall(
|
|
70
|
-
if (this.logDebug) this.emit(
|
|
103
|
+
const systemInfo = await this.ubusCall('system', 'board');
|
|
104
|
+
if (this.logDebug) this.emit('debug', `System info data: ${JSON.stringify(systemInfo, null, 2)}`);
|
|
71
105
|
|
|
72
|
-
const wirelessStatus = await this.ubusCall(
|
|
73
|
-
if (this.logDebug) this.emit(
|
|
106
|
+
const wirelessStatus = await this.ubusCall('network.wireless', 'status');
|
|
107
|
+
if (this.logDebug) this.emit('debug', `Wireless status data: ${JSON.stringify(wirelessStatus, null, 2)}`);
|
|
74
108
|
|
|
75
109
|
const wirelessRadios = Object.values(wirelessStatus.radios).map(radio => ({
|
|
76
110
|
name: radio.name,
|
|
@@ -83,14 +117,13 @@ class OpenWrt extends EventEmitter {
|
|
|
83
117
|
}));
|
|
84
118
|
|
|
85
119
|
const ssids = wirelessRadios.flatMap(radio => radio.interfaces);
|
|
86
|
-
|
|
87
|
-
this.emit(
|
|
88
|
-
this.emit(
|
|
89
|
-
this.emit(
|
|
90
|
-
this.emit("ssids", ssids);
|
|
120
|
+
this.emit('systemInfo', systemInfo);
|
|
121
|
+
this.emit('wirelessStatus', wirelessStatus);
|
|
122
|
+
this.emit('wirelessRadios', wirelessRadios);
|
|
123
|
+
this.emit('ssids', ssids);
|
|
91
124
|
|
|
92
125
|
if (this.firstRun) {
|
|
93
|
-
this.emit(
|
|
126
|
+
this.emit('success', `Connect success`);
|
|
94
127
|
this.firstRun = false;
|
|
95
128
|
}
|
|
96
129
|
|
|
@@ -100,40 +133,44 @@ class OpenWrt extends EventEmitter {
|
|
|
100
133
|
openWrtInfo.wirelessRadios = wirelessRadios;
|
|
101
134
|
openWrtInfo.ssids = ssids;
|
|
102
135
|
|
|
103
|
-
if (this.logDebug) this.emit(
|
|
136
|
+
if (this.logDebug) this.emit('debug', `OpenWrt Data: ${JSON.stringify(openWrtInfo, null, 2)}`);
|
|
104
137
|
return openWrtInfo;
|
|
105
138
|
} catch (error) {
|
|
106
|
-
if (this.logError) this.emit(
|
|
139
|
+
if (this.logError) this.emit('error', `Connect error: ${error.message}`);
|
|
107
140
|
return openWrtInfo;
|
|
108
141
|
}
|
|
109
142
|
}
|
|
110
143
|
|
|
111
|
-
// --- Włączanie / wyłączanie SSID ---
|
|
112
144
|
async send(type, ssidName, state) {
|
|
113
145
|
switch (type) {
|
|
114
|
-
case
|
|
146
|
+
case 'ssid':
|
|
115
147
|
await this.handleWithLock(async () => {
|
|
116
|
-
if (this.logDebug) this.emit(
|
|
148
|
+
if (this.logDebug) this.emit('debug', `${state ? 'Enabling' : 'Disabling'} SSID ${ssidName}`);
|
|
117
149
|
|
|
118
|
-
const status = await this.ubusCall(
|
|
150
|
+
const status = await this.ubusCall('network.wireless', 'status');
|
|
119
151
|
const iface = await this.functions.findIfaceBySsid(status, ssidName);
|
|
120
152
|
if (!iface) throw new Error(`SSID ${ssidName} not found`);
|
|
121
153
|
|
|
122
154
|
const section = iface.section;
|
|
123
155
|
if (!section) throw new Error(`No UCI section for SSID ${ssidName}`);
|
|
124
156
|
|
|
125
|
-
await this.ubusCall(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
157
|
+
await this.ubusCall('uci', 'set',
|
|
158
|
+
{
|
|
159
|
+
config: 'wireless',
|
|
160
|
+
section: section,
|
|
161
|
+
values: {
|
|
162
|
+
disabled: state ? '0' : '1'
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
);
|
|
132
166
|
|
|
133
|
-
|
|
167
|
+
await this.ubusCall('uci', 'commit', { config: 'wireless' });
|
|
168
|
+
await this.ubusCall('network.wireless', 'reload', {});
|
|
169
|
+
|
|
170
|
+
if (this.logDebug) this.emit('debug', `Send SSID ${ssidName} ${state ? 'enabled' : 'disabled'}`);
|
|
134
171
|
});
|
|
135
172
|
break;
|
|
136
|
-
case
|
|
173
|
+
case 'switch':
|
|
137
174
|
break;
|
|
138
175
|
}
|
|
139
176
|
}
|
|
@@ -141,4 +178,3 @@ class OpenWrt extends EventEmitter {
|
|
|
141
178
|
|
|
142
179
|
export default OpenWrt;
|
|
143
180
|
|
|
144
|
-
|