homebridge-openwrt-control 0.4.3 → 0.4.4

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/CHANGELOG.md CHANGED
@@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  - After update to v0.1.0 the plugin need to be reconfigured!
11
11
 
12
+ ## [0.4.4] - (15.10.2026)
13
+
14
+ ### Changes
15
+
16
+ - fixed: after a restart of the router the plugin could report `Access denied` for up to 4 minutes. A call that was refused twice in a row (the router was still starting) was remembered as denied by the ACL and the plugin did not log in again. Only optional calls (`iwinfo`) are remembered now, and only when the session was created for that call, a required call is read again on the next poll
17
+ - changed: what the ACL refused is forgotten after the session was renewed, so a changed ACL on the router is picked up without a restart of the plugin
18
+
12
19
  ## [0.4.3] - (15.10.2026)
13
20
 
14
21
  ### Changes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "OpenWrt Control",
3
3
  "name": "homebridge-openwrt-control",
4
- "version": "0.4.3",
4
+ "version": "0.4.4",
5
5
  "description": "Homebridge plugin to control OpenWrt flashed devices.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
package/src/openwrt.js CHANGED
@@ -116,11 +116,15 @@ class OpenWrt extends EventEmitter {
116
116
  }
117
117
 
118
118
  // retry is only for reads. One more try after a network hiccup, and one new login when the router no longer knows
119
- // the cached session (a restarted router answers every call with Access denied until the cached session expires)
120
- async ubusCall(service, method, params = {}, retry = false) {
119
+ // the cached session (a restarted router answers every call with Access denied until the cached session expires).
120
+ // optional marks a call a router may refuse by ACL, only such a call is remembered as denied, a required call is
121
+ // never given up on so a router that is still starting is read again on the next poll
122
+ async ubusCall(service, method, params = {}, retry = false, optional = false) {
121
123
  const key = `${service}.${method}`;
124
+ let renewed = false;
122
125
 
123
126
  for (let attempt = 0; ; attempt++) {
127
+ const cached = this.sessionId !== null && Date.now() < this.sessionExpiresAt;
124
128
  const session = await this.login();
125
129
 
126
130
  let response;
@@ -139,17 +143,23 @@ class OpenWrt extends EventEmitter {
139
143
  const error = response.data?.error;
140
144
  if (error) {
141
145
  const denied = error.code === -32002 || /access denied/i.test(error.message ?? '');
142
- if (denied && retry && attempt === 0 && !this.aclDenied.has(key)) {
146
+
147
+ // A cached session may be one the router forgot, log in again once. A call the ACL is known to refuse is skipped
148
+ if (denied && retry && attempt === 0 && cached && !(optional && this.aclDenied.has(key))) {
143
149
  this.sessionId = null;
144
150
  this.sessionExpiresAt = 0;
151
+ renewed = true;
145
152
  continue;
146
153
  }
147
154
 
148
- // Denied with a fresh session is the ACL, do not log in again for it on every poll
149
- if (denied && retry) this.aclDenied.add(key);
155
+ // Refused with a session that was just created is the ACL, not asked again with a new login on every poll
156
+ if (denied && optional && !cached) this.aclDenied.add(key);
150
157
  throw new Error(error.message || 'Ubus call error');
151
158
  }
152
159
 
160
+ // The router had forgotten the session, what it refused before may be allowed again
161
+ if (renewed) this.aclDenied.clear();
162
+
153
163
  return response.data.result[1];
154
164
  }
155
165
  }
@@ -270,7 +280,7 @@ class OpenWrt extends EventEmitter {
270
280
 
271
281
  const optional = async (service, method, params) => {
272
282
  try {
273
- return await this.ubusCall(service, method, params, true);
283
+ return await this.ubusCall(service, method, params, true, true);
274
284
  } catch (error) {
275
285
  if (this.logDebug) this.emit('debug', `Optional ubus call ${service} ${method} failed: ${error.message}`);
276
286
  return null;