homebridge-openwrt-control 0.4.0 → 0.4.2

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,19 @@ 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.2] - (29.09.2026)
13
+
14
+ ### Changes
15
+
16
+ - fixed: Home Assistant discovery, the config and the state are published again after a restart of the broker, a broker without persistence loses the retained messages
17
+
18
+ ## [0.4.1] - (25.09.2026)
19
+
20
+ ### Changes
21
+
22
+ - fix: Home Assistant radio entities had the same name on routers with two radios of one band (two `Wi-Fi 5 GHz`), radios are now named by band and radio number (`5 GHz Radio 0`, `Restart 5 GHz Radio 0`, `Channel 5 GHz Radio 0`), SSIDs get the radio added when the same network is on two radios of one band (`Dom 5 GHz Radio 2`). Entity ids do not change
23
+ - readme update
24
+
12
25
  ## [0.4.0] - (25.09.2026)
13
26
 
14
27
  ### Changes
package/README.md CHANGED
@@ -154,12 +154,12 @@ With `mqtt.haDiscovery` the router appears in Home Assistant as one device with
154
154
  | Entity | Type | Description |
155
155
  | --- | --- | --- |
156
156
  | `WAN` | binary_sensor (connectivity) | WAN interface up, `Internet` on routers without a `wan` interface |
157
- | `Wi-Fi 2.4 GHz`, `Wi-Fi 5 GHz`... | switch | Radio on/off |
158
- | `<SSID> <band>` | switch | SSID on/off |
159
- | `Restart Wi-Fi <band>` | button (restart) | Radio restart |
157
+ | `2.4 GHz Radio 0`, `5 GHz Radio 1`... | switch | Radio on/off, named by band and radio number |
158
+ | `<SSID> <band>` | switch | SSID on/off, the radio is added (`Dom 5 GHz Radio 2`) when the same network is on two radios of one band |
159
+ | `Restart <band> Radio <n>` | button (restart) | Radio restart |
160
160
  | `Reboot`, `Reload network`, `Reload Wi-Fi` | button | System reboot, network and wireless reload |
161
161
  | `Wi-Fi clients`, `<SSID> <band> clients` | sensor | Connected clients, total and per SSID |
162
- | `Channel <band>`, `TX power <band>` | sensor (diagnostic) | Current radio channel and TX power in dBm |
162
+ | `Channel <band> Radio <n>`, `TX power <band> Radio <n>` | sensor (diagnostic) | Current radio channel and TX power in dBm |
163
163
  | `WAN IP`, `Firmware`, `Last boot`, `Load`, `Memory usage` | sensor (diagnostic) | System information |
164
164
  | `<SSID> <band> QR code` | image | QR code to join the network, only with `mqtt.haWifiQr` |
165
165
 
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.0",
4
+ "version": "0.4.2",
5
5
  "description": "Homebridge plugin to control OpenWrt flashed devices.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
@@ -53,6 +53,13 @@ class HaDiscovery {
53
53
  }
54
54
  }
55
55
 
56
+ // The broker may have lost the retained messages (restart without persistence), the next sync sends everything again
57
+ reset() {
58
+ this.lastConfig = {};
59
+ this.lastState = '';
60
+ this.lastImage = {};
61
+ }
62
+
56
63
  has(suffix, available) {
57
64
  if (available) this.seen.add(suffix);
58
65
  return this.seen.has(suffix);
@@ -164,25 +171,30 @@ class HaDiscovery {
164
171
  button('network_reload', { NetworkReload: true }, { name: 'Reload network', icon: 'mdi:lan-pending', entity_category: 'config' });
165
172
  button('wireless_reload', { WirelessReload: true }, { name: 'Reload Wi-Fi', icon: 'mdi:wifi-refresh', entity_category: 'config' });
166
173
 
167
- // Radios
174
+ // Radios, named by band and radio number (5 GHz Radio 0), tri-band routers have two radios of one band
168
175
  for (const radio of info.wirelessRadios ?? []) {
169
176
  const id = radio.name;
170
177
  const key = this.key(id);
171
- const label = BandLabel[radio.band] ?? id;
178
+ const label = this.radioLabel(radio);
172
179
  const radioInfo = ext.radios?.[id] ?? {};
173
- toggle(`radio_${key}`, id, 'Radio', { name: `Wi-Fi ${label}`, icon: 'mdi:wifi', value_template: `{{ 'ON' if value_json.radios['${id}'].on else 'OFF' }}` });
174
- button(`radio_${key}_restart`, { RadioRestart: { id } }, { name: `Restart Wi-Fi ${label}`, device_class: 'restart', entity_category: 'config' });
180
+ toggle(`radio_${key}`, id, 'Radio', { name: label, icon: 'mdi:wifi', value_template: `{{ 'ON' if value_json.radios['${id}'].on else 'OFF' }}` });
181
+ button(`radio_${key}_restart`, { RadioRestart: { id } }, { name: `Restart ${label}`, device_class: 'restart', entity_category: 'config' });
175
182
  if (this.has(`radio_${key}_channel`, radioInfo.channel != null)) sensor(`radio_${key}_channel`, { name: `Channel ${label}`, icon: 'mdi:access-point', entity_category: 'diagnostic', value_template: state(`.radios['${id}'].channel`) });
176
183
  if (this.has(`radio_${key}_txpower`, radioInfo.txpower != null)) sensor(`radio_${key}_txpower`, { name: `TX power ${label}`, icon: 'mdi:signal', unit_of_measurement: 'dBm', state_class: 'measurement', entity_category: 'diagnostic', value_template: state(`.radios['${id}'].txpower`) });
177
184
  }
178
185
 
179
186
  // SSIDs, the id is the UCI section so renaming the network keeps the entity
187
+ // SSIDs named by network and band (Dom 5 GHz), the radio is added when the same network is on two radios of one band
180
188
  const uci = info.wirelessInfo?.values ?? {};
189
+ const ssidBand = (ssid) => `${ssid.name} ${BandLabel[ssid.band] ?? ssid.radio ?? ''}`.trim();
190
+ const ssidLabels = (info.wirelessSsids ?? []).map(ssidBand);
181
191
  for (const ssid of info.wirelessSsids ?? []) {
182
192
  if (!ssid.section || !ssid.name) continue;
183
193
  const id = ssid.section;
184
194
  const key = this.key(id);
185
- const label = `${ssid.name} ${BandLabel[ssid.band] ?? ssid.radio ?? ''}`.trim();
195
+ const radio = (info.wirelessRadios ?? []).find(r => r.name === ssid.radio);
196
+ const duplicate = ssidLabels.filter(label => label === ssidBand(ssid)).length > 1;
197
+ const label = duplicate && radio ? `${ssid.name} ${this.radioLabel(radio)}` : ssidBand(ssid);
186
198
  toggle(`ssid_${key}`, id, 'Ssid', { name: label, icon: 'mdi:wifi-lock', value_template: `{{ 'ON' if value_json.ssids['${id}'].on else 'OFF' }}` });
187
199
  if (clientsAvailable && (ssid.mode ?? 'ap') === 'ap') sensor(`ssid_${key}_clients`, { name: `${label} clients`, icon: 'mdi:account-multiple', state_class: 'measurement', value_template: state(`.ssids['${id}'].clients`) });
188
200
 
@@ -248,6 +260,14 @@ class HaDiscovery {
248
260
  return qr.createSvgTag({ cellSize: 8, margin: 4, scalable: true });
249
261
  }
250
262
 
263
+ // 5 GHz Radio 0, the number from the radio name (radio0), other names as they are
264
+ radioLabel(radio) {
265
+ const number = String(radio.name).match(/^radio(\d+)$/)?.[1];
266
+ const band = BandLabel[radio.band];
267
+ const name = number !== undefined ? `Radio ${number}` : radio.name;
268
+ return band ? `${band} ${name}` : name;
269
+ }
270
+
251
271
  // Object id part of a radio or UCI section name
252
272
  key(id) {
253
273
  return String(id).replace(/[^a-zA-Z0-9_-]/g, '_');
package/src/mqtt.js CHANGED
@@ -36,6 +36,7 @@ class Mqtt extends EventEmitter {
36
36
  } : {})
37
37
  };
38
38
 
39
+ this.connected = false;
39
40
  const startTime = Date.now();
40
41
  let hasConnected = false;
41
42
  let warnedStalled = false;
@@ -45,6 +46,9 @@ class Mqtt extends EventEmitter {
45
46
  hasConnected = true;
46
47
  this.emit('connected', `MQTT v${protocolVersion} connected.`);
47
48
  if (this.haDiscovery) this.publishRetained(this.availabilityTopic, 'online').catch(() => { });
49
+ // Every connect, also when the broker was not running at start or restarted, devices publish again
50
+ this.connected = true;
51
+ this.emit('online');
48
52
 
49
53
  try {
50
54
  await new Promise((resolve, reject) => {
@@ -90,6 +94,7 @@ class Mqtt extends EventEmitter {
90
94
  if (config.logDebug) this.emit('debug', 'MQTT Reconnecting...');
91
95
  })
92
96
  .on('close', () => {
97
+ this.connected = false;
93
98
  if (!hasConnected && !warnedStalled && Date.now() - startTime > 30000) {
94
99
  warnedStalled = true;
95
100
  this.emit('warn', `MQTT has not connected after 30s of retries using protocol v${protocolVersion}. Check broker address, credentials, and whether the broker supports this MQTT protocol version.`);
package/src/router.js CHANGED
@@ -224,6 +224,11 @@ class Router extends EventEmitter {
224
224
  .on('connected', msg => {
225
225
  this.mqttConnected = true;
226
226
  this.emit('success', msg);
227
+ })
228
+ .on('online', () => {
229
+ // Every connect, the broker may have lost the retained messages after a restart
230
+ this.mqttConnected = true;
231
+ this.ha?.reset();
227
232
  this.haSync();
228
233
  })
229
234
  .on('set', async (key, value) => {