iobroker.heos 2.2.0 → 2.2.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/README.md +8 -0
- package/admin/jsonConfig.json +3 -0
- package/io-package.json +33 -30
- package/lib/heos-player.js +54 -24
- package/lib/heos-upnp.js +4 -0
- package/main.js +40 -26
- package/package.json +21 -21
package/README.md
CHANGED
|
@@ -144,6 +144,14 @@ Alternative you can use the script from Uhula: https://forum.iobroker.net/post/4
|
|
|
144
144
|
Placeholder for the next version (at the beginning of the line):
|
|
145
145
|
### **WORK IN PROGRESS**
|
|
146
146
|
-->
|
|
147
|
+
### 2.2.2 (2024-10-30)
|
|
148
|
+
* (withstu) add workaround for tidal connect sid = 0 bug and fix audio format
|
|
149
|
+
* (withstu) increase minimum node.js version to recommended version 18
|
|
150
|
+
* (withstu) project maintenance
|
|
151
|
+
|
|
152
|
+
### 2.2.1 (2024-01-14)
|
|
153
|
+
* (withstu) add workaround for node 19+ ECONNRESET bug #299
|
|
154
|
+
|
|
147
155
|
### 2.2.0 (2024-01-06)
|
|
148
156
|
* (withstu) update dependencies
|
|
149
157
|
* (withstu) add admin 5 UI support
|
package/admin/jsonConfig.json
CHANGED
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "heos",
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.2",
|
|
5
5
|
"news": {
|
|
6
|
+
"2.2.2": {
|
|
7
|
+
"en": "add workaround for tidal connect sid = 0 bug and fix audio format\nincrease minimum node.js version to recommended version 18\nproject maintenance",
|
|
8
|
+
"de": "fügen sie workaround für tidal connect sid = 0 bug hinzu und reparieren sie audioformat\nminimal node.js-version auf empfohlene version 18 erhöhen\nprojektwartung",
|
|
9
|
+
"ru": "добавить обход для приливного соединения sid = 0 клопов и исправить аудио формат\nувеличить минимальную версию node.js до рекомендуемой версии 18\nтехническое обслуживание проекта",
|
|
10
|
+
"pt": "adicionar solução alternativa para tidal conectar sid = 0 bug e corrigir o formato de áudio\naumentar a versão node.js mínima para a versão recomendada 18\nmanutenção do projeto",
|
|
11
|
+
"nl": "toe te voegen workaround voor getijdenverbinding sid = 0 bug en fix audio-formaat\nverhoog minimum node.js versie naar aanbevolen versie 18\nprojectonderhoud",
|
|
12
|
+
"fr": "ajouter une solution de rechange pour la connexion de marée sid = 0 bug et corriger le format audio\naugmenter la version minimum node.js à la version recommandée 18\nentretien des projets",
|
|
13
|
+
"it": "aggiungere workaround per tidal connect sid = 0 bug e correggere il formato audio\naumentare la versione minima node.js alla versione consigliata 18\nmanutenzione del progetto",
|
|
14
|
+
"es": "añadir workaround for tidal connect sid = 0 bug and fix audio format\naumentar la versión mínima node.js a la versión recomendada 18\nmantenimiento de proyectos",
|
|
15
|
+
"pl": "dodaj pracę dla połączenia pływowego sid = 0 błędów i napraw format audio\nzwiększenie minimalnej wersji node.js do zalecanej wersji 18\nutrzymanie projektu",
|
|
16
|
+
"uk": "add workaround for tidal connection sid = 0 помилка і виправити аудіо формат\nзбільшити мінімальний вузол.js версія для рекомендованої версії 18\nсупровід проекту",
|
|
17
|
+
"zh-cn": "添加潮汐连接 sid = 0 bug 的绕行并修正音频格式\n将最小节点.js版本增加到建议版本18\n项目维护"
|
|
18
|
+
},
|
|
19
|
+
"2.2.1": {
|
|
20
|
+
"en": "add workaround for node 19+ ECONNRESET bug #299",
|
|
21
|
+
"de": "workaround für Knoten hinzufügen 19+ ECONNRESET Bug #299",
|
|
22
|
+
"ru": "добавить обход для узла 19+ ECONNRESET bug #299",
|
|
23
|
+
"pt": "adicionar solução para o nó 19+ ECONNRESET bug #299",
|
|
24
|
+
"nl": "workaround toevoegen voor knooppunt 19+ ECONNRESET bug #299",
|
|
25
|
+
"fr": "ajouter une solution de rechange pour le noeud 19+ bug ECONNRESET #299",
|
|
26
|
+
"it": "aggiungere il lavoro per nodo 19+ ECONNRESET bug #299",
|
|
27
|
+
"es": "añadir trabajo alrededor del nodo 19+ ECONNRESET bug #299",
|
|
28
|
+
"pl": "dodaj pracę dla węzła 19 + ECONNRESET błąd # 299",
|
|
29
|
+
"uk": "add workaround для вершини 19+ ECONNRESET помилка #299",
|
|
30
|
+
"zh-cn": "为节点添加工作环路 19+ 经济错误 # 299"
|
|
31
|
+
},
|
|
6
32
|
"2.2.0": {
|
|
7
33
|
"en": "update dependencies\nadd admin 5 UI support\nimprove preferred IP handling\nimprove undefined station handling #299\nreduce upnp requests",
|
|
8
34
|
"de": "aktualisierung der abhängigkeiten\nadmin 5 UI Unterstützung hinzufügen\nverbesserung der bevorzugten IP-Behandlung\nundefinierte stationshandling #299 verbessern\nreduzieren von upp-anfragen",
|
|
@@ -42,19 +68,6 @@
|
|
|
42
68
|
"uk": "кріплення трубопроводів і видалення вузла 14.x",
|
|
43
69
|
"zh-cn": "f 配件和取消14x的支助"
|
|
44
70
|
},
|
|
45
|
-
"1.12.3": {
|
|
46
|
-
"en": "update dependencies",
|
|
47
|
-
"de": "aktualisierung der abhängigkeiten",
|
|
48
|
-
"ru": "обновление зависимостей",
|
|
49
|
-
"pt": "dependências",
|
|
50
|
-
"nl": "vertaling:",
|
|
51
|
-
"fr": "mettre à jour les dépendances",
|
|
52
|
-
"it": "aggiornamento dipendenze",
|
|
53
|
-
"es": "dependencias de actualización",
|
|
54
|
-
"pl": "zależności",
|
|
55
|
-
"uk": "оновлення залежності",
|
|
56
|
-
"zh-cn": "a. 最新受扶养人"
|
|
57
|
-
},
|
|
58
71
|
"1.12.2": {
|
|
59
72
|
"en": "optimize error handling",
|
|
60
73
|
"de": "optimierung der fehlerbehandlung",
|
|
@@ -80,19 +93,6 @@
|
|
|
80
93
|
"pl": "lider optymalizacji wyborów",
|
|
81
94
|
"uk": "оптимізація виборів лідера",
|
|
82
95
|
"zh-cn": "优化领导人选举"
|
|
83
|
-
},
|
|
84
|
-
"1.12.0": {
|
|
85
|
-
"en": "optimize scope handling\nswitch to HEOS default cmd delimiter\nadd configuration to prefer list of IPs for adapter connection\noptimize error handling",
|
|
86
|
-
"de": "optimieren sie die handhabung des anwendungsbereichs\nschalter zu HEOS Standard cmd Begrenzung\nkonfiguration hinzufügen, um die Liste der IPs für Adapteranschluss zu bevorzugen\noptimierung der fehlerbehandlung",
|
|
87
|
-
"ru": "оптимизация обработки сфер\nпереключиться на HEOS по умолчанию cmd delimiter\nдобавить конфигурацию, чтобы предпочитать список IP для подключения адаптера\nоптимизировать обработку ошибок",
|
|
88
|
-
"pt": "otimizar o gerenciamento de escopo\nmudar para delimitador cmd padrão HEOS\nadicionar configuração para preferir lista de IPs para conexão de adaptador\notimizar o manuseio de erros",
|
|
89
|
-
"nl": "vertaling:\nwissel naar HOS default cmd delimiter\nvoeg configuratie toe aan de lijst van IP's voor aanpassingsverbinding\nvertaling:",
|
|
90
|
-
"fr": "optimiser la manipulation de la portée\npasser à HEOS délimiteur cmd par défaut\najouter la configuration pour préférer la liste des IP pour la connexion d'adaptateur\noptimiser la manipulation des erreurs",
|
|
91
|
-
"it": "ottimizzare la gestione delle aree\npassare al delimitatore cmd predefinito HEOS\naggiungere la configurazione per preferire l'elenco degli IP per la connessione dell'adattatore\nottimizzare la gestione degli errori",
|
|
92
|
-
"es": "optimizar el manejo del alcance\nconmutación al delimitador por defecto HEOS cmd\nañadir configuración para preferir la lista de IPs para la conexión del adaptador\noptimizar el manejo del error",
|
|
93
|
-
"pl": "optymalizacja zakresu obsługi\nprzełącz do HEOS do domyślnie cm delimiter\ndodawanie konfiguracji do preferowania listy IP do połączenia adapterowego\noptymalizowanie błędów",
|
|
94
|
-
"uk": "оптимізація управління обсягами\nпереключення до HEOS за замовчуванням cmd delimiter\nдодати конфігурацію для вибору IP-адреси адаптера\nоптимізація обробки помилок",
|
|
95
|
-
"zh-cn": "优化处理范围\n转换到HEOS违约情况\n备选案文:\n优化错误处理"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
|
@@ -127,9 +127,11 @@
|
|
|
127
127
|
"keywords": [
|
|
128
128
|
"HEOS"
|
|
129
129
|
],
|
|
130
|
-
"
|
|
130
|
+
"licenseInformation": {
|
|
131
|
+
"license": "MIT",
|
|
132
|
+
"type": "free"
|
|
133
|
+
},
|
|
131
134
|
"platform": "Javascript/Node.js",
|
|
132
|
-
"main": "main.js",
|
|
133
135
|
"icon": "heos.png",
|
|
134
136
|
"enabled": true,
|
|
135
137
|
"extIcon": "https://raw.githubusercontent.com/withstu/ioBroker.heos/main/admin/heos.png",
|
|
@@ -141,12 +143,13 @@
|
|
|
141
143
|
"compact": true,
|
|
142
144
|
"connectionType": "local",
|
|
143
145
|
"dataSource": "poll",
|
|
146
|
+
"tier": 2,
|
|
144
147
|
"adminUI": {
|
|
145
148
|
"config": "json"
|
|
146
149
|
},
|
|
147
150
|
"dependencies": [
|
|
148
151
|
{
|
|
149
|
-
"js-controller": ">=
|
|
152
|
+
"js-controller": ">=5.0.19"
|
|
150
153
|
}
|
|
151
154
|
],
|
|
152
155
|
"globalDependencies": [
|
package/lib/heos-player.js
CHANGED
|
@@ -60,7 +60,7 @@ class HeosPlayer {
|
|
|
60
60
|
this.restore_timeout = undefined;
|
|
61
61
|
this.respond_timeout = undefined;
|
|
62
62
|
this.now_playing_update_timeout = undefined;
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
this.repeatStates = {
|
|
65
65
|
0:'off',
|
|
66
66
|
1:'on_all',
|
|
@@ -1417,6 +1417,12 @@ class HeosPlayer {
|
|
|
1417
1417
|
this.logDebug('[upnp] get ' + service + ' state failed: ' + err, false);
|
|
1418
1418
|
}
|
|
1419
1419
|
}
|
|
1420
|
+
|
|
1421
|
+
if(leader_state){
|
|
1422
|
+
//TODO
|
|
1423
|
+
} else {
|
|
1424
|
+
//TODO
|
|
1425
|
+
}
|
|
1420
1426
|
} else {
|
|
1421
1427
|
this.logDebug('[upnp] get ' + service + ' state is not supported by player ' + this.name + ' (' + this.ip + ')', false);
|
|
1422
1428
|
}
|
|
@@ -1456,6 +1462,13 @@ class HeosPlayer {
|
|
|
1456
1462
|
this.logDebug('[upnp] get ' + service + ' state failed: ' + err, false);
|
|
1457
1463
|
}
|
|
1458
1464
|
}
|
|
1465
|
+
|
|
1466
|
+
if(leader_state){
|
|
1467
|
+
//TODO
|
|
1468
|
+
} else {
|
|
1469
|
+
//TODO
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1459
1472
|
if(state
|
|
1460
1473
|
&& state.DevicePower
|
|
1461
1474
|
&& state.DevicePower['@_val']){
|
|
@@ -1503,6 +1516,12 @@ class HeosPlayer {
|
|
|
1503
1516
|
this.logDebug('[upnp] get ' + service + ' state failed: ' + err, false);
|
|
1504
1517
|
}
|
|
1505
1518
|
}
|
|
1519
|
+
|
|
1520
|
+
if(leader_state){
|
|
1521
|
+
//TODO
|
|
1522
|
+
} else {
|
|
1523
|
+
//TODO
|
|
1524
|
+
}
|
|
1506
1525
|
} else {
|
|
1507
1526
|
this.logDebug('[upnp] get ' + service + ' state is not supported by player ' + this.name + ' (' + this.ip + ')', false);
|
|
1508
1527
|
}
|
|
@@ -1542,6 +1561,12 @@ class HeosPlayer {
|
|
|
1542
1561
|
this.logDebug('[upnp] get ' + service + ' state failed: ' + err, false);
|
|
1543
1562
|
}
|
|
1544
1563
|
}
|
|
1564
|
+
|
|
1565
|
+
if(leader_state){
|
|
1566
|
+
//TODO
|
|
1567
|
+
} else {
|
|
1568
|
+
//TODO
|
|
1569
|
+
}
|
|
1545
1570
|
} else {
|
|
1546
1571
|
this.logDebug('[upnp] get ' + service + ' state is not supported by player ' + this.name + ' (' + this.ip + ')', false);
|
|
1547
1572
|
}
|
|
@@ -1604,12 +1629,8 @@ class HeosPlayer {
|
|
|
1604
1629
|
}
|
|
1605
1630
|
|
|
1606
1631
|
let format = '';
|
|
1607
|
-
if(meta.desc &&
|
|
1608
|
-
|
|
1609
|
-
if(desc['@_id'] == 'audioFormat'){
|
|
1610
|
-
format = desc.value;
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1632
|
+
if(meta.desc && meta.desc['@_id'] == 'audioFormat') {
|
|
1633
|
+
format = meta.desc.value;
|
|
1613
1634
|
}
|
|
1614
1635
|
this.heos.setState(this.state_path + 'current_audio_format', format, true);
|
|
1615
1636
|
} else {
|
|
@@ -1669,6 +1690,12 @@ class HeosPlayer {
|
|
|
1669
1690
|
}
|
|
1670
1691
|
}
|
|
1671
1692
|
|
|
1693
|
+
if(leader_state){
|
|
1694
|
+
//TODO
|
|
1695
|
+
} else {
|
|
1696
|
+
//TODO
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1672
1699
|
if(state){
|
|
1673
1700
|
this.power = (state == 'ON') ? true : false;
|
|
1674
1701
|
this.heos.setState(this.state_path + 'power', this.power, true);
|
|
@@ -1689,7 +1716,7 @@ class HeosPlayer {
|
|
|
1689
1716
|
};
|
|
1690
1717
|
if(this.upnp.hasService(service) && this.upnp.hasServiceAction(service, action)){
|
|
1691
1718
|
try{
|
|
1692
|
-
|
|
1719
|
+
await this.upnp.sendCommand(service, action, data);
|
|
1693
1720
|
} catch(err){
|
|
1694
1721
|
if(err.code != 'ECONNABORTED') {
|
|
1695
1722
|
this.heos.raiseFailures(this.ip, ERROR_CODES.Upnp);
|
|
@@ -1711,8 +1738,8 @@ class HeosPlayer {
|
|
|
1711
1738
|
* @param {String} cmd
|
|
1712
1739
|
*/
|
|
1713
1740
|
async parseResponse(jdata, jmsg, cmd_group, cmd) {
|
|
1714
|
-
const pid = jmsg.pid;
|
|
1715
|
-
|
|
1741
|
+
//const pid = jmsg.pid;
|
|
1742
|
+
|
|
1716
1743
|
this.detectHeosResponseTimeout();
|
|
1717
1744
|
try {
|
|
1718
1745
|
switch (cmd_group) {
|
|
@@ -1848,7 +1875,10 @@ class HeosPlayer {
|
|
|
1848
1875
|
}, 30000);
|
|
1849
1876
|
|
|
1850
1877
|
//Filter invalid responses
|
|
1851
|
-
if(jdata.payload.hasOwnProperty('sid') && jdata.payload.sid != 0){
|
|
1878
|
+
if(jdata.payload.hasOwnProperty('sid') && (jdata.payload.sid != 0 || JSON.stringify(jdata.payload).includes('tidal.com'))){
|
|
1879
|
+
if(JSON.stringify(jdata.payload).includes('tidal.com')) {
|
|
1880
|
+
jdata.payload.sid = 10;
|
|
1881
|
+
}
|
|
1852
1882
|
this.muteRegex(JSON.stringify(jdata.payload));
|
|
1853
1883
|
|
|
1854
1884
|
if (jdata.payload.hasOwnProperty('sid')) {
|
|
@@ -1926,7 +1956,7 @@ class HeosPlayer {
|
|
|
1926
1956
|
this.heos.setState(this.state_path + 'current_image_color_background', imageColors.backgroundColor, true);
|
|
1927
1957
|
this.heos.setState(this.state_path + 'current_image_color_foreground', imageColors.foregroundColor, true);
|
|
1928
1958
|
} catch(colorerr){
|
|
1929
|
-
this.logDebug('Image color extraction failed');
|
|
1959
|
+
this.logDebug('Image color extraction failed: ' + colorerr);
|
|
1930
1960
|
this.heos.setState(this.state_path + 'current_image_color_palette', '', true);
|
|
1931
1961
|
this.heos.setState(this.state_path + 'current_image_color_background', '', true);
|
|
1932
1962
|
this.heos.setState(this.state_path + 'current_image_color_foreground', '', true);
|
|
@@ -1991,7 +2021,7 @@ class HeosPlayer {
|
|
|
1991
2021
|
if(this.isPlayerGroupLeader()){
|
|
1992
2022
|
await this.updateUpnp();
|
|
1993
2023
|
const group_players = this.getGroupPlayers();
|
|
1994
|
-
for (
|
|
2024
|
+
for (let i = 0; i < group_players.length; i++) {
|
|
1995
2025
|
await group_players[i].updateUpnp();
|
|
1996
2026
|
}
|
|
1997
2027
|
}
|
|
@@ -2014,9 +2044,9 @@ class HeosPlayer {
|
|
|
2014
2044
|
};
|
|
2015
2045
|
//Load previous
|
|
2016
2046
|
if (jmsg.returned < jmsg.count) {
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2047
|
+
let start = 1;
|
|
2048
|
+
let end = 50;
|
|
2049
|
+
let pageCmd = '';
|
|
2020
2050
|
if(jmsg.hasOwnProperty('range')){
|
|
2021
2051
|
const range = jmsg.range.split(',');
|
|
2022
2052
|
start = parseInt(range[0]) + 1;
|
|
@@ -2051,7 +2081,7 @@ class HeosPlayer {
|
|
|
2051
2081
|
}
|
|
2052
2082
|
|
|
2053
2083
|
//Queue items
|
|
2054
|
-
for (
|
|
2084
|
+
for (let i = 0; i < jdata.payload.length; i++) {
|
|
2055
2085
|
const payload = jdata.payload[i];
|
|
2056
2086
|
payload['name'] = '';
|
|
2057
2087
|
payload['type'] = 'media';
|
|
@@ -2064,9 +2094,9 @@ class HeosPlayer {
|
|
|
2064
2094
|
|
|
2065
2095
|
//Load next
|
|
2066
2096
|
if (jmsg.returned < jmsg.count) {
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2097
|
+
let start = 1;
|
|
2098
|
+
let end = 50;
|
|
2099
|
+
let pageCmd = '';
|
|
2070
2100
|
if(jmsg.hasOwnProperty('range')){
|
|
2071
2101
|
const range = jmsg.range.split(',');
|
|
2072
2102
|
start = parseInt(range[0]) + 1;
|
|
@@ -2218,7 +2248,7 @@ class HeosPlayer {
|
|
|
2218
2248
|
Target: target
|
|
2219
2249
|
};
|
|
2220
2250
|
try{
|
|
2221
|
-
|
|
2251
|
+
await this.upnp.sendCommand(service, action, data);
|
|
2222
2252
|
} catch(err){
|
|
2223
2253
|
this.logWarn('seek failed:' + err, false);
|
|
2224
2254
|
}
|
|
@@ -2253,9 +2283,9 @@ class HeosPlayer {
|
|
|
2253
2283
|
}
|
|
2254
2284
|
|
|
2255
2285
|
/**
|
|
2256
|
-
*
|
|
2257
|
-
* @param {*} object
|
|
2258
|
-
* @param {*} value
|
|
2286
|
+
*
|
|
2287
|
+
* @param {*} object
|
|
2288
|
+
* @param {*} value
|
|
2259
2289
|
* @returns {number|string|undefined}
|
|
2260
2290
|
*/
|
|
2261
2291
|
getKeyByValue(object, value) {
|
package/lib/heos-upnp.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
8
|
const { URL } = require('url');
|
|
9
|
+
const http = require('http');
|
|
9
10
|
const axios = require('axios');
|
|
10
11
|
const {decode} = require('html-entities');
|
|
11
12
|
const keyInObject = require('./tools').keyInObject;
|
|
@@ -27,6 +28,7 @@ class HeosUPnP {
|
|
|
27
28
|
async init() {
|
|
28
29
|
this.logSilly('[init] Get UPNP details: ' + this.url);
|
|
29
30
|
const response = await axios({
|
|
31
|
+
httpAgent: new http.Agent({ keepAlive: false }),
|
|
30
32
|
method: 'get',
|
|
31
33
|
url: this.url,
|
|
32
34
|
timeout: 30000
|
|
@@ -79,6 +81,7 @@ class HeosUPnP {
|
|
|
79
81
|
if(!this.hasService(id)){
|
|
80
82
|
this.logSilly('[parseServices] Get Service: ' + service.SCPDURL);
|
|
81
83
|
const response = await axios({
|
|
84
|
+
httpAgent: new http.Agent({ keepAlive: false }),
|
|
82
85
|
method: 'get',
|
|
83
86
|
url: service.SCPDURL,
|
|
84
87
|
timeout: 30000
|
|
@@ -191,6 +194,7 @@ class HeosUPnP {
|
|
|
191
194
|
|
|
192
195
|
this.logSilly('[sendCommand] Send command: ' + service.controlURL);
|
|
193
196
|
const response = await axios({
|
|
197
|
+
httpAgent: new http.Agent({ keepAlive: false }),
|
|
194
198
|
method: 'post',
|
|
195
199
|
url: service.controlURL,
|
|
196
200
|
headers: {
|
package/main.js
CHANGED
|
@@ -195,11 +195,19 @@ class Heos extends utils.Adapter {
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
logDebug(msg, force) {
|
|
198
|
-
this.
|
|
198
|
+
if (!force && this.silent_log_mode) {
|
|
199
|
+
this.log.debug(msg);
|
|
200
|
+
} else {
|
|
201
|
+
this.log.debug(msg);
|
|
202
|
+
}
|
|
199
203
|
}
|
|
200
204
|
|
|
201
205
|
logSilly(msg, force) {
|
|
202
|
-
this.
|
|
206
|
+
if (!force && this.silent_log_mode) {
|
|
207
|
+
this.log.silly(msg);
|
|
208
|
+
} else {
|
|
209
|
+
this.log.silly(msg);
|
|
210
|
+
}
|
|
203
211
|
}
|
|
204
212
|
|
|
205
213
|
async onReady() {
|
|
@@ -708,7 +716,8 @@ class Heos extends utils.Adapter {
|
|
|
708
716
|
}
|
|
709
717
|
|
|
710
718
|
getAllIndexes(arr, val) {
|
|
711
|
-
|
|
719
|
+
const indexes = [];
|
|
720
|
+
let i;
|
|
712
721
|
for (i = 0; i < arr.length; i++)
|
|
713
722
|
if (arr[i] === val)
|
|
714
723
|
indexes.push(i);
|
|
@@ -738,7 +747,7 @@ class Heos extends utils.Adapter {
|
|
|
738
747
|
|
|
739
748
|
const responses = data.split(/(?={"heos")/g);
|
|
740
749
|
|
|
741
|
-
|
|
750
|
+
const parseQueue = [];
|
|
742
751
|
for (let r = 0; r < responses.length; r++) {
|
|
743
752
|
if (responses[r].trim().length > 0) {
|
|
744
753
|
const response = responses[r].trim();
|
|
@@ -781,7 +790,7 @@ class Heos extends utils.Adapter {
|
|
|
781
790
|
try {
|
|
782
791
|
entry = decodeURI(entry);
|
|
783
792
|
} catch (e) {
|
|
784
|
-
|
|
793
|
+
this.logSilly('ignore a malformed URI: ' + e);
|
|
785
794
|
}
|
|
786
795
|
const param = entry.split('=');
|
|
787
796
|
if (param.length > 1) {
|
|
@@ -1330,7 +1339,7 @@ class Heos extends utils.Adapter {
|
|
|
1330
1339
|
if (jmsg.hasOwnProperty('level')) {
|
|
1331
1340
|
const leadHeosPlayer = this.players[jmsg.gid];
|
|
1332
1341
|
if (leadHeosPlayer) {
|
|
1333
|
-
|
|
1342
|
+
const memberPids = leadHeosPlayer.group_pid.split(',');
|
|
1334
1343
|
for (let i = 0; i < memberPids.length; i++) {
|
|
1335
1344
|
const pid = memberPids[i];
|
|
1336
1345
|
const heosPlayer = this.players[pid];
|
|
@@ -1343,7 +1352,7 @@ class Heos extends utils.Adapter {
|
|
|
1343
1352
|
if (jmsg.hasOwnProperty('mute')) {
|
|
1344
1353
|
const leadHeosPlayer = this.players[jmsg.gid];
|
|
1345
1354
|
if (leadHeosPlayer) {
|
|
1346
|
-
|
|
1355
|
+
const memberPids = leadHeosPlayer.group_pid.split(',');
|
|
1347
1356
|
for (let i = 0; i < memberPids.length; i++) {
|
|
1348
1357
|
const pid = memberPids[i];
|
|
1349
1358
|
const heosPlayer = this.players[pid];
|
|
@@ -1384,7 +1393,7 @@ class Heos extends utils.Adapter {
|
|
|
1384
1393
|
switch (cmd) {
|
|
1385
1394
|
case 'get_music_sources':
|
|
1386
1395
|
if ((jdata.hasOwnProperty('payload'))) {
|
|
1387
|
-
|
|
1396
|
+
const folderPath = 'sources';
|
|
1388
1397
|
//Folder
|
|
1389
1398
|
await this.setObjectAsync(folderPath, {
|
|
1390
1399
|
type: 'folder',
|
|
@@ -1531,9 +1540,9 @@ class Heos extends utils.Adapter {
|
|
|
1531
1540
|
|
|
1532
1541
|
//Load previous
|
|
1533
1542
|
if (jmsg.returned < jmsg.count) {
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1543
|
+
let start = 1;
|
|
1544
|
+
let end = 50;
|
|
1545
|
+
let pageCmd = '';
|
|
1537
1546
|
if (jmsg.hasOwnProperty('range')) {
|
|
1538
1547
|
const range = jmsg.range.split(',');
|
|
1539
1548
|
start = parseInt(range[0]) + 1;
|
|
@@ -1567,9 +1576,10 @@ class Heos extends utils.Adapter {
|
|
|
1567
1576
|
}
|
|
1568
1577
|
}
|
|
1569
1578
|
|
|
1579
|
+
let folderPath = '';
|
|
1570
1580
|
switch (sid) {
|
|
1571
1581
|
case 1025:
|
|
1572
|
-
|
|
1582
|
+
folderPath = 'sources.1025';
|
|
1573
1583
|
//Folder
|
|
1574
1584
|
const playlists = [];
|
|
1575
1585
|
for (i = 0; i < jdata.payload.length; i++) {
|
|
@@ -1609,7 +1619,7 @@ class Heos extends utils.Adapter {
|
|
|
1609
1619
|
}
|
|
1610
1620
|
break;
|
|
1611
1621
|
case 1028:
|
|
1612
|
-
|
|
1622
|
+
folderPath = 'sources.1028';
|
|
1613
1623
|
//Folder
|
|
1614
1624
|
const presets = [];
|
|
1615
1625
|
for (i = 0; i < jdata.payload.length; i++) {
|
|
@@ -1670,9 +1680,9 @@ class Heos extends utils.Adapter {
|
|
|
1670
1680
|
|
|
1671
1681
|
//Load next
|
|
1672
1682
|
if (jmsg.returned < jmsg.count) {
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1683
|
+
let start = 1;
|
|
1684
|
+
let end = 50;
|
|
1685
|
+
let pageCmd = '';
|
|
1676
1686
|
if (jmsg.hasOwnProperty('range')) {
|
|
1677
1687
|
const range = jmsg.range.split(',');
|
|
1678
1688
|
start = parseInt(range[0]) + 1;
|
|
@@ -1728,7 +1738,7 @@ class Heos extends utils.Adapter {
|
|
|
1728
1738
|
if (jmsg.hasOwnProperty('level')) {
|
|
1729
1739
|
const leadHeosPlayer = this.players[jmsg.gid];
|
|
1730
1740
|
if (leadHeosPlayer) {
|
|
1731
|
-
|
|
1741
|
+
const memberPids = leadHeosPlayer.group_pid.split(',');
|
|
1732
1742
|
for (let i = 0; i < memberPids.length; i++) {
|
|
1733
1743
|
const pid = memberPids[i];
|
|
1734
1744
|
const heosPlayer = this.players[pid];
|
|
@@ -1747,7 +1757,7 @@ class Heos extends utils.Adapter {
|
|
|
1747
1757
|
if (jmsg.hasOwnProperty('state')) {
|
|
1748
1758
|
const leadHeosPlayer = this.players[jmsg.gid];
|
|
1749
1759
|
if (leadHeosPlayer) {
|
|
1750
|
-
|
|
1760
|
+
const memberPids = leadHeosPlayer.group_pid.split(',');
|
|
1751
1761
|
for (let i = 0; i < memberPids.length; i++) {
|
|
1752
1762
|
const pid = memberPids[i];
|
|
1753
1763
|
const heosPlayer = this.players[pid];
|
|
@@ -2000,7 +2010,7 @@ class Heos extends utils.Adapter {
|
|
|
2000
2010
|
for (let i = 0; i < payload.length; i++) {
|
|
2001
2011
|
let playerConnected = true;
|
|
2002
2012
|
const player = payload[i];
|
|
2003
|
-
|
|
2013
|
+
const pid = player.pid + ''; //Convert to String
|
|
2004
2014
|
if (player.hasOwnProperty('ip') && player.ip != '127.0.0.1') {
|
|
2005
2015
|
foundPlayerIps.push(player.ip);
|
|
2006
2016
|
}
|
|
@@ -2025,9 +2035,9 @@ class Heos extends utils.Adapter {
|
|
|
2025
2035
|
if (this.preferred_player_ips.length > 0
|
|
2026
2036
|
&& this.preferred_player_ips.indexOf(this.ip) === -1
|
|
2027
2037
|
&& this.preferred_player_ips.indexOf(player.ip) !== -1) {
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2038
|
+
this.manual_search_mode = true;
|
|
2039
|
+
this.logInfo('preferred player ' + player.ip + ' found. Reconnect.');
|
|
2040
|
+
this.reconnect();
|
|
2031
2041
|
}
|
|
2032
2042
|
try {
|
|
2033
2043
|
await heosPlayer.connect();
|
|
@@ -2046,8 +2056,8 @@ class Heos extends utils.Adapter {
|
|
|
2046
2056
|
}
|
|
2047
2057
|
}
|
|
2048
2058
|
//Remove disconnected players && Update reboot times for not connected players
|
|
2049
|
-
|
|
2050
|
-
for (
|
|
2059
|
+
const connectedPlayerIps = [];
|
|
2060
|
+
for (const pid in this.players) {
|
|
2051
2061
|
if (!connectedPlayers.includes(pid)) {
|
|
2052
2062
|
await this.stopPlayer(pid);
|
|
2053
2063
|
} else {
|
|
@@ -2953,13 +2963,17 @@ class Heos extends utils.Adapter {
|
|
|
2953
2963
|
this.registerChangeEvents(false);
|
|
2954
2964
|
this.net_client.destroy();
|
|
2955
2965
|
this.net_client.unref();
|
|
2956
|
-
}catch(e){
|
|
2966
|
+
}catch(e){
|
|
2967
|
+
this.logSilly('disconnect failed: ' + e);
|
|
2968
|
+
}
|
|
2957
2969
|
this.net_client = undefined;
|
|
2958
2970
|
}
|
|
2959
2971
|
if (typeof this.nodessdp_client !== 'undefined') {
|
|
2960
2972
|
try {
|
|
2961
2973
|
this.nodessdp_client.stop();
|
|
2962
|
-
}catch(e){
|
|
2974
|
+
}catch(e){
|
|
2975
|
+
this.logSilly('nodessdp client stop failed: ' + e);
|
|
2976
|
+
}
|
|
2963
2977
|
this.nodessdp_client = undefined;
|
|
2964
2978
|
}
|
|
2965
2979
|
await this.setStateAsync('error', false, true);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.heos",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"description": "The adapter lets control HEOS from ioBroker",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "withstu",
|
|
@@ -23,39 +23,39 @@
|
|
|
23
23
|
"url": "https://github.com/withstu/ioBroker.heos"
|
|
24
24
|
},
|
|
25
25
|
"engines": {
|
|
26
|
-
"node": ">=
|
|
26
|
+
"node": ">= 18"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@iobroker/adapter-core": "^3.
|
|
30
|
-
"fast-xml-parser": "^4.
|
|
31
|
-
"axios": "^1.
|
|
32
|
-
"html-entities": "^2.
|
|
29
|
+
"@iobroker/adapter-core": "^3.2.2",
|
|
30
|
+
"fast-xml-parser": "^4.5.0",
|
|
31
|
+
"axios": "^1.7.7",
|
|
32
|
+
"html-entities": "^2.5.2",
|
|
33
33
|
"node-ssdp": "^4.0.1",
|
|
34
34
|
"node-vibrant": "^3.1.6"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@alcalzone/release-script": "^3.
|
|
38
|
-
"@alcalzone/release-script-plugin-iobroker": "^3.
|
|
39
|
-
"@alcalzone/release-script-plugin-license": "^3.
|
|
40
|
-
"@alcalzone/release-script-plugin-manual-review": "^3.
|
|
41
|
-
"@iobroker/adapter-dev": "^1.
|
|
42
|
-
"@iobroker/testing": "^
|
|
43
|
-
"@tsconfig/node16": "^16.1.
|
|
37
|
+
"@alcalzone/release-script": "^3.8.0",
|
|
38
|
+
"@alcalzone/release-script-plugin-iobroker": "^3.7.2",
|
|
39
|
+
"@alcalzone/release-script-plugin-license": "^3.7.0",
|
|
40
|
+
"@alcalzone/release-script-plugin-manual-review": "^3.7.0",
|
|
41
|
+
"@iobroker/adapter-dev": "^1.3.0",
|
|
42
|
+
"@iobroker/testing": "^5.0.0",
|
|
43
|
+
"@tsconfig/node16": "^16.1.3",
|
|
44
44
|
"@types/chai": "^4.3.6",
|
|
45
45
|
"@types/chai-as-promised": "^7.1.8",
|
|
46
|
-
"@types/mocha": "^10.0.
|
|
47
|
-
"@types/node": "^
|
|
48
|
-
"@types/proxyquire": "^1.3.
|
|
46
|
+
"@types/mocha": "^10.0.9",
|
|
47
|
+
"@types/node": "^22.8.4",
|
|
48
|
+
"@types/proxyquire": "^1.3.31",
|
|
49
49
|
"@types/sinon": "^17.0.2",
|
|
50
50
|
"@types/sinon-chai": "^3.2.12",
|
|
51
|
-
"chai": "^4.
|
|
51
|
+
"chai": "^4.4.1",
|
|
52
52
|
"chai-as-promised": "^7.1.1",
|
|
53
|
-
"eslint": "^
|
|
54
|
-
"mocha": "^10.2
|
|
53
|
+
"eslint": "^9.13.0",
|
|
54
|
+
"mocha": "^10.8.2",
|
|
55
55
|
"proxyquire": "^2.1.3",
|
|
56
|
-
"sinon": "^
|
|
56
|
+
"sinon": "^19.0.2",
|
|
57
57
|
"sinon-chai": "^3.7.0",
|
|
58
|
-
"typescript": "~5.
|
|
58
|
+
"typescript": "~5.6.3"
|
|
59
59
|
},
|
|
60
60
|
"main": "main.js",
|
|
61
61
|
"files": [
|