iobroker.absolutehumidity 0.0.4 → 0.0.6

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 CHANGED
@@ -35,6 +35,13 @@ use different Magnus, Tetens, Sonntag, Bolton or Buck coefficient sets.
35
35
  Placeholder for the next version (at the beginning of the line):
36
36
  ### **WORK IN PROGRESS**
37
37
  -->
38
+ ### 0.0.6 (2026-07-06)
39
+ * (BenAhrdt) Sort devices after refresh in case of absolute humidity
40
+
41
+ ### 0.0.5 (2026-07-05)
42
+ * (BenAhrdt) Id will change in case of renameing device
43
+ * (BenAhrdt) Add second manual calculation for compare
44
+
38
45
  ### 0.0.4 (2026-07-05)
39
46
  * (BenAhrdt) Build Config in adapter own device object
40
47
 
@@ -5,6 +5,8 @@
5
5
  "Open Device Manager": "Device Manager öffnen",
6
6
  "Open adapter tab": "Adapter-Tab öffnen",
7
7
  "Manual calculation": "Manuelle Berechnung",
8
+ "Outdoor": "Außen",
9
+ "Indoor": "Innen",
8
10
  "Add device": "Gerät hinzufügen",
9
11
  "Add a temperature and humidity device": "Temperatur- und Luftfeuchte-Gerät hinzufügen",
10
12
  "Edit device": "Gerät bearbeiten",
@@ -19,6 +21,12 @@
19
21
  "Relative humidity": "Relative Luftfeuchte",
20
22
  "Relative humidity state": "State für relative Luftfeuchte",
21
23
  "Create relative humidity state in adapter": "State für relative Luftfeuchte im Adapter anlegen",
24
+ "Outdoor device": "Gerät befindet sich außen",
22
25
  "Absolute humidity": "Absolute Luftfeuchte",
23
- "Dew point temperature": "Taupunkttemperatur"
26
+ "Dew point temperature": "Taupunkttemperatur",
27
+ "Ventilation info unavailable": "Die Lüftungsempfehlung ist noch nicht verfügbar, weil die absolute Luftfeuchte noch nicht berechnet wurde.",
28
+ "Outdoor ventilation reference": "Außenreferenz: Die absolute Luftfeuchte beträgt {absoluteHumidity} g/m³. Dieser Wert wird für die Lüftungsempfehlung der Innenräume verwendet.",
29
+ "Indoor ventilation info without outdoor reference": "Innen: Die absolute Luftfeuchte beträgt {absoluteHumidity} g/m³. Markiere ein Außengerät, um eine Lüftungsempfehlung zu erhalten.",
30
+ "Ventilation recommended because indoor is higher": "Lüften könnte sinnvoll sein: Innen beträgt die absolute Luftfeuchte {absoluteHumidity} g/m³, außen {outdoorAbsoluteHumidity} g/m³. Innen ist es um {difference} g/m³ feuchter.",
31
+ "Ventilation not recommended because indoor is not higher": "Lüften dürfte aktuell weniger sinnvoll sein: Innen beträgt die absolute Luftfeuchte {absoluteHumidity} g/m³, außen {outdoorAbsoluteHumidity} g/m³. Innen ist die absolute Luftfeuchte nicht höher."
24
32
  }
@@ -5,6 +5,8 @@
5
5
  "Open Device Manager": "Open Device Manager",
6
6
  "Open adapter tab": "Open adapter tab",
7
7
  "Manual calculation": "Manual calculation",
8
+ "Outdoor": "Outdoor",
9
+ "Indoor": "Indoor",
8
10
  "Add device": "Add device",
9
11
  "Add a temperature and humidity device": "Add a temperature and humidity device",
10
12
  "Edit device": "Edit device",
@@ -19,6 +21,12 @@
19
21
  "Relative humidity": "Relative humidity",
20
22
  "Relative humidity state": "Relative humidity state",
21
23
  "Create relative humidity state in adapter": "Create relative humidity state in adapter",
24
+ "Outdoor device": "Device is outdoors",
22
25
  "Absolute humidity": "Absolute humidity",
23
- "Dew point temperature": "Dew point temperature"
26
+ "Dew point temperature": "Dew point temperature",
27
+ "Ventilation info unavailable": "The ventilation recommendation is not available yet because absolute humidity has not been calculated.",
28
+ "Outdoor ventilation reference": "Outdoor reference: Absolute humidity is {absoluteHumidity} g/m³. This value is used for indoor ventilation recommendations.",
29
+ "Indoor ventilation info without outdoor reference": "Indoor: Absolute humidity is {absoluteHumidity} g/m³. Mark one device as outdoors to receive a ventilation recommendation.",
30
+ "Ventilation recommended because indoor is higher": "Ventilation could be useful: Indoor absolute humidity is {absoluteHumidity} g/m³, outdoor is {outdoorAbsoluteHumidity} g/m³. Indoor air is {difference} g/m³ more humid.",
31
+ "Ventilation not recommended because indoor is not higher": "Ventilation may be less useful right now: Indoor absolute humidity is {absoluteHumidity} g/m³, outdoor is {outdoorAbsoluteHumidity} g/m³. Indoor absolute humidity is not higher."
24
32
  }
@@ -5,6 +5,8 @@
5
5
  "Open Device Manager": "Abrir Device Manager",
6
6
  "Open adapter tab": "Abrir pestaña del adaptador",
7
7
  "Manual calculation": "Cálculo manual",
8
+ "Outdoor": "Exterior",
9
+ "Indoor": "Interior",
8
10
  "Add device": "Añadir dispositivo",
9
11
  "Add a temperature and humidity device": "Añadir dispositivo de temperatura y humedad",
10
12
  "Edit device": "Editar dispositivo",
@@ -19,6 +21,12 @@
19
21
  "Relative humidity": "Humedad relativa",
20
22
  "Relative humidity state": "Estado de humedad relativa",
21
23
  "Create relative humidity state in adapter": "Crear estado de humedad relativa en el adaptador",
24
+ "Outdoor device": "El dispositivo está en el exterior",
22
25
  "Absolute humidity": "Humedad absoluta",
23
- "Dew point temperature": "Temperatura del punto de rocío"
26
+ "Dew point temperature": "Temperatura del punto de rocío",
27
+ "Ventilation info unavailable": "La recomendación de ventilación aún no está disponible porque no se ha calculado la humedad absoluta.",
28
+ "Outdoor ventilation reference": "Referencia exterior: la humedad absoluta es {absoluteHumidity} g/m³. Este valor se usa para recomendar la ventilación interior.",
29
+ "Indoor ventilation info without outdoor reference": "Interior: la humedad absoluta es {absoluteHumidity} g/m³. Marca un dispositivo como exterior para recibir una recomendación de ventilación.",
30
+ "Ventilation recommended because indoor is higher": "Ventilar podría ser útil: la humedad absoluta interior es {absoluteHumidity} g/m³ y la exterior {outdoorAbsoluteHumidity} g/m³. El interior tiene {difference} g/m³ más humedad.",
31
+ "Ventilation not recommended because indoor is not higher": "Ventilar podría ser menos útil ahora: la humedad absoluta interior es {absoluteHumidity} g/m³ y la exterior {outdoorAbsoluteHumidity} g/m³. La humedad absoluta interior no es mayor."
24
32
  }
@@ -5,6 +5,8 @@
5
5
  "Open Device Manager": "Ouvrir Device Manager",
6
6
  "Open adapter tab": "Ouvrir l'onglet de l'adaptateur",
7
7
  "Manual calculation": "Calcul manuel",
8
+ "Outdoor": "Extérieur",
9
+ "Indoor": "Intérieur",
8
10
  "Add device": "Ajouter un appareil",
9
11
  "Add a temperature and humidity device": "Ajouter un appareil de température et humidité",
10
12
  "Edit device": "Modifier l'appareil",
@@ -19,6 +21,12 @@
19
21
  "Relative humidity": "Humidité relative",
20
22
  "Relative humidity state": "État d'humidité relative",
21
23
  "Create relative humidity state in adapter": "Créer l'état d'humidité relative dans l'adaptateur",
24
+ "Outdoor device": "L'appareil est à l'extérieur",
22
25
  "Absolute humidity": "Humidité absolue",
23
- "Dew point temperature": "Température du point de rosée"
26
+ "Dew point temperature": "Température du point de rosée",
27
+ "Ventilation info unavailable": "La recommandation d'aération n'est pas encore disponible, car l'humidité absolue n'a pas encore été calculée.",
28
+ "Outdoor ventilation reference": "Référence extérieure : l'humidité absolue est de {absoluteHumidity} g/m³. Cette valeur est utilisée pour les recommandations d'aération intérieures.",
29
+ "Indoor ventilation info without outdoor reference": "Intérieur : l'humidité absolue est de {absoluteHumidity} g/m³. Marquez un appareil comme extérieur pour recevoir une recommandation d'aération.",
30
+ "Ventilation recommended because indoor is higher": "L'aération pourrait être utile : l'humidité absolue intérieure est de {absoluteHumidity} g/m³, celle de l'extérieur de {outdoorAbsoluteHumidity} g/m³. L'intérieur est plus humide de {difference} g/m³.",
31
+ "Ventilation not recommended because indoor is not higher": "L'aération pourrait être moins utile pour le moment : l'humidité absolue intérieure est de {absoluteHumidity} g/m³, celle de l'extérieur de {outdoorAbsoluteHumidity} g/m³. L'humidité absolue intérieure n'est pas plus élevée."
24
32
  }
@@ -5,6 +5,8 @@
5
5
  "Open Device Manager": "Apri Device Manager",
6
6
  "Open adapter tab": "Apri scheda adattatore",
7
7
  "Manual calculation": "Calcolo manuale",
8
+ "Outdoor": "Esterno",
9
+ "Indoor": "Interno",
8
10
  "Add device": "Aggiungi dispositivo",
9
11
  "Add a temperature and humidity device": "Aggiungi dispositivo di temperatura e umidità",
10
12
  "Edit device": "Modifica dispositivo",
@@ -19,6 +21,12 @@
19
21
  "Relative humidity": "Umidità relativa",
20
22
  "Relative humidity state": "Stato umidità relativa",
21
23
  "Create relative humidity state in adapter": "Crea stato umidità relativa nell'adattatore",
24
+ "Outdoor device": "Il dispositivo è all'esterno",
22
25
  "Absolute humidity": "Umidità assoluta",
23
- "Dew point temperature": "Temperatura del punto di rugiada"
26
+ "Dew point temperature": "Temperatura del punto di rugiada",
27
+ "Ventilation info unavailable": "La raccomandazione di ventilazione non è ancora disponibile perché l'umidità assoluta non è stata calcolata.",
28
+ "Outdoor ventilation reference": "Riferimento esterno: l'umidità assoluta è {absoluteHumidity} g/m³. Questo valore viene usato per le raccomandazioni di ventilazione interne.",
29
+ "Indoor ventilation info without outdoor reference": "Interno: l'umidità assoluta è {absoluteHumidity} g/m³. Contrassegna un dispositivo come esterno per ricevere una raccomandazione di ventilazione.",
30
+ "Ventilation recommended because indoor is higher": "Ventilare potrebbe essere utile: l'umidità assoluta interna è {absoluteHumidity} g/m³, quella esterna {outdoorAbsoluteHumidity} g/m³. L'interno è più umido di {difference} g/m³.",
31
+ "Ventilation not recommended because indoor is not higher": "Ventilare potrebbe essere meno utile ora: l'umidità assoluta interna è {absoluteHumidity} g/m³, quella esterna {outdoorAbsoluteHumidity} g/m³. L'umidità assoluta interna non è più alta."
24
32
  }
@@ -5,6 +5,8 @@
5
5
  "Open Device Manager": "Device Manager openen",
6
6
  "Open adapter tab": "Adaptertabblad openen",
7
7
  "Manual calculation": "Handmatige berekening",
8
+ "Outdoor": "Buiten",
9
+ "Indoor": "Binnen",
8
10
  "Add device": "Apparaat toevoegen",
9
11
  "Add a temperature and humidity device": "Temperatuur- en vochtigheidsapparaat toevoegen",
10
12
  "Edit device": "Apparaat bewerken",
@@ -19,6 +21,12 @@
19
21
  "Relative humidity": "Relatieve luchtvochtigheid",
20
22
  "Relative humidity state": "Relatieve-luchtvochtigheidstate",
21
23
  "Create relative humidity state in adapter": "Relatieve-luchtvochtigheidstate in adapter aanmaken",
24
+ "Outdoor device": "Apparaat bevindt zich buiten",
22
25
  "Absolute humidity": "Absolute luchtvochtigheid",
23
- "Dew point temperature": "Dauwpunttemperatuur"
26
+ "Dew point temperature": "Dauwpunttemperatuur",
27
+ "Ventilation info unavailable": "Het ventilatieadvies is nog niet beschikbaar omdat de absolute luchtvochtigheid nog niet is berekend.",
28
+ "Outdoor ventilation reference": "Buitenreferentie: de absolute luchtvochtigheid is {absoluteHumidity} g/m³. Deze waarde wordt gebruikt voor ventilatieadvies binnen.",
29
+ "Indoor ventilation info without outdoor reference": "Binnen: de absolute luchtvochtigheid is {absoluteHumidity} g/m³. Markeer een apparaat als buiten om ventilatieadvies te ontvangen.",
30
+ "Ventilation recommended because indoor is higher": "Ventileren kan zinvol zijn: binnen is de absolute luchtvochtigheid {absoluteHumidity} g/m³, buiten {outdoorAbsoluteHumidity} g/m³. Binnen is het {difference} g/m³ vochtiger.",
31
+ "Ventilation not recommended because indoor is not higher": "Ventileren lijkt nu minder zinvol: binnen is de absolute luchtvochtigheid {absoluteHumidity} g/m³, buiten {outdoorAbsoluteHumidity} g/m³. De absolute luchtvochtigheid binnen is niet hoger."
24
32
  }
@@ -5,6 +5,8 @@
5
5
  "Open Device Manager": "Otwórz Device Manager",
6
6
  "Open adapter tab": "Otwórz kartę adaptera",
7
7
  "Manual calculation": "Obliczenie ręczne",
8
+ "Outdoor": "Na zewnątrz",
9
+ "Indoor": "Wewnątrz",
8
10
  "Add device": "Dodaj urządzenie",
9
11
  "Add a temperature and humidity device": "Dodaj urządzenie temperatury i wilgotności",
10
12
  "Edit device": "Edytuj urządzenie",
@@ -19,6 +21,12 @@
19
21
  "Relative humidity": "Wilgotność względna",
20
22
  "Relative humidity state": "Stan wilgotności względnej",
21
23
  "Create relative humidity state in adapter": "Utwórz stan wilgotności względnej w adapterze",
24
+ "Outdoor device": "Urządzenie znajduje się na zewnątrz",
22
25
  "Absolute humidity": "Wilgotność bezwzględna",
23
- "Dew point temperature": "Temperatura punktu rosy"
26
+ "Dew point temperature": "Temperatura punktu rosy",
27
+ "Ventilation info unavailable": "Zalecenie wietrzenia nie jest jeszcze dostępne, ponieważ wilgotność bezwzględna nie została obliczona.",
28
+ "Outdoor ventilation reference": "Odniesienie zewnętrzne: wilgotność bezwzględna wynosi {absoluteHumidity} g/m³. Ta wartość jest używana do zaleceń wietrzenia pomieszczeń.",
29
+ "Indoor ventilation info without outdoor reference": "Wewnątrz: wilgotność bezwzględna wynosi {absoluteHumidity} g/m³. Oznacz jedno urządzenie jako zewnętrzne, aby otrzymać zalecenie wietrzenia.",
30
+ "Ventilation recommended because indoor is higher": "Wietrzenie może być przydatne: wilgotność bezwzględna wewnątrz wynosi {absoluteHumidity} g/m³, na zewnątrz {outdoorAbsoluteHumidity} g/m³. Wewnątrz jest o {difference} g/m³ wilgotniej.",
31
+ "Ventilation not recommended because indoor is not higher": "Wietrzenie może być teraz mniej przydatne: wilgotność bezwzględna wewnątrz wynosi {absoluteHumidity} g/m³, na zewnątrz {outdoorAbsoluteHumidity} g/m³. Wilgotność bezwzględna wewnątrz nie jest wyższa."
24
32
  }
@@ -5,6 +5,8 @@
5
5
  "Open Device Manager": "Abrir Device Manager",
6
6
  "Open adapter tab": "Abrir aba do adaptador",
7
7
  "Manual calculation": "Cálculo manual",
8
+ "Outdoor": "Exterior",
9
+ "Indoor": "Interior",
8
10
  "Add device": "Adicionar dispositivo",
9
11
  "Add a temperature and humidity device": "Adicionar dispositivo de temperatura e umidade",
10
12
  "Edit device": "Editar dispositivo",
@@ -19,6 +21,12 @@
19
21
  "Relative humidity": "Umidade relativa",
20
22
  "Relative humidity state": "Estado de umidade relativa",
21
23
  "Create relative humidity state in adapter": "Criar estado de umidade relativa no adaptador",
24
+ "Outdoor device": "O dispositivo está no exterior",
22
25
  "Absolute humidity": "Umidade absoluta",
23
- "Dew point temperature": "Temperatura do ponto de orvalho"
26
+ "Dew point temperature": "Temperatura do ponto de orvalho",
27
+ "Ventilation info unavailable": "A recomendação de ventilação ainda não está disponível porque a umidade absoluta ainda não foi calculada.",
28
+ "Outdoor ventilation reference": "Referência exterior: a umidade absoluta é {absoluteHumidity} g/m³. Este valor é usado para recomendações de ventilação interna.",
29
+ "Indoor ventilation info without outdoor reference": "Interior: a umidade absoluta é {absoluteHumidity} g/m³. Marque um dispositivo como exterior para receber uma recomendação de ventilação.",
30
+ "Ventilation recommended because indoor is higher": "Ventilar pode ser útil: a umidade absoluta interna é {absoluteHumidity} g/m³, a externa {outdoorAbsoluteHumidity} g/m³. O interior está {difference} g/m³ mais úmido.",
31
+ "Ventilation not recommended because indoor is not higher": "Ventilar pode ser menos útil agora: a umidade absoluta interna é {absoluteHumidity} g/m³, a externa {outdoorAbsoluteHumidity} g/m³. A umidade absoluta interna não é maior."
24
32
  }
@@ -5,6 +5,8 @@
5
5
  "Open Device Manager": "Открыть Device Manager",
6
6
  "Open adapter tab": "Открыть вкладку адаптера",
7
7
  "Manual calculation": "Ручной расчет",
8
+ "Outdoor": "Снаружи",
9
+ "Indoor": "Внутри",
8
10
  "Add device": "Добавить устройство",
9
11
  "Add a temperature and humidity device": "Добавить устройство температуры и влажности",
10
12
  "Edit device": "Редактировать устройство",
@@ -19,6 +21,12 @@
19
21
  "Relative humidity": "Относительная влажность",
20
22
  "Relative humidity state": "Состояние относительной влажности",
21
23
  "Create relative humidity state in adapter": "Создать состояние относительной влажности в адаптере",
24
+ "Outdoor device": "Устройство находится снаружи",
22
25
  "Absolute humidity": "Абсолютная влажность",
23
- "Dew point temperature": "Температура точки росы"
26
+ "Dew point temperature": "Температура точки росы",
27
+ "Ventilation info unavailable": "Рекомендация по проветриванию пока недоступна, потому что абсолютная влажность еще не рассчитана.",
28
+ "Outdoor ventilation reference": "Наружный ориентир: абсолютная влажность составляет {absoluteHumidity} г/м³. Это значение используется для рекомендаций по проветриванию помещений.",
29
+ "Indoor ventilation info without outdoor reference": "Внутри: абсолютная влажность составляет {absoluteHumidity} г/м³. Отметьте одно устройство как наружное, чтобы получить рекомендацию по проветриванию.",
30
+ "Ventilation recommended because indoor is higher": "Проветривание может быть полезно: внутри абсолютная влажность {absoluteHumidity} г/м³, снаружи {outdoorAbsoluteHumidity} г/м³. Внутри влажнее на {difference} г/м³.",
31
+ "Ventilation not recommended because indoor is not higher": "Проветривание сейчас может быть менее полезным: внутри абсолютная влажность {absoluteHumidity} г/м³, снаружи {outdoorAbsoluteHumidity} г/м³. Внутренняя абсолютная влажность не выше."
24
32
  }
@@ -5,6 +5,8 @@
5
5
  "Open Device Manager": "Відкрити Device Manager",
6
6
  "Open adapter tab": "Відкрити вкладку адаптера",
7
7
  "Manual calculation": "Ручний розрахунок",
8
+ "Outdoor": "Зовні",
9
+ "Indoor": "Всередині",
8
10
  "Add device": "Додати пристрій",
9
11
  "Add a temperature and humidity device": "Додати пристрій температури та вологості",
10
12
  "Edit device": "Редагувати пристрій",
@@ -19,6 +21,12 @@
19
21
  "Relative humidity": "Відносна вологість",
20
22
  "Relative humidity state": "Стан відносної вологості",
21
23
  "Create relative humidity state in adapter": "Створити стан відносної вологості в адаптері",
24
+ "Outdoor device": "Пристрій знаходиться зовні",
22
25
  "Absolute humidity": "Абсолютна вологість",
23
- "Dew point temperature": "Температура точки роси"
26
+ "Dew point temperature": "Температура точки роси",
27
+ "Ventilation info unavailable": "Рекомендація щодо провітрювання ще недоступна, тому що абсолютну вологість ще не розраховано.",
28
+ "Outdoor ventilation reference": "Зовнішній орієнтир: абсолютна вологість становить {absoluteHumidity} г/м³. Це значення використовується для рекомендацій щодо провітрювання приміщень.",
29
+ "Indoor ventilation info without outdoor reference": "Всередині: абсолютна вологість становить {absoluteHumidity} г/м³. Позначте один пристрій як зовнішній, щоб отримати рекомендацію щодо провітрювання.",
30
+ "Ventilation recommended because indoor is higher": "Провітрювання може бути корисним: всередині абсолютна вологість {absoluteHumidity} г/м³, зовні {outdoorAbsoluteHumidity} г/м³. Усередині вологіше на {difference} г/м³.",
31
+ "Ventilation not recommended because indoor is not higher": "Провітрювання зараз може бути менш корисним: всередині абсолютна вологість {absoluteHumidity} г/м³, зовні {outdoorAbsoluteHumidity} г/м³. Абсолютна вологість усередині не вища."
24
32
  }
@@ -5,6 +5,8 @@
5
5
  "Open Device Manager": "打开 Device Manager",
6
6
  "Open adapter tab": "打开适配器标签页",
7
7
  "Manual calculation": "手动计算",
8
+ "Outdoor": "室外",
9
+ "Indoor": "室内",
8
10
  "Add device": "添加设备",
9
11
  "Add a temperature and humidity device": "添加温湿度设备",
10
12
  "Edit device": "编辑设备",
@@ -19,6 +21,12 @@
19
21
  "Relative humidity": "相对湿度",
20
22
  "Relative humidity state": "相对湿度状态",
21
23
  "Create relative humidity state in adapter": "在适配器中创建相对湿度状态",
24
+ "Outdoor device": "设备位于室外",
22
25
  "Absolute humidity": "绝对湿度",
23
- "Dew point temperature": "露点温度"
26
+ "Dew point temperature": "露点温度",
27
+ "Ventilation info unavailable": "通风建议尚不可用,因为尚未计算绝对湿度。",
28
+ "Outdoor ventilation reference": "室外参考:绝对湿度为 {absoluteHumidity} g/m³。该值用于室内通风建议。",
29
+ "Indoor ventilation info without outdoor reference": "室内:绝对湿度为 {absoluteHumidity} g/m³。请将一个设备标记为室外,以获取通风建议。",
30
+ "Ventilation recommended because indoor is higher": "通风可能有用:室内绝对湿度为 {absoluteHumidity} g/m³,室外为 {outdoorAbsoluteHumidity} g/m³。室内高出 {difference} g/m³。",
31
+ "Ventilation not recommended because indoor is not higher": "现在通风可能作用较小:室内绝对湿度为 {absoluteHumidity} g/m³,室外为 {outdoorAbsoluteHumidity} g/m³。室内绝对湿度并不更高。"
24
32
  }
@@ -35,10 +35,10 @@
35
35
  "color": "#ffffff"
36
36
  }
37
37
  },
38
- "_previewCard": {
38
+ "_previewCards": {
39
39
  "type": "staticText",
40
40
  "format": "html",
41
- "text": "<div class='ah-preview-card' style='width:300px;background:#d3d3d3;border-radius:4px;overflow:hidden;box-shadow:0 2px 4px rgba(0,0,0,.25);margin-top:24px;color:#000;font-family:Roboto,Arial,sans-serif;'><div style='height:60px;background:#0f4c81;color:#fff;display:flex;align-items:center;padding:0 18px;gap:18px;font-weight:700;'><img src='adapter/absolutehumidity/absolutehumidity.svg' alt='' style='width:34px;height:34px;object-fit:contain;' onload='(async img=>{const c=img.closest(\".ah-preview-card\");if(!c||c.dataset.ahI18nDone)return;c.dataset.ahI18nDone=\"1\";const raw=String(window.systemLang||window.adminLanguage||navigator.language||\"en\").toLowerCase();const lang=raw.startsWith(\"zh\")?\"zh-cn\":raw.slice(0,2);const load=async l=>{const r=await fetch(\"adapter/absolutehumidity/i18n/\"+l+\".json\");return r.ok?r.json():null;};try{const d=(await load(lang))||(await load(\"en\"))||{};c.querySelectorAll(\"[data-ah-i18n]\").forEach(e=>{const k=e.dataset.ahI18n;e.textContent=d[k]||k;});}catch(e){}})(this)'><span data-ah-i18n='Manual calculation'>Manual calculation</span></div><div style='padding:18px 16px 20px;'><div style='color:#00a51a;font-size:20px;margin-bottom:18px;'>↔</div><div style='display:grid;grid-template-columns:1fr auto;gap:14px 16px;align-items:center;'><label for='ah-preview-temp'><span data-ah-i18n='Temperature'>Temperature</span>:</label><span><input id='ah-preview-temp' data-ah-temp type='number' value='21' step='0.1' style='width:72px;background:#fff;border:1px solid #ccc;border-radius:3px;padding:4px 6px;text-align:right;color:#000;' onchange='event.stopPropagation();event.stopImmediatePropagation();' oninput='event.stopPropagation();event.stopImmediatePropagation();const r=this.closest(\".ah-preview-card\"),t=Number(r.querySelector(\"[data-ah-temp]\").value),h=Number(r.querySelector(\"[data-ah-rh]\").value),abs=r.querySelector(\"[data-ah-abs]\"),dew=r.querySelector(\"[data-ah-dew]\");if(Number.isFinite(t)&&Number.isFinite(h)&&h>=0&&h<=100){const es=6.112*Math.exp((17.67*t)/(t+243.5)),e=h/100*es;abs.textContent=(Math.round(((216.7*e)/(273.15+t))*100)/100).toFixed(2);}else abs.textContent=\"\";if(Number.isFinite(t)&&Number.isFinite(h)&&h>0&&h<=100){const a=Math.log(h/100)+(17.62*t)/(243.12+t);dew.textContent=(Math.round(((243.12*a)/(17.62-a))*100)/100).toFixed(2);}else dew.textContent=\"\";'> <span style='color:#555;font-size:12px;'>°C</span></span><label for='ah-preview-rh'><span data-ah-i18n='Relative humidity'>Relative humidity</span>:</label><span><input id='ah-preview-rh' data-ah-rh type='number' value='50' min='0' max='100' step='1' style='width:72px;background:#fff;border:1px solid #ccc;border-radius:3px;padding:4px 6px;text-align:right;color:#000;' onchange='event.stopPropagation();event.stopImmediatePropagation();' oninput='event.stopPropagation();event.stopImmediatePropagation();const r=this.closest(\".ah-preview-card\"),t=Number(r.querySelector(\"[data-ah-temp]\").value),h=Number(r.querySelector(\"[data-ah-rh]\").value),abs=r.querySelector(\"[data-ah-abs]\"),dew=r.querySelector(\"[data-ah-dew]\");if(Number.isFinite(t)&&Number.isFinite(h)&&h>=0&&h<=100){const es=6.112*Math.exp((17.67*t)/(t+243.5)),e=h/100*es;abs.textContent=(Math.round(((216.7*e)/(273.15+t))*100)/100).toFixed(2);}else abs.textContent=\"\";if(Number.isFinite(t)&&Number.isFinite(h)&&h>0&&h<=100){const a=Math.log(h/100)+(17.62*t)/(243.12+t);dew.textContent=(Math.round(((243.12*a)/(17.62-a))*100)/100).toFixed(2);}else dew.textContent=\"\";'> <span style='color:#555;font-size:12px;'>%</span></span><span><span data-ah-i18n='Absolute humidity'>Absolute humidity</span>:</span><span style='text-align:right;'><span data-ah-abs>9.16</span> <span style='color:#555;font-size:12px;'>g/m³</span></span><span><span data-ah-i18n='Dew point temperature'>Dew point temperature</span>:</span><span style='text-align:right;'><span data-ah-dew>10.18</span> <span style='color:#555;font-size:12px;'>°C</span></span></div><div style='height:34px;'></div></div></div>",
41
+ "text": "<div style='display:flex;justify-content:center;gap:32px;flex-wrap:wrap;margin-top:24px;font-family:Roboto,Arial,sans-serif;'><div data-ah-card='outdoor' style='width:300px;min-height:404px;background:#d3d3d3;border-radius:4px;overflow:hidden;box-shadow:0 2px 4px rgba(0,0,0,.25);color:#000;'><div style='height:60px;background:#21867a;color:#fff;display:flex;align-items:center;padding:0 18px;gap:18px;font-weight:700;font-size:15px;'><img src='adapter/absolutehumidity/absolutehumidity.svg' alt='' style='width:34px;height:34px;object-fit:contain;' onload='(async img=>{if(window.ahPreviewReady)return;window.ahPreviewReady=1;const raw=String(window.systemLang||window.adminLanguage||navigator.language||\"en\").toLowerCase();const lang=raw.startsWith(\"zh\")?\"zh-cn\":raw.slice(0,2);const load=async l=>{try{const r=await fetch(\"adapter/absolutehumidity/i18n/\"+l+\".json\");return r.ok?r.json():null;}catch(e){return null;}};const dict=(await load(lang))||(await load(\"en\"))||{};const text=(k,f)=>dict[k]||f||k;const fill=(s,v)=>Object.entries(v).reduce((r,e)=>r.replaceAll(\"{\"+e[0]+\"}\",e[1]),s);window.ahPreviewUpdate=()=>{document.querySelectorAll(\"[data-ah-card]\").forEach(c=>{const t=Number(c.querySelector(\"[data-ah-temp]\").value),h=Number(c.querySelector(\"[data-ah-rh]\").value),abs=c.querySelector(\"[data-ah-abs]\"),dew=c.querySelector(\"[data-ah-dew]\");if(Number.isFinite(t)&&Number.isFinite(h)&&h>=0&&h<=100){const es=6.112*Math.exp(17.67*t/(t+243.5)),e=h/100*es,a=(216.7*e)/(273.15+t);abs.textContent=a.toFixed(2);abs.dataset.value=String(a);}else{abs.textContent=\"\";abs.dataset.value=\"\";}if(Number.isFinite(t)&&Number.isFinite(h)&&h>0&&h<=100){const x=Math.log(h/100)+17.62*t/(243.12+t);dew.textContent=(243.12*x/(17.62-x)).toFixed(2);}else dew.textContent=\"\";});const out=document.querySelector(\"[data-ah-card=outdoor]\"),inn=document.querySelector(\"[data-ah-card=indoor]\");const outAbs=Number(out.querySelector(\"[data-ah-abs]\").dataset.value),inAbs=Number(inn.querySelector(\"[data-ah-abs]\").dataset.value);out.querySelector(\"[data-ah-summary]\").textContent=fill(text(\"Outdoor ventilation reference\"),{absoluteHumidity:Number.isFinite(outAbs)?outAbs.toFixed(2):\"\"});const diff=inAbs-outAbs;const key=diff>0?\"Ventilation recommended because indoor is higher\":\"Ventilation not recommended because indoor is not higher\";inn.querySelector(\"[data-ah-summary]\").textContent=fill(text(key),{absoluteHumidity:Number.isFinite(inAbs)?inAbs.toFixed(2):\"\",outdoorAbsoluteHumidity:Number.isFinite(outAbs)?outAbs.toFixed(2):\"\",difference:Number.isFinite(diff)?Math.abs(diff).toFixed(2):\"\"});};document.querySelectorAll(\"[data-ah-i18n]\").forEach(e=>{e.textContent=text(e.dataset.ahI18n,e.textContent);});window.ahPreviewUpdate();})(this)'><span data-ah-i18n='Outdoor'>Outdoor</span></div><div style='padding:18px 16px 20px;box-sizing:border-box;'><div style='height:24px;margin-bottom:22px;display:flex;align-items:center;'><i class='material-icons' aria-hidden='true' style='color:#00a51a;font-size:22px;line-height:22px;'>link</i></div><div style='display:grid;grid-template-columns:28px 1fr auto;gap:18px 8px;align-items:center;font-size:16px;'><svg viewBox='0 0 24 24' width='24' height='24' aria-hidden='true'><path fill='none' stroke='#1976d2' stroke-width='2'stroke-linecap='round' stroke-linejoin='round'd='M14 14.76V5a4 4 0 0 0-8 0v9.76a6 6 0 1 0 8 0Z'/><path fill='#1976d2'd='M10 17.5a2.5 2.5 0 1 1-2-2.45V8a2 2 0 0 1 4 0v7.05a2.5 2.5 0 0 1-2 2.45Z'/></svg><span><span data-ah-i18n='Temperature'>Temperature</span>:</span><span style='white-space:nowrap;'><input data-ah-temp type='number' value='16' step='0.1' style='width:72px;background:#fff;border:1px solid #ccc;border-radius:3px;padding:4px 6px;text-align:right;color:#000;font-size:14px;' oninput='event.stopPropagation();window.ahPreviewUpdate&&window.ahPreviewUpdate();'> <span style='font-size:14px;'>°C</span></span><svg viewBox='0 0 24 24' width='24' height='24' aria-hidden='true'><path fill='#03a9f4'd='M12 2.7 6.6 9.3A8.2 8.2 0 0 0 5 14a7 7 0 0 0 14 0 8.2 8.2 0 0 0-1.6-4.7L12 2.7Z'/><text x='12' y='16'text-anchor='middle'font-family='Arial, sans-serif'font-size='7'font-weight='700'fill='#fff'>%</text></svg><span><span data-ah-i18n='Relative humidity'>Relative humidity</span>:</span><span style='white-space:nowrap;'><input data-ah-rh type='number' value='60' min='0' max='100' step='1' style='width:72px;background:#fff;border:1px solid #ccc;border-radius:3px;padding:4px 6px;text-align:right;color:#000;font-size:14px;' oninput='event.stopPropagation();window.ahPreviewUpdate&&window.ahPreviewUpdate();'> <span style='font-size:14px;'>%</span></span><svg viewBox='0 0 24 24' width='24' height='24' aria-hidden='true'><path fill='#03a9f4'd='M12 2.7 6.6 9.3A8.2 8.2 0 0 0 5 14a7 7 0 0 0 14 0 8.2 8.2 0 0 0-1.6-4.7L12 2.7Z'/><path fill='rgba(255,255,255,.7)'d='M8.4 14.1c.3 2.1 1.6 3.3 3.4 3.7-2.8.3-5-1.2-5.4-3.6-.2-1.2.2-2.4 1.1-3.5-.1 1.2.2 2.4.9 3.4Z'/></svg><span><span data-ah-i18n='Absolute humidity'>Absolute humidity</span>:</span><span style='text-align:right;white-space:nowrap;'><span data-ah-abs>8.17</span> <span style='font-size:14px;'>g/m³</span></span><svg viewBox='0 0 24 24' width='24' height='24' aria-hidden='true'><path fill='none' stroke='#1976d2' stroke-width='2'stroke-linecap='round' stroke-linejoin='round'd='M10 13.9V5a3 3 0 0 0-6 0v8.9a5 5 0 1 0 6 0Z'/><path fill='#1976d2'd='M7 17.6a2.1 2.1 0 0 1-1-4V8a1 1 0 0 1 2 0v5.6a2.1 2.1 0 0 1-1 4Z'/><path fill='#03a9f4'd='M17 6.4 13.7 10a5 5 0 0 0-1.2 3.2 4.5 4.5 0 0 0 9 0 5 5 0 0 0-1.2-3.2L17 6.4Z'/></svg><span><span data-ah-i18n='Dew point temperature'>Dew point temperature</span>:</span><span style='text-align:right;white-space:nowrap;'><span data-ah-dew>8.23</span> <span style='font-size:14px;'>°C</span></span></div><p style='margin:18px 0 0;font-size:14px;line-height:1.35;'><span data-ah-summary>Outdoor reference: Absolute humidity is 8.17 g/m³. This value is used for indoor ventilation recommendations.</span></p></div></div><div data-ah-card='indoor' style='width:300px;min-height:404px;background:#d3d3d3;border-radius:4px;overflow:hidden;box-shadow:0 2px 4px rgba(0,0,0,.25);color:#000;'><div style='height:60px;background:#0f4c81;color:#fff;display:flex;align-items:center;padding:0 18px;gap:18px;font-weight:700;font-size:15px;'><img src='adapter/absolutehumidity/absolutehumidity.svg' alt='' style='width:34px;height:34px;object-fit:contain;'><span data-ah-i18n='Indoor'>Indoor</span></div><div style='padding:18px 16px 20px;box-sizing:border-box;'><div style='height:24px;margin-bottom:22px;display:flex;align-items:center;'><i class='material-icons' aria-hidden='true' style='color:#00a51a;font-size:22px;line-height:22px;'>link</i></div><div style='display:grid;grid-template-columns:28px 1fr auto;gap:18px 8px;align-items:center;font-size:16px;'><svg viewBox='0 0 24 24' width='24' height='24'><path fill='none' stroke='#1976d2' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M14 14.76V5a4 4 0 0 0-8 0v9.76a6 6 0 1 0 8 0Z'/><path fill='#1976d2' d='M10 17.5a2.5 2.5 0 1 1-2-2.45V8a2 2 0 0 1 4 0v7.05a2.5 2.5 0 0 1-2 2.45Z'/></svg><span><span data-ah-i18n='Temperature'>Temperature</span>:</span><span style='white-space:nowrap;'><input data-ah-temp type='number' value='22' step='0.1' style='width:72px;background:#fff;border:1px solid #ccc;border-radius:3px;padding:4px 6px;text-align:right;color:#000;font-size:14px;' oninput='event.stopPropagation();window.ahPreviewUpdate&&window.ahPreviewUpdate();'> <span style='font-size:14px;'>°C</span></span><svg viewBox='0 0 24 24' width='24' height='24'><path fill='#03a9f4' d='M12 2.7 6.6 9.3A8.2 8.2 0 0 0 5 14a7 7 0 0 0 14 0 8.2 8.2 0 0 0-1.6-4.7L12 2.7Z'/><text x='12' y='16' text-anchor='middle' font-family='Arial,sans-serif' font-size='7' font-weight='700' fill='#fff'>%</text></svg><span><span data-ah-i18n='Relative humidity'>Relative humidity</span>:</span><span style='white-space:nowrap;'><input data-ah-rh type='number' value='50' min='0' max='100' step='1' style='width:72px;background:#fff;border:1px solid #ccc;border-radius:3px;padding:4px 6px;text-align:right;color:#000;font-size:14px;' oninput='event.stopPropagation();window.ahPreviewUpdate&&window.ahPreviewUpdate();'> <span style='font-size:14px;'>%</span></span><svg viewBox='0 0 24 24' width='24' height='24'><path fill='#03a9f4' d='M12 2.7 6.6 9.3A8.2 8.2 0 0 0 5 14a7 7 0 0 0 14 0 8.2 8.2 0 0 0-1.6-4.7L12 2.7Z'/><path fill='rgba(255,255,255,.7)' d='M8.4 14.1c.3 2.1 1.6 3.3 3.4 3.7-2.8.3-5-1.2-5.4-3.6-.2-1.2.2-2.4 1.1-3.5-.1 1.2.2 2.4.9 3.4Z'/></svg><span><span data-ah-i18n='Absolute humidity'>Absolute humidity</span>:</span><span style='text-align:right;white-space:nowrap;'><span data-ah-abs>9.70</span> <span style='font-size:14px;'>g/m³</span></span><svg viewBox='0 0 24 24' width='24' height='24'><path fill='none' stroke='#1976d2' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M10 13.9V5a3 3 0 0 0-6 0v8.9a5 5 0 1 0 6 0Z'/><path fill='#1976d2' d='M7 17.6a2.1 2.1 0 0 1-1-4V8a1 1 0 0 1 2 0v5.6a2.1 2.1 0 0 1-1 4Z'/><path fill='#03a9f4' d='M17 6.4 13.7 10a5 5 0 0 0-1.2 3.2 4.5 4.5 0 0 0 9 0 5 5 0 0 0-1.2-3.2L17 6.4Z'/></svg><span><span data-ah-i18n='Dew point temperature'>Dew point temperature</span>:</span><span style='text-align:right;white-space:nowrap;'><span data-ah-dew>11.09</span> <span style='font-size:14px;'>°C</span></span></div><p style='margin:18px 0 0;font-size:14px;line-height:1.35;'><span data-ah-summary>Ventilation could be useful: Indoor absolute humidity is 9.70 g/m³, outdoor is 8.17 g/m³. Indoor air is 1.53 g/m³ more humid.</span></p></div></div></div>",
42
42
  "newLine": true,
43
43
  "xs": 12,
44
44
  "sm": 12,
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "absolutehumidity",
4
- "version": "0.0.4",
4
+ "version": "0.0.6",
5
5
  "news": {
6
+ "0.0.6": {
7
+ "en": "Sort devices after refresh in case of absolute humidity",
8
+ "de": "Sortieren Sie die Geräte nach der Auffrischung im Falle absoluter Luftfeuchtigkeit.",
9
+ "ru": "После обновления отсортируйте устройства в случае повышенной абсолютной влажности.",
10
+ "pt": "Ordene os dispositivos após a atualização em caso de umidade absoluta.",
11
+ "nl": "Sorteer de apparaten na het vernieuwen in geval van extreme luchtvochtigheid.",
12
+ "fr": "Trier les appareils après actualisation en cas d'humidité absolue",
13
+ "it": "Ordina i dispositivi dopo l'aggiornamento in caso di umidità assoluta",
14
+ "es": "Clasifique los dispositivos después de la actualización en caso de humedad absoluta.",
15
+ "pl": "Posortuj urządzenia po odświeżeniu w przypadku wilgotności bezwzględnej",
16
+ "uk": "Сортуйте пристрої після оновлення за умови абсолютної вологості",
17
+ "zh-cn": "刷新后,在绝对湿度情况下对设备进行排序"
18
+ },
19
+ "0.0.5": {
20
+ "en": "Id will change in case of renameing device\nAdd second manual calculation for compare",
21
+ "de": "Die ID ändert sich, wenn das Gerät umbenannt wird.\nFüge eine zweite manuelle Berechnung zum Vergleich hinzu.",
22
+ "ru": "Идентификатор изменится в случае переименования устройства.\nДобавьте второй ручной расчет для сравнения.",
23
+ "pt": "O ID será alterado caso o dispositivo seja renomeado.\nAdicionar um segundo cálculo manual para comparação.",
24
+ "nl": "De ID verandert als het apparaat een andere naam krijgt.\nVoeg een tweede handmatige berekening toe ter vergelijking.",
25
+ "fr": "L'identifiant changera en cas de changement de nom de l'appareil.\nAjouter un deuxième calcul manuel pour la comparaison",
26
+ "it": "L'ID cambierà in caso di ridenominazione del dispositivo.\nAggiungi un secondo calcolo manuale per il confronto",
27
+ "es": "El ID cambiará en caso de que se cambie el nombre del dispositivo.\nAgregar un segundo cálculo manual para comparar",
28
+ "pl": "Identyfikator ulegnie zmianie w przypadku zmiany nazwy urządzenia\nDodaj drugie obliczenie ręczne w celu porównania",
29
+ "uk": "Ідентифікатор зміниться у разі перейменування пристрою\nДодати другий ручний розрахунок для порівняння",
30
+ "zh-cn": "设备重命名时,ID 将会更改。\n添加第二个手动计算以进行比较。"
31
+ },
6
32
  "0.0.4": {
7
33
  "en": "Build Config in adapter own device object",
8
34
  "de": "Konfiguration im eigenen Geräteobjekt des Adapters erstellen",
@@ -6,12 +6,14 @@ const STATE_RELATIVE_HUMIDITY = 'relativeHumidity';
6
6
  const STATE_ABSOLUTE_HUMIDITY = 'absoluteHumidity';
7
7
  const STATE_DEW_POINT_TEMPERATURE = 'dewPointTemperature';
8
8
  const CARD_HEADER_BACKGROUND = '#0f4c81';
9
+ const OUTDOOR_CARD_HEADER_BACKGROUND = '#21867a';
9
10
  const ADAPTER_ICON = 'adapter/absolutehumidity/absolutehumidity.svg';
10
11
 
11
12
  module.exports = {
12
13
  ADAPTER_ICON,
13
14
  CARD_HEADER_BACKGROUND,
14
15
  DEVICE_ROOT,
16
+ OUTDOOR_CARD_HEADER_BACKGROUND,
15
17
  STATE_ABSOLUTE_HUMIDITY,
16
18
  STATE_DEW_POINT_TEMPERATURE,
17
19
  STATE_RELATIVE_HUMIDITY,
@@ -1,10 +1,11 @@
1
- /* eslint-disable jsdoc/require-jsdoc, jsdoc/require-param-description, jsdoc/reject-any-type */
1
+ /* eslint-disable jsdoc/check-tag-names, jsdoc/require-jsdoc, jsdoc/require-param-description, jsdoc/reject-any-type */
2
2
  'use strict';
3
3
 
4
4
  const { DeviceManagement } = require('@iobroker/dm-utils');
5
5
  const {
6
6
  ADAPTER_ICON,
7
7
  CARD_HEADER_BACKGROUND,
8
+ OUTDOOR_CARD_HEADER_BACKGROUND,
8
9
  STATE_ABSOLUTE_HUMIDITY,
9
10
  STATE_DEW_POINT_TEMPERATURE,
10
11
  STATE_RELATIVE_HUMIDITY,
@@ -45,18 +46,25 @@ const TEMPERATURE_STATE_FILTER =
45
46
  const RELATIVE_HUMIDITY_STATE_FILTER =
46
47
  "const unit = String(obj.common?.unit || '').trim().toLowerCase().replace(/\\s+/g, ''); return obj.type === 'state' && obj.common?.type === 'number' && (unit === '' || unit === '%');";
47
48
 
49
+ /**
50
+ * @augments {DeviceManagement<any, string>}
51
+ */
48
52
  class AbsoluteHumidityDeviceManagement extends DeviceManagement {
49
53
  /**
50
- * @param {import('../../main')} adapter
54
+ * @param {any} adapter
51
55
  */
52
56
  constructor(adapter) {
53
57
  super(adapter, true);
58
+ this.refreshSequence = 0;
54
59
  }
55
60
 
61
+ /**
62
+ * @returns {import('@iobroker/dm-utils').InstanceDetails} Instance information.
63
+ */
56
64
  getInstanceInfo() {
57
65
  return {
58
66
  apiVersion: 'v3',
59
- communicationStateId: 'info.deviceManager',
67
+ communicationStateId: `${this.adapter.namespace}.info.deviceManager`,
60
68
  actions: [
61
69
  {
62
70
  id: 'addDevice',
@@ -101,7 +109,7 @@ class AbsoluteHumidityDeviceManagement extends DeviceManagement {
101
109
  * @param {import('@iobroker/dm-utils').DeviceLoadContext<string>} context
102
110
  */
103
111
  async loadDevices(context) {
104
- const devices = this.adapter.getConfiguredDevices();
112
+ const devices = await getDevicesSortedByAbsoluteHumidity(this.adapter);
105
113
 
106
114
  context.setTotalDevices(devices.length);
107
115
 
@@ -111,21 +119,36 @@ class AbsoluteHumidityDeviceManagement extends DeviceManagement {
111
119
  context.addDevice(createDeviceInfo(this.adapter, device, sourceValidation));
112
120
  }
113
121
  }
122
+
123
+ async refreshDevices() {
124
+ this.refreshSequence += 1;
125
+ // dm-gui-components exposes backend commands, but the Admin JSONConfig wrapper currently
126
+ // does not subscribe to this state. Keep sending it for compatible/future wrappers.
127
+ await this.sendCommandToGui(
128
+ /** @type {any} */ ({
129
+ command: 'all',
130
+ sequence: this.refreshSequence,
131
+ }),
132
+ );
133
+ }
114
134
  }
115
135
 
116
136
  /**
117
- * @param {import('../../main')} adapter
137
+ * @param {any} adapter
118
138
  * @param {Record<string, any>} device
119
139
  * @param {{ valid: boolean; temperatureStateValid: boolean; relativeHumidityStateValid: boolean }} sourceValidation
140
+ * @returns {import('@iobroker/dm-utils').DeviceInfo<string>} Device manager card information.
120
141
  */
121
142
  function createDeviceInfo(adapter, device, sourceValidation) {
122
143
  return {
123
144
  id: device.id,
124
145
  name: device.name,
125
146
  icon: ADAPTER_ICON,
126
- backgroundColor: CARD_HEADER_BACKGROUND,
147
+ backgroundColor: device.isOutdoor ? OUTDOOR_CARD_HEADER_BACKGROUND : CARD_HEADER_BACKGROUND,
127
148
  status: sourceValidation.valid
128
- ? 'connected'
149
+ ? {
150
+ connection: 'connected',
151
+ }
129
152
  : {
130
153
  connection: 'disconnected',
131
154
  warning: translate('Invalid source state'),
@@ -170,9 +193,10 @@ function createDeviceInfo(adapter, device, sourceValidation) {
170
193
  }
171
194
 
172
195
  /**
173
- * @param {import('../../main')} adapter
196
+ * @param {any} adapter
174
197
  * @param {Record<string, any>} device
175
198
  * @param {{ valid: boolean; temperatureStateValid: boolean; relativeHumidityStateValid: boolean }} sourceValidation
199
+ * @returns {import('@iobroker/dm-utils').DeviceDetails<string>} Device manager custom information.
176
200
  */
177
201
  function createDeviceCustomInfo(adapter, device, sourceValidation) {
178
202
  return {
@@ -247,6 +271,7 @@ function createDeviceCustomInfo(adapter, device, sourceValidation) {
247
271
  * @param {string} unit
248
272
  * @param {boolean} foreign
249
273
  * @param {string} labelIcon
274
+ * @returns {import('@iobroker/dm-utils').ConfigItemAny} State display item.
250
275
  */
251
276
  function createStateInfoItem(label, oid, unit, foreign, labelIcon) {
252
277
  return {
@@ -277,7 +302,7 @@ function createSvgIcon(svg) {
277
302
  }
278
303
 
279
304
  /**
280
- * @param {import('@iobroker/dm-utils').ActionContext} context
305
+ * @param {any} context
281
306
  * @param {Record<string, any> | undefined} device
282
307
  */
283
308
  async function showDeviceForm(context, device) {
@@ -286,6 +311,7 @@ async function showDeviceForm(context, device) {
286
311
  data: device
287
312
  ? {
288
313
  name: device.name,
314
+ isOutdoor: device.isOutdoor === true,
289
315
  temperatureStateId: device.temperatureStateId,
290
316
  relativeHumidityStateId: device.relativeHumidityStateId,
291
317
  createTemperatureState: device.createTemperatureState,
@@ -293,6 +319,7 @@ async function showDeviceForm(context, device) {
293
319
  }
294
320
  : {
295
321
  name: '',
322
+ isOutdoor: false,
296
323
  temperatureStateId: '',
297
324
  relativeHumidityStateId: '',
298
325
  createTemperatureState: true,
@@ -357,13 +384,76 @@ function getDeviceFormSchema() {
357
384
  xs: 12,
358
385
  sm: 12,
359
386
  },
387
+ isOutdoor: {
388
+ type: 'checkbox',
389
+ label: translate('Outdoor device'),
390
+ newLine: true,
391
+ xs: 12,
392
+ sm: 12,
393
+ },
360
394
  },
361
395
  };
362
396
  }
363
397
 
398
+ /**
399
+ * @param {any} adapter
400
+ * @param {Record<string, any>[]} devices
401
+ */
402
+ async function getDevicesSortedByAbsoluteHumidity(adapter, devices = adapter.getConfiguredDevices()) {
403
+ const devicesWithHumidity = await Promise.all(
404
+ devices.map(async device => ({
405
+ device,
406
+ absoluteHumidity: await readAbsoluteHumidityValue(adapter, device),
407
+ })),
408
+ );
409
+
410
+ return devicesWithHumidity
411
+ .sort(
412
+ (left, right) => compareAbsoluteHumidity(left, right) || left.device.name.localeCompare(right.device.name),
413
+ )
414
+ .map(entry => entry.device);
415
+ }
416
+
417
+ /**
418
+ * @param {{ absoluteHumidity: number | null }} left
419
+ * @param {{ absoluteHumidity: number | null }} right
420
+ */
421
+ function compareAbsoluteHumidity(left, right) {
422
+ if (left.absoluteHumidity === null && right.absoluteHumidity === null) {
423
+ return 0;
424
+ }
425
+
426
+ if (left.absoluteHumidity === null) {
427
+ return 1;
428
+ }
429
+
430
+ if (right.absoluteHumidity === null) {
431
+ return -1;
432
+ }
433
+
434
+ return left.absoluteHumidity - right.absoluteHumidity;
435
+ }
436
+
437
+ /**
438
+ * @param {any} adapter
439
+ * @param {Record<string, any>} device
440
+ */
441
+ async function readAbsoluteHumidityValue(adapter, device) {
442
+ try {
443
+ const state = await adapter.getStateAsync(`${adapter.getDeviceObjectId(device.id)}.${STATE_ABSOLUTE_HUMIDITY}`);
444
+ const value = Number(state?.val);
445
+
446
+ return Number.isFinite(value) ? value : null;
447
+ } catch (error) {
448
+ adapter.log.debug(`Cannot read absolute humidity for device "${device.name}": ${error.message}`);
449
+ return null;
450
+ }
451
+ }
452
+
364
453
  module.exports = {
365
454
  AbsoluteHumidityDeviceManagement,
366
455
  createDeviceInfo,
456
+ getDevicesSortedByAbsoluteHumidity,
367
457
  getDeviceFormSchema,
368
458
  showDeviceForm,
369
459
  };
@@ -15,6 +15,18 @@ function createUniqueDeviceId(name, devices) {
15
15
  return id;
16
16
  }
17
17
 
18
+ /**
19
+ * @param {string} name
20
+ * @param {string} currentId
21
+ * @param {Record<string, any>[]} devices
22
+ */
23
+ function createUpdatedDeviceId(name, currentId, devices) {
24
+ return createUniqueDeviceId(
25
+ name,
26
+ devices.filter(device => device.id !== currentId),
27
+ );
28
+ }
29
+
18
30
  /**
19
31
  * @param {string} baseId
20
32
  * @param {Set<string>} usedIds
@@ -76,6 +88,7 @@ function replaceGermanUmlauts(value) {
76
88
  module.exports = {
77
89
  createUniqueDeviceId,
78
90
  createUniqueIdFromBase,
91
+ createUpdatedDeviceId,
79
92
  legacySanitizeId,
80
93
  replaceGermanUmlauts,
81
94
  sanitizeId,
package/main.js CHANGED
@@ -13,7 +13,13 @@ const {
13
13
  STATE_TEMPERATURE,
14
14
  } = require('./lib/modules/constants');
15
15
  const { AbsoluteHumidityDeviceManagement } = require('./lib/modules/deviceManager');
16
- const { createUniqueDeviceId, createUniqueIdFromBase, legacySanitizeId, sanitizeId } = require('./lib/modules/idUtils');
16
+ const {
17
+ createUniqueDeviceId,
18
+ createUniqueIdFromBase,
19
+ createUpdatedDeviceId,
20
+ legacySanitizeId,
21
+ sanitizeId,
22
+ } = require('./lib/modules/idUtils');
17
23
  const { translate } = require('./lib/modules/i18n');
18
24
 
19
25
  class Absolutehumidity extends utils.Adapter {
@@ -87,10 +93,13 @@ class Absolutehumidity extends utils.Adapter {
87
93
  async updateDevice(id, data) {
88
94
  const oldDevice = this.getDeviceById(id);
89
95
  const devices = this.getConfiguredDevices();
90
- const device = this.normalizeDeviceFormData(data, id);
96
+ const updatedId = createUpdatedDeviceId(data.name, id, devices);
97
+ const device = this.normalizeDeviceFormData(data, updatedId);
91
98
  const updatedDevices = devices.map(existingDevice => (existingDevice.id === id ? device : existingDevice));
92
99
 
93
- if (oldDevice) {
100
+ if (oldDevice && oldDevice.id !== device.id) {
101
+ await this.deleteObjectIfExists(this.getDeviceObjectId(oldDevice.id), { recursive: true });
102
+ } else if (oldDevice) {
94
103
  await this.deleteObsoleteDeviceStates(oldDevice, device);
95
104
  }
96
105
 
@@ -120,6 +129,7 @@ class Absolutehumidity extends utils.Adapter {
120
129
  return {
121
130
  id,
122
131
  name: String(data.name || id).trim(),
132
+ isOutdoor: data.isOutdoor === true,
123
133
  temperatureStateId: String(data.temperatureStateId || '').trim(),
124
134
  relativeHumidityStateId: String(data.relativeHumidityStateId || '').trim(),
125
135
  createTemperatureState: data.createTemperatureState !== false,
@@ -412,6 +422,7 @@ class Absolutehumidity extends utils.Adapter {
412
422
  native: {
413
423
  temperatureStateId: device.temperatureStateId,
414
424
  relativeHumidityStateId: device.relativeHumidityStateId,
425
+ isOutdoor: device.isOutdoor === true,
415
426
  },
416
427
  });
417
428
 
@@ -582,6 +593,22 @@ class Absolutehumidity extends utils.Adapter {
582
593
  for (const device of affectedDevices) {
583
594
  await this.updateDeviceValues(device);
584
595
  }
596
+
597
+ if (affectedDevices.length) {
598
+ await this.refreshDeviceManagerDevices();
599
+ }
600
+ }
601
+
602
+ async refreshDeviceManagerDevices() {
603
+ if (!this.deviceManagement) {
604
+ return;
605
+ }
606
+
607
+ try {
608
+ await this.deviceManagement.refreshDevices();
609
+ } catch (error) {
610
+ this.log.debug(`Cannot refresh Device Manager view: ${error.message}`);
611
+ }
585
612
  }
586
613
 
587
614
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.absolutehumidity",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "build absolute humidity from actual temperature and relative humidity",
5
5
  "author": {
6
6
  "name": "BenAhrdt",