homebridge-eosstb 2.4.0-beta.2 → 2.4.0-beta.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 +25 -0
- package/README.md +1 -2
- package/index.js +250 -206
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,17 @@ See the [Readme file](https://github.com/jsiegenthaler/homebridge-eosstb/blob/ma
|
|
|
5
5
|
Please restart Homebridge after every plugin update.
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
## 2.4.0-beta.4 (2026-05-10)
|
|
9
|
+
|
|
10
|
+
- Improved performance of refreshMasterChannelList
|
|
11
|
+
|
|
12
|
+
## 2.4.0-beta.3 (2026-05-10)
|
|
13
|
+
|
|
14
|
+
This release focusses improved error handling and has extra debugging added to catch a refresh error
|
|
15
|
+
|
|
16
|
+
- Improved handling of errors for web requests
|
|
17
|
+
- Added extra debugging to assist in catching a refresh error in refreshMasterChannelList
|
|
18
|
+
|
|
8
19
|
## 2.4.0-beta.2 (2026-05-09)
|
|
9
20
|
|
|
10
21
|
This release focusses on ensuring mqtt long-term stability, and fixes an issue where the channel name was not shown on startup.
|
|
@@ -44,6 +55,20 @@ This release represents a major rewrite of the plugin, significantly improving r
|
|
|
44
55
|
- Bumped dependency "tough-cookie": "^6.0.1",
|
|
45
56
|
- Bumped dependency "ws": "^8.20.0"
|
|
46
57
|
|
|
58
|
+
## 2.3.9 (2026-05-09)
|
|
59
|
+
- Fixed Error on Homebridge v2: Cannot read properties of undefined (reading 'STRING')
|
|
60
|
+
- Adapted hidden channel name to reduce warning messages with Homebridge v2
|
|
61
|
+
- Updated iOS and Homebridge version references in Readme
|
|
62
|
+
- Bumped engine "^1.11.4||^2.0.0",
|
|
63
|
+
- Bumped engine "node": "^24.15.0"
|
|
64
|
+
- Bumped dependency "axios": "^1.16.0",
|
|
65
|
+
- Bumped dependency "axios-cookiejar-support": "^7.0.0",
|
|
66
|
+
- Bumped dependency "mqtt": "^5.15.1",
|
|
67
|
+
- Bumped dependency "qs": "^6.15.1",
|
|
68
|
+
- Bumped dependency "semver": "^7.8.0",
|
|
69
|
+
- Bumped dependency "tough-cookie": "^6.0.1",
|
|
70
|
+
- Bumped dependency "ws": "^8.20.0"
|
|
71
|
+
|
|
47
72
|
## 2.3.8 (2026-02-27)
|
|
48
73
|
|
|
49
74
|
This is a maintenance release to bring dependencies up to date.
|
package/README.md
CHANGED
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
|
|
21
21
|
The logon method to the backend systems changed in January / February 2024. I managed to get CH working again from April 2026 for CH. NL was confirmed working OK in May 2026. BE was confirmed working OK in June 2024.
|
|
22
22
|
|
|
23
|
-
If you know anything about session authentication and are able to help, please get in touch.
|
|
24
23
|
</b><hr>
|
|
25
24
|
|
|
26
25
|
[](https://www.npmjs.com/package/homebridge-eosstb)
|
|
@@ -110,7 +109,7 @@ This plugin is not provided by Telenet or Sunrise or Virgin Media or Ziggo or an
|
|
|
110
109
|
## Requirements
|
|
111
110
|
|
|
112
111
|
- An Apple iPhone or iPad with iOS/iPadOS 14.0 (or later). Developed on iOS 14.1-26.4, earlier versions not tested.
|
|
113
|
-
- [Homebridge](https://homebridge.io/) v1.1.116 (or later). Developed on Homebridge 1.1.116-2.0.
|
|
112
|
+
- [Homebridge](https://homebridge.io/) v1.1.116 (or later). Developed on Homebridge 1.1.116-2.0.2, earlier versions not tested.
|
|
114
113
|
- A TV subscription from one of the supported countries and TV providers.
|
|
115
114
|
- An online account for viewing TV in the web app (often part of your TV package), see the table above.
|
|
116
115
|
- An ARRIS DCX960 or HUMAX EOS1008R / 2008C / VIP5002W set-top box, provided by your TV provider as part of your TV subscription, called by the system an "EOSSTB", "EOS2STB" or "APLSTB" and marketed under different names in different countries.
|
package/index.js
CHANGED
|
@@ -355,7 +355,8 @@ class StbPlatform {
|
|
|
355
355
|
this.accessories = [];
|
|
356
356
|
this.stbDevices = []; // store stbDevice in this.stbDevices
|
|
357
357
|
this.masterChannelList = [];
|
|
358
|
-
this.
|
|
358
|
+
this.masterChannelListRefreshedAt = null; // null = never fetched since startup
|
|
359
|
+
this.masterChannelListExpiryDate = 0; // epoch = always expired on first run, forces immediate fetch
|
|
359
360
|
this.checkChannelListTimeout = null; // nightly scheduler handler
|
|
360
361
|
this.mqttReconnecting = false; // nightly reconnect indicator
|
|
361
362
|
this.isDev = config.devMode === true;
|
|
@@ -856,9 +857,10 @@ class StbPlatform {
|
|
|
856
857
|
// refreshing to avoid a race condition during session startup
|
|
857
858
|
if (this.mqttReconnecting) {
|
|
858
859
|
const THREE_MIN_MS = 3 * 60 * 1000;
|
|
859
|
-
const retryDelayMs =
|
|
860
|
+
const retryDelayMs =
|
|
861
|
+
THREE_MIN_MS + Math.floor(Math.random() * THREE_MIN_MS);
|
|
860
862
|
this.log.info(
|
|
861
|
-
|
|
863
|
+
"StbPlatform: channel list refresh deferred - MQTT reconnect in progress, retrying in a few minutes",
|
|
862
864
|
);
|
|
863
865
|
this.checkChannelListTimeout = setTimeout(async () => {
|
|
864
866
|
if (this.isShuttingDown) return;
|
|
@@ -903,7 +905,6 @@ class StbPlatform {
|
|
|
903
905
|
}, msUntilReconnect);
|
|
904
906
|
} // end of _scheduleNightlyMqttReconnect
|
|
905
907
|
|
|
906
|
-
|
|
907
908
|
/**
|
|
908
909
|
* Attempt the nightly MQTT reconnect.
|
|
909
910
|
* If any STB is currently online (user may be watching), defers by 1 hour
|
|
@@ -926,7 +927,7 @@ class StbPlatform {
|
|
|
926
927
|
// give up if max retries reached
|
|
927
928
|
if (retryCount >= MAX_RETRIES) {
|
|
928
929
|
this.log.info(
|
|
929
|
-
|
|
930
|
+
"StbPlatform: nightly MQTT reconnect skipped - STB still active after max retries, rescheduling for next night",
|
|
930
931
|
);
|
|
931
932
|
this._scheduleNightlyMqttReconnect();
|
|
932
933
|
return;
|
|
@@ -935,7 +936,8 @@ class StbPlatform {
|
|
|
935
936
|
// retry in 1 hour plus a random 0–30 min buffer
|
|
936
937
|
const ONE_HOUR_MS = 60 * 60 * 1000;
|
|
937
938
|
const THIRTY_MIN_MS = 30 * 60 * 1000;
|
|
938
|
-
const retryDelayMs =
|
|
939
|
+
const retryDelayMs =
|
|
940
|
+
ONE_HOUR_MS + Math.floor(Math.random() * THIRTY_MIN_MS);
|
|
939
941
|
const retryAt = new Date(Date.now() + retryDelayMs);
|
|
940
942
|
|
|
941
943
|
this.log.info(
|
|
@@ -953,12 +955,15 @@ class StbPlatform {
|
|
|
953
955
|
// no STB is active - safe to reconnect
|
|
954
956
|
try {
|
|
955
957
|
this.mqttReconnecting = true; // signal to channel list refresh to pause
|
|
956
|
-
this.log.info(
|
|
958
|
+
this.log.info("StbPlatform: nightly MQTT reconnect starting...");
|
|
957
959
|
await this.endMqttSession();
|
|
958
960
|
await this.startMqttClient();
|
|
959
|
-
this.log.info(
|
|
961
|
+
this.log.info("StbPlatform: nightly MQTT reconnect completed");
|
|
960
962
|
} catch (err) {
|
|
961
|
-
this.log.error(
|
|
963
|
+
this.log.error(
|
|
964
|
+
"StbPlatform: nightly MQTT reconnect failed:",
|
|
965
|
+
err.message,
|
|
966
|
+
);
|
|
962
967
|
} finally {
|
|
963
968
|
this.mqttReconnecting = false; // always clear the flag, even on failure
|
|
964
969
|
}
|
|
@@ -983,7 +988,7 @@ class StbPlatform {
|
|
|
983
988
|
* 10. startMqttClient — connect to the mqtt broker
|
|
984
989
|
*
|
|
985
990
|
* Each step is individually awaited, so failures are caught at the right
|
|
986
|
-
* step and
|
|
991
|
+
* step and stepName is accurate when logged.
|
|
987
992
|
*
|
|
988
993
|
* @param {string} watchdogInstance - log prefix for this watchdog invocation
|
|
989
994
|
* @param {string} debugPrefix - debug() colour prefix
|
|
@@ -994,12 +999,13 @@ class StbPlatform {
|
|
|
994
999
|
Object.keys(sessionState)[this.currentSessionState],
|
|
995
1000
|
);
|
|
996
1001
|
|
|
997
|
-
//
|
|
1002
|
+
// stepName tracks which step we're on so the catch block can log a
|
|
998
1003
|
// meaningful message rather than a generic "something failed".
|
|
999
|
-
let
|
|
1004
|
+
let stepName = "";
|
|
1000
1005
|
|
|
1001
1006
|
try {
|
|
1002
1007
|
// ── Step 1: Get backend config (endpoint URLs) for the country ──────────
|
|
1008
|
+
stepName = "get config";
|
|
1003
1009
|
this.log.debug("%s: ++++ step 1: calling getConfig", watchdogInstance);
|
|
1004
1010
|
debug(debugPrefix + "calling getConfig");
|
|
1005
1011
|
|
|
@@ -1013,7 +1019,7 @@ class StbPlatform {
|
|
|
1013
1019
|
);
|
|
1014
1020
|
|
|
1015
1021
|
// ── Step 2: Authenticate and create a session ──────────────────────────
|
|
1016
|
-
|
|
1022
|
+
stepName = "create session";
|
|
1017
1023
|
this.log.debug(
|
|
1018
1024
|
"%s: ++++ step 2: calling createSession for country %s",
|
|
1019
1025
|
watchdogInstance,
|
|
@@ -1024,6 +1030,12 @@ class StbPlatform {
|
|
|
1024
1030
|
|
|
1025
1031
|
const sessionHouseholdId = await this.createSession();
|
|
1026
1032
|
// Result stored in this.session by createSession()
|
|
1033
|
+
// debugging help to get session keys
|
|
1034
|
+
// session object keys: ["accessToken","householdId","refreshToken","refreshTokenExpiry","username","issuedAt"]
|
|
1035
|
+
this.log.debug(
|
|
1036
|
+
"session object keys: %s",
|
|
1037
|
+
JSON.stringify(Object.keys(this.session ?? {})),
|
|
1038
|
+
);
|
|
1027
1039
|
|
|
1028
1040
|
this.log.debug(
|
|
1029
1041
|
"%s: ++++++ step 2 done: session created, householdId %s",
|
|
@@ -1032,7 +1044,7 @@ class StbPlatform {
|
|
|
1032
1044
|
);
|
|
1033
1045
|
|
|
1034
1046
|
// ── Step 3: Fetch customer profile and assigned devices ────────────────
|
|
1035
|
-
|
|
1047
|
+
stepName = "discover platform";
|
|
1036
1048
|
this.log.debug(
|
|
1037
1049
|
"%s: ++++ step 3: calling getPersonalizationData for householdId %s",
|
|
1038
1050
|
watchdogInstance,
|
|
@@ -1128,7 +1140,7 @@ class StbPlatform {
|
|
|
1128
1140
|
}
|
|
1129
1141
|
|
|
1130
1142
|
// ── Step 8: Discover and configure HomeKit accessories ─────────────────
|
|
1131
|
-
|
|
1143
|
+
stepName = "discover devices";
|
|
1132
1144
|
this.log.debug(
|
|
1133
1145
|
"%s: ++++ step 8: calling discoverDevices",
|
|
1134
1146
|
watchdogInstance,
|
|
@@ -1146,7 +1158,7 @@ class StbPlatform {
|
|
|
1146
1158
|
);
|
|
1147
1159
|
|
|
1148
1160
|
// ── Step 9: Get the mqtt broker token ─────────────────────────────────
|
|
1149
|
-
|
|
1161
|
+
stepName = "start mqtt session";
|
|
1150
1162
|
this.log.debug("%s: ++++ step 9: calling getMqttToken", watchdogInstance);
|
|
1151
1163
|
debug(debugPrefix + "calling getMqttToken");
|
|
1152
1164
|
|
|
@@ -1183,15 +1195,66 @@ class StbPlatform {
|
|
|
1183
1195
|
watchdogInstance,
|
|
1184
1196
|
);
|
|
1185
1197
|
} catch (errorReason) {
|
|
1186
|
-
// One of the steps above threw or rejected. Log the failed
|
|
1187
|
-
//
|
|
1188
|
-
|
|
1198
|
+
// One of the steps above threw or rejected. Log the failed stepName
|
|
1199
|
+
// alongside the error message for easy diagnosis.
|
|
1200
|
+
const errMsg =
|
|
1201
|
+
errorReason instanceof Error
|
|
1202
|
+
? errorReason.message
|
|
1203
|
+
: String(errorReason);
|
|
1204
|
+
this.log.warn("%s: Failed to %s: %s", watchdogInstance, stepName, errMsg);
|
|
1189
1205
|
this.currentSessionState = sessionState.DISCONNECTED;
|
|
1190
1206
|
this.currentStatusFault = Characteristic.StatusFault.GENERAL_FAULT;
|
|
1191
1207
|
// sessionWatchdogRunning is reset in the finally block of the caller.
|
|
1192
1208
|
}
|
|
1193
1209
|
} // end of _runFullStartupSequence
|
|
1194
1210
|
|
|
1211
|
+
/**
|
|
1212
|
+
* _handleWebError
|
|
1213
|
+
*
|
|
1214
|
+
* Standardised catch-block handler for all outbound HTTP/Axios calls.
|
|
1215
|
+
* Builds a consistent human-readable error message, sets session state
|
|
1216
|
+
* to DISCONNECTED on ENOTFOUND, logs at debug level, then re-throws.
|
|
1217
|
+
*
|
|
1218
|
+
* @param {Error} error - the caught error
|
|
1219
|
+
* @param {string} action - what the caller was trying to do, e.g.
|
|
1220
|
+
* "get config data for countryCode ch"
|
|
1221
|
+
* @param {string|URL} url - the URL that was called (for debug context)
|
|
1222
|
+
*/
|
|
1223
|
+
_handleWebError(error, action, url) {
|
|
1224
|
+
const urlStr = String(url ?? error.config?.url ?? "");
|
|
1225
|
+
let errReason = `Could not ${action}:`;
|
|
1226
|
+
|
|
1227
|
+
if (error.isAxiosError) {
|
|
1228
|
+
errReason += ` ${error.code}`;
|
|
1229
|
+
|
|
1230
|
+
if (error.response) {
|
|
1231
|
+
errReason += ` (HTTP ${error.response.status})`;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
if (error.code === "ENOTFOUND") {
|
|
1235
|
+
errReason += " - no internet connection";
|
|
1236
|
+
this.currentSessionState = sessionState.DISCONNECTED;
|
|
1237
|
+
}
|
|
1238
|
+
} else {
|
|
1239
|
+
errReason += ` — ${error.message ?? String(error)}`;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
if (urlStr) errReason += ` — ${urlStr}`;
|
|
1243
|
+
|
|
1244
|
+
// Summary always visible:
|
|
1245
|
+
this.log.error("_handleWebError: %s", errReason);
|
|
1246
|
+
|
|
1247
|
+
this.log.debug("_handleWebError: %s — full error:", errReason, error);
|
|
1248
|
+
if (error.response?.data) {
|
|
1249
|
+
this.log.debug(
|
|
1250
|
+
"_handleWebError: response body: %s",
|
|
1251
|
+
JSON.stringify(error.response.data).substring(0, 400),
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
throw new Error(errReason, { cause: error });
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1195
1258
|
/**
|
|
1196
1259
|
* Discovers all physical devices from the backend and maps them to HomeKit accessories.
|
|
1197
1260
|
* Creates new accessories for uncached devices, and restores existing ones from cache.
|
|
@@ -2720,8 +2783,8 @@ class StbPlatform {
|
|
|
2720
2783
|
);
|
|
2721
2784
|
}
|
|
2722
2785
|
throw new Error(
|
|
2723
|
-
|
|
2724
|
-
|
|
2786
|
+
// use a simple clean message to tell the user his credentials are likely wrong
|
|
2787
|
+
`Step 4 of 5: login failed — check your username and password`,
|
|
2725
2788
|
);
|
|
2726
2789
|
}
|
|
2727
2790
|
|
|
@@ -3247,6 +3310,18 @@ class StbPlatform {
|
|
|
3247
3310
|
return;
|
|
3248
3311
|
}
|
|
3249
3312
|
|
|
3313
|
+
// Log session state before the request - DIAGNOSES DEBUG ONLY
|
|
3314
|
+
const tokenAge = this.session?.issuedAt
|
|
3315
|
+
? Math.round((Date.now() - this.session.issuedAt) / 1000 / 60)
|
|
3316
|
+
: null;
|
|
3317
|
+
const sessionId = this.session?.householdId ?? "(none)";
|
|
3318
|
+
|
|
3319
|
+
this.log.debug(
|
|
3320
|
+
"refreshMasterChannelList: starting | householdId=%s | tokenAgeMinutes=%s",
|
|
3321
|
+
sessionId,
|
|
3322
|
+
tokenAge ?? "unknown",
|
|
3323
|
+
);
|
|
3324
|
+
|
|
3250
3325
|
// exit immediately if channel list has not expired
|
|
3251
3326
|
if (Date.now() < this.masterChannelListExpiryDate) {
|
|
3252
3327
|
if (this.debugLevel > 1) {
|
|
@@ -3265,16 +3340,6 @@ class StbPlatform {
|
|
|
3265
3340
|
// syntax:
|
|
3266
3341
|
// https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/channels?byLocationId=41043&includeInvisible=true&includeNotEntitled=true&personalised=true&sort=channelNumber
|
|
3267
3342
|
// https://prod.spark.sunrisetv.ch/eng/web/linear-service/v2/channels?cityId=401&language=en&productClass=Orion-DASH
|
|
3268
|
-
/*
|
|
3269
|
-
let url = COUNTRY_BASE_URLS[this.config.country.toLowerCase()] + '/channels';
|
|
3270
|
-
url = url + '?byLocationId=' + this.session.locationId // locationId needed to get user-specific list
|
|
3271
|
-
url = url + '&includeInvisible=true' // includeInvisible
|
|
3272
|
-
url = url + '&includeNotEntitled=true' // includeNotEntitled
|
|
3273
|
-
url = url + '&personalised=true' // personalised
|
|
3274
|
-
url = url + '&sort=channelNumber' // sort
|
|
3275
|
-
*/
|
|
3276
|
-
//url = 'https://prod.spark.sunrisetv.ch/eng/web/linear-service/v2/channels?cityId=401&language=en&productClass=Orion-DASH'
|
|
3277
|
-
//let url = COUNTRY_BASE_URLS[this.config.country.toLowerCase()] + '/eng/web/linear-service/v2/channels';
|
|
3278
3343
|
const url = new URL(`${this.configsvc.linearService.URL}/v2/channels`);
|
|
3279
3344
|
url.searchParams.set("cityId", this.customer.cityId);
|
|
3280
3345
|
url.searchParams.set("language", "en");
|
|
@@ -3283,6 +3348,7 @@ class StbPlatform {
|
|
|
3283
3348
|
if (this.debugLevel > 1) {
|
|
3284
3349
|
this.log.warn("refreshMasterChannelList: GET %s", url);
|
|
3285
3350
|
}
|
|
3351
|
+
|
|
3286
3352
|
try {
|
|
3287
3353
|
// call the webservice to get all available channels
|
|
3288
3354
|
const config = {
|
|
@@ -3297,6 +3363,29 @@ class StbPlatform {
|
|
|
3297
3363
|
"https://www.horizon.tv/",
|
|
3298
3364
|
},
|
|
3299
3365
|
};
|
|
3366
|
+
// extra debugging to help catch refresh issues
|
|
3367
|
+
this.log.debug(
|
|
3368
|
+
"refreshMasterChannelList: request headers | x-oesp-token=%s...%s | x-oesp-username=%s | Referer=%s",
|
|
3369
|
+
this.session.accessToken?.substring(0, 8) ?? "(null)", // first 8 chars only — don't log the full token
|
|
3370
|
+
this.session.accessToken?.slice(-4) ?? "", // last 4 chars
|
|
3371
|
+
this.session.username ?? "(null)",
|
|
3372
|
+
config.headers.Referer,
|
|
3373
|
+
);
|
|
3374
|
+
// extra debugging to help catch refresh issues
|
|
3375
|
+
this.log.debug(
|
|
3376
|
+
"refreshMasterChannelList: preflight | cityId=%s | tokenPresent=%s | tokenLength=%s | username=%s | prevExpiryWas=%s | lastRefreshedAt=%s",
|
|
3377
|
+
this.customer.cityId,
|
|
3378
|
+
!!this.session?.accessToken,
|
|
3379
|
+
this.session?.accessToken?.length ?? 0,
|
|
3380
|
+
this.session?.username ?? "(none)",
|
|
3381
|
+
this.masterChannelListExpiryDate
|
|
3382
|
+
? new Date(this.masterChannelListExpiryDate).toLocaleString()
|
|
3383
|
+
: "(never set)",
|
|
3384
|
+
this.masterChannelListRefreshedAt
|
|
3385
|
+
? new Date(this.masterChannelListRefreshedAt).toLocaleString()
|
|
3386
|
+
: "(never)",
|
|
3387
|
+
);
|
|
3388
|
+
|
|
3300
3389
|
const response = await axiosWS(config);
|
|
3301
3390
|
if (this.debugLevel > 1) {
|
|
3302
3391
|
this.log.warn(
|
|
@@ -3309,46 +3398,53 @@ class StbPlatform {
|
|
|
3309
3398
|
response.data.length,
|
|
3310
3399
|
);
|
|
3311
3400
|
}
|
|
3312
|
-
//this.log(response.data);
|
|
3313
3401
|
|
|
3314
3402
|
// the header contains the following:
|
|
3315
3403
|
// Cache-Control: max-age=600, public, stale-if-error=43200
|
|
3316
|
-
// this could be used to set expiry date...
|
|
3317
3404
|
const cacheControl = response.headers["cache-control"];
|
|
3318
|
-
const
|
|
3319
|
-
|
|
3405
|
+
const maxAge = cacheControl
|
|
3406
|
+
?.split(",")
|
|
3407
|
+
.find((part) => part.trim().startsWith("max-age="))
|
|
3408
|
+
?.split("=")[1];
|
|
3409
|
+
const serverMaxAge = maxAge ? parseInt(maxAge, 10) : null; //get the max age from the server
|
|
3320
3410
|
const validForSecs =
|
|
3321
3411
|
serverMaxAge ||
|
|
3322
3412
|
this.config.masterChannelListValidFor ||
|
|
3323
3413
|
MASTER_CHANNEL_LIST_VALID_FOR_S;
|
|
3324
3414
|
|
|
3325
|
-
|
|
3326
|
-
this.masterChannelListExpiryDate = Date.now() + validForSecs * 1000; // always a number
|
|
3415
|
+
this.masterChannelListExpiryDate = Date.now() + validForSecs * 1000;
|
|
3327
3416
|
|
|
3328
|
-
// load the channel list with all channels found
|
|
3329
|
-
this.masterChannelList = [];
|
|
3330
3417
|
const channels = response.data;
|
|
3331
3418
|
this.log.debug("Channels to process:", channels.length);
|
|
3332
|
-
|
|
3419
|
+
response.data = null; // release raw payload for GC
|
|
3420
|
+
|
|
3421
|
+
// Performance optimisation: Single pass — pre-allocated array + Map built together, shared object refs
|
|
3422
|
+
const newList = new Array(channels.length);
|
|
3423
|
+
const newMap = new Map();
|
|
3424
|
+
|
|
3425
|
+
for (let i = 0; i < channels.length; i++) {
|
|
3426
|
+
const ch = channels[i];
|
|
3333
3427
|
if (this.debugLevel > 2) {
|
|
3334
3428
|
this.log(
|
|
3335
3429
|
"Processing channel:",
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3430
|
+
ch.logicalChannelNumber,
|
|
3431
|
+
ch.id,
|
|
3432
|
+
ch.name,
|
|
3339
3433
|
);
|
|
3340
3434
|
}
|
|
3341
|
-
|
|
3342
|
-
id:
|
|
3343
|
-
name: cleanNameForHomeKit(
|
|
3344
|
-
logicalChannelNumber:
|
|
3345
|
-
linearProducts:
|
|
3346
|
-
}
|
|
3435
|
+
const entry = {
|
|
3436
|
+
id: ch.id,
|
|
3437
|
+
name: cleanNameForHomeKit(ch.name),
|
|
3438
|
+
logicalChannelNumber: ch.logicalChannelNumber,
|
|
3439
|
+
linearProducts: ch.linearProducts,
|
|
3440
|
+
};
|
|
3441
|
+
newList[i] = entry;
|
|
3442
|
+
newMap.set(ch.id, entry);
|
|
3347
3443
|
}
|
|
3348
|
-
|
|
3349
|
-
this.
|
|
3350
|
-
|
|
3351
|
-
);
|
|
3444
|
+
|
|
3445
|
+
this.masterChannelList = newList;
|
|
3446
|
+
this.masterChannelMap = newMap;
|
|
3447
|
+
this.masterChannelListRefreshedAt = Date.now();
|
|
3352
3448
|
|
|
3353
3449
|
this.log(
|
|
3354
3450
|
"MasterChannelList contains %s channels, valid until %s",
|
|
@@ -3356,24 +3452,10 @@ class StbPlatform {
|
|
|
3356
3452
|
new Date(this.masterChannelListExpiryDate).toLocaleString(), // format for display only
|
|
3357
3453
|
);
|
|
3358
3454
|
|
|
3359
|
-
if (this.debugLevel > 1) {
|
|
3360
|
-
this.log.warn(
|
|
3361
|
-
"refreshMasterChannelList: Master channel list refreshed with %s channels, valid until %s",
|
|
3362
|
-
this.masterChannelList.length,
|
|
3363
|
-
new Date(this.masterChannelListExpiryDate).toLocaleString(),
|
|
3364
|
-
);
|
|
3365
|
-
}
|
|
3366
3455
|
return this.masterChannelList;
|
|
3456
|
+
//++++++++++++++++++++++++++++++++++++++++++++++++
|
|
3367
3457
|
} catch (error) {
|
|
3368
|
-
|
|
3369
|
-
? `${error.code}: ${error.hostname ?? error.config?.url ?? ""}`
|
|
3370
|
-
: (error.message ?? String(error));
|
|
3371
|
-
|
|
3372
|
-
if (error.isAxiosError && error.code === "ENOTFOUND") {
|
|
3373
|
-
this.currentSessionState = sessionState.DISCONNECTED;
|
|
3374
|
-
}
|
|
3375
|
-
this.log.warn("refreshMasterChannelList error:", errReason);
|
|
3376
|
-
throw new Error(errReason, { cause: error }); // { cause } preserves the original for debugging
|
|
3458
|
+
this._handleWebError(error, `refresh master channel list`, url);
|
|
3377
3459
|
}
|
|
3378
3460
|
} // end of refreshMasterChannelList
|
|
3379
3461
|
|
|
@@ -3438,16 +3520,11 @@ class StbPlatform {
|
|
|
3438
3520
|
this.configsvc = response.data; // store the entire config data for future use in this.configsvc
|
|
3439
3521
|
return this.configsvc;
|
|
3440
3522
|
} catch (error) {
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
this.currentSessionState = sessionState.DISCONNECTED;
|
|
3447
|
-
}
|
|
3448
|
-
}
|
|
3449
|
-
this.log.debug(`getConfig error:`, error);
|
|
3450
|
-
throw new Error(errReason);
|
|
3523
|
+
this._handleWebError(
|
|
3524
|
+
error,
|
|
3525
|
+
`get config data for countryCode ${countryCode}`,
|
|
3526
|
+
url,
|
|
3527
|
+
);
|
|
3451
3528
|
}
|
|
3452
3529
|
} // end of getConfig
|
|
3453
3530
|
|
|
@@ -3598,20 +3675,11 @@ class StbPlatform {
|
|
|
3598
3675
|
//this.log.warn('getPersonalizationData: all done, returnng customerStatus: %s', this.customer.customerStatus);
|
|
3599
3676
|
return this.customer;
|
|
3600
3677
|
} catch (error) {
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
householdId
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
errReason = error.code + ": " + (error.hostname || "");
|
|
3607
|
-
// if no connection then set session to disconnected to force a session reconnect
|
|
3608
|
-
if (error.code === "ENOTFOUND") {
|
|
3609
|
-
this.currentSessionState = sessionState.DISCONNECTED;
|
|
3610
|
-
}
|
|
3611
|
-
}
|
|
3612
|
-
//this.log('%s %s', errText, (errReason || ''));
|
|
3613
|
-
this.log.debug(`getPersonalizationData error:`, error);
|
|
3614
|
-
throw error;
|
|
3678
|
+
this._handleWebError(
|
|
3679
|
+
error,
|
|
3680
|
+
`get personalization data for household ${householdId}`,
|
|
3681
|
+
url,
|
|
3682
|
+
);
|
|
3615
3683
|
}
|
|
3616
3684
|
} // end of getPersonalizationData
|
|
3617
3685
|
|
|
@@ -3661,12 +3729,11 @@ class StbPlatform {
|
|
|
3661
3729
|
);
|
|
3662
3730
|
}
|
|
3663
3731
|
} catch (error) {
|
|
3664
|
-
this.
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3732
|
+
this._handleWebError(
|
|
3733
|
+
error,
|
|
3734
|
+
`set personalization data for device ${deviceId}`,
|
|
3735
|
+
url,
|
|
3668
3736
|
);
|
|
3669
|
-
this.log.debug("setPersonalizationDataForDevice: error:", error);
|
|
3670
3737
|
}
|
|
3671
3738
|
} // end of setPersonalizationDataForDevice
|
|
3672
3739
|
|
|
@@ -3725,15 +3792,11 @@ class StbPlatform {
|
|
|
3725
3792
|
}
|
|
3726
3793
|
return this.entitlements;
|
|
3727
3794
|
} catch (error) {
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
this.currentSessionState = sessionState.DISCONNECTED;
|
|
3734
|
-
}
|
|
3735
|
-
this.log.debug(`getEntitlements error:`, error);
|
|
3736
|
-
throw new Error(errReason);
|
|
3795
|
+
this._handleWebError(
|
|
3796
|
+
error,
|
|
3797
|
+
`get entitlements data for household ${householdId}`,
|
|
3798
|
+
url,
|
|
3799
|
+
);
|
|
3737
3800
|
}
|
|
3738
3801
|
} // end of getEntitlements
|
|
3739
3802
|
|
|
@@ -3910,29 +3973,11 @@ class StbPlatform {
|
|
|
3910
3973
|
|
|
3911
3974
|
return this.currentRecordingState;
|
|
3912
3975
|
} catch (error) {
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
" " +
|
|
3919
|
-
(error.hostname || "") +
|
|
3920
|
-
": " +
|
|
3921
|
-
(error.response?.status ?? "") +
|
|
3922
|
-
" " +
|
|
3923
|
-
(error.response?.statusText ?? "") +
|
|
3924
|
-
": " +
|
|
3925
|
-
(error.config?.url ?? "");
|
|
3926
|
-
if (error.code === "ENOTFOUND") {
|
|
3927
|
-
this.currentSessionState = sessionState.DISCONNECTED;
|
|
3928
|
-
}
|
|
3929
|
-
this.log.debug("getRecordingState error:", error);
|
|
3930
|
-
throw new Error(errReason);
|
|
3931
|
-
} else {
|
|
3932
|
-
this.log.warn("getRecordingState error:");
|
|
3933
|
-
this.log.warn(error);
|
|
3934
|
-
throw error;
|
|
3935
|
-
}
|
|
3976
|
+
this._handleWebError(
|
|
3977
|
+
error,
|
|
3978
|
+
`get recording status for household ${householdId}`,
|
|
3979
|
+
url,
|
|
3980
|
+
);
|
|
3936
3981
|
}
|
|
3937
3982
|
} // end of getRecordingState
|
|
3938
3983
|
|
|
@@ -4122,29 +4167,11 @@ class StbPlatform {
|
|
|
4122
4167
|
|
|
4123
4168
|
return this.currentRecordingState;
|
|
4124
4169
|
} catch (error) {
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
" " +
|
|
4131
|
-
(error.hostname || "") +
|
|
4132
|
-
": " +
|
|
4133
|
-
(error.response?.status ?? "") +
|
|
4134
|
-
" " +
|
|
4135
|
-
(error.response?.statusText ?? "") +
|
|
4136
|
-
": " +
|
|
4137
|
-
(error.config?.url ?? "");
|
|
4138
|
-
if (error.code === "ENOTFOUND") {
|
|
4139
|
-
this.currentSessionState = sessionState.DISCONNECTED;
|
|
4140
|
-
}
|
|
4141
|
-
this.log.debug("getRecordingBookings error:", error);
|
|
4142
|
-
throw new Error(errReason);
|
|
4143
|
-
} else {
|
|
4144
|
-
this.log.warn("getRecordingBookings error:");
|
|
4145
|
-
this.log.warn(error);
|
|
4146
|
-
throw error;
|
|
4147
|
-
}
|
|
4170
|
+
this._handleWebError(
|
|
4171
|
+
error,
|
|
4172
|
+
`get recording bookings for household ${householdId}`,
|
|
4173
|
+
url,
|
|
4174
|
+
);
|
|
4148
4175
|
}
|
|
4149
4176
|
} // end of getRecordingBookings
|
|
4150
4177
|
|
|
@@ -4181,14 +4208,11 @@ class StbPlatform {
|
|
|
4181
4208
|
this.log.warn(response.data);
|
|
4182
4209
|
return true;
|
|
4183
4210
|
} catch (error) {
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
}
|
|
4190
|
-
}
|
|
4191
|
-
this.log.warn(`getExperimentalEndpoint error:`, error);
|
|
4211
|
+
this._handleWebError(
|
|
4212
|
+
error,
|
|
4213
|
+
`get experimental endpoint for household ${householdId}`,
|
|
4214
|
+
url,
|
|
4215
|
+
);
|
|
4192
4216
|
}
|
|
4193
4217
|
} // end of getExperimentalEndpoint
|
|
4194
4218
|
|
|
@@ -4429,7 +4453,11 @@ class StbPlatform {
|
|
|
4429
4453
|
|
|
4430
4454
|
// announce ourselves as an active HGO client before requesting UI status
|
|
4431
4455
|
// the STB uses this retained presence message to decide which clients to respond to
|
|
4432
|
-
this.setHgoState(
|
|
4456
|
+
this.setHgoState(
|
|
4457
|
+
householdId,
|
|
4458
|
+
this.mqttClient.options.clientId,
|
|
4459
|
+
"ONLINE_RUNNING",
|
|
4460
|
+
);
|
|
4433
4461
|
|
|
4434
4462
|
// request initial UI status for each device, with a short delay to allow
|
|
4435
4463
|
// the STB to process the HGO presence announcement first
|
|
@@ -4441,7 +4469,10 @@ class StbPlatform {
|
|
|
4441
4469
|
setTimeout(() => {
|
|
4442
4470
|
this.devices.forEach((device) => {
|
|
4443
4471
|
// request the initial UI status for each device
|
|
4444
|
-
this.getUiStatus(
|
|
4472
|
+
this.getUiStatus(
|
|
4473
|
+
device.deviceId,
|
|
4474
|
+
this.mqttClient.options.clientId,
|
|
4475
|
+
);
|
|
4445
4476
|
|
|
4446
4477
|
// retry after 10 seconds if no CPE.uiStatus response has arrived yet
|
|
4447
4478
|
setTimeout(() => {
|
|
@@ -4452,7 +4483,10 @@ class StbPlatform {
|
|
|
4452
4483
|
device.deviceId,
|
|
4453
4484
|
);
|
|
4454
4485
|
}
|
|
4455
|
-
this.getUiStatus(
|
|
4486
|
+
this.getUiStatus(
|
|
4487
|
+
device.deviceId,
|
|
4488
|
+
this.mqttClient.options.clientId,
|
|
4489
|
+
);
|
|
4456
4490
|
}
|
|
4457
4491
|
}, 10 * 1000); // 10 second retry delay
|
|
4458
4492
|
});
|
|
@@ -4556,7 +4590,8 @@ class StbPlatform {
|
|
|
4556
4590
|
const deviceIndex = this.devices.findIndex(
|
|
4557
4591
|
(device) => device.deviceId === deviceId,
|
|
4558
4592
|
);
|
|
4559
|
-
const stbDevice =
|
|
4593
|
+
const stbDevice =
|
|
4594
|
+
deviceIndex > -1 ? this.stbDevices[deviceIndex] : null;
|
|
4560
4595
|
|
|
4561
4596
|
// Box setting: StandbyPowerConsumption = FastStart / ActiveStart / EcoSlowstart
|
|
4562
4597
|
// "Fast start": when turned off, goes to ONLINE_STANDBY and stays there. Box can be turned on via mqtt
|
|
@@ -4569,7 +4604,10 @@ class StbPlatform {
|
|
|
4569
4604
|
// Detect power-off → power-on transition per device.
|
|
4570
4605
|
// Set PLAY immediately; CPE.uiStatus will overwrite with the
|
|
4571
4606
|
// accurate speed-derived state shortly after.
|
|
4572
|
-
if (
|
|
4607
|
+
if (
|
|
4608
|
+
stbDevice?.previousPowerState ===
|
|
4609
|
+
Characteristic.Active.INACTIVE
|
|
4610
|
+
) {
|
|
4573
4611
|
currMediaState = Characteristic.CurrentMediaState.PLAY;
|
|
4574
4612
|
if (this.debugLevel > 0) {
|
|
4575
4613
|
this.log.warn(
|
|
@@ -4577,7 +4615,7 @@ class StbPlatform {
|
|
|
4577
4615
|
deviceId,
|
|
4578
4616
|
);
|
|
4579
4617
|
}
|
|
4580
|
-
}
|
|
4618
|
+
}
|
|
4581
4619
|
break;
|
|
4582
4620
|
case "ONLINE_STANDBY": // ONLINE_STANDBY: power is off, device is on standby, still reachable over the network, can be turned on via mqtt.
|
|
4583
4621
|
currStatusActive = Characteristic.Active.ACTIVE; // bool, 0 = not active, 1 = active
|
|
@@ -4610,9 +4648,9 @@ class StbPlatform {
|
|
|
4610
4648
|
|
|
4611
4649
|
// After the switch, if box is running, request current UI state
|
|
4612
4650
|
//if (stbState === 'ONLINE_RUNNING') {
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
//}
|
|
4651
|
+
// Small delay gives the STB a moment to settle before responding
|
|
4652
|
+
//setTimeout(() => this.mqttRequestUiStatus(deviceId), 500);
|
|
4653
|
+
//}
|
|
4616
4654
|
}
|
|
4617
4655
|
|
|
4618
4656
|
// handle CPE UI status messages for the STB
|
|
@@ -5002,7 +5040,7 @@ class StbPlatform {
|
|
|
5002
5040
|
this.setHgoState(
|
|
5003
5041
|
this.session.householdId,
|
|
5004
5042
|
this.mqttClient.options.clientId,
|
|
5005
|
-
|
|
5043
|
+
"OFFLINE",
|
|
5006
5044
|
);
|
|
5007
5045
|
|
|
5008
5046
|
// unsubscribe from all subscribedTopics before tearing down the session
|
|
@@ -5010,7 +5048,7 @@ class StbPlatform {
|
|
|
5010
5048
|
this.log.info(
|
|
5011
5049
|
"mqttClient: No topics to unsubscribe from, skipping unsubscribe.",
|
|
5012
5050
|
);
|
|
5013
|
-
|
|
5051
|
+
|
|
5014
5052
|
this.mqttClient.end(false, {}, (endErr) => {
|
|
5015
5053
|
if (endErr) {
|
|
5016
5054
|
this.log.error("MQTT end error:", endErr);
|
|
@@ -5216,17 +5254,16 @@ class StbPlatform {
|
|
|
5216
5254
|
const message = JSON.stringify({
|
|
5217
5255
|
source: mqttClientId,
|
|
5218
5256
|
state: state,
|
|
5219
|
-
deviceType:
|
|
5220
|
-
mac:
|
|
5221
|
-
ipAddress:
|
|
5257
|
+
deviceType: "HGO",
|
|
5258
|
+
mac: "",
|
|
5259
|
+
ipAddress: "",
|
|
5222
5260
|
});
|
|
5223
5261
|
if (this.debugLevel > 0) {
|
|
5224
|
-
this.log.warn(
|
|
5262
|
+
this.log.warn("setHgoState: publishing %s to topic: %s", state, topic);
|
|
5225
5263
|
}
|
|
5226
5264
|
this.mqttPublishMessage(topic, message, { qos: 2, retain: true });
|
|
5227
5265
|
}
|
|
5228
5266
|
|
|
5229
|
-
|
|
5230
5267
|
// send a channel change request to the settopbox via mqtt
|
|
5231
5268
|
// using the CPE.pushToTV message
|
|
5232
5269
|
// the friendlyDeviceName appears on the TV in a popup window
|
|
@@ -5285,7 +5322,10 @@ class StbPlatform {
|
|
|
5285
5322
|
// @param {string} deviceId - The STB device ID (e.g. "000378-EOS2STB-00852052xxxx")
|
|
5286
5323
|
mqttRequestUiStatus(deviceId) {
|
|
5287
5324
|
if (!this.mqttClient?.connected) {
|
|
5288
|
-
this.log.warn(
|
|
5325
|
+
this.log.warn(
|
|
5326
|
+
"%s: mqttRequestUiStatus: MQTT not connected, skipping",
|
|
5327
|
+
deviceId,
|
|
5328
|
+
);
|
|
5289
5329
|
return;
|
|
5290
5330
|
}
|
|
5291
5331
|
if (this.debugLevel > 0) {
|
|
@@ -5296,9 +5336,9 @@ class StbPlatform {
|
|
|
5296
5336
|
}
|
|
5297
5337
|
|
|
5298
5338
|
const payload = JSON.stringify({
|
|
5299
|
-
version:
|
|
5300
|
-
type:
|
|
5301
|
-
source: this.mqttClient.options.clientId,
|
|
5339
|
+
version: "1.3.18",
|
|
5340
|
+
type: "CPE.pullFromTV",
|
|
5341
|
+
source: this.mqttClient.options.clientId, // your mqttClientId
|
|
5302
5342
|
messageTimeStamp: Date.now(),
|
|
5303
5343
|
});
|
|
5304
5344
|
|
|
@@ -5308,8 +5348,7 @@ class StbPlatform {
|
|
|
5308
5348
|
qos: 1,
|
|
5309
5349
|
retain: false,
|
|
5310
5350
|
});
|
|
5311
|
-
|
|
5312
|
-
}
|
|
5351
|
+
}
|
|
5313
5352
|
|
|
5314
5353
|
// set the media state of the settopbox via mqtt
|
|
5315
5354
|
// media state is controlled by speedRate
|
|
@@ -6566,10 +6605,7 @@ class StbDevice {
|
|
|
6566
6605
|
inputSourceService
|
|
6567
6606
|
.getCharacteristic(Characteristic.ConfiguredName)
|
|
6568
6607
|
.setProps({
|
|
6569
|
-
perms: [
|
|
6570
|
-
this.api.hap.Perms.PAIRED_READ,
|
|
6571
|
-
this.api.hap.Perms.NOTIFY,
|
|
6572
|
-
],
|
|
6608
|
+
perms: [this.api.hap.Perms.PAIRED_READ, this.api.hap.Perms.NOTIFY],
|
|
6573
6609
|
})
|
|
6574
6610
|
.onGet(() => this.getInputName(i));
|
|
6575
6611
|
//.onSet((value) => this.setInputName(i, value));
|
|
@@ -7960,7 +7996,10 @@ class StbDevice {
|
|
|
7960
7996
|
// triple rapid VolDown presses triggers setMute
|
|
7961
7997
|
if (volumeSelectorValue === Characteristic.VolumeSelector.DECREMENT) {
|
|
7962
7998
|
// Guard: ensure array is properly initialised
|
|
7963
|
-
if (
|
|
7999
|
+
if (
|
|
8000
|
+
!Array.isArray(this.lastVolDownKeyPress) ||
|
|
8001
|
+
this.lastVolDownKeyPress.length < 3
|
|
8002
|
+
) {
|
|
7964
8003
|
this.lastVolDownKeyPress = [0, 0, 0];
|
|
7965
8004
|
}
|
|
7966
8005
|
|
|
@@ -7969,14 +8008,14 @@ class StbDevice {
|
|
|
7969
8008
|
this.lastVolDownKeyPress = this.lastVolDownKeyPress.slice(0, 3); // keep only last 3
|
|
7970
8009
|
|
|
7971
8010
|
// Now assign the calculated value to the outer variable
|
|
7972
|
-
tripleVolDownPress =
|
|
8011
|
+
tripleVolDownPress =
|
|
8012
|
+
this.lastVolDownKeyPress[0] - this.lastVolDownKeyPress[2];
|
|
7973
8013
|
|
|
7974
8014
|
this.log.debug(
|
|
7975
8015
|
"%s: setVolume: Timediff between volDownKeyPress[0] and volDownKeyPress[2]: %s ms",
|
|
7976
8016
|
this.name,
|
|
7977
8017
|
tripleVolDownPress,
|
|
7978
|
-
);
|
|
7979
|
-
|
|
8018
|
+
);
|
|
7980
8019
|
}
|
|
7981
8020
|
|
|
7982
8021
|
// check for triple press of volDown, send setMute if tripleVolDownPress less than triplePressTime of 800ms
|
|
@@ -8014,7 +8053,11 @@ class StbDevice {
|
|
|
8014
8053
|
|
|
8015
8054
|
try {
|
|
8016
8055
|
if (this.debugLevel > 0) {
|
|
8017
|
-
this.log.warn(
|
|
8056
|
+
this.log.warn(
|
|
8057
|
+
"%s: setVolume: Sending command %s",
|
|
8058
|
+
this.name,
|
|
8059
|
+
command,
|
|
8060
|
+
);
|
|
8018
8061
|
}
|
|
8019
8062
|
await new Promise((resolve, reject) => {
|
|
8020
8063
|
exec(command, (error, _stdout, stderr) => {
|
|
@@ -8380,13 +8423,13 @@ class StbDevice {
|
|
|
8380
8423
|
// logChangeOnly = TRUE: only the changes are logged, no media state change occurs. Needed when sending remote keypresses to prevent double commands
|
|
8381
8424
|
// CHAR_NAMES: TargetMediaState: [ 'UUID', 'PLAY', 'PAUSE', 'STOP' ]
|
|
8382
8425
|
//if (this.debugLevel > 1) {
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8426
|
+
this.log.info(
|
|
8427
|
+
"%s: setTargetMediaState to %s [%s]",
|
|
8428
|
+
this.name,
|
|
8429
|
+
targetMediaState,
|
|
8430
|
+
CHAR_NAMES.TargetMediaState[targetMediaState + 1],
|
|
8431
|
+
);
|
|
8432
|
+
// }
|
|
8390
8433
|
|
|
8391
8434
|
if (!logChangeOnly) {
|
|
8392
8435
|
// send the setMediaState command if we are not just logging the change
|
|
@@ -8399,16 +8442,17 @@ class StbDevice {
|
|
|
8399
8442
|
// PLAY 0 - 1 Play
|
|
8400
8443
|
// PAUSE 1 - 0 Paused
|
|
8401
8444
|
// STOP 2 - 0 Paused
|
|
8402
|
-
const newBoxMediaState =
|
|
8445
|
+
const newBoxMediaState =
|
|
8446
|
+
targetMediaState === Characteristic.TargetMediaState.PLAY ? 1 : 0;
|
|
8403
8447
|
const newBoxMediaStateName = newBoxMediaState === 1 ? "Play" : "Paused";
|
|
8404
8448
|
|
|
8405
8449
|
//if (this.debugLevel >= 0) {
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8450
|
+
this.log(
|
|
8451
|
+
"%s: setTargetMediaState: Calling setMediaState with newBoxMediaState %s [%s]",
|
|
8452
|
+
this.name,
|
|
8453
|
+
newBoxMediaState,
|
|
8454
|
+
newBoxMediaStateName,
|
|
8455
|
+
);
|
|
8412
8456
|
//}
|
|
8413
8457
|
/*
|
|
8414
8458
|
switch (targetMediaState) {
|
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-beta.
|
|
6
|
+
"version": "2.4.0-beta.4",
|
|
7
7
|
"platformname": "eosstb",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"axios": "^1.16.0",
|