homebridge-openwrt-control 0.0.2-beta.8 → 0.0.2-beta.9
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/package.json +1 -1
- package/src/openwrt.js +72 -75
package/package.json
CHANGED
package/src/openwrt.js
CHANGED
|
@@ -1,110 +1,76 @@
|
|
|
1
|
-
import EventEmitter from
|
|
2
|
-
import
|
|
3
|
-
import Functions from
|
|
4
|
-
import ImpulseGenerator from
|
|
1
|
+
import EventEmitter from "events";
|
|
2
|
+
import { exec } from "child_process";
|
|
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.
|
|
10
|
+
this.host = config.host;
|
|
11
|
+
this.user = config.auth?.user || "root";
|
|
12
|
+
this.passwd = config.auth?.passwd || "";
|
|
13
|
+
|
|
12
14
|
this.logError = config.log?.error;
|
|
13
15
|
this.logDebug = config.log?.debug;
|
|
14
16
|
|
|
15
|
-
//external integration
|
|
16
|
-
this.restFulEnabled = config.restFul?.enable || false;
|
|
17
|
-
this.mqttEnabled = config.mqtt?.enable || false;
|
|
18
|
-
|
|
19
17
|
this.firstRun = true;
|
|
20
18
|
this.lock = false;
|
|
21
19
|
|
|
22
|
-
this.sessionId = null;
|
|
23
|
-
this.sessionExpiresAt = 0;
|
|
24
|
-
|
|
25
20
|
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
|
-
});
|
|
33
21
|
|
|
34
22
|
this.impulseGenerator = new ImpulseGenerator()
|
|
35
|
-
.on(
|
|
23
|
+
.on("connect", () => this.handleWithLock(async () => {
|
|
36
24
|
await this.connect();
|
|
37
25
|
}))
|
|
38
|
-
.on(
|
|
39
|
-
this.emit(state ?
|
|
26
|
+
.on("state", (state) => {
|
|
27
|
+
this.emit(state ? "success" : "warn", `Impulse generator ${state ? "started" : "stopped"}`);
|
|
40
28
|
});
|
|
41
29
|
}
|
|
42
30
|
|
|
43
31
|
async handleWithLock(fn) {
|
|
44
32
|
if (this.lock) return;
|
|
45
33
|
this.lock = true;
|
|
46
|
-
|
|
47
34
|
try {
|
|
48
35
|
await fn();
|
|
49
36
|
} catch (error) {
|
|
50
|
-
this.emit(
|
|
51
|
-
);
|
|
37
|
+
this.emit("error", `Impulse generator error: ${error.message}`);
|
|
52
38
|
} finally {
|
|
53
39
|
this.lock = false;
|
|
54
40
|
}
|
|
55
41
|
}
|
|
56
42
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
43
|
+
// --- Helper do wywołań SSH ---
|
|
44
|
+
async sshCall(command) {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
const sshCmd = `ssh ${this.user}@${this.host} '${command.replace(/'/g, `'\\''`)}'`;
|
|
47
|
+
exec(sshCmd, (error, stdout, stderr) => {
|
|
48
|
+
if (error) return reject(new Error(stderr || error.message));
|
|
49
|
+
try {
|
|
50
|
+
const json = JSON.parse(stdout);
|
|
51
|
+
resolve(json);
|
|
52
|
+
} catch (parseError) {
|
|
53
|
+
reject(new Error(`Invalid JSON from SSH: ${parseError.message}`));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
68
56
|
});
|
|
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;
|
|
80
57
|
}
|
|
81
58
|
|
|
59
|
+
// --- ubus call przez SSH ---
|
|
82
60
|
async ubusCall(service, method, params = {}) {
|
|
83
|
-
const
|
|
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];
|
|
61
|
+
const cmd = `ubus call ${service} ${method} '${JSON.stringify(params)}'`;
|
|
62
|
+
return await this.sshCall(cmd);
|
|
97
63
|
}
|
|
98
64
|
|
|
65
|
+
// --- Pobranie info i statusu ---
|
|
99
66
|
async connect() {
|
|
100
|
-
const openWrtInfo = { state: false, systemInfo: {}, wirelessStatus: {}, wirelessRadios: [], ssids: [] }
|
|
101
|
-
|
|
67
|
+
const openWrtInfo = { state: false, systemInfo: {}, wirelessStatus: {}, wirelessRadios: [], ssids: [] };
|
|
102
68
|
try {
|
|
103
|
-
const systemInfo = await this.ubusCall(
|
|
104
|
-
if (this.logDebug) this.emit(
|
|
69
|
+
const systemInfo = await this.ubusCall("system", "board");
|
|
70
|
+
if (this.logDebug) this.emit("debug", `[${this.host}] System info: ${JSON.stringify(systemInfo, null, 2)}`);
|
|
105
71
|
|
|
106
|
-
const wirelessStatus = await this.ubusCall(
|
|
107
|
-
if (this.logDebug) this.emit(
|
|
72
|
+
const wirelessStatus = await this.ubusCall("network.wireless", "status");
|
|
73
|
+
if (this.logDebug) this.emit("debug", `[${this.host}] Wireless status: ${JSON.stringify(wirelessStatus, null, 2)}`);
|
|
108
74
|
|
|
109
75
|
const wirelessRadios = Object.values(wirelessStatus.radios).map(radio => ({
|
|
110
76
|
name: radio.name,
|
|
@@ -117,13 +83,14 @@ class OpenWrt extends EventEmitter {
|
|
|
117
83
|
}));
|
|
118
84
|
|
|
119
85
|
const ssids = wirelessRadios.flatMap(radio => radio.interfaces);
|
|
120
|
-
|
|
121
|
-
this.emit(
|
|
122
|
-
this.emit(
|
|
123
|
-
this.emit(
|
|
86
|
+
|
|
87
|
+
this.emit("systemInfo", systemInfo);
|
|
88
|
+
this.emit("wirelessStatus", wirelessStatus);
|
|
89
|
+
this.emit("wirelessRadios", wirelessRadios);
|
|
90
|
+
this.emit("ssids", ssids);
|
|
124
91
|
|
|
125
92
|
if (this.firstRun) {
|
|
126
|
-
this.emit(
|
|
93
|
+
this.emit("success", `Connect success`);
|
|
127
94
|
this.firstRun = false;
|
|
128
95
|
}
|
|
129
96
|
|
|
@@ -133,14 +100,44 @@ class OpenWrt extends EventEmitter {
|
|
|
133
100
|
openWrtInfo.wirelessRadios = wirelessRadios;
|
|
134
101
|
openWrtInfo.ssids = ssids;
|
|
135
102
|
|
|
136
|
-
if (this.logDebug) this.emit(
|
|
103
|
+
if (this.logDebug) this.emit("debug", `[${this.host}] OpenWrt Data: ${JSON.stringify(openWrtInfo, null, 2)}`);
|
|
137
104
|
return openWrtInfo;
|
|
138
105
|
} catch (error) {
|
|
139
|
-
if (this.logError) this.emit(
|
|
106
|
+
if (this.logError) this.emit("error", `[${this.host}] Connect error: ${error.message}`);
|
|
140
107
|
return openWrtInfo;
|
|
141
108
|
}
|
|
142
109
|
}
|
|
143
110
|
|
|
111
|
+
// --- Włączanie / wyłączanie SSID ---
|
|
112
|
+
async send(type, ssidName, state) {
|
|
113
|
+
switch (type) {
|
|
114
|
+
case "ssid":
|
|
115
|
+
await this.handleWithLock(async () => {
|
|
116
|
+
if (this.logDebug) this.emit("debug", `[${this.host}] ${state ? "Enabling" : "Disabling"} SSID ${ssidName}`);
|
|
117
|
+
|
|
118
|
+
const status = await this.ubusCall("network.wireless", "status");
|
|
119
|
+
const iface = await this.functions.findIfaceBySsid(status, ssidName);
|
|
120
|
+
if (!iface) throw new Error(`SSID ${ssidName} not found`);
|
|
121
|
+
|
|
122
|
+
const section = iface.section;
|
|
123
|
+
if (!section) throw new Error(`No UCI section for SSID ${ssidName}`);
|
|
124
|
+
|
|
125
|
+
await this.ubusCall("uci", "set", {
|
|
126
|
+
config: "wireless",
|
|
127
|
+
section: section,
|
|
128
|
+
values: { disabled: state ? "0" : "1" }
|
|
129
|
+
});
|
|
130
|
+
await this.ubusCall("uci", "commit", { config: "wireless" });
|
|
131
|
+
await this.ubusCall("network.wireless", "reload", {});
|
|
132
|
+
|
|
133
|
+
if (this.logDebug) this.emit("debug", `[${this.host}] SSID ${ssidName} ${state ? "enabled" : "disabled"}`);
|
|
134
|
+
});
|
|
135
|
+
break;
|
|
136
|
+
case "switch":
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
144
141
|
async send(type, ssidName, state) {
|
|
145
142
|
switch (type) {
|
|
146
143
|
case 'ssid':
|