homebridge-eosstb 2.4.0-alpha.47 → 2.4.0-beta.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 +24 -253
- package/index.js +211 -51
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,274 +4,45 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
See the [Readme file](https://github.com/jsiegenthaler/homebridge-eosstb/blob/master/README.md) for full plugin documentation.
|
|
5
5
|
Please restart Homebridge after every plugin update.
|
|
6
6
|
|
|
7
|
-
# Bug Fixes and Improvements
|
|
8
7
|
|
|
9
|
-
##
|
|
8
|
+
## 2.4.0-beta.2 (2026-05-09)
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
review all http endpoints, make sure a suitable log entry is being made so I can check the data is plausible
|
|
10
|
+
This release focusses on ensuring mqtt long-term stability, and fixes an issue where the channel name was not shown on startup.
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
purchaseService
|
|
18
|
-
recordingService
|
|
19
|
-
linearService
|
|
20
|
-
sessionService
|
|
12
|
+
- Rescheduled nightly channel list refresh to 0000-0400 instead of 0000-0600
|
|
13
|
+
- Added an automatic daily mqtt reconnect at a random time between 0400-0600 to avoid long running mqtt sessions. Only restarts if settop box is turned off
|
|
14
|
+
- Fixed issue where current channel was not displayed on plugin startup
|
|
21
15
|
|
|
22
|
-
IMPORTANR
|
|
23
|
-
Implement setTargetMediaState to send the Play/Pause/Stop functions, so that Eve can control the media state. Watch out for sending commands twice when using the remote control. maybe the sendKey redirects to the setmediaState?
|
|
24
16
|
|
|
25
|
-
|
|
26
|
-
Behavious: SetMediaState from 0 to 1 will start playing.
|
|
27
|
-
Behavious: SetMediaState from 2 to 1 will start playing.
|
|
28
|
-
Behavious: SetMediaState from 1 to 2 will start playing.
|
|
29
|
-
unreliable, compare to webclient... this is driving me crazy!
|
|
30
|
-
might have to revert to sendKeys to set Play and Stop/Pause
|
|
17
|
+
## 2.4.0-beta.1 (2026-05-09)
|
|
31
18
|
|
|
19
|
+
This release represents a major rewrite of the plugin, significantly improving robustness, HAP compliance, and code quality throughout, and making it work for Switzerland.
|
|
32
20
|
|
|
21
|
+
- Added CH login support: Adapted the login sequence and updated config.schema.json to support the new Switzerland login method
|
|
22
|
+
- Overhauled HAP compliance: Full audit and rewrite of all HAP code for strict compliance
|
|
23
|
+
- Added support for Homebridge v2: Plugin now fully supports Homebridge 2.0.0+ and Node.js 24+; resolved breaking changes introduced by HAP-NodeJS v1 shipped with Homebridge v2
|
|
24
|
+
- Improved MQTT handling: Optimised mqtt code and added clean unsubscribe on plugin shutdown
|
|
25
|
+
- Improved channel list management: Master channel list refresh now runs once daily at a random time between 00:00–06:00
|
|
26
|
+
- Updated channel ConfiguredName to read-only
|
|
27
|
+
- Optimised handling of remote control and media control
|
|
28
|
+
- Improved robustness and startup
|
|
29
|
+
- Improved overall code quality
|
|
30
|
+
- Updated dependencies to current versions
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
make sendKey logging consistent
|
|
32
|
+
## 2.3.9 (2026-05-09)
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
Persistance test:
|
|
42
|
-
1. Hide the channel SRF info using Home app
|
|
43
|
-
2. Force-close and reopen the home app. Confirm channel is still hidden
|
|
44
|
-
3. Confirm the current visibility state in the plugin logs is correct
|
|
45
|
-
3. Restart the plugin
|
|
46
|
-
4. Observe the current visibility state in the plugin logs - does it get the right value from HomeKit HAP? If so, no persistance required.
|
|
47
|
-
|
|
48
|
-
Device name: this comes from backend
|
|
49
|
-
Channel name: overwrite not allowed - can we disable in HomeKit. Yes, but prevents setting visibility
|
|
50
|
-
|
|
51
|
-
CHALLENGE
|
|
52
|
-
The mostWatchedChannelList is not working
|
|
53
|
-
|
|
54
|
-
## 2.4.0-alpha.47 (2026-05-09)
|
|
55
|
-
- Improved the startup default setting of media state when a power-on transition is detected
|
|
56
|
-
|
|
57
|
-
## 2.4.0-alpha.46 (2026-05-09)
|
|
58
|
-
- Fixed the issue with volume commands
|
|
59
|
-
|
|
60
|
-
## 2.4.0-alpha.45 (2026-05-09)
|
|
61
|
-
- Added some debugging to the volume commands to trace an issue
|
|
62
|
-
|
|
63
|
-
## 2.4.0-alpha.44 (2026-05-09)
|
|
64
|
-
- Fixed some log level issues
|
|
65
|
-
- Fixed issue with Remove volumeDown causing Unhandled error thrown inside write handler for characteristic
|
|
66
|
-
|
|
67
|
-
## 2.4.0-alpha.43 (2026-05-09)
|
|
68
|
-
- Bumped dependency "semver": "^7.8.0",
|
|
69
|
-
|
|
70
|
-
## 2.4.0-alpha.42 (2026-05-07)
|
|
71
|
-
- changed the name of hidden channels from HIDDEN_xx to HIDDENxx to stop the HAP-NodeJS WARNING: The accessory 'HIDDEN_32' has an invalid 'Name' characteristic
|
|
72
|
-
|
|
73
|
-
## 2.4.0-alpha.42 (2026-05-07)
|
|
74
|
-
- changed the name of hidden channels from HIDDEN_xx to HIDDENxx to stop the HAP-NodeJS WARNING: The accessory 'HIDDEN_32' has an invalid 'Name' characteristic
|
|
75
|
-
|
|
76
|
-
## 2.4.0-alpha.41 (2026-05-07)
|
|
77
|
-
- fixed typos in this change log
|
|
78
|
-
|
|
79
|
-
## 2.4.0-alpha.40 (2026-05-07)
|
|
80
|
-
- Changes to code to support HAP-NodeJS still works with Homebridge v1.11.x
|
|
81
|
-
- Reinstated engine "homebridge": "^1.11.4||^2.0.0",
|
|
82
|
-
|
|
83
|
-
## 2.4.0-alpha.39 (2026-05-07)
|
|
84
|
-
- fixed issues caused by HAP-NodeJS v1 released with Homebridge v2 where use of enums off the Characteristic class is no longer supported
|
|
85
|
-
- due to these HAP-NodeJS changes, support for Homebridge versions below 2.0.0 is no longer provided
|
|
86
|
-
- Bumped engine "homebridge": "^2.0.0",
|
|
34
|
+
- Fixed Error on Homebridge v2: Cannot read properties of undefined (reading 'STRING')
|
|
35
|
+
- Adapted hidden channel name to reduce warning messages with Homebridge v2
|
|
36
|
+
- Updated iOS and Homebridge version references in Readme
|
|
37
|
+
- Bumped engine "^1.11.4||^2.0.0",
|
|
87
38
|
- Bumped engine "node": "^24.15.0"
|
|
88
39
|
- Bumped dependency "axios": "^1.16.0",
|
|
89
40
|
- Bumped dependency "axios-cookiejar-support": "^7.0.0",
|
|
90
41
|
- Bumped dependency "mqtt": "^5.15.1",
|
|
91
|
-
- Bumped dependency "puppeteer-core": "^24.43.0",
|
|
92
42
|
- Bumped dependency "qs": "^6.15.1",
|
|
43
|
+
- Bumped dependency "semver": "^7.8.0",
|
|
93
44
|
- Bumped dependency "tough-cookie": "^6.0.1",
|
|
94
|
-
- Bumped dependency "ws": "^8.20.0"
|
|
95
|
-
|
|
96
|
-
## 2.4.0-alpha.38 (2026-03-07)
|
|
97
|
-
|
|
98
|
-
- changes to settargetmediastate & setMediaState
|
|
99
|
-
|
|
100
|
-
## 2.4.0-alpha.37 (2026-03-07)
|
|
101
|
-
|
|
102
|
-
- changes to settargetmediastate
|
|
103
|
-
|
|
104
|
-
## 2.4.0-alpha.36 (2026-03-07)
|
|
105
|
-
|
|
106
|
-
- changes to settargetmediastate
|
|
107
|
-
|
|
108
|
-
## 2.4.0-alpha.35 (2026-03-07)
|
|
109
|
-
|
|
110
|
-
- changes to settargetmediastate
|
|
111
|
-
|
|
112
|
-
## 2.4.0-alpha.34 (2026-03-07)
|
|
113
|
-
|
|
114
|
-
- changes to settargetmediastate
|
|
115
|
-
|
|
116
|
-
## 2.4.0-alpha.33 (2026-03-07)
|
|
117
|
-
|
|
118
|
-
- optimised getmqtttoken
|
|
119
|
-
- checked function of setTargetMediaState , needs testing, controlled by Eve
|
|
120
|
-
|
|
121
|
-
## 2.4.0-alpha.32 (2026-03-07)
|
|
122
|
-
|
|
123
|
-
- made all urls into proper url objects
|
|
124
|
-
- fixed issue with getMostWatchedChannels
|
|
125
|
-
|
|
126
|
-
## 2.4.0-alpha.31 (2026-03-07)
|
|
127
|
-
|
|
128
|
-
- change the master channel list refresh to once a day at a random time between 0000 and 0600. The user setting has no impact and can be removed
|
|
129
|
-
- cleaned up some more diagnostic logging
|
|
130
|
-
|
|
131
|
-
## 2.4.0-alpha.30 (2026-03-07)
|
|
132
|
-
|
|
133
|
-
- cleaned up some diagnostic logging
|
|
134
|
-
|
|
135
|
-
## 2.4.0-alpha.29 (2026-03-06)
|
|
136
|
-
|
|
137
|
-
- optimised refreshDeviceChannelList
|
|
138
|
-
|
|
139
|
-
## 2.4.0-alpha.28 (2026-03-06)
|
|
140
|
-
|
|
141
|
-
- fixed issue with detecting status, introduce 2 versions ago
|
|
142
|
-
|
|
143
|
-
## 2.4.0-alpha.27 (2026-03-06)
|
|
144
|
-
|
|
145
|
-
-- removed test code to detect plugin shutdown
|
|
146
|
-
|
|
147
|
-
## 2.4.0-alpha.26 (2026-03-06)
|
|
148
|
-
|
|
149
|
-
-- added test code to detect plugin shutdown
|
|
150
|
-
- added clean unsubscribe on plugin shutdown
|
|
151
|
-
|
|
152
|
-
## 2.4.0-alpha.25 (2026-03-05)
|
|
153
|
-
|
|
154
|
-
- fixed introduced bug in setRemoteKey
|
|
155
|
-
|
|
156
|
-
## 2.4.0-alpha.24 (2026-03-05)
|
|
157
|
-
|
|
158
|
-
- made channel ConfiguredName read only as the backend defines the channel name
|
|
159
|
-
|
|
160
|
-
## 2.4.0-alpha.23 (2026-03-05)
|
|
161
|
-
|
|
162
|
-
- optimised setRemoteKey
|
|
163
|
-
|
|
164
|
-
## 2.4.0-alpha.22 (2026-03-05)
|
|
165
|
-
|
|
166
|
-
- fixed error handling in refreshMasterChannelList
|
|
167
|
-
|
|
168
|
-
## 2.4.0-alpha.21 (2026-03-05)
|
|
169
|
-
|
|
170
|
-
- fixed logging bug in sendKey
|
|
171
|
-
|
|
172
|
-
## 2.4.0-alpha.20 (2026-03-05)
|
|
173
|
-
|
|
174
|
-
- improved accessory information display to show a better serialnumber
|
|
175
|
-
- updated set-top box model name for 2008C
|
|
176
|
-
- added more robustness to many calls in case we never get a configsvc response
|
|
177
|
-
- optimised the mqttDeviceStateHandler
|
|
178
|
-
- improved refreshMasterChannelList
|
|
179
|
-
- improved a lot of webservice calls, removing promises and going to try-catch
|
|
180
|
-
|
|
181
|
-
## 2.4.0-alpha.19 (2026-03-04)
|
|
182
|
-
|
|
183
|
-
- removed some dead code
|
|
184
|
-
- enabled handler for setClosedCaptions and setPictureMode, test control from Eve app
|
|
185
|
-
- improved send key logging
|
|
186
|
-
|
|
187
|
-
## 2.4.0-alpha.18 (2026-03-03)
|
|
188
|
-
|
|
189
|
-
- Fixed dislayOrder crash on startup - check this!
|
|
190
|
-
- Optimised post publishExternalAccessories HAP updates
|
|
191
|
-
- Changed all updateValue to updateCharacteristic post-publish to be more HAP compliant
|
|
192
|
-
|
|
193
|
-
## 2.4.0-alpha.17 (2026-03-03)
|
|
194
|
-
|
|
195
|
-
- Cleaned up the platform code
|
|
196
|
-
- Changed all get/set handlers to async
|
|
197
|
-
- Optimised all get/set handlers
|
|
198
|
-
- More HAP minor bug fixes and optimisations
|
|
199
|
-
|
|
200
|
-
## 2.4.0-alpha.16 (2026-03-03)
|
|
201
|
-
|
|
202
|
-
- Fixed bug: TypeError: this.prepareinputSourceServices is not a function
|
|
203
|
-
|
|
204
|
-
## 2.4.0-alpha.15 (2026-03-03)
|
|
205
|
-
|
|
206
|
-
- Renamed Current Channnel Id and Current Channel Name to Active Channel Id and Active Channel Name for consistency with Active Identifier
|
|
207
|
-
|
|
208
|
-
## 2.4.0-alpha.14 (2026-03-03)
|
|
209
|
-
|
|
210
|
-
- Optimised HAP code for strict compliance
|
|
211
|
-
- Removed debug logging
|
|
212
|
-
|
|
213
|
-
## 2.4.0-alpha.13 (2026-03-03)
|
|
214
|
-
|
|
215
|
-
- Fixes to logging of getInputName for diagnostics
|
|
216
|
-
|
|
217
|
-
## 2.4.0-alpha.12 (2026-03-03)
|
|
218
|
-
|
|
219
|
-
- More improvements to get ConfiguredName working properly on the Eve app (needs testing for both TV and Inputs)
|
|
220
|
-
|
|
221
|
-
## 2.4.0-alpha.11 (2026-03-03)
|
|
222
|
-
|
|
223
|
-
- Fixed logging bug in setInputName
|
|
224
|
-
|
|
225
|
-
## 2.4.0-alpha.10 (2026-03-03)
|
|
226
|
-
|
|
227
|
-
## 2.4.0-alpha.9 (2026-03-03)
|
|
228
|
-
|
|
229
|
-
## 2.4.0-alpha.8 (2026-03-03)
|
|
230
|
-
|
|
231
|
-
- More improvements to get ConfiguredName working properly on the Eve app (needs testing for both TV and Inputs)
|
|
232
|
-
|
|
233
|
-
## 2.4.0-alpha.7 (2026-03-03)
|
|
234
|
-
|
|
235
|
-
- Corrected some debug log levels
|
|
236
|
-
- Fixed ConfiguredName being empty on the Eve app (needs testing for both TV and Inputs)
|
|
237
|
-
|
|
238
|
-
## 2.4.0-alpha.6 (2026-03-02)
|
|
239
|
-
|
|
240
|
-
- Removed getMute and getVolume, these are not supported
|
|
241
|
-
- More code optimisations
|
|
242
|
-
|
|
243
|
-
## 2.4.0-alpha.5 (2026-03-02)
|
|
244
|
-
|
|
245
|
-
- More code performance improvements
|
|
246
|
-
- Improved all HAP code
|
|
247
|
-
|
|
248
|
-
## 2.4.0-alpha.4 (2026-03-02)
|
|
249
|
-
|
|
250
|
-
- Fixed self bug in volume control
|
|
251
|
-
|
|
252
|
-
## 2.4.0-alpha.4 (2026-03-02)
|
|
253
|
-
|
|
254
|
-
- Fixed self bug in volume control
|
|
255
|
-
|
|
256
|
-
## 2.4.0-alpha.3 (2026-03-02)
|
|
257
|
-
|
|
258
|
-
- Fixed new introduced bug with displayed channel being incorrect (offset by 1)
|
|
259
|
-
- Added "devMode": true support to config.json
|
|
260
|
-
|
|
261
|
-
## 2.4.0-alpha.2 (2026-03-01)
|
|
262
|
-
|
|
263
|
-
- Improved README.md text
|
|
264
|
-
- Improved config.schema.json description text
|
|
265
|
-
- Improved discovery of devices and accessory setup
|
|
266
|
-
- Improved mqtt handling
|
|
267
|
-
- Improved overall code robustness and fixed many small bugs
|
|
268
|
-
- Fixed spelling mistakes in comments
|
|
269
|
-
|
|
270
|
-
## 2.4.0-alpha.1 (2026-02-27)
|
|
271
|
-
|
|
272
|
-
- Adapted login sequence for CH
|
|
273
|
-
- Updated config.schema.json to support new CH login method and improced description texts
|
|
274
|
-
- Bumped dependency "axios": "^1.13.6",
|
|
45
|
+
- Bumped dependency "ws": "^8.20.0"
|
|
275
46
|
|
|
276
47
|
## 2.3.8 (2026-02-27)
|
|
277
48
|
|
package/index.js
CHANGED
|
@@ -357,6 +357,7 @@ class StbPlatform {
|
|
|
357
357
|
this.masterChannelList = [];
|
|
358
358
|
this.masterChannelListExpiryDate = 0; // epoch = always expired on first run
|
|
359
359
|
this.checkChannelListTimeout = null; // nightly scheduler handler
|
|
360
|
+
this.mqttReconnecting = false; // nightly reconnect indicator
|
|
360
361
|
this.isDev = config.devMode === true;
|
|
361
362
|
this.debugLevel = this.config.debugLevel || 0; // debugLevel defaults to 0 (minimum)
|
|
362
363
|
|
|
@@ -822,7 +823,7 @@ class StbPlatform {
|
|
|
822
823
|
|
|
823
824
|
/**
|
|
824
825
|
* Schedule the next nightly master channel list refresh.
|
|
825
|
-
* Picks a random time between 00:00 and
|
|
826
|
+
* Picks a random time between 00:00 and 04:00 the following day,
|
|
826
827
|
* then reschedules itself so the pattern repeats indefinitely.
|
|
827
828
|
*
|
|
828
829
|
* Using setTimeout (not setInterval) means each day gets a fresh
|
|
@@ -834,9 +835,9 @@ class StbPlatform {
|
|
|
834
835
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
835
836
|
tomorrow.setHours(0, 0, 0, 0);
|
|
836
837
|
|
|
837
|
-
// Add a random offset: anywhere from 0 ms up to (but not including)
|
|
838
|
-
const
|
|
839
|
-
const randomOffsetMs = Math.floor(Math.random() *
|
|
838
|
+
// Add a random offset: anywhere from 0 ms up to (but not including) 4 hours
|
|
839
|
+
const FOUR_HOURS_MS = 4 * 60 * 60 * 1000;
|
|
840
|
+
const randomOffsetMs = Math.floor(Math.random() * FOUR_HOURS_MS);
|
|
840
841
|
|
|
841
842
|
const nextRefreshAt = new Date(tomorrow.getTime() + randomOffsetMs);
|
|
842
843
|
const msUntilRefresh = nextRefreshAt.getTime() - Date.now();
|
|
@@ -850,11 +851,121 @@ class StbPlatform {
|
|
|
850
851
|
// Store the timer handle so shutdown can cancel it
|
|
851
852
|
this.checkChannelListTimeout = setTimeout(async () => {
|
|
852
853
|
if (this.isShuttingDown) return; // bail out if we're going down
|
|
854
|
+
|
|
855
|
+
// if an MQTT reconnect is in progress, wait a few minutes before
|
|
856
|
+
// refreshing to avoid a race condition during session startup
|
|
857
|
+
if (this.mqttReconnecting) {
|
|
858
|
+
const THREE_MIN_MS = 3 * 60 * 1000;
|
|
859
|
+
const retryDelayMs = THREE_MIN_MS + Math.floor(Math.random() * THREE_MIN_MS);
|
|
860
|
+
this.log.info(
|
|
861
|
+
'StbPlatform: channel list refresh deferred - MQTT reconnect in progress, retrying in a few minutes',
|
|
862
|
+
);
|
|
863
|
+
this.checkChannelListTimeout = setTimeout(async () => {
|
|
864
|
+
if (this.isShuttingDown) return;
|
|
865
|
+
await this._refreshChannelList();
|
|
866
|
+
this._scheduleNightlyChannelListRefresh();
|
|
867
|
+
}, retryDelayMs);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
|
|
853
871
|
await this._refreshChannelList();
|
|
854
872
|
this._scheduleNightlyChannelListRefresh(); // reschedule for the next day
|
|
855
873
|
}, msUntilRefresh);
|
|
856
874
|
} // end of _scheduleNightlyChannelListRefresh
|
|
857
875
|
|
|
876
|
+
/**
|
|
877
|
+
* Schedule the next nightly MQTT reconnect.
|
|
878
|
+
* Picks a random time between 04:00 and 06:00 the following day
|
|
879
|
+
* to avoid overlapping with the channel list refresh (00:00–04:00).
|
|
880
|
+
* Reschedules itself so the pattern repeats indefinitely.
|
|
881
|
+
*/
|
|
882
|
+
_scheduleNightlyMqttReconnect() {
|
|
883
|
+
const tomorrow = new Date();
|
|
884
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
885
|
+
tomorrow.setHours(4, 0, 0, 0);
|
|
886
|
+
|
|
887
|
+
const TWO_HOURS_MS = 2 * 60 * 60 * 1000;
|
|
888
|
+
const randomOffsetMs = Math.floor(Math.random() * TWO_HOURS_MS);
|
|
889
|
+
|
|
890
|
+
const nextReconnectAt = new Date(tomorrow.getTime() + randomOffsetMs);
|
|
891
|
+
const msUntilReconnect = nextReconnectAt.getTime() - Date.now();
|
|
892
|
+
|
|
893
|
+
if (this.debugLevel > 0) {
|
|
894
|
+
this.log.warn(
|
|
895
|
+
`StbPlatform: next nightly MQTT reconnect scheduled for ${nextReconnectAt.toLocaleString()}`,
|
|
896
|
+
);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
this.mqttReconnectTimeout = setTimeout(async () => {
|
|
900
|
+
if (this.isShuttingDown) return;
|
|
901
|
+
await this._attemptNightlyMqttReconnect();
|
|
902
|
+
// _attemptNightlyMqttReconnect reschedules for the next night once done
|
|
903
|
+
}, msUntilReconnect);
|
|
904
|
+
} // end of _scheduleNightlyMqttReconnect
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* Attempt the nightly MQTT reconnect.
|
|
909
|
+
* If any STB is currently online (user may be watching), defers by 1 hour
|
|
910
|
+
* plus a random offset and tries again, rather than interrupting the session.
|
|
911
|
+
* Once the reconnect completes (or fails), reschedules for the next night.
|
|
912
|
+
* Retries 3 times then gives up, and the next reconnect will be the next day.
|
|
913
|
+
*/
|
|
914
|
+
async _attemptNightlyMqttReconnect(retryCount = 0) {
|
|
915
|
+
if (this.isShuttingDown) return;
|
|
916
|
+
|
|
917
|
+
const MAX_RETRIES = 3; // give up after 3 deferrals (~3-4.5 hours past 04:00)
|
|
918
|
+
|
|
919
|
+
// check if any STB is currently active - if so, defer to avoid
|
|
920
|
+
// interrupting a user who may be watching TV and using the remote
|
|
921
|
+
const anyStbOnline = this.devices.some(
|
|
922
|
+
(device) => device.currentPowerState === Characteristic.Active.ACTIVE,
|
|
923
|
+
);
|
|
924
|
+
|
|
925
|
+
if (anyStbOnline) {
|
|
926
|
+
// give up if max retries reached
|
|
927
|
+
if (retryCount >= MAX_RETRIES) {
|
|
928
|
+
this.log.info(
|
|
929
|
+
'StbPlatform: nightly MQTT reconnect skipped - STB still active after max retries, rescheduling for next night',
|
|
930
|
+
);
|
|
931
|
+
this._scheduleNightlyMqttReconnect();
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// retry in 1 hour plus a random 0–30 min buffer
|
|
936
|
+
const ONE_HOUR_MS = 60 * 60 * 1000;
|
|
937
|
+
const THIRTY_MIN_MS = 30 * 60 * 1000;
|
|
938
|
+
const retryDelayMs = ONE_HOUR_MS + Math.floor(Math.random() * THIRTY_MIN_MS);
|
|
939
|
+
const retryAt = new Date(Date.now() + retryDelayMs);
|
|
940
|
+
|
|
941
|
+
this.log.info(
|
|
942
|
+
`StbPlatform: nightly MQTT reconnect deferred - STB is active (attempt ${retryCount + 1}/${MAX_RETRIES}). Retrying at ${retryAt.toLocaleString()}`,
|
|
943
|
+
);
|
|
944
|
+
|
|
945
|
+
// store handle so shutdown can cancel the deferred retry too
|
|
946
|
+
this.mqttReconnectTimeout = setTimeout(async () => {
|
|
947
|
+
if (this.isShuttingDown) return;
|
|
948
|
+
await this._attemptNightlyMqttReconnect(retryCount + 1);
|
|
949
|
+
}, retryDelayMs);
|
|
950
|
+
return; // don't reschedule for next night yet - that happens after a successful reconnect
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
// no STB is active - safe to reconnect
|
|
954
|
+
try {
|
|
955
|
+
this.mqttReconnecting = true; // signal to channel list refresh to pause
|
|
956
|
+
this.log.info('StbPlatform: nightly MQTT reconnect starting...');
|
|
957
|
+
await this.endMqttSession();
|
|
958
|
+
await this.startMqttClient();
|
|
959
|
+
this.log.info('StbPlatform: nightly MQTT reconnect completed');
|
|
960
|
+
} catch (err) {
|
|
961
|
+
this.log.error('StbPlatform: nightly MQTT reconnect failed:', err.message);
|
|
962
|
+
} finally {
|
|
963
|
+
this.mqttReconnecting = false; // always clear the flag, even on failure
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
this._scheduleNightlyMqttReconnect(); // reschedule for next night
|
|
967
|
+
} // end of _attemptNightlyMqttReconnect
|
|
968
|
+
|
|
858
969
|
/**
|
|
859
970
|
* _runFullStartupSequence
|
|
860
971
|
*
|
|
@@ -4278,12 +4389,8 @@ class StbPlatform {
|
|
|
4278
4389
|
// ------ device subscriptions ------
|
|
4279
4390
|
// subscribe only to what we need
|
|
4280
4391
|
|
|
4281
|
-
// turn on our clientId. This is similar to turning on a box, it tells the server we are online
|
|
4282
|
-
// our clientId must be up and running to send commands (power, channel, etc) to the physical device
|
|
4283
|
-
// this.setHgoOnlineRunning(householdId, mqttClientId);
|
|
4284
|
-
|
|
4285
4392
|
// householdId/mqttClientId: subscribe to own clientId to get data for ourselves
|
|
4286
|
-
// subscribe to all devices
|
|
4393
|
+
// subscribe to all devices before the setHgoState is sent
|
|
4287
4394
|
this.mqttSubscribeToTopic(
|
|
4288
4395
|
householdId + "/" + this.mqttClient.options.clientId,
|
|
4289
4396
|
); // subscribe to our own mqttClientId to get all data
|
|
@@ -4320,32 +4427,36 @@ class StbPlatform {
|
|
|
4320
4427
|
// reset so the 10-second retry fires correctly if the box doesn't respond
|
|
4321
4428
|
this.lastMqttUiStatusMessageReceived = null;
|
|
4322
4429
|
|
|
4430
|
+
// announce ourselves as an active HGO client before requesting UI status
|
|
4431
|
+
// the STB uses this retained presence message to decide which clients to respond to
|
|
4432
|
+
this.setHgoState(householdId, this.mqttClient.options.clientId, 'ONLINE_RUNNING');
|
|
4433
|
+
|
|
4434
|
+
// request initial UI status for each device, with a short delay to allow
|
|
4435
|
+
// the STB to process the HGO presence announcement first
|
|
4323
4436
|
// CPE.uiStatus messages are received via the householdId and mqttClientId
|
|
4324
4437
|
// topics which are already subscribed above.
|
|
4325
4438
|
// getUiStatus is called here to request the initial UI state from each device.
|
|
4326
4439
|
// retain: false is used (see getUiStatus) so a retry is scheduled in case the box
|
|
4327
4440
|
// is temporarily unreachable when the initial request is sent.
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4441
|
+
setTimeout(() => {
|
|
4442
|
+
this.devices.forEach((device) => {
|
|
4443
|
+
// request the initial UI status for each device
|
|
4444
|
+
this.getUiStatus(device.deviceId, this.mqttClient.options.clientId);
|
|
4445
|
+
|
|
4446
|
+
// retry after 10 seconds if no CPE.uiStatus response has arrived yet
|
|
4447
|
+
setTimeout(() => {
|
|
4448
|
+
if (!this.lastMqttUiStatusMessageReceived) {
|
|
4449
|
+
if (this.debugLevel > 0) {
|
|
4450
|
+
this.log.warn(
|
|
4451
|
+
"getUiStatus: no CPE.uiStatus received yet for %s, retrying",
|
|
4452
|
+
device.deviceId,
|
|
4453
|
+
);
|
|
4454
|
+
}
|
|
4455
|
+
this.getUiStatus(device.deviceId, this.mqttClient.options.clientId);
|
|
4341
4456
|
}
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
);
|
|
4346
|
-
}
|
|
4347
|
-
}, 10 * 1000); // 10 second retry delay
|
|
4348
|
-
});
|
|
4457
|
+
}, 10 * 1000); // 10 second retry delay
|
|
4458
|
+
});
|
|
4459
|
+
}, 500); // 500ms for STB to register our HGO presence before we request status
|
|
4349
4460
|
|
|
4350
4461
|
resolve(true); // all subscriptions registered — session is ready
|
|
4351
4462
|
} catch (err) {
|
|
@@ -4462,7 +4573,7 @@ class StbPlatform {
|
|
|
4462
4573
|
currMediaState = Characteristic.CurrentMediaState.PLAY;
|
|
4463
4574
|
if (this.debugLevel > 0) {
|
|
4464
4575
|
this.log.warn(
|
|
4465
|
-
"mqttClient: STB status:
|
|
4576
|
+
"mqttClient: STB status: Power-on transition detected for %s, setting mediaState to PLAY",
|
|
4466
4577
|
deviceId,
|
|
4467
4578
|
);
|
|
4468
4579
|
}
|
|
@@ -4496,6 +4607,12 @@ class StbPlatform {
|
|
|
4496
4607
|
this.log.warn("mqttClient: %s %s", deviceId, stbState);
|
|
4497
4608
|
}
|
|
4498
4609
|
}
|
|
4610
|
+
|
|
4611
|
+
// After the switch, if box is running, request current UI state
|
|
4612
|
+
//if (stbState === 'ONLINE_RUNNING') {
|
|
4613
|
+
// Small delay gives the STB a moment to settle before responding
|
|
4614
|
+
//setTimeout(() => this.mqttRequestUiStatus(deviceId), 500);
|
|
4615
|
+
//}
|
|
4499
4616
|
}
|
|
4500
4617
|
|
|
4501
4618
|
// handle CPE UI status messages for the STB
|
|
@@ -4878,16 +4995,26 @@ class StbPlatform {
|
|
|
4878
4995
|
return resolve(true);
|
|
4879
4996
|
}
|
|
4880
4997
|
|
|
4881
|
-
//
|
|
4998
|
+
// get all subscribed topics
|
|
4882
4999
|
const topics = this.subscribedTopics ?? [];
|
|
5000
|
+
|
|
5001
|
+
// announce HGO offline while the connection is still live, before any teardown
|
|
5002
|
+
this.setHgoState(
|
|
5003
|
+
this.session.householdId,
|
|
5004
|
+
this.mqttClient.options.clientId,
|
|
5005
|
+
'OFFLINE',
|
|
5006
|
+
);
|
|
5007
|
+
|
|
5008
|
+
// unsubscribe from all subscribedTopics before tearing down the session
|
|
4883
5009
|
if (topics.length === 0) {
|
|
4884
5010
|
this.log.info(
|
|
4885
5011
|
"mqttClient: No topics to unsubscribe from, skipping unsubscribe.",
|
|
4886
5012
|
);
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
5013
|
+
|
|
5014
|
+
this.mqttClient.end(false, {}, (endErr) => {
|
|
5015
|
+
if (endErr) {
|
|
5016
|
+
this.log.error("MQTT end error:", endErr);
|
|
5017
|
+
return reject(endErr);
|
|
4891
5018
|
}
|
|
4892
5019
|
this.log.info(
|
|
4893
5020
|
"mqttClient: Disconnected cleanly. No topics found to unsubscribe from.",
|
|
@@ -4897,15 +5024,15 @@ class StbPlatform {
|
|
|
4897
5024
|
return;
|
|
4898
5025
|
}
|
|
4899
5026
|
|
|
4900
|
-
this.mqttClient.unsubscribe(topics, (
|
|
4901
|
-
if (
|
|
4902
|
-
this.log.error("MQTT unsubscribe error:",
|
|
5027
|
+
this.mqttClient.unsubscribe(topics, (unsubErr) => {
|
|
5028
|
+
if (unsubErr) {
|
|
5029
|
+
this.log.error("MQTT unsubscribe error:", unsubErr);
|
|
4903
5030
|
// still attempt to end even if unsubscribe failed
|
|
4904
5031
|
}
|
|
4905
|
-
this.mqttClient.end(false, {}, (
|
|
4906
|
-
if (
|
|
4907
|
-
this.log.error("MQTT end error:",
|
|
4908
|
-
return reject(
|
|
5032
|
+
this.mqttClient.end(false, {}, (endErr) => {
|
|
5033
|
+
if (endErr) {
|
|
5034
|
+
this.log.error("MQTT end error:", endErr);
|
|
5035
|
+
return reject(endErr);
|
|
4909
5036
|
}
|
|
4910
5037
|
this.log.info(
|
|
4911
5038
|
"mqttClient: Disconnected cleanly. All topics unsubscribed.",
|
|
@@ -4990,7 +5117,7 @@ class StbPlatform {
|
|
|
4990
5117
|
"mqttPublishMessage: Publish Message:\r\nTopic: %s\r\nMessage: %s\r\nOptions: %s",
|
|
4991
5118
|
Topic,
|
|
4992
5119
|
Message,
|
|
4993
|
-
Options,
|
|
5120
|
+
JSON.stringify(Options),
|
|
4994
5121
|
);
|
|
4995
5122
|
}
|
|
4996
5123
|
this.mqttClient.publish(Topic, Message, Options, (err) => {
|
|
@@ -5081,23 +5208,25 @@ class StbPlatform {
|
|
|
5081
5208
|
});
|
|
5082
5209
|
}
|
|
5083
5210
|
|
|
5084
|
-
//
|
|
5085
|
-
|
|
5086
|
-
|
|
5211
|
+
// set the HGO session state (online or offline)
|
|
5212
|
+
// called on mqtt connect (ONLINE_RUNNING) and on mqtt disconnect (OFFLINE)
|
|
5213
|
+
// retain: true ensures the broker overwrites any previous retained state
|
|
5214
|
+
setHgoState(householdId, mqttClientId, state) {
|
|
5087
5215
|
const topic = `${householdId}/${mqttClientId}/status`;
|
|
5088
5216
|
const message = JSON.stringify({
|
|
5089
5217
|
source: mqttClientId,
|
|
5090
|
-
state:
|
|
5091
|
-
deviceType:
|
|
5092
|
-
mac:
|
|
5093
|
-
ipAddress:
|
|
5218
|
+
state: state,
|
|
5219
|
+
deviceType: 'HGO',
|
|
5220
|
+
mac: '',
|
|
5221
|
+
ipAddress: '',
|
|
5094
5222
|
});
|
|
5095
5223
|
if (this.debugLevel > 0) {
|
|
5096
|
-
this.log.warn(
|
|
5224
|
+
this.log.warn('setHgoState: publishing %s to topic: %s', state, topic);
|
|
5097
5225
|
}
|
|
5098
5226
|
this.mqttPublishMessage(topic, message, { qos: 2, retain: true });
|
|
5099
5227
|
}
|
|
5100
5228
|
|
|
5229
|
+
|
|
5101
5230
|
// send a channel change request to the settopbox via mqtt
|
|
5102
5231
|
// using the CPE.pushToTV message
|
|
5103
5232
|
// the friendlyDeviceName appears on the TV in a popup window
|
|
@@ -5151,6 +5280,37 @@ class StbPlatform {
|
|
|
5151
5280
|
}
|
|
5152
5281
|
}
|
|
5153
5282
|
|
|
5283
|
+
// Request the current UI status from the STB.
|
|
5284
|
+
// The STB responds with a CPE.uiStatus message on the household channel.
|
|
5285
|
+
// @param {string} deviceId - The STB device ID (e.g. "000378-EOS2STB-00852052xxxx")
|
|
5286
|
+
mqttRequestUiStatus(deviceId) {
|
|
5287
|
+
if (!this.mqttClient?.connected) {
|
|
5288
|
+
this.log.warn('%s: mqttRequestUiStatus: MQTT not connected, skipping', deviceId);
|
|
5289
|
+
return;
|
|
5290
|
+
}
|
|
5291
|
+
if (this.debugLevel > 0) {
|
|
5292
|
+
this.log.warn(
|
|
5293
|
+
"mqttRequestUiStatus: Requesting UI status for %s",
|
|
5294
|
+
deviceId,
|
|
5295
|
+
);
|
|
5296
|
+
}
|
|
5297
|
+
|
|
5298
|
+
const payload = JSON.stringify({
|
|
5299
|
+
version: '1.3.18',
|
|
5300
|
+
type: 'CPE.pullFromTV',
|
|
5301
|
+
source: this.mqttClient.options.clientId, // your mqttClientId
|
|
5302
|
+
messageTimeStamp: Date.now(),
|
|
5303
|
+
});
|
|
5304
|
+
|
|
5305
|
+
const topic = `${this.session.householdId}/${deviceId}`;
|
|
5306
|
+
|
|
5307
|
+
this.mqttPublishMessage(topic, payload, {
|
|
5308
|
+
qos: 1,
|
|
5309
|
+
retain: false,
|
|
5310
|
+
});
|
|
5311
|
+
|
|
5312
|
+
}
|
|
5313
|
+
|
|
5154
5314
|
// set the media state of the settopbox via mqtt
|
|
5155
5315
|
// media state is controlled by speedRate
|
|
5156
5316
|
// speedRate can be one of: -64 -30 -6 -2 0 2 6 30 64. 0=Paused, 1=Play, >1=FastForward, <0=Rewind
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"displayName": "Homebridge EOSSTB",
|
|
4
4
|
"description": "Add your set-top box to Homekit (for Telenet BE, Sunrise CH, UPC SK, Virgin Media GB & IE, Ziggo NL)",
|
|
5
5
|
"author": "Jochen Siegenthaler (https://github.com/jsiegenthaler/)",
|
|
6
|
-
"version": "2.4.0-
|
|
6
|
+
"version": "2.4.0-beta.2",
|
|
7
7
|
"platformname": "eosstb",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"axios": "^1.16.0",
|