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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/openwrt.js +72 -75
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.8",
4
+ "version": "0.0.2-beta.9",
5
5
  "description": "Homebridge plugin to control OpenWrt flashed devices.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
package/src/openwrt.js CHANGED
@@ -1,110 +1,76 @@
1
- import EventEmitter from 'events';
2
- import axios from 'axios';
3
- import Functions from './functions.js';
4
- import ImpulseGenerator from './impulsegenerator.js';
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.user = config.auth?.user;
11
- this.passwd = config.auth?.passwd;
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('connect', () => this.handleWithLock(async () => {
23
+ .on("connect", () => this.handleWithLock(async () => {
36
24
  await this.connect();
37
25
  }))
38
- .on('state', (state) => {
39
- this.emit(state ? 'success' : 'warn', `Impulse generator ${state ? 'started' : 'stopped'}`);
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('error', `Impulse generator error: ${error.message}`
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
- 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 }]
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 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];
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('system', 'board');
104
- if (this.logDebug) this.emit('debug', `System info data: ${JSON.stringify(systemInfo, null, 2)}`);
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('network.wireless', 'status');
107
- if (this.logDebug) this.emit('debug', `Wireless status data: ${JSON.stringify(wirelessStatus, null, 2)}`);
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
- this.emit('systemInfo', systemInfo);
121
- this.emit('wirelessStatus', wirelessStatus);
122
- this.emit('wirelessRadios', wirelessRadios);
123
- this.emit('ssids', ssids);
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('success', `Connect success`);
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('debug', `OpenWrt Data: ${JSON.stringify(openWrtInfo, null, 2)}`);
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('error', `Connect error: ${error.message}`);
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':