homebridge-openwrt-control 0.0.2-beta.7 → 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 -77
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.7",
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,114 +1,78 @@
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.name = config.name;
11
10
  this.host = config.host;
12
- this.user = config.auth.user;
13
- this.passwd = config.auth.passwd;
11
+ this.user = config.auth?.user || "root";
12
+ this.passwd = config.auth?.passwd || "";
13
+
14
14
  this.logError = config.log?.error;
15
15
  this.logDebug = config.log?.debug;
16
16
 
17
- //external integration
18
- this.restFulEnabled = config.restFul?.enable || false;
19
- this.mqttEnabled = config.mqtt?.enable || false;
20
-
21
17
  this.firstRun = true;
22
18
  this.lock = false;
23
19
 
24
- this.sessionId = null;
25
- this.sessionExpiresAt = 0;
26
-
27
20
  this.functions = new Functions();
28
- this.axiosInstance = axios.create({
29
- baseURL: `http://${config.host}/ubus`,
30
- timeout: 5000,
31
- headers: {
32
- 'Content-Type': 'application/json'
33
- }
34
- });
35
21
 
36
22
  this.impulseGenerator = new ImpulseGenerator()
37
- .on('connect', () => this.handleWithLock(async () => {
23
+ .on("connect", () => this.handleWithLock(async () => {
38
24
  await this.connect();
39
25
  }))
40
- .on('state', (state) => {
41
- 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"}`);
42
28
  });
43
29
  }
44
30
 
45
31
  async handleWithLock(fn) {
46
32
  if (this.lock) return;
47
33
  this.lock = true;
48
-
49
34
  try {
50
35
  await fn();
51
36
  } catch (error) {
52
- this.emit('error', `Impulse generator error: ${error.message}`
53
- );
37
+ this.emit("error", `Impulse generator error: ${error.message}`);
54
38
  } finally {
55
39
  this.lock = false;
56
40
  }
57
41
  }
58
42
 
59
- async login() {
60
- const now = Date.now();
61
- if (this.sessionId && now < this.sessionExpiresAt) {
62
- return this.sessionId;
63
- }
64
-
65
- const response = await this.axiosInstance.post('', {
66
- jsonrpc: '2.0',
67
- id: 1,
68
- method: 'call',
69
- 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
+ });
70
56
  });
71
-
72
- const result = response.data?.result?.[1];
73
- if (!result?.ubus_rpc_session) {
74
- throw new Error('ubus login failed');
75
- }
76
-
77
- this.sessionId = result.ubus_rpc_session;
78
- this.sessionExpiresAt = now + 240_000;
79
-
80
- if (this.logDebug) this.emit('debug', `Ubus login OK`);
81
- return this.sessionId;
82
57
  }
83
58
 
59
+ // --- ubus call przez SSH ---
84
60
  async ubusCall(service, method, params = {}) {
85
- const session = await this.login();
86
-
87
- const response = await this.axiosInstance.post('', {
88
- jsonrpc: '2.0',
89
- id: 2,
90
- method: 'call',
91
- params: [session, service, method, params]
92
- });
93
-
94
- if (response.data?.error) {
95
- throw new Error(response.data.error.message || 'ubus call error');
96
- }
97
-
98
- return response.data.result[1];
61
+ const cmd = `ubus call ${service} ${method} '${JSON.stringify(params)}'`;
62
+ return await this.sshCall(cmd);
99
63
  }
100
64
 
65
+ // --- Pobranie info i statusu ---
101
66
  async connect() {
102
- const openWrtInfo = { state: false, systemInfo: {}, wirelessStatus: {}, wirelessRadios: [], ssids: [] }
103
-
67
+ const openWrtInfo = { state: false, systemInfo: {}, wirelessStatus: {}, wirelessRadios: [], ssids: [] };
104
68
  try {
105
- const systemInfo = await this.ubusCall('system', 'board');
106
- 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)}`);
107
71
 
108
- const wirelessStatus = await this.ubusCall('network.wireless', 'status');
109
- 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)}`);
110
74
 
111
- const wirelessRadios = Object.values(status.radios).map(radio => ({
75
+ const wirelessRadios = Object.values(wirelessStatus.radios).map(radio => ({
112
76
  name: radio.name,
113
77
  state: radio.up === true,
114
78
  interfaces: Object.values(radio.interfaces).map(i => ({
@@ -119,13 +83,14 @@ class OpenWrt extends EventEmitter {
119
83
  }));
120
84
 
121
85
  const ssids = wirelessRadios.flatMap(radio => radio.interfaces);
122
- this.emit('systemInfo', systemInfo);
123
- this.emit('wirelessStatus', wirelessStatus);
124
- this.emit('wirelessRadios', wirelessRadios);
125
- 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);
126
91
 
127
92
  if (this.firstRun) {
128
- this.emit('success', `Connect success`);
93
+ this.emit("success", `Connect success`);
129
94
  this.firstRun = false;
130
95
  }
131
96
 
@@ -135,14 +100,44 @@ class OpenWrt extends EventEmitter {
135
100
  openWrtInfo.wirelessRadios = wirelessRadios;
136
101
  openWrtInfo.ssids = ssids;
137
102
 
138
- 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)}`);
139
104
  return openWrtInfo;
140
105
  } catch (error) {
141
- if (this.logError) this.emit('error', `Connect error: ${error.message}`);
106
+ if (this.logError) this.emit("error", `[${this.host}] Connect error: ${error.message}`);
142
107
  return openWrtInfo;
143
108
  }
144
109
  }
145
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
+
146
141
  async send(type, ssidName, state) {
147
142
  switch (type) {
148
143
  case 'ssid':