// Servicemeldungen Script zum erfassen von aktuellen Servicemeldungen und halten der historie fuer einen definierten Zeitraum (Historie)
// Servicemeldungen koennen ueber bekannte services gesendet werden
// Trigger kann ausgewaehlt werden (entweder REGA anzahl = Servicemeldungen oder einzelne IDs) // States werden vom script angelegt
// Autor Looxer01 02.11.2024 Version 1.0 (initiale Version)
// Version 1.01 - 02.11.24 Sabotage Alarm fuer HM-Classic Sensoren angepasst. (Error >= 1 und <= 7) // formatierung mit Zeilenumbruch korrigiert
// Version 1.02 - 03.11.24 Replacements als Funktion // Handling von geloeschten Datenpunkten // Ausschlussliste bei subscription der Geraete ID // Kosmetik
// Version 1.03 - 04.11.24 Stringumwandlung gefixt / JSON fuer aktuelle Meldungen und historische Meldungen hinzugefuegt.
// Version 1.04 - 05.11.24 im Datenpunkt id_JSON_Servicemeldung_Aktuell wird ein falscher Text gezeigt // Quick Fix - keine historische Meldung bei Status 0
// Version 1.05 - 10.11.24 Fix fuer Status 0 fuer historische Meldungen. Text aus Tabelle: StandardstatusMessages verwendet // Text angepasst in Tabelle fuer 0
// Batteriemeldung erweitert // Telegram Instanz und User hinzugefügt
// WICHTIGE Aenderung fuer REGA subscription: Intelligenterer Umgang bei vielen Aenderungen von Anzahl der Servicmeldungen aus der CCU
// Version 1.06 - 12.11.24 GruppenSelektoren auskommentiert fuer unreach // korrektur fuer REGA subcription:Timer variable zuruecksetzen // Instanzen zur Selektion sind jetzt als Variabel definiert - z.B. um CuxD auszuschliessen
// HM-Classic Sabotage counts werden umgeleitet von error auf Sabotage
// Version 1.07 - 13.11.24 Zähler für Sabotage funktioniert jetzt für HMClassic und HMIP // Text StandardMessages angepasst //Fuer alle Messenger Services kann die gewuenschte Instanz angegeben werden
// Version 1.08 - 14.11.24 Einstellungsbereich aufgeraeumt- weitere Kosmetik // Fix Low_Bat Meldung
// Version 1.09 - 15.11.24 Ueberfluessiges log fuer Json String entfernt // moegliche ungueltige StatusMeldung mit mehr Infos versehen // Create states WarnMeldung statt ErrorMeldung
// Version 1.10 - 17.11.24 Versuch der Behandlung von Fehlern, wenn die ID nicht existiert - CheckAll Schleife geaendert und ForEach ersetzt // Log fuer DebugLevel1 angepasst
// Version 1.11 - 17.11.24 Instanzen koennen jetzt komplett vergeben werden / 9 = nicht beruecksichtigen - z.B. bei CuxD und Wired
// Version 1.12 - 17.11.24 Wired Alarme hinzugefügt // Overheat und UnderVoltage auch zu non Wired hinzugefuegt
// Version 1.20 - 19.11.24 Optimierung der Selektoren // Kurztext Option fuer Messenger hinzugefügt // Einstellungsbereich restrukturiert // Code Optimierungen
//
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
// Muss-Einstellungen ( HM-Classic , HMIP, Wired - hier müssen zwingend die Instanzen stimmmen )
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
// Im folgenden sind die Instanzen gelistet fuer die die Selektion erfolgt
// bitte 9 Eintragen falls eine Instanz nicht relevant ist // Gruppeninstanzen sind normalerweise nicht relevant // Wired ist momentan noch in Entwicklung
// CuxD Instanzen duerfen nicht eingetragen werden
const HMClassicInstanz = 0; // HM-Classic Instanz eintragen // 9 = falls nicht relevant
const HMIPInstanz = 1; // Homematic IP instanz // 9 = falls nicht relevant
const WiredIClassicInstanz = 9; // Wired Instanz // 9 = falls nicht relevant
const GruppenInstanz = 9; // bzw virtuelle GeräteInstanz- 9 = nicht relevant - Die Gruppen werden i.d.R. nicht gebraucht - Empfehlung: 9
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
// Kann-Einstellungen
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
// Pfad kann angepasst werden fuer userdata pfad einfach // entfernen
const path = "javascript.0.ServicemeldungenVol2.";
//const path = "0_userdata.0.ServicemeldungenVol2."; // alternativ zum javascript pfad
// schreibt einen logeintrag in ein externes file (Excel Format) / nur bei GeraeteIDTrigger = true
const logflag = true;
const LogPath = "/opt/iobroker/log/ServicemeldungenVol2.csv"; // Pfad und Dateiname des externen Logsconstst / nur bei GeraeteIDTrigger = true
//const LogPath = "/iobroker/log/ServicemeldungenVol2.csv";"; // Pfad fuer Windows/ nur bei GeraeteIDTrigger = true // iobroker ist der angenommene iobroker home-pfad
// Text der erscheinen soll, wenn keine SM vorliegen
const MessageBeiKeinerSM = 'Derzeit keine Servicemeldungen' // auf '' setzen wenn kein Text gezeigt werden soll
//Geraete die nicht ueberwacht werden sollen. Geraete-IDs eingeben - Komma getrennt erfassen
const Ausschlussliste = ['003660xxx62C5D', '00091D8xxx7410']; // immer mit Komma trennen
// debug level kann eingestellt werden - wenn alles laeuft dann 0 = ruhe im log
// debug level 0 kein log // debug level 1 - nur die wichtigsten Meldungen werden gelistet // debug level 2 - mehr als nur die wichtigsten Meldungen aber ohne einzelne IDs
// debug level 3 - hier werden auch einzelne IDs gelistet (koennten lange listen werden)
const debugLevel = 0 ;
// wenn GeraeteIDTrigger auf true gestellt wird, dann wird fuer jeden Datenpukt mit Relevanz fuer eine Servicemeldung eine subscription angelegt.
// Vorteil ist, dass auch eine Historie und ein Log fuer Servicemeldungen geschrieben werden kann: Nachteil: bei 80 CCU Geraeten ungefaehr 300 Susbsriptions
// Wenn die variable auf false steht, dann wird auf hm.rega.0.maintenance eine subsription angelegt: Vorteil: 1 Subscription , Nachteil: keine Servicemeldungs Historie
const GeraeteIDTrigger = true; // true = viele subscriptions - false = 1 subscritpion
// fuer alle Spalten mit true werden die Nachrichten ueber den zugeordneten Dienst versendet
// Voraussetzung ist, dass der entsprechende Adapter installiert und konfiguriert ist
const services = ['email', 'whatsApp', 'Signal', 'Telegram', 'Pushover', 'Pushsafer'];
const MessengerScope = {
'UNREACH_ALARM': [false, true, false, false, false, false],
'LOWBAT_ALARM': [false, true, false, false, false, false],
'SABOTAGE_ALARM': [false, true, false, false, false, false],
'CONFIG_PENDING': [false, true, false, false, false, false],
'Sonstige': [false, false, false, false, false, false],
'keineSM': [false, true, false, false, false, false],
}
const MessengerInstanz = [0, 0, 0, 0, 0, 0 ]; // Instanz des Messengers
const TextTypeKurz = [false, true, true, true, true, true ]; // bei true wird der Kurztext gesendet - sonst der Langtext
// email-Einstellungen
const emailAddresse = "Vorname-Nachname@web.de"
const Headline = "ioBroker Servicemeldung"; // Ueberschrift Messages fuer email und Pushsafer
// telegram Einstellungen
const TelegramUser = "";
//-----------------------------------------------------------------------------------------------------
//Experten Einstellungen
//-----------------------------------------------------------------------------------------------------
// Texte werden in "history" hinzugefuegt und etsprechend des schedules wieder geloescht -- nur relvant wenn GeraeteIDTrigger = false
const scheduleTimeClearSMTexte = "2 0 1 * *"; // Sam 1. tag des monats um 00:02 morgens - sollen alle Servicemeldungen der Woche datenpunkt der SM-Texte geloescht werden
// const scheduleTimeClearSMTexte = "58 23 * * 0"; // alernative Sonntags um 23:58 Uhr sollen alle Servicemeldungen der Woche im datenpunkt der SM-Texte geloescht werden
//Batterie-Zuordnungen fuer Servicmeldungen
const batteryTypes = {
'1x CR2016': ['HM-RC-4', 'HM-RC-4-B', 'HM-RC-Key3', 'HM-RC-Key3-B', 'HM-RC-P1', 'HM-RC-Sec3', 'HM-RC-Sec3-B', 'ZEL STG RM HS 4'],
'1x CR2032': ['HM-PB-2-WM', 'HM-PB-4-WM', 'HM-PBI-4-FM', 'HM-SCI-3-FM', 'HM-Sec-TiS', 'HM-SwI-3-FM', 'HmIP-FCI1'],
'2x LR14': ['HM-Sec-Sir-WM', 'HM-OU-CFM-TW', 'HM-OU-CFM-Pl', 'HM-OU-CF-Pl'],
'2x LR44/AG13': ['HM-Sec-SC', 'HM-Sec-SC2L', 'HM-Sec-SC-2', 'HM-Sec-RHS'],
'2x LR6/AA': ['HM-CC-VD', 'HM-CC-RT-DN', 'HM-Sec-WDS', 'HM-Sec-WDS-2', 'HM-CC-TC', 'HM-Dis-TD-T', 'HB-UW-Sen-THPL-I', 'HM-WDS40-TH-I', 'HM-WDS40-TH-I-2',
'HM-WDS10-TH-O', 'HmIP-SMI', 'HMIP-eTRV', 'HM-WDS30-OT2-SM-2', 'HmIP-SMO', 'HmIP-SMO-A', 'HmIP-SPI', 'HmIP-eTRV-2',
'HmIP-SPDR', 'HmIP-STHO-A', 'HmIP-eTRV-B', 'HmIP-PCBS-BAT', 'HmIP-STHO', 'HmIP-eTRV-C',
'HmIP-WGC', 'HmIP-eTRV-C-2', 'HmIP-eTRV-E', 'HmIP-eTRV-2 I9F', 'HmIP-eTRV-E-S', 'ELV-SH-SW1-BAT'],
'3x LR6/AA': ['HmIP-SWO-PL', 'HM-Sec-MDIR', 'HM-Sec-MDIR-2', 'HM-Sec-SD', 'HM-Sec-Key', 'HM-Sec-Key-S', 'HM-Sec-Key-O', 'HM-Sen-Wa-Od', 'HM-Sen-MDIR',
'HM-Sen-MDIR-O', 'HM-Sen-MDIR-O-2', 'HM-WDS100-C6-O', 'HM-WDS100-C6-O-2', 'HmIP-ASIR', 'HmIP-SWO-B', 'HM-Sen-MDIR-O-3', 'HM-Sec-MDIR-3',
'HmIP-SWO-PR', 'HmIP-DLD', 'HmIP-ASIR-2'],
'4x LR6/AA': ['HM-CCU-1', 'HM-ES-TX-WM', 'HM-WDC7000'],
'1x LR3/AAA': ['HM-RC-4-2', 'HM-RC-4-3', 'HM-RC-Key4-2', 'HM-RC-Key4-3', 'HM-RC-Sec4-2', 'HM-RC-Sec4-3', 'HM-Sec-RHS-2', 'HM-Sec-SCo', 'HmIP-KRC4',
'HmIP-KRCA', 'HmIP-SRH', 'HMIP-SWDO', 'HmIP-DBB', 'HmIP-RCB1', 'HmIP-KRCK', 'HmIP-SWDO-2'],
'2x LR3/AAA': ['HmIP-WRCR', 'HmIP-SWD','HM-TC-IT-WM-W-EU', 'HM-Dis-WM55', 'HM-Dis-EP-WM55', 'HM-PB-2-WM55', 'HM-PB-2-WM55-2', 'HM-PB-6-WM55', 'HM-PBI-2-FM', 'HM-RC-8', 'HM-Sen-DB-PCB',
'HM-Sen-EP', 'HM-Sen-MDIR-SM', 'HM-Sen-MDIR-WM55', 'HM-WDS30-T-O', 'HM-WDS30-OT2-SM', 'HmIP-STH', 'HmIP-STHD', 'HmIP-WRC2', 'HmIP-WRC6', 'HmIP-WTH', 'HmIP-WTH-2',
'HmIP-SAM', 'HmIP-SLO', 'HMIP-SWDO-I', 'HmIP-FCI6', 'HmIP-SMI55', 'HM-PB-2-FM', 'HmIP-SWDM', 'HmIP-SCI', 'HmIP-SWDM-B2', 'HmIP-RC8', 'ALPHA-IP-RBG', 'HmIP-DSD-PCB',
'HmIP-WRCD', 'HmIP-WRC2-A', 'HmIP-WTH-B-2', 'HmIP-WTH-A', 'HmIP-STV', 'HmIP-WKP'],
'3x LR3/AAA': ['HM-PB-4Dis-WM', 'HM-PB-4Dis-WM-2', 'HM-RC-Dis-H-x-EU', 'HM-Sen-LI-O'],
'3x AAA Akkus - bitte laden': ['HM-RC-19', 'HM-RC-19-B', 'HM-RC-12', 'HM-RC-12-B', 'HM-RC-12-W'],
'3x LR14/C': ['HmIP-MP3P'],
'9Volt Block leer oder unbestimmt': ['HM-LC-Sw1-Ba-PCB', 'HM-LC-Sw4-PCB', 'HM-MOD-EM-8', 'HM-MOD-Re-8', 'HM-Sen-RD-O', 'HM-OU-CM-PCB', 'HM-LC-Sw4-WM'],
'Festbatterie leer': ['HmIP-STE2-PCB', 'HM-Sec-SD-2', 'HmIP-SWSD', 'HmIP-PCBS'],
'ohne Batterie': ['HM-LC-Sw1PBU-FM', 'HM-LC-Sw1-Pl-DN-R1', 'HM-LC-Sw1-DR', 'HM-LC-RGBW-WM', 'HM-LC-Sw1-Pl-CT-R1', 'HmIP-HEATING', 'HM-LC-Sw1-FM', 'HM-LC-Sw2-FM', 'HM-LC-Sw4-DR',
'HM-LC-Sw1-Pl', 'HM-LC-Sw1-Pl-2', 'HM-LC-Sw4-Ba-PCB', 'HM-LC-Sw1-SM', 'HM-LC-Sw4-SM', 'HM-Sys-sRP-Pl', 'HM-LC-Sw2PBU-FM', 'HM-LC-Sw1-PCB', 'HM-LC-Sw4-DR-2'],
'Akku entladen - bitte aufladen': ['HM-Sec-Win', 'HM-Sec-SFA-SM', 'HM-RC-19-SW']
};
// Rega Pfad und TextPfade
const PathRega = 'hm-rega.0.maintenance';
const id_Text_ServicemeldungLang = path+'TextLangAktuelleSM'; // Objekt wo die Servicemeldung hingeschrieben werden soll (String) = path+'TextLang'; // Objekt wo die Servicemeldung hingeschrieben werden soll (String) Lange (normale) Version
const id_Text_ServicemeldungKurz = path+'TextKurzAktuelleSM'; // Objekt wo die Servicemeldung hingeschrieben werden soll (String) - kurze Version
const id_Text_Servicemeldung_History = path+'TestLangVergangeneSM'; // Objekt wo die Servicemeldung hinzugefuegt werden soll (String) - Lange Version (es gibt nur lang)
const id_JSON_Servicemeldung_Aktuell = path+'JSONAktuelleSM'; // JSON Tabelle Datenpunkt Aktuelle SM
const id_JSON_Servicemeldung_Historie = path+'JSONVergangeneSM'; // JSON Tabelle Datenpunkt Historische SM
// Count-Pfade (Zaehlungen)
const id_IST_LOWBAT = path+'Anzahl_LOWBAT' // HM classic; & HMIP =
const id_IST_UNREACH = path+'Anzahl_UNREACH'
const id_IST_STICKY_UNREACH = path+'Anzahl_STICKY_UNREACH' //*Anzahl Sticky Unreach (zu bestaetigende unreach)
const id_IST_CONFIG_PENDING = path+'Anzahl_CONFIG_PENDING';
const id_IST_UPDATE_PENDING = path+'Anzahl_Update_PENDING';
const id_IST_DEVICE_IN_BOOTLOADER = path+'Anzahl_DEVICE_IN_BOOTLOADER';
const id_IST_ERROR = path+'Anzahl_in_ERROR';
const id_IST_ERROR_NON_FLAT_POSITIONING = path+'Anzahl_NON_FLAT_POSITIONING';
const id_IST_FAULT_REPORTING = path+'Anzahl_FAULT_REPORTING';
const id_IST_SABOTAGE = path+'Anzahl_SABOTAGE';
const id_IST_ERROR_REDUCED = path+'Anzahl_ERROR_REDUCED';
const id_IST_STICKY_SABOTAGE = path+'Anzahl_Sticky_SABOTAGE';
const id_IST_USBH_POWERFAIL = path+'Anzahl_USBH_POWERFAIL';
const id_IST_U_SOURCE_FAIL = path+'Anzahl_U_SOURCE_FAIL ';
const id_IST_Gesamt = path+'Anzahl_GESAMT'
const id_IST_SMAktuell = path+'Anzahl_SM-Aktuell'
// Standard Servicemeldungen, wenn alle anderen nicht zutreffen
const StandardstatusMessages = ['keine Stoerung', 'Stoerung', 'bestaetigte Servicemeldung'];
// hier sind alle bekannten Servicemeldungen zugeordnet (ueber Status-Datenpunkte des Geraetes)
const statusMessages = {
UNREACH_ALARM: ['keine Kommunikationsfehler', 'Kommunikation gestoert', 'Kommunikation war gestoert'],
STICKY_UNREACH_ALARM: ['keine Kommunikationsfehler', 'Kommunikation gestoert', 'Kommunikation war gestoert'],
SABOTAGE_ALARM: ['Keine Sabotage', 'Sabotage', 'Sabotage aufgehoben'],
LOWBAT_ALARM: ['Batterie ok', 'Batterie niedrig', 'Batterie ok'],
LOW_BAT_ALARM: ['Batterie ok', 'Batterie niedrig', 'Batterie ok'],
ERROR_NON_FLAT_POSITIONING_ALARM: ['Keine Meldung', 'Geraet wurde angehoben.', 'Geraet wurde angehoben: Bestaetigt'],
CONFIG_PENDING_ALARM: ['keine Meldung', 'Konfigurationsdaten stehen zur Uebertragung an', 'Konfigurationsdaten standen zur Uebertragung an'],
UPDATE_PENDING_ALARM: ['kein Update verfuegbar', 'Update verfuegbar', 'Update wurde eingespielt'],
DEVICE_IN_BOOTLOADER_ALARM: ['Keine Meldung', 'Geraet startet neu', 'Geraet wurde neu gestartet'],
};
const errorMessages = {
'HM-Sec-RHS': { 7: 'Sabotage' },
'HM-Sec-RHS-2': { 7: 'Sabotage' },
'HM-Sec-SC': { 7: 'Sabotage' },
'HM-Sec-SC-2': { 7: 'Sabotage' },
'HM-Sec-SCo': { 7: 'Sabotage' },
'HM-Sec-MD': { 7: 'Sabotage' },
'HM-Sec-MDIR': { 7: 'Sabotage' },
'HM-Sec-MDIR-2':{ 7: 'Sabotage' },
'HM-Sec-Key': { 1: 'Einkuppeln fehlgeschlagen', 2: 'Motorlauf abgebrochen' },
'HM-Sec-Key-S': { 1: 'Einkuppeln fehlgeschlagen', 2: 'Motorlauf abgebrochen' },
'HM-Sec-Key-O': { 1: 'Einkuppeln fehlgeschlagen', 2: 'Motorlauf abgebrochen' },
'HM-CC-VD': { 1: 'Ventil Antrieb blockiert', 2: 'Ventil nicht montiert', 3: 'Stellbereich zu klein', 4: 'Batteriezustand niedrig'
}
};
const faultMessages = {
'HM-CC-RT-DN': {
0: 'keine Stoerung',
1: 'Ventil blockiert',
2: 'Einstellbereich Ventil zu gross',
3: 'Einstellbereich Ventil zu klein',
4: 'Kommunikationsfehler',
6: 'Spannung Batterien/Akkus gering',
7: 'Fehlstellung Ventil'
}
};
// Umlaut Umwandlung und entfernung PUnkte - kann aber auch erweitert werden
const replacements = { // Umwandlung fuer Namen der Geraete (common.name)
'.': ' ',
'ä': 'ae',
'ü': 'ue',
'ö': 'oe',
'ß': 'ss'
};
// moegliche Homematic Instanzen (CuxD ausgeschlossen)
const instanceIds = [
{ name: 'HMClassicInstanz', id: HMClassicInstanz },
{ name: 'HMIPInstanz', id: HMIPInstanz },
{ name: 'GruppenInstanz', id: GruppenInstanz },
{ name: 'WiredIClassicInstanz', id: WiredIClassicInstanz },
];
// hier koennen die Alarmgruppen ggf erweitert werden - Aus Alarmgruppe und Instanz wird der Selector gebastelt und in Tabelle Selectors gesammelt
const alarmTypes = [
{ key: 'UNREACH_ALARM', suffixes: ['UNREACH_ALARM'] },
{ key: 'STICKY_UNREACH_ALARM', suffixes: ['STICKY_UNREACH_ALARM'] },
{ key: 'CONFIG_PENDING_ALARM', suffixes: ['CONFIG_PENDING_ALARM'] },
{ key: 'UPDATE_PENDING_ALARM', suffixes: ['UPDATE_PENDING_ALARM'] },
{ key: 'LOWBAT_ALARM', suffixes: ['LOWBAT_ALARM', 'LOW_BAT_ALARM'] },
{ key: 'DEVICE_IN_BOOTLOADER_ALARM', suffixes: ['DEVICE_IN_BOOTLOADER_ALARM'] },
{ key: 'ERROR', suffixes: ['ERROR'] },
{ key: 'FAULT_REPORTING', suffixes: ['FAULT_REPORTING'] },
{ key: 'SABOTAGE_ALARM', suffixes: ['SABOTAGE_ALARM'] },
{ key: 'ERROR_NON_FLAT_POSITIONING_ALARM', suffixes: ['ERROR_NON_FLAT_POSITIONING_ALARM'] },
{ key: 'OVERHEAT_ALARM', suffixes: ['ERROR_OVERHEAT_ALARM'] },
{ key: 'UNDERVOLTAGE_ALARM', suffixes: ['ERROR_UNDERVOLTAGE_ALARM'] }
];
//-----------------------------------------------------------------------------------------------------
//Ende Einstellungen
//-----------------------------------------------------------------------------------------------------
// IDs für alle Instanzen und Alarmtypen sammeln
const selectors = alarmTypes.map(alarmType => {
const collectedIds = [];
instanceIds.forEach(instance => {
if (instance.id !== 9) {
alarmType.suffixes.forEach(suffix => {
// @ts-ignore
$(`state[id=hm-rpc.${instance.id}.*.${suffix}]`).each(id => collectedIds.push(id)); // zusammenbasteln des selectors
});
}
});
return { name: alarmType.key, ids: collectedIds };
});
selectors.forEach(selector => {
log(`fuer die Alarmgruppe: ${selector.name} wurden ${selector.ids.length} IDs gefunden${debugLevel >= 3 ? ` ${selector.ids}` : ''}`);
});
let AktuelleSMjsonString = [] // alle aktuellen Servicemeldungen als JSON
// Aufbau MessageCollector - Beispiel
//{ "Error": { "Email": [ "Error Alarm " ], "SMS": ["Error" ] },
// "Unreach": { "Email": ["Alarm: Eindringling im Gebäude!"], "SMS": [ "Eindringling" ] } }
let MessageSendCollector = {}; // alle aktuellen Servicemeldungen zum senden an messaging services
// Initialisierung des Objekts für alle Alarmtypen und Services
alarmTypes.forEach((type) => {
const alarmKey = type.key; // Verwende die `key`-Eigenschaft als Schlüssel
MessageSendCollector[alarmKey] = {}; // Erstelle ein Objekt für den Alarmtyp
services.forEach((service) => {
MessageSendCollector[alarmKey][service] = []; // Erstelle ein leeres Array für jeden Service
});
});
// Variablen für den Timer, um die 5-Sekunden-Wartezeit zu steuern - relevant fuer HM-REGA subscription
let changeTimeout = null;
let countIdsInnerhalbTimeout = 0;
// create States
CreateStates(() => {
Check_All()
});
// Subscriptions erstellen
if (GeraeteIDTrigger) {
SubscribeGeraeteID();
}else{
SubscribeRegaDP();
}
//-----------------------------------------------------------------------------------------------------
// Schedule zum Loeschen des Datenpunktwertes der Histore
//-----------------------------------------------------------------------------------------------------
schedule(scheduleTimeClearSMTexte, function() {
setState(id_Text_Servicemeldung_History, '');
setState(id_JSON_Servicemeldung_Historie, []);
log(`Datenpunkt ${id_Text_Servicemeldung_History} geloescht`);
});
//-----------------------------------------------------------------------------------------------------
// Funktion SubscribeRegaDP
// Erstellung der Subscriptions auf REGA Datenpunkt // es werden 5 Sekunden lang vorliegende Aenderungen gesammelt
//-----------------------------------------------------------------------------------------------------
function SubscribeRegaDP() {
if (debugLevel >= 2) { log(`Routine SubscribeRegaDP wird ausgefuehrt - Pfad des Datenpunkts: ${PathRega}`, "info");}
on({id: PathRega, change: 'any'}, function (obj) {
if (obj.state.val === obj.oldState.val) { // Überprüfen, ob sich der Wert des Datenpunkts geändert hat
return; // Keine Änderung, also nichts tun
}
countIdsInnerhalbTimeout++;
if (debugLevel >= 2) { log(`Datenpunkt ${PathRega} hat sich geaendert. Neuer Wert: ${obj.state.val}`, "info");}
// Falls schon ein Timer läuft, diesen abbrechen
if (changeTimeout) {
clearTimeout(changeTimeout);
}
// Setze einen neuen Timer auf 5 Sekunden, um die Funktion Servicemeldung aufzurufen
changeTimeout = setTimeout(function() {
Servicemeldung(); // Funktion wird nach 5 Sekunden ohne weitere Änderungen aufgerufen
}, 5000); // 5000 ms = 5 Sekunden
});
} // ende funktion
//-----------------------------------------------------------------------------------------------------
// Funktion Subscribe GeraeteID
// Erstellung der Subscriptions auf GeraeteID und Datenpunkt Ebene
//-----------------------------------------------------------------------------------------------------
function SubscribeGeraeteID() {
if(debugLevel >= 2) { log(`Routine SubscribeGeraeteID wird ausgefuehrt`, "info");}
let callCount = 0; // fuer Timer Funktion
let timeoutActive = false; // fuer Timer Funktion
selectors.forEach(selector => {
if (selector.ids.length > 0) {
if(debugLevel >= 2) {log(`SubscribeGeraeteID: Prozessiere selector: ${selector.name}`);};
const filteredIds = selector.ids.filter(id => { // IDs filtern: nur IDs behalten, deren Geraete-ID nicht in der Ausschlussliste ist
const parts = id.split('.'); // Extrahiere die Geraete-ID aus der vollstaendigen ID (dritte Stelle)
const deviceId = parts[2]; // Hier ist die Geraete-ID das dritte Element
if (Ausschlussliste.includes(deviceId)) { // ueberpruefen, ob die Geraete-ID in der Ausschlussliste ist
if(debugLevel >= 2) { log(`ID ${deviceId} aus den subscriptions entfernt (wegen Ausschlussliste) : ${id}`);};
return false; // Diese ID wird gefiltert
}
return true; // Diese ID bleibt
});
filteredIds.forEach(id => {
on({ id: id, change: "any" }, obj => {
if (obj.state.val === obj.oldState.val) {
return;
}
if (timeoutActive) {
return; // Wenn der Timeout aktiv ist, keine weitere Verarbeitung
}
callCount++;
// Wenn mehr als 10 Aufrufe innerhalb von 1 Sekunde
if (callCount >= 50) {
timeoutActive = true; // Wartezeit aktivieren
log("SubscribeGeraeteID: Servicemeldungen: Zu viele Servicemeldungen wurden generiert, warte 5 Minuten.","warn");
setTimeout(() => {
timeoutActive = false; // Timeout beenden
callCount = 0; // Zaehler zuruecksetzen
log("Servicemeldungen: Wartezeit beendet, weitere Servicemeldungen sind jetzt moeglich.");
}, 5 * 60 * 1000); // 5 Minuten in Millisekunden
}
Servicemeldung(obj); // "Servicemeldung" aufrufen
setTimeout(() => {
// Reset des Zaehlers nach 1 Sekunde
callCount = Math.max(0, callCount - 1);
}, 1000);
});
}); // EndIDLoop
} else {
if(debugLevel >= 1 ) {log(`SubscribeGeraeteID: No matching states found for ${selector.name}`);};
}
}); //endSelectorLoop
} // EndFunction
//-----------------------------------------------------------------------------------------------------
// Kernfunktion Sevicemeldung
// erstmal die aktuelle Servicemeldung analysieren und loggen
//-----------------------------------------------------------------------------------------------------
function Servicemeldung(obj) {
if (debugLevel >= 2) log(`Routine Servicemeldung wird ausgefuehrt`, "info");
if (!GeraeteIDTrigger) { // nur wenn ueber REGA Servicemeldungen von der CCU reagiert werden soll
if (debugLevel >= 1) {log(`Routine Servicemeldung wird ausgefuehrt - Es wurden insgesamt ${countIdsInnerhalbTimeout} Änderungen festgestellt.`, "info");}
countIdsInnerhalbTimeout = 0; // Reset der Zählung
changeTimeout = null; // Reset des Timeouts fuer den REGA Trigger
const AnzahlSM = Check_All();
const regaState = getState(PathRega).val;
if (debugLevel >= 1) { log("REGA Anzahl SM " + regaState + " anzahlSM " + AnzahlSM);};
if (regaState === 0 || AnzahlSM === 0) {
setState(id_Text_ServicemeldungLang, MessageBeiKeinerSM);
setState(id_Text_ServicemeldungKurz, MessageBeiKeinerSM);
addMessageToCollector('keineSM', MessageBeiKeinerSM, MessageBeiKeinerSM);
sendMessage('keineSM');
return;
}
sendMessage();
return;
}
// jetzt die subscriptions die ueber Aenderungen von Datenpunkten laufen also bei GeraeteIDTrigger = true - Servicemeldungen in die Historie schreiben
const AnzahlSM = Check_All();
const id_name = obj.id.split('.')[2];
if (!existsState(obj.id)) {
log("Routine Servicemeldungen - Geraet " + id_name +" scheint zwischenzeitlich nicht mehr zu existieren - Empfehlung: script neu starten","warn")
return;
}
if (AnzahlSM === 0) { // keine Servicmeldungen
delete MessageSendCollector['keineSM'];
addMessageToCollector('keineSM', MessageBeiKeinerSM, MessageBeiKeinerSM);
sendMessage('keineSM');
}
if (Ausschlussliste.includes(id_name)) {
if(debugLevel >= 2) { log(`Routine Servicemeldung ID ${id_name} hat eine Aenderung gemeldet wird aber uebersprungen wegen Ausschlussliste`, "info");}
return;
}
let commonObj = getObject(obj.id.substring(0, obj.id.lastIndexOf('.') - 2));
let common_name = ReplaceString(commonObj.common.name);
const meldungsart = obj.id.split('.')[4];
const status = obj.newState.val;
const native_type = getObject(obj.id.substring(0, obj.id.lastIndexOf('.') - 2)).native.TYPE;
let status_textLang = DefineServiceMessage(meldungsart, native_type, status,obj.id,"lang");
let status_textKurz = DefineServiceMessage(meldungsart, native_type, status,obj.id,"kurz");
if(debugLevel >= 1 ) { log(`ServicemeldungenVol2: neue Servicemeldung ist ${status_textLang} Meldungsart ist ${meldungsart} `);}
const datum_seit = func_get_datum(obj.id);
// Status "0" wurde gesetzt. Bei HM-Classic war das der Status um zu melden, dass die Servicemeldung zurueckgesetzt wurde
if(status === 0 ) {
status_textLang = DefineServiceMessage(meldungsart, native_type, status, obj.id, "lang")
status_textKurz = DefineServiceMessage(meldungsart, native_type, status, obj.id, "kurz")
if(debugLevel >= 2 ) { log(`Routine Servicemeldung - status ist 0 - status_text ist ${status_textLang} Meldungsart ist ${meldungsart} `);}
}
// externes log erzeugen
writelog(common_name, id_name, meldungsart, status, status_textLang);
// Historische Servicemeldung als Text speichern
appendToState(id_Text_Servicemeldung_History, status_textLang);
//historische Servicemeldung als Json speichern (additiv)
let HistorischeSMjsonString = []
const stateValue = getState(id_JSON_Servicemeldung_Historie).val;
if (stateValue) {
try {
HistorischeSMjsonString = JSON.parse(stateValue);
} catch (error) {
log(`Fehler beim Parsen des JSON: ${error}`);
HistorischeSMjsonString = []; // Fallback auf leeres Array
}
}
HistorischeSMjsonString.push(createJsonEntry(datum_seit, meldungsart, common_name, id_name, status,status_textLang));
const jsonString = JSON.stringify(HistorischeSMjsonString);
setState(id_JSON_Servicemeldung_Historie, jsonString);
// Messenger Dienste aktivieren
delete MessageSendCollector[meldungsart];
addMessageToCollector(meldungsart, status_textKurz, status_textLang);
sendMessage(meldungsart);
}
//-----------------------------------------------------------------------------------------------------
// Kompeletter Durchgang
// jetzt alle Servicemeldungen durchzaehlen
//-----------------------------------------------------------------------------------------------------
function Check_All() {
if(debugLevel >= 2) { log(`Routine Check_All wird ausgefuehrt`, "info");}
let count_all = 0;
let count_Akut = 0;
let count_Akut_UNREACH_ALARM = 0;
let count_Akut_Sticky_UNREACH_ALARM = 0;
let count_Akut_CONFIG_PENDING_ALARM = 0;
let count_Akut_UPDATE_PENDING_ALARM = 0;
let count_Akut_LOWBAT_ALARM = 0;
let count_Akut_DEVICE_IN_BOOTLOADER_ALARM = 0;
let count_Akut_ERROR = 0;
let count_Akut_FAULT_REPORTING = 0;
let count_Akut_SABOTAGE_ALARM = 0;
let count_Akut_Sticky_SABOTAGE_ALARM = 0;
let count_Akut_ERROR_NON_FLAT_POSITIONING_ALARM = 0;
let count_Akut_ERROR_REDUCED = 0;
let count_Akut_USBH_POWERFAIL = 0;
let count_Akut_U_SOURCE_FAIL = 0;
let count_Akut_STICKY_SABOTAGE = 0;
let id;
let parts;
let common_name;
let id_name;
let native_type;
let GeraeteID;
let meldungsart;
let ServiceMeldungTextKurz;
let ServiceMeldungTextLang;
let status;
let datum_seit;
let commonObj;
let ServicemeldungMessagesLang = [];
let ServicemeldungMessagesKurz = [];
let objectcheck;
AktuelleSMjsonString = [];
for (let j = 0; j < selectors.length; j++) { // Umstellung auf klassische for-Schleife und Durchgang durch alle Selectors
const selector = selectors[j];
if (selector.ids.length > 0) {
for (let i = 0; i < selector.ids.length; i++) {
id = selector.ids[i];
parts = id.split('.'); // Extrahiere die Geraete-ID aus der vollstaendigen ID (dritte Stelle)
GeraeteID = parts[2]; // Hier ist die Geraete-ID das dritte Element
if (!existsState(id)) {
log("Routine Check_All - Geraet "+GeraeteID +" scheint zwischenzeitlich nicht mehr zu existieren - Empfehlung: script neu starten","warn");
continue; // überspringe dieses Element und fahre mit der nächsten fort
}
// Überprüfen, ob die Geraete-ID in der Ausschlussliste ist
if (Ausschlussliste.includes(GeraeteID)) {
if(debugLevel >= 1) {
log(`Routine Check_All ID ${GeraeteID} wird uebersprungen wegen Ausschlussliste`, "info");
}
continue; // überspringe die ID, wenn sie in der Ausschlussliste ist
}
objectcheck = getObject(id.substring(0, id.lastIndexOf('.') - 2));
// evt Fehlermeldung mit falscher ID behandeln
if (objectcheck && objectcheck.native && objectcheck.native.TYPE) {
native_type = objectcheck.native.TYPE;
} else {
log(`Fehler: Das Objekt mit ID ${id} oder die native.TYPE-Eigenschaft ist nicht vorhanden.`, "warn");
continue; // Zur naesten ID im Loop
}
commonObj = getObject(id.substring(0, id.lastIndexOf('.') - 2));
common_name = ReplaceString(commonObj.common.name);
id_name = id.split('.')[2];
meldungsart = id.split('.')[4];
status = getState(id).val;
datum_seit = func_get_datum(id);
// Switch-Case zur Überprüfung der verschiedenen Alarmtypen
switch (selector.name) {
case 'UNREACH_ALARM':
if(status === 1) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextLang);
addMessageToCollector('UNREACH_ALARM', ServiceMeldungTextKurz, ServiceMeldungTextLang);
count_Akut_UNREACH_ALARM++;
count_Akut++;
}
break;
case 'Sticky_UNREACH_ALARM':
if(status === 1) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextKurz);
addMessageToCollector('Sticky_UNREACH_ALARM', ServiceMeldungTextKurz, ServiceMeldungTextLang);
count_Akut_Sticky_UNREACH_ALARM++;
count_Akut++;
}
break;
case 'UPDATE_PENDING_ALARM':
if(status === 1) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextKurz);
addMessageToCollector('UPDATE_PENDING_ALARM', ServiceMeldungTextKurz, ServiceMeldungTextLang);
count_Akut_UPDATE_PENDING_ALARM++;
count_Akut++;
}
break;
case 'LOWBAT_ALARM':
if(status === 1) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextKurz);
addMessageToCollector('LOWBAT_ALARM', ServiceMeldungTextKurz, ServiceMeldungTextLang);
count_Akut_LOWBAT_ALARM++;
count_Akut++;
}
break;
case 'DEVICE_IN_BOOTLOADER_ALARM':
if(status === 1) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextKurz);
addMessageToCollector('DEVICE_IN_BOOTLOADER_ALARM', ServiceMeldungTextKurz, ServiceMeldungTextLang);
count_Akut_DEVICE_IN_BOOTLOADER_ALARM++;
count_Akut++;
}
break;
case 'ERROR':
if (status >= 1 && status <= 7) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextKurz);
addMessageToCollector('ERROR', ServiceMeldungTextKurz, ServiceMeldungTextLang);
if (status === 7) {
count_Akut_SABOTAGE_ALARM++; // Nur für HM-Classic-messagetype = error status = 7 entspricht sabotage
} else {
count_Akut_ERROR++;
}
count_Akut++;
}
break;
case 'FAULT_REPORTING':
if(status === 1) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextKurz);
addMessageToCollector('FAULT_REPORTING', ServiceMeldungTextKurz, ServiceMeldungTextLang);
count_Akut_FAULT_REPORTING++;
count_Akut++;
}
break;
case 'SABOTAGE_ALARM':
if(status === 1) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextKurz);
addMessageToCollector('SABOTAGE_ALARM', ServiceMeldungTextKurz, ServiceMeldungTextLang);
count_Akut_SABOTAGE_ALARM++;
count_Akut++;
}
break;
case 'ERROR_NON_FLAT_POSITIONING_ALARM':
if(status === 1) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextKurz);
addMessageToCollector('ERROR_NON_FLAT_POSITIONING_ALARM', ServiceMeldungTextKurz, ServiceMeldungTextLang);
count_Akut_ERROR_NON_FLAT_POSITIONING_ALARM++;
count_Akut++;
}
break;
case 'CONFIG_PENDING':
if(status === 1) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextKurz);
addMessageToCollector('CONFIG_PENDING', ServiceMeldungTextKurz, ServiceMeldungTextLang);
count_Akut_CONFIG_PENDING_ALARM++;
count_Akut++;
}
break;
case 'STICKY_SABOTAGE':
if(status === 2) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextKurz);
addMessageToCollector('STICKY_SABOTAGE', ServiceMeldungTextKurz, ServiceMeldungTextLang);
count_Akut_STICKY_SABOTAGE++;
count_Akut++;
}
break;
default:
if(status === 1) {
ServiceMeldungTextLang = DefineServiceMessage(selector.name, native_type, status, id, "lang");
ServicemeldungMessagesLang.push(ServiceMeldungTextLang);
ServiceMeldungTextKurz = DefineServiceMessage(selector.name, native_type, status, id, "kurz");
ServicemeldungMessagesKurz.push(ServiceMeldungTextKurz);
addMessageToCollector('ERROR', ServiceMeldungTextKurz, ServiceMeldungTextLang);
count_Akut_ERROR++;
count_Akut++;
}
break;
}
count_all++; // Zählt die Gesamtanzahl der überprüften IDs
}
} else {
if (debugLevel >= 1 ) {log(`No matching states found for ${selector.name}`);}
}
} // Ende der äußeren Schleife
const jsonString = JSON.stringify(AktuelleSMjsonString);
setState(id_JSON_Servicemeldung_Aktuell, jsonString);
// Formatiere die Nachrichten
let formattedMessagesLang = ServicemeldungMessagesLang.join('
');
let formattedMessagesKurz = ServicemeldungMessagesKurz.join('
');
// Speichere die formatierten Nachrichten
if(count_Akut === 0){
setState(id_Text_ServicemeldungLang, MessageBeiKeinerSM);
setState(id_Text_ServicemeldungKurz, MessageBeiKeinerSM);
} else {
setState(id_Text_ServicemeldungLang, formattedMessagesLang);
setState(id_Text_ServicemeldungKurz, formattedMessagesKurz);
}
// Einzelne Zähler speichern
setState(id_IST_UNREACH, count_Akut_UNREACH_ALARM);
setState(id_IST_STICKY_UNREACH, count_Akut_Sticky_UNREACH_ALARM);
setState(id_IST_LOWBAT, count_Akut_LOWBAT_ALARM);
setState(id_IST_CONFIG_PENDING, count_Akut_CONFIG_PENDING_ALARM);
setState(id_IST_UPDATE_PENDING, count_Akut_UPDATE_PENDING_ALARM);
setState(id_IST_DEVICE_IN_BOOTLOADER, count_Akut_DEVICE_IN_BOOTLOADER_ALARM);
setState(id_IST_ERROR, count_Akut_ERROR);
setState(id_IST_ERROR_NON_FLAT_POSITIONING, count_Akut_ERROR_NON_FLAT_POSITIONING_ALARM);
setState(id_IST_FAULT_REPORTING, count_Akut_FAULT_REPORTING);
setState(id_IST_SABOTAGE, count_Akut_SABOTAGE_ALARM);
setState(id_IST_ERROR_REDUCED, count_Akut_ERROR_REDUCED);
setState(id_IST_STICKY_SABOTAGE, count_Akut_Sticky_SABOTAGE_ALARM);
setState(id_IST_USBH_POWERFAIL, count_Akut_USBH_POWERFAIL);
setState(id_IST_U_SOURCE_FAIL, count_Akut_U_SOURCE_FAIL);
// Gesamtzähler speichern
setState(id_IST_Gesamt, count_all);
setState(id_IST_SMAktuell, count_Akut);
if(debugLevel >= 2) {
log(`Es wurden insgesamt ${count_all} IDs gecheckt - insgesamt gibt es ${count_Akut} Servicemeldungen`, "info");
log("Davon gibt es zur Zeit aktuelle Servicemeldungen: " + count_Akut);
log("SM count_Akut_UNREACH_ALARM " + count_Akut_UNREACH_ALARM);
log("SM count_Akut_CONFIG_PENDING_ALARM " + count_Akut_CONFIG_PENDING_ALARM);
log("SM count_Akut_UPDATE_PENDING_ALARM " + count_Akut_UPDATE_PENDING_ALARM);
log("SM count_Akut_LOWBAT_ALARM " + count_Akut_LOWBAT_ALARM);
log("SM count_Akut_DEVICE_IN_BOOTLOADER_ALARM " + count_Akut_DEVICE_IN_BOOTLOADER_ALARM);
log("SM count_Akut_ERROR " + count_Akut_ERROR);
log("SM count_Akut_FAULT_REPORTING " + count_Akut_FAULT_REPORTING);
log("SM count_Akut_SABOTAGE_ALARM " + count_Akut_SABOTAGE_ALARM);
log("SM count_Akut_ERROR_NON_FLAT_POSITIONING_ALARM " + count_Akut_ERROR_NON_FLAT_POSITIONING_ALARM);
log("SM count_Akut_ERROR_REDUCED " + count_Akut_ERROR_REDUCED);
log("SM count_Akut_STICKY_SABOTAGE " + count_Akut_STICKY_SABOTAGE);
log("SM count_Akut_U_SOURCE_FAIL " + count_Akut_U_SOURCE_FAIL);
log("SM count_Akut_USBH_POWERFAIL " + count_Akut_USBH_POWERFAIL);
}
if(debugLevel >= 3) {
console.log(`Gesammelte Servicemeldungen Lang: ${ServicemeldungMessagesLang}`);
console.log(`Gesammelte Servicemeldungen Kurz: ${ServicemeldungMessagesKurz}`);
}
return count_Akut;
}
//-----------------------------------------------------------------------------------------------------
// Message ERmittlung
//-----------------------------------------------------------------------------------------------------
function DefineServiceMessage(meldungsart, native_type, status, id, version) {
if (debugLevel >= 2) { log(`Routine DefineServiceMessage wird ausgefuehrt meldungsart ${meldungsart}`, "info"); }
let ServiceMessage; // Rueckgabewert
let parts = id.split('.'); // Extrahiere die Geraete-ID aus der vollstaendigen ID (dritte Stelle)
let commonObj = getObject(id.substring(0, id.lastIndexOf('.') - 2));
let common_name = ReplaceString(commonObj.common.name);
let id_name = parts[2];
let datum_seit = func_get_datum(id);
// Im Folgenden werden lange und kurze Versionen von Servicemeldungen erzeugt
switch (meldungsart) {
case "CONFIG_PENDING":
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - ${statusMessages.CONFIG_PENDING_ALARM[status]}`
: `${common_name} ${statusMessages.CONFIG_PENDING_ALARM[status]}`;
if (version === "lang") {
AktuelleSMjsonString.push( createJsonEntry ( datum_seit, meldungsart, common_name, id_name, status, statusMessages.CONFIG_PENDING_ALARM[status], null) );
}
break;
case "LOW_BAT_ALARM":
case "LOWBAT_ALARM":
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - ${statusMessages.LOWBAT_ALARM[status]} - Batteriebezeichnung: ${func_Batterie(native_type)}`
: `${common_name} ${statusMessages.LOWBAT_ALARM[status]}`;
if (version === "lang") {
AktuelleSMjsonString.push( createJsonEntry ( datum_seit, meldungsart, common_name, id_name,status,statusMessages.LOWBAT_ALARM[status],func_Batterie(native_type) ));
}
break;
case "STICKY_UNREACH_ALARM":
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - ${statusMessages.STICKY_UNREACH_ALARM[status]}`
: `${common_name} ${statusMessages.STICKY_UNREACH_ALARM[status]}`;
if (version === "lang") {
AktuelleSMjsonString.push(createJsonEntry(datum_seit, meldungsart, common_name, id_name,status,statusMessages.STICKY_UNREACH_ALARM[status],null ));
}
break;
case "UNREACH_ALARM":
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - ${statusMessages.UNREACH_ALARM[status]}`
: `${common_name} ${statusMessages.UNREACH_ALARM[status]}`;
if (version === "lang") {
AktuelleSMjsonString.push(createJsonEntry(datum_seit, meldungsart, common_name, id_name,status,statusMessages.UNREACH_ALARM[status],null ));
}
break;
case "DEVICE_IN_BOOTLOADER_ALARM":
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - ${statusMessages.DEVICE_IN_BOOTLOADER_ALARM[status]}`
: `${common_name} ${statusMessages.DEVICE_IN_BOOTLOADER_ALARM[status]}`;
if (version === "lang") {
AktuelleSMjsonString.push(createJsonEntry(datum_seit, meldungsart, common_name, id_name,status,statusMessages.DEVICE_IN_BOOTLOADER_ALARM[status],null ));
}
break;
case "UPDATE_PENDING_ALARM":
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - ${statusMessages.UPDATE_PENDING_ALARM[status]}`
: `${common_name} ${statusMessages.UPDATE_PENDING_ALARM[status]}`;
if (version === "lang") {
AktuelleSMjsonString.push(createJsonEntry(datum_seit, meldungsart, common_name, id_name,status,statusMessages.UPDATE_PENDING_ALARM[status],null ));
}
break;
case "SABOTAGE_ALARM":
case "SABOTAGE":
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - ${statusMessages.SABOTAGE_ALARM[status]}`
: `${common_name} ${statusMessages.SABOTAGE_ALARM[status]}`;
if (version === "lang") {
AktuelleSMjsonString.push(createJsonEntry(datum_seit, meldungsart, common_name, id_name,status,statusMessages.SABOTAGE_ALARM[status],null ));
}
break;
case "ERROR_NON_FLAT_POSITIONING_ALARM":
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - ${statusMessages.ERROR_NON_FLAT_POSITIONING_ALARM[status]}`
: `${common_name} ${statusMessages.ERROR_NON_FLAT_POSITIONING_ALARM[status]}`;
if (version === "lang") {
AktuelleSMjsonString.push(createJsonEntry(datum_seit, meldungsart, common_name, id_name,status,statusMessages.ERROR_NON_FLAT_POSITIONING_ALARM[status],null ));
}
break;
case "ERROR":
if (status >= 1 && status <= 7) { // nur wenn kein status = 0
if (errorMessages[native_type] && errorMessages[native_type][status]) {
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - ${errorMessages[native_type][status]}`
: `${common_name} ${errorMessages[native_type][status]}`;
if (version === "lang") {
AktuelleSMjsonString.push(createJsonEntry(datum_seit, meldungsart, common_name, id_name,status,errorMessages[native_type][status],null ));
}
} // endif errorMessages
} // endif Status >=1...
if (status === 0) { // nicht HIMIP Geräte die auf Error und status 0 stehen - Message aufgehoben fuer Historie
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - $StandardstatusMessages[status]}`
: `${common_name} ${errorMessages[native_type][status]}`;
if (version === "lang") {
AktuelleSMjsonString.push(createJsonEntry(datum_seit, meldungsart, common_name, id_name,status,StandardstatusMessages[status],null ));
}
}
break;
case "FAULT_REPORTING":
if (faultMessages[native_type] && faultMessages[native_type][status]) {
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - ${faultMessages[native_type][status]}`
: `${common_name} ${faultMessages[native_type][status]}`;
if (version === "lang") {
AktuelleSMjsonString.push(createJsonEntry(datum_seit, meldungsart, common_name, id_name,status,faultMessages[native_type][status],null ));
}
}
break;
default:
if (status < 0 || status >= StandardstatusMessages.length) {
ServiceMessage = `datum_seit, meldungsart, common_name, id_name,- Ungueltiger Status`; // fuer ungueltige Statuswerte
} else {
ServiceMessage = version === "lang"
? `${datum_seit} - ${meldungsart} - ${common_name} - (${id_name}) - ${status} - ${StandardstatusMessages[status]}`
: `${common_name} ${StandardstatusMessages[status]}`;
if (version === "lang") {
AktuelleSMjsonString.push(createJsonEntry(datum_seit, meldungsart, common_name, id_name,status,StandardstatusMessages[status],null ));
}
}
}
return ServiceMessage; // Nur einmal am Ende zurueckgeben
}
//-----------------------------------------------------------------------------------------------------
// sendMessage Hier werden die Nachrichten fuer den jeweiligen Service aufbereitet
//-----------------------------------------------------------------------------------------------------
function sendMessage(messageType = null) {
if (debugLevel >= 2) {
console.log(`Routine sendMessage wird ausgeführt für messageType: ${messageType || 'alle'} (alle Nachrichten)`);
}
const messageTypesToProcess = messageType ? [messageType] : Object.keys(MessageSendCollector);
// Kombiniere Nachrichten für jeden Dienst über alle Typen hinweg
const combinedMessagesByService = {};
messageTypesToProcess.forEach((type) => {
const messagesByService = MessageSendCollector[type] || {};
Object.keys(messagesByService).forEach((service) => {
if (!combinedMessagesByService[service]) {
combinedMessagesByService[service] = [];
}
combinedMessagesByService[service] = combinedMessagesByService[service].concat(messagesByService[service]);
});
// Lösche den Typ nach der Verarbeitung
delete MessageSendCollector[type];
});
// Sende kombinierte Nachrichten an die jeweiligen Dienste
Object.keys(combinedMessagesByService).forEach((service) => {
const combinedMessage = combinedMessagesByService[service].join('\n');
if (combinedMessage.trim().length > 0) {
sendToService(service, combinedMessage);
}
});
}
//-----------------------------------------------------------------------------------------------------
// sendToService - hier wird der Versand vorgenommen
// Reihenfolge: Email, WhatsApp, Signal, Telegram, Pushover, Pushsafer
// MessengerInstanz = [0, 0, 0, 0, 0, 0] Instanzen der Messenger-Dienste in
//-----------------------------------------------------------------------------------------------------
function sendToService(service, combinedMessage) {
if(debugLevel >=1){log(`Message wird versendet mit: ${service}: ${combinedMessage}`);}
switch (service) {
case "email":
sendTo(`email.${MessengerInstanz[0]}`, "send", {
text: combinedMessage,
to: emailAddresse,
subject: Headline
});
break;
case "whatsApp":
sendTo(`whatsapp-cmb.${MessengerInstanz[1]}`, "send", {
text: combinedMessage
});
break;
case "Signal":
sendTo(`signal-cmb.${MessengerInstanz[2]}`, "send", {
text: combinedMessage
});
break;
case "Telegram":
sendTo(`telegram.${MessengerInstanz[3]}`, "send", {
text: combinedMessage,
user: TelegramUser // Telegram User ID, um den Nachrichteneempfänger festzulegen
});
break;
case "Pushover":
sendTo(`pushover.${MessengerInstanz[4]}`, "send", {
message: combinedMessage,
sound: ""
});
break;
case "Pushsafer":
sendTo(`pushsafer.${MessengerInstanz[5]}`, "send", {
message: combinedMessage,
title: Headline
});
break;
default:
log(`Unbekannter Service: ${service}`, "warn");
}
}
//-----------------------------------------------------------------------------------------------------
// addMessageToCollector Messages werden unter berücksichtigung der folgenden Objekte in den MessageCollector genommen
// MessengerScope, Services, AlarmTypes, TextTypeKurz
//-----------------------------------------------------------------------------------------------------
function addMessageToCollector(messageType, MessageKurz, MessageLang) {
// Überprüfung, ob der `messageType` in `alarmTypes` existiert
const isValidMessageType = alarmTypes.some((type) => type.key === messageType);
// Wenn der messageType ungültig ist, "Sonstige" als Fallback verwenden
let actualMessageType = isValidMessageType ? messageType : "Sonstige";
if (!isValidMessageType && debugLevel >= 1 && messageType != "keineSM") {
console.warn(`Unbekannter messageType "${messageType}". Fallback auf "Sonstige".`);
}
// Sonderbehandlung für "keineSM" - Diese wird behandelt wie jeder andere messageType
if (messageType === "keineSM") {
actualMessageType = "keineSM"; // Setze den messageType explizit auf "keineSM"
}
// Sicherstellen, dass der Typ im MessageSendCollector existiert
if (!MessageSendCollector[actualMessageType]) {
MessageSendCollector[actualMessageType] = {};
}
// Überprüfen, ob der actualMessageType im MessengerScope vorhanden ist, falls nicht, 'Sonstige' verwenden
let messengerConfig = MessengerScope[actualMessageType];
// Wenn der messageType nicht im MessengerScope definiert ist, benutze die Konfiguration für 'Sonstige'
if (!messengerConfig) {
messengerConfig = MessengerScope['Sonstige'] || Array(services.length).fill(false);
}
// Nachricht nur hinzufügen, wenn die Konfiguration für den Service aktiv ist
messengerConfig.forEach((isActive, index) => {
if (isActive) {
const service = services[index];
// Nachricht nur hinzufügen, wenn die Konfiguration für den Service aktiv ist
if (!MessageSendCollector[actualMessageType][service]) {
MessageSendCollector[actualMessageType][service] = [];
}
// Auswahl von MessageKurz oder MessageLang basierend auf TextTypeKurz
const messageToAdd = TextTypeKurz[index] ? MessageKurz : MessageLang;
// Nachricht nur hinzufügen, wenn sie noch nicht existiert
if (!MessageSendCollector[actualMessageType][service].includes(messageToAdd)) {
MessageSendCollector[actualMessageType][service].push(messageToAdd);
}
}
});
}
//-----------------------------------------------------------------------------------------------------
// ReplaceString // ersetzen entsprechend tabelle replacements
//-----------------------------------------------------------------------------------------------------
function ReplaceString(string) {
for (const [key, value] of Object.entries(replacements)) {
// Escape den Punkt (.) für den regulären Ausdruck
const escapedKey = key.replace('.', '\\.');
string = string.replace(new RegExp(escapedKey, 'g'), value);
}
return string;
}
//-----------------------------------------------------------------------------------------------------
// func_get_datum aktuelles Datum formatiert
//-----------------------------------------------------------------------------------------------------
function func_get_datum(id) {
// const datum = formatDate(getState(id).lc, "TT.MM.JJ SS:mm:ss");
const datum = formatDate(getState(id).ts, "TT.MM.JJ SS:mm:ss");
return datum < '01.01.71 01:00:00' ? '' : `${datum} Uhr`;
}
//-----------------------------------------------------------------------------------------------------
// func_Batterie Batterieermittlung
//-----------------------------------------------------------------------------------------------------
function func_Batterie(native_type) {
if(debugLevel >= 2) { log(`Routine func_Batterie wird ausgefuehrt`, "info");}
const normalizedType = native_type.toUpperCase();
return Object.keys(batteryTypes).find(battery =>
batteryTypes[battery].some(device => device.toUpperCase() === normalizedType)
) || 'unbekannt';
}
//-----------------------------------------------------------------------------------------------------
// Funktion createJsonEntry erzeugen einer JSON Tabelle
//-----------------------------------------------------------------------------------------------------
function createJsonEntry(datum_seit, meldungsart, common_name, id_name, status, statusMessages, Batterie) {
// Erstelle das JSON-Objekt
return {
datum_seit: datum_seit,
meldungsart: meldungsart,
common_name: common_name,
id_name: id_name,
status: status,
status_message: statusMessages,
batterie_bezeichnung: Batterie
};
}
//-----------------------------------------------------------------------------------------------------
// Funktion schreibt einen Logeintrag in das Filesystem und auch in das interne Log-System (looxer)
//-----------------------------------------------------------------------------------------------------
function writelog(Name, id_name, SMType, SMStatus, SMStatus_Text) {
if(debugLevel >= 2) { log(`Routine writelog wird ausgefuehrt`, "info");}
const fs = require('fs'); // enable write fuer externes log
if (!logflag) return;
const logdate = formatDate(new Date(), "TT.MM.JJJJ");
const logtime = formatDate(new Date(), "SS:mm:ss");
const logEntry = `${logdate} ;${logtime} ;${Name} ;${id_name} ; ${SMType} ;${SMStatus} ;${SMStatus_Text}\n`;
const headerLine = "Datum;Uhrzeit;Name;ID-Name;Meldungssart;Status;Servicemeldung\n";
fs.readFile(LogPath, 'utf8', function(err, data) {
if (!err) {
fs.appendFileSync(LogPath, logEntry, 'utf8');
} else {
log("Logfile nicht gefunden - wird angelegt", "info");
fs.writeFileSync(LogPath, headerLine + logEntry, 'utf8');
}
});
}
//-----------------------------------------------------------------------------------------------------
// Funktion zum Hinzufuegen einer neuen Zeile am Anfang des bestehenden State (looxer)
//-----------------------------------------------------------------------------------------------------
function appendToState(id, newText) {
if(debugLevel >= 2) { log(`Routine appendToState wird ausgefuehrt`, "info");}
const updatedText = newText + '
' + getState(id).val;
setState(id, updatedText);
}
//-----------------------------------------------------------------------------------------------------
// Funktion Create States
//-----------------------------------------------------------------------------------------------------
async function CreateStates(callback) {
if (debugLevel >= 2) { log(`Routine CreateStates wird ausgefuehrt`, "info"); }
try {
await createStateAsync(id_Text_ServicemeldungLang, "", { read: true, write: true, type: 'string', name: 'Servicemeldungen LangText', desc: 'LangText Servicemeldung' });
await createStateAsync(id_Text_ServicemeldungKurz, "", { read: true, write: true, type: 'string', name: 'Servicemeldungen KurzText', desc: 'KurzText Servicemeldung' });
await createStateAsync(id_JSON_Servicemeldung_Aktuell, "", { read: true, write: true, type: 'string', name: 'Aktuelle Servicemeldungen als JSON', desc: 'Vergangene Servicemeldung JSON' });
await createStateAsync(id_JSON_Servicemeldung_Historie, "", { read: true, write: true, type: 'string', name: 'Servicemeldungen History', desc: 'History Servicemeldung' });
await createStateAsync(id_Text_Servicemeldung_History, "", { read: true, write: true, type: 'string', name: 'Servicemeldungen History', desc: 'History Servicemeldung' });
await createStateAsync(id_IST_Gesamt, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen Anzahl Total', desc: 'Anzahl Servicemeldungen' });
await createStateAsync(id_IST_SMAktuell, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen Anzahl Aktuelle SM', desc: 'Anzahl Aktuelle Servicemeldungen' });
await createStateAsync(id_IST_LOWBAT, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen Lowbat Anzahl Total', desc: 'Lowbat Anzahl Servicemeldungen' });
await createStateAsync(id_IST_UNREACH, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen Unreach Anzahl Total', desc: 'Unreach Anzahl Servicemeldungen' });
await createStateAsync(id_IST_STICKY_UNREACH, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen Sticky Unreach Anzahl Total', desc: 'Sticky Unreach Anzahl Servicemeldungen' });
await createStateAsync(id_IST_ERROR, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen ERROR Anzahl Total', desc: 'ERROR Anzahl Servicemeldungen' });
await createStateAsync(id_IST_CONFIG_PENDING, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen ausstehende Konfig Anzahl Total', desc: 'Ausstehende Konfig Anzahl Servicemeldungen' });
await createStateAsync(id_IST_UPDATE_PENDING, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen ausstehende Updates Anzahl Total', desc: 'Ausstehende Updates Anzahl Servicemeldungen' });
await createStateAsync(id_IST_DEVICE_IN_BOOTLOADER, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen DEVICE_IN_BOOTLOADER Anzahl Total', desc: 'DEVICE_IN_BOOTLOADER Anzahl Servicemeldungen' });
await createStateAsync(id_IST_ERROR_NON_FLAT_POSITIONING, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen ERROR_NON_FLAT_POSITIONING Anzahl Total', desc: 'ERROR_NON_FLAT_POSITIONING Anzahl Servicemeldungen' });
await createStateAsync(id_IST_FAULT_REPORTING, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen FAULT_REPORTING Anzahl Total', desc: 'FAULT_REPORTING Anzahl Servicemeldungen' });
await createStateAsync(id_IST_SABOTAGE, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen SABOTAGE Anzahl Total', desc: 'SABOTAGE Anzahl Servicemeldungen' });
await createStateAsync(id_IST_ERROR_REDUCED, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen ERROR_REDUCED Anzahl Total', desc: 'ERROR_REDUCED Anzahl Servicemeldungen' });
await createStateAsync(id_IST_STICKY_SABOTAGE, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen STICKY_SABOTAGE Anzahl Total', desc: 'STICKY_SABOTAGE Anzahl Servicemeldungen' });
await createStateAsync(id_IST_USBH_POWERFAIL , 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen USBH_POWERFAIL Anzahl Total', desc: 'USBH_POWERFAIL Anzahl Servicemeldungen' });
await createStateAsync(id_IST_U_SOURCE_FAIL, 0, { read: true, write: true, type: 'number', name: 'Servicemeldungen SOURCE_FAIL Anzahl Total', desc: 'SOURCE_FAIL Servicemeldungen' });
// Aufruf des Callbacks nach Abschluss aller Operationen
if (callback) await callback();
} catch (error) {
log(`Routine Create States - Fehler beim Erstellen der Zustaende: ${error}`, "warn");
}
}