NEWS
Tasmota Steckdosen per MQTT + JavaScript direkt ansteuern
-
Changelog:
- 31.10.2021 erste öffentliche Version 1.6
- 02.03.2023 Version 1.18
- 29.09.2024 Version 1.24
Noch in Entwicklung / geplant:
- Firmware + Gerätetyp (Steckdose oder Licht/Dimmer/RGB) automatisch erkennen
Umgang mit Tasmota-Geräten mit mehreren Schaltausgängen (bisher von Hand im Skript angepasst)- Integration der RGB-Version dieses Skriptes in die normale Version
Vorwort:
Auf Grund einer Nachfrage poste ich mal mal meinen persönlichen Lösungsweg für die Einbindung von über 60 Tasmota-Geräten bei mir zu Hause in ioBroker.Ich nutze dazu Mosquitto als MQTT-Broker (mit Installiert auf dem ioBroker), den MQTT Adapter als Client zu diesem und je ein eigenes JavaScript pro Tasmota-Gerät zur Auswertung. Der Grund ist das ich damals schon meine Geräte mit einem MQTT-Server verbunden hatte und darauf auch diverse andere Scripte und Dienste zugriffen (bevor ich mit ioBroker angefangen habe). Diese sollten so weiter funktionieren können. Aber per MQTT haben die Steckdosen dann z.B. kein True/False-Datenpunkt den man z.B. für einen Schalter in der VIS verwenden könnte. Der Sonoff-Adapter ist zwar auch ein MQTT-Broker für die Tasmota-Geräte, man kann sich aber nicht als Client mit diesem Verbinden. Also brauchte ich ein Skript.
Schritt 1: Mosquitto installieren:
Da gibt es genug Anleitungen im Internet. Für Ubuntu (und sollte auch auf dem Raspberry Pi funktionieren) habe ich diese genutzt: How to install and secure Mosquitto on Ubuntu 20.04.Dabei solltet Ihr Abweichend von der Anleitung folgendes ändern:
In der/etc/mosquitto/conf.d/default.conf
Solltet Ihr den Eintrag listener von 9001 auf 9002 ändern und Mosquitto neu starten:
... port 1883 listener 9002 protocol websockets ...
Grund ist das zumindest bei mir die JavaScript-Instanz von ioBroker schon Port 9001 belegt.
Die Einstellungen oben starten auf Port 1883 den MQTT-Broker und auf Port 9002 kann Alternativ per Websocket mit den MQTT-Broker kommuniziert werden. Der Port 1883 sollte entweder in ioBroker nicht von einem anderen Adapter belegt sein (etwa dem Sonoff-Adapter oder einer bestehenden MQTT-Server Instanz) oder ihr wählt einen anderen Port in der Mosquitto-Konfiguration.Schritt 2: Zugriff auf Mosquitto testen:
Ich nehme dazu gerne den MQTT-Explorer: http://mqtt-explorer.com/
Da sollte unten $SYS zu sehen sein mit Informationen zum Mosquitto-Server:
Schritt 3: Einstellungen unter Tasmota:
In der Weboberfläche des Tasmota-Gerätes stelle ich nun den MQTT-Server ein:
Der Host ist mein ioBroker-Server, der Port ist in Mosquitto konfiguriert.
Nach dem Speichern sollte Ihr im MQTT-Explorer das Gerät schon sehen können, und zwar unter den Topics (=Unterordnern) tele, stat und cmnd:Schritt 4: MQTT-Adapter in ioBroker:
Installiert in ioBroker den MQTT Broker/Client und installiert diesen:
bzw.Der Adapter ist bei mir wie folgt eingestellt:
Unter den Datenpunkten des Adapters sollte Ihr nun im Prinzip das gleiche sehe wie im MQTT-Explorer. Sonst einfach mal das Tasmota-Gerät neu starten, der MQTT-Adapter kann nur Meldungen sehen die nach seiner Verbindungsherstellung gekommen sind.
Schritt 5: JavaScript pro Tasmota-Gerät
Das Skript stelle einen POWER Datenpunkt zur Verfügung der in der VIS genutzt werden kann um das Gerät ein- oder auszuschalten. Zusätzlich werden ein paar Informationen zu Version und WLAN gesammelt:// Setup var s_DeviceName = "Gosund166"; // Suffix wird an den Devicenamen für die Zieldatenpunkte angehängt, z.B. "-Waschmaschine" (KEINE Punkte!!!) var s_Suffix = "-2fach"; // -------------------------------------------------------------------------------------- // Bei Tasmota-Firmware ab Verion 9.5 auf true setzen, bis Version 9.3.1 auf false setzen var b_Firmware95 = true; // Erfassung von Leistungs und Verbrauchsdaten var b_Energy = false; // Anzahl der schaltbaren Ausgänge, 1 bis 4, 1 = nur POWER, ab 2 und mehr POWER1, POWER2 usw. var i_NumberOfPower = 1; // EasyMeter Q3A gemäß https://tasmota.github.io/docs/Smart-Meter-Interface/#easymeter-q1d-ascii-obis var b_EasyMeterQ3A = false; // Erfassung von Temperaturwerten (Shelly 1PM) var b_Temperature = false; // Erfassung HC-SR04 Ultraschall-Sensor var b_hcsr04 = false; // Sollen die Datenpunkte nachträglich korrigiert werden? var b_CorrectDatapoints = false; // Einschaltdauer erfassen (muss noch getestet werden, nicht benutzen!) var b_HourMeter = false; // Name der MQTT-Instanz var s_mqtt_Instance = "mqtt.0"; // Festlegen der Skriptversion (für Auswertungen) var s_VersionJSScript = "1.24" // Logging aktivieren für das Debuggen in die JavaScript-Console und in das ioBroker Log (true oder false): var b_UseLogging = false; // // Changelog: // ---------- // 13.03.2021 1.0 erste Version mit Versionsnummer + optische Aufbereitung des Quellcodes // 14.03.2021 1.1 Umbau auf fromNe: / Einbau Logging / Einführung Changelog // 25.03.2021 1.2 Ermittlung der Einschaltdauer erster Versuch // 08.05.2021 1.3 Anpassung an JS controller 3.3.8 (ackn bei Datenpunkten die read-only sind) // 30.08.2021 1.4 Angepasst an Tasmota 9.5.0 (hart) // 31.10.2021 1.5 Auswahl der Firmware-Version per Variable // 31.10.2021 1.6 Pfad auf 0_userdata.0 geändert, Name des AccessPoints herauskommentiert. // 31.10.2021 1.7 Heraussuchen des AccessPoint-Names konfigurierbar gemacht // 04.11.2021 1.8 Erstellen der Datenpunkte mit await-Funktion. So muss das Skript nicht mehr 2x gestartet werden. // 20.11.2021 1.9 Bei allen Werten aus JSON-Objekten vor den Schreiben in States explizite Umwandlung in String oder Number // 12.12.2021 1.10 Stromverbrauch mit wird nun auch erfasst sofern entsprechende Daten geliefert werden /tele/xxx/SENSOR // 12.12.2021 1.11 Und kleinere Fehler beseitigt (in Debugging-Meldungen / Typen Konvertierung) // 12.12.2021 1.12 Zusätzliche Datenpunkte für Einschaltdauer hinzugefügt, die aktuelle Dauer wird hochgezählt und in 2 Datenpunkten festgehalten. // Die Berechnung erfolgt jedesmal wenn eine /tele/xxxx/STATE Meldung eingeht. // 09.02.2022 1.13 Shelly Temperatur + Einheiten korrigiert // 26.06.2022 1.14 Temperatur Optional gemacht per Schalter // Optionales Suffix für die Zieldatenpunkte // 28.06.2022 1.15 Einschaltdauer - Default Wert für Einschaltzeit ist nun die aktuelle Zeit (Falls Gerät noch nie ausgeschaltet war) // 19.07.2022 1.16 FriendlyName wird nun mit ausgewertet (Bezeichnung unter der Echo & Co. das Gerät finden) // 25.07.2022 1.17 Script-Version mit als Datenpunkt aufgenommen + Einheiten von Datenpunkten hinzugefügt (auch nachträglich) // 25.07.2022 1.18 Name des Scriptes als Datenpunkt aufgenommen // 04.04.2023 1.19 EasyMeterQ3A auslesen eingebaut // 25.03.2024 1.20 HC-SR04 Ultraschall Sensor // 16.04.2024 1.21 Fehler bei Zeiterfassung (wenn nicht aktiv) behoben, Zeiterfassung default deaktiviert // 12.06.2024 1.22 Eventlog lokal in das Skript aufgenommen statt über globale Funktion // 28.09.2024 1.23 Umbau auf Möglichkeit mit mehreren Schaltern POWER <=> POWER1 bis POWER4 // 29.09.2024 1.24 Bestätigt/Unbestätigt bei POWER-Datenpunkten + Fehlerbehebung // // 2020 - 2024 von Bernhard Linz / Bernhard@znil.net // #################################################################################################################################################### // Beschreibung: // ------------- // Grundaufgabe ist es einen Datenpunkt bereitzustellen über welchen der POWER Status des Tasmota Gerätes als Boolean true false // ausgelesen aber auch gesetzt werden kann - so wie es viele Widgets in VIS benötigen // Dazu wird der MQTT Datenpunkt /stat/{Gerätename}/POWER ausgewertet und per /cmnd/{Gerätename}/POWER ggf. gesetzt // Zusätzlich werden weitere Informationen gesammelt, z.B. mit welchen AccessPoint das Gerät verbunden ist // // Setup: // ------ // oben in Zeile 2 den Namen des Tasmota-Gerätes setzen so wie dieser unter mqtt.0.stat auftaucht. // Name wird durch die Tasmota Optionen // Topic {NamedesGerätes} // MqttClient {NamedesGerätes} // gesetzt und sollte für diese Script bei beiden Identisch sein // // Das Suffix in Zeile 2 wird an die 0_userdata.0 Datenpunkte angehängt // Ist die Firmware des Tasmota-Gerätes 9.5 oder höher so muss "b_Firmware95 = true" gesetzt werden (Die Pfade im MQTT haben sich geändert) // Soll der Energieverbauch erfasst werden so muss "b_Energy = true;" gesetzt werden, die Meldungen von tele/xxx/SENSOR werden dann ausgewertet // #################################################################################################################################################### // Private Einstellungen die nur für meine Umgebung funktionieren oder von euch zuerst die Voraussetzungen geschafft werden müssen // Soll der Name des AccessPoints ermittelt werden? // @ts-ignore var b_GetNameOfAccessPoints = false; // Pfad für das auslesen des AccessPoints. Dort gibt es für jeden AccessPoint einen Datenpunkt vom Typ String welcher die MAC als ID und den Namen als Wert hat var s_AccessPoints_path = "0_userdata.0.001-Konstanten.WLAN."; // Zentrales Log über alle Ein- und Ausschaltvorgänge führen var b_UseSystemEventLog = false; // #################################################################################################################################################### // http://www.network-science.de/ascii/ Font: big // __ __ _ _ _ // \ \ / / (_) | | | | // \ \ / /_ _ _ __ _ __ _| |__ | | ___ _ __ // \ \/ / _` | '__| |/ _` | '_ \| |/ _ \ '_ \ // \ / (_| | | | | (_| | |_) | | __/ | | | // \/ \__,_|_| |_|\__,_|_.__/|_|\___|_| |_| // #################################################################################################################################################### // #################################################################################################################################################### // unsere JavaScript-Instanz um zu prüfen ob die Änderung durch MQTT oder durch VIS ausgelöst wurde // @ts-ignore const o_js_Instance = 'system.adapter.javascript.' + instance; // und der erste Log-Eintrag DebugWarning("Startup: Setze Variablen ..."); // Datenpunktstammpfad //var s_state_rootpath = "javascript.0.tasmota."; var s_state_rootpath = "0_userdata.0.tasmota."; var s_state_FullPath = s_state_rootpath + s_DeviceName + s_Suffix; // True/False Datenpunkt für VIS & Co var s_state_power_path = s_state_FullPath + ".POWER"; // Datenpunkt an den Tasmota den aktuellen POWER Zustand meldet if (i_NumberOfPower == 1) { var s_mqtt_POWER_path = s_mqtt_Instance + ".stat." + s_DeviceName + ".POWER"; } else { var s_mqtt_POWER_path = s_mqtt_Instance + ".stat." + s_DeviceName + ".POWER*"; } // Datenpunkt an den die letzte Aktion von Tasmota gesendet wird var s_mqtt_RESULT_path = s_mqtt_Instance + ".stat." + s_DeviceName + ".RESULT"; // Datenpunkt den man setzen muss um den Status zu ändern (ON oder OFF oder Toggle) var s_mqtt_CMND_path = s_mqtt_Instance + ".cmnd." + s_DeviceName + ".POWER"; // Datenpunkt in welchen die regelmäßigen MQTT Statusmeldungen STATE landen var s_mqtt_STATE_path = s_mqtt_Instance + ".tele." + s_DeviceName + ".STATE"; // Datenpunkt in welchen die regelmäßigen MQTT Statusmeldungen INFO1 landen (enthält unter anderem die Tasmota-Version) var s_mqtt_INFO1_path = s_mqtt_Instance + ".tele." + s_DeviceName + ".INFO1"; // Datenpunkt in welchen die regelmäßigen MQTT Statusmeldungen INFO2 landen (enthält die IP-Adresse) var s_mqtt_INFO2_path = s_mqtt_Instance + ".tele." + s_DeviceName + ".INFO2"; // Datenpunkt in welchen die regelmäßigen MQTT Statusmeldungen SENSOR landen (enthält Daten zum Energieverbrauch wenn unterstützt) var s_mqtt_SENSOR_path = s_mqtt_Instance + ".tele." + s_DeviceName + ".SENSOR"; // Datenpunkt in welchen die regelmäßigen MQTT Statusmeldungen stat/.../STATUS landen (enthält den FriendlyName) var s_mqtt_STATUS_path = s_mqtt_Instance + ".stat." + s_DeviceName + ".STATUS"; // Temporäre Variable für verschiedene Auswertungen var s_tempjson; // Variablen für die Zeitauswertung var i_global_unixtimeSwitchedOn = 0; var i_global_unixtimeSwitchedOff = 0; var i_global_LastSwichtedOnDuration = 0; var i_global_OperationHoursCounter = 0; var i_global_CurrentPowerOnTimeSeconds = 0; var i_global_CurrentPowerOnTimeH = ""; // Gibt eine Fehlermeldung wenn diese Variable nicht extra definiert wurde var myAccessPoint; //Fehlerzähler var i_ErrorCounter = 0; // #################################################################################################################################################### // #################################################################################################################################################### // ______ _ _ _ // | ____| | | | | (_) // | |__ _ _ _ __ | | _| |_ _ ___ _ __ ___ _ __ // | __| | | | '_ \| |/ / __| |/ _ \| '_ \ / _ \ '_ \ // | | | |_| | | | | <| |_| | (_) | | | | __/ | | | // |_| \__,_|_| |_|_|\_\\__|_|\___/|_| |_|\___|_| |_| // #################################################################################################################################################### // #################################################################################################################################################### // DebugWarning gibt in der Console eine Warnmeldung aus wenn b_UseLogging auf true steht /* accepts parameters * s_debugmessage = Print this text to console via warn */ function DebugWarning(s_debugmessage) { if (b_UseLogging == true) { console.warn(s_debugmessage); } } // #################################################################################################################################################### // Wandelt Sekunden in Tage/Stunden/Minuten/Sekunden um: function ConvertTimeHumanReadable(i_seconds) { var i_days = Math.floor(i_seconds / (24 * 60 * 60)); i_seconds -= i_days * (24 * 60 * 60); var i_hours = Math.floor(i_seconds / (60 * 60)); i_seconds -= i_hours * (60 * 60); var i_minutes = Math.floor(i_seconds / (60)); i_seconds -= i_minutes * (60); return ((0 < i_days) ? (i_days + "d ") : "") + ((0 < i_hours) ? (i_hours + "h ") : "") + ((0 < i_minutes) ? (i_minutes + "m ") : "") + ((0 < i_seconds) ? (i_seconds + "s") : ""); } // #################################################################################################################################################### // Berechnet die Einschaltdauer etc., als Funktion da mehrmals benötigt function CalculateSwitchedOnDuration() { // Diese Funktion wird immer dann aufgerufen wenn ein Ausschalten registriert wurde var i_Duration = i_global_unixtimeSwitchedOff - i_global_unixtimeSwitchedOn; var s_Duration = ConvertTimeHumanReadable(i_Duration); // Letzte Einschaltdauer setzen setState(s_state_FullPath + ".tmp.LastSwichtedOnDuration", i_Duration, true); setState(s_state_FullPath + ".Time-LastSwichtedOnDuration", s_Duration, true); // Betriebsstundenzähler erhöhen var i_TotalDuration = getState(s_state_FullPath + ".tmp.OperationHoursCounter").val; i_TotalDuration = i_TotalDuration + i_Duration; var s_TotalDuration = ConvertTimeHumanReadable(i_TotalDuration); setState(s_state_FullPath + ".tmp.OperationHoursCounter", i_TotalDuration, true); setState(s_state_FullPath + ".Time-OperationHoursCounter", s_TotalDuration, true); } // #################################################################################################################################################### // Modifiziert einen Datenpunkt und fügt eine Einheit dazu function SetUnit(setunit_id, setunit_unit) { if (b_CorrectDatapoints == true) { try { var setunit_obj = getObject(setunit_id); // setunit_obj.common.name = 'neuer Name'; setunit_obj.common.unit = setunit_unit; // @ts-ignore setObject(setunit_id, setunit_obj); } catch (e) { // nichts machen i_ErrorCounter++; } } } // #################################################################################################################################################### // Eventlog, abgeschaut bei https://www.smarthome-tricks.de/software-iobroker/eigenes-logging-in-iobroker/ function createEventlog(EventType, EventText) { let tasmotaEventListDestination = "0_userdata.0.EventLog.Tasmota."; // vorhandene Einträge einlesen let EventList = getState(tasmotaEventListDestination + "EventLogTasmota").val; // Anzahl der Maximal erlaubten Einträge einlesen let maxEventCount = getState("0_userdata.0.EventLog.Tasmota.maxEventCount").val; // Nur die letzten x Einträge im Script belassen let eventList = EventList.split('<br>'); let eventCount = eventList.length; let newEventList = ""; for (var i = 0; i < eventCount; i++) { if ( i < (maxEventCount-1) ) { newEventList = newEventList + "<br>" + eventList[i]; } else { break; } } EventList = newEventList; // Neue Event-Id und Zeitpunkt ermitteln let EventId = getState(tasmotaEventListDestination + "NextEventId").val; let EventDateTime = formatDate(getDateObject((new Date().getTime())), "TT.MM.JJ hh:mm:ss"); EventId = EventId + 1; setState(tasmotaEventListDestination + "NextEventId", EventId); let FormatedEventId = ("0000000" + EventId).slice(-7); let EventLog = FormatedEventId + " - " + EventDateTime + " - " + EventType + " - " + EventText; EventList = EventLog + EventList; setState(tasmotaEventListDestination + "EventLogTasmota", EventList); } // #################################################################################################################################################### // Benötigte Datenpunkte erstellen async function CreateMyStatesAndStartup() { try { DebugWarning("Startup: Erstelle ggf. Datenpunkte ..."); // ####################################################################################################### // POWER if (b_hcsr04 == false) { if (i_NumberOfPower == 1) { DebugWarning("Erstelle: " + s_state_FullPath + ".POWER"); await createStateAsync(s_state_FullPath + ".POWER", false, { type: 'boolean', read: true, write: true, role: "switch", name: s_DeviceName + s_Suffix + '.POWER' }); } else { for (let i = 1; i < (i_NumberOfPower + 1); i++) { DebugWarning("Erstelle: " + s_state_FullPath + ".POWER" + String(i)); await createStateAsync(s_state_FullPath + ".POWER" + String(i), false, { type: 'boolean', read: true, write: true, role: "switch", name: s_DeviceName + s_Suffix + '.POWER' + String(i) }); } } } // ####################################################################################################### // Version-JS-Script await createStateAsync(s_state_FullPath + ".Version-JS-Script", s_VersionJSScript, { type: 'string', read: true, write: false, name: 'Version-JS-Script' }); // ####################################################################################################### // Version-JS-Script-Path await createStateAsync(s_state_FullPath + ".Version-JS-Script-Path", scriptName, { type: 'string', read: true, write: false, name: 'Name und Pfad des Skriptes' }); // ####################################################################################################### // RSSI await createStateAsync(s_state_FullPath + ".RSII", 0, { type: 'number', read: true, write: false, name: 'WLAN Stärke in %', unit: "%" }); //SetUnit(s_state_FullPath + ".RSII", "%"); // ####################################################################################################### // Basisstation 1 await createStateAsync(s_state_FullPath + ".BSSId", "00:00:00:00:00:00", { type: 'string', read: true, write: false, name: 'MAC des AccessPoints' }); // ####################################################################################################### // Basisstation 2 if (b_GetNameOfAccessPoints == true) { await createStateAsync(s_state_FullPath + ".AccessPoint", "unbekannt", { type: 'string', read: true, write: false, name: 'Name des AccessPoints' }); } // ####################################################################################################### // Kanal await createStateAsync(s_state_FullPath + ".Channel", 0, { type: 'number', read: true, write: false, name: 'WLAN Kanal' }); // ####################################################################################################### // IP-Adresse await createStateAsync(s_state_FullPath + ".IPAddress", "0.0.0.0", { type: 'string', read: true, write: false, name: 'IP-Address' }); // ####################################################################################################### // Modul (Gerätetyp) await createStateAsync(s_state_FullPath + ".DeviceType", "Generic", { type: 'string', read: true, write: false, name: 'Device Type' }); // ####################################################################################################### // Version (Firmware) await createStateAsync(s_state_FullPath + ".Version", "0.0.0", { type: 'string', read: true, write: false, name: 'Version' }); // ####################################################################################################### // FriendlyName (Rufname Amazon Echo & Co) await createStateAsync(s_state_FullPath + ".FriendlyName", "Tasmota", { type: 'string', read: true, write: false, name: 'FriendlyName' }); // ####################################################################################################### // Datenpunkte für Betriebsstundenzähler / Einschaltdauer if (b_HourMeter == true) { // Zeit wann eingeschaltet await createStateAsync(s_state_FullPath + ".tmp.unixtimeSwitchedOn", 0, { type: 'number', read: true, write: true, name: 'Einschaltzeit als Unix-Timestamp', unit: "unixtime" }); SetUnit(s_state_FullPath + ".tmp.unixtimeSwitchedOn", "unixtime"); // ####################################################################################################### // Zeit wann ausgeschaltet await createStateAsync(s_state_FullPath + ".tmp.unixtimeSwitchedOff", 0, { type: 'number', read: true, write: true, name: 'Ausschaltzeit als Unix-Timestamp', unit: "unixtime" }); SetUnit(s_state_FullPath + ".tmp.unixtimeSwitchedOff", "unixtime"); // ####################################################################################################### // Letzte Einschaltdauer await createStateAsync(s_state_FullPath + ".tmp.LastSwichtedOnDuration", 0, { type: 'number', read: true, write: true, name: 'Letzte Einschaltdauer', unit: "s" }); SetUnit(s_state_FullPath + ".tmp.LastSwichtedOnDuration", "s"); // ####################################################################################################### // Summe der Einschaltdauer await createStateAsync(s_state_FullPath + ".tmp.OperationHoursCounter", 0, { type: 'number', read: true, write: true, name: 'Summe Einschaltdauer', unit: "s" }); SetUnit(s_state_FullPath + ".tmp.OperationHoursCounter", "s"); // ####################################################################################################### // Letzte Einschaltdauer Lesbar in HH:MM:SS await createStateAsync(s_state_FullPath + ".Time-LastSwichtedOnDuration", "0s", { type: 'string', read: true, write: true, name: 'Letzte Einschaltdauer' }); // ####################################################################################################### // Gesamte Einschaltdauer Lesbar in HH:MM:SS await createState(s_state_FullPath + ".Time-OperationHoursCounter", "0s", { type: 'string', read: true, write: true, name: 'Letzte Einschaltdauer' }); // ####################################################################################################### // Aktuelle Einschaltdauer in Sekunden await createState(s_state_FullPath + ".Time-CurrentPowerOnTimeSeconds", 0, { type: 'number', read: true, write: true, name: 'Aktuelle Einschaltdauer in Sekunden', unit: "s" }); SetUnit(s_state_FullPath + ".Time-CurrentPowerOnTimeSeconds", "s"); // ####################################################################################################### // Aktuelle Einschaltdauer Lesbar in HH:MM:SS await createState(s_state_FullPath + ".Time-CurrentPowerOnTimeH", "0s", { type: 'string', read: true, write: true, name: 'Aktuelle Einschaltdauer in Tagen, Stunden, Minuten, Sekunden' }); // ####################################################################################################### } // Datenpunkte für Stromverbrauch if (b_Energy == true) { // Gesamter Energieverbrauch await createState(s_state_FullPath + ".Energy-Total", 0, { type: 'number', read: true, write: true, name: 'Energie Total', unit: "kWh" }); SetUnit(s_state_FullPath + ".Energy-Total", "kWh"); // ####################################################################################################### // Energieverbrauch gestern await createState(s_state_FullPath + ".Energy-Yesterday", 0, { type: 'number', read: true, write: true, name: 'Energie Gestern', unit: "kWh" }); SetUnit(s_state_FullPath + ".Energy-Yesterday", "kWh"); // ####################################################################################################### // Energieverbrauch Heute await createState(s_state_FullPath + ".Energy-Today", 0, { type: 'number', read: true, write: true, name: 'Energie Heute', unit: "kWh" }); SetUnit(s_state_FullPath + ".Energy-Yesterday", "kWh"); // ####################################################################################################### // Energieverbrauch Aktuell/Momentan/Jetzt gerade await createState(s_state_FullPath + ".Energy-Power", 0, { type: 'number', read: true, write: true, name: 'Energie Momentan', unit: "W" }); SetUnit(s_state_FullPath + ".Energy-Power", "W"); // ####################################################################################################### // Energieverbrauch aktuelle Spannung await createState(s_state_FullPath + ".Energy-Voltage", 0, { type: 'number', read: true, write: true, name: 'Energie Spannung Momentan', unit: "V" }); SetUnit(s_state_FullPath + ".Energy-Voltage", "V"); // ####################################################################################################### // Energieverbrauch aktueller Stromfluss await createState(s_state_FullPath + ".Energy-Current", 0, { type: 'number', read: true, write: true, name: 'Energie Stromfluss Momentan', unit: "A" }); SetUnit(s_state_FullPath + ".Energy-Current", "A"); // ####################################################################################################### } if (b_Temperature == true) { // ####################################################################################################### // Temperatur await createState(s_state_FullPath + ".Temperature", 0, { type: 'number', read: true, write: true, name: 'Energie Stromfluss Momentan', unit: "°C" }); SetUnit(s_state_FullPath + ".Temperature", "°C"); // ####################################################################################################### } if (b_EasyMeterQ3A == true) { // ####################################################################################################### // Stromzähler EasyMeter Q3A via Tasmota // Verbrauch-Summe await createState(s_state_FullPath + ".Verbrauch-Summe", 0, { type: 'number', read: true, write: true, name: 'Verbrauch Summe', unit: "kWh" }); // Einspeisung-Summe await createState(s_state_FullPath + ".Einspeisung-Summe", 0, { type: 'number', read: true, write: true, name: 'Einspeisung Summe', unit: "kWh" }); // Watt L1 await createState(s_state_FullPath + ".Watt-L1", 0, { type: 'number', read: true, write: true, name: 'Watt-L1', unit: "W" }); // Watt L2 await createState(s_state_FullPath + ".Watt-L2", 0, { type: 'number', read: true, write: true, name: 'Watt-L2', unit: "W" }); // Watt L3 await createState(s_state_FullPath + ".Watt-L3", 0, { type: 'number', read: true, write: true, name: 'Watt-L3', unit: "W" }); // Watt Summe await createState(s_state_FullPath + ".Watt-Summe", 0, { type: 'number', read: true, write: true, name: 'Watt-Summe', unit: "W" }); // Volt L1 await createState(s_state_FullPath + ".Volt-L1", 0, { type: 'number', read: true, write: true, name: 'Volt-L1', unit: "V" }); // Volt L2 await createState(s_state_FullPath + ".Volt-L2", 0, { type: 'number', read: true, write: true, name: 'Volt-L2', unit: "V" }); // Volt L3 await createState(s_state_FullPath + ".Volt-L3", 0, { type: 'number', read: true, write: true, name: 'Volt-L3', unit: "V" }); } if (b_hcsr04 == true) { // ####################################################################################################### // Ultraschall Entfernungssensor // Verbrauch-Summe await createState(s_state_FullPath + ".Distance", 0, { type: 'number', read: true, write: false, name: 'Distance in cm', unit: "cm" }); } // Startup - Startwerte schon mal ermitteln und schreiben DebugWarning("Startup: aktuellen Status von POWER holen und schreiben"); // Beim Start einmal den aktuellen Status von MQTT stat/POWER holen und schreiben if (b_hcsr04 == false) { if (i_NumberOfPower == 1) { s_tempjson = getState(s_mqtt_POWER_path).val; if (s_tempjson == "ON") { setState(s_state_power_path, true, true); if (b_HourMeter == true) { // letztes TimeStamp für das Einschalten wieder auslesen damit Dauer berechnet werden kann i_global_unixtimeSwitchedOn = getState(s_state_FullPath + ".tmp.unixtimeSwitchedOn").val; // Kann sein das der Wert 0 ist wenn das Gerät noch nie ausgeschaltet war, dann nehmen wir eben die aktuelle Zeit if (i_global_unixtimeSwitchedOn == 0) { i_global_unixtimeSwitchedOn = Math.floor(Date.now() / 1000); setState(s_state_FullPath + ".tmp.unixtimeSwitchedOn", i_global_unixtimeSwitchedOn, true); } } } else { setState(s_state_power_path, false, true); } } else { for (let i = 1; i < (i_NumberOfPower + 1); i++) { s_tempjson = getState(s_mqtt_POWER_path.replace("*",String(i))).val; if (s_tempjson == "ON") { setState(s_state_power_path + String(i), true, true); if (b_HourMeter == true) { // letztes TimeStamp für das Einschalten wieder auslesen damit Dauer berechnet werden kann i_global_unixtimeSwitchedOn = getState(s_state_FullPath + ".tmp.unixtimeSwitchedOn").val; // Kann sein das der Wert 0 ist wenn das Gerät noch nie ausgeschaltet war, dann nehmen wir eben die aktuelle Zeit if (i_global_unixtimeSwitchedOn == 0) { i_global_unixtimeSwitchedOn = Math.floor(Date.now() / 1000); setState(s_state_FullPath + ".tmp.unixtimeSwitchedOn", i_global_unixtimeSwitchedOn, true); } } } else { setState(s_state_power_path + String(i), false, true); } } } } // ####################################################################################################### // Version setzen / aktualisieren setState(s_state_FullPath + ".Version-JS-Script", s_VersionJSScript, true); setState(s_state_FullPath + ".Version-JS-Script-Path", scriptName, true); // ####################################################################################################### // Beim Start einmal einfach die IP-Adresse / Firmware etc. falls schon vorhanden: DebugWarning("Startup: aktuellen Status von INFO1 holen und schreiben"); if (await existsStateAsync(s_mqtt_INFO1_path)) { s_tempjson = JSON.parse(getState(s_mqtt_INFO1_path).val); if (b_Firmware95 == false) { // bis Tasmota Version 9.3.1 DebugWarning("Startup: DeviceType: " + String(s_tempjson.Module)); await setStateAsync(s_state_FullPath + ".DeviceType", String(s_tempjson.Module), true); DebugWarning("Startup: Version: " + String(s_tempjson.Version)); await setStateAsync(s_state_FullPath + ".Version", String(s_tempjson.Version), true); } else { // ab Tasmota Version 9.5 DebugWarning("Startup: DeviceType: " + s_tempjson.Info1.Module); await setStateAsync(s_state_FullPath + ".DeviceType", String(s_tempjson.Info1.Module), true); DebugWarning("Startup: Version: " + s_tempjson.Info1.Version); await setStateAsync(s_state_FullPath + ".Version", String(s_tempjson.Info1.Version), true); } } // ####################################################################################################### DebugWarning("Startup: aktuellen Status von INFO2 holen und schreiben"); if (await existsStateAsync(s_mqtt_INFO2_path)) { s_tempjson = JSON.parse(getState(s_mqtt_INFO2_path).val); if (b_Firmware95 == false) { // bis Tasmota Version 9.3.1 await setStateAsync(s_state_FullPath + ".IPAddress", String(s_tempjson.IPAddress), true); DebugWarning("Startup: IPAddress: " + String(s_tempjson.IPAddress)); } else { // ab Tasmota Version 9.5 await setStateAsync(s_state_FullPath + ".IPAddress", String(s_tempjson.Info2.IPAddress), true); DebugWarning("Startup: IPAddress: " + String(s_tempjson.Info2.IPAddress)); } } // ####################################################################################################### if (b_Energy == true) { DebugWarning("Startup: aktuellen Status von SENSOR holen und schreiben"); if (await existsStateAsync(s_mqtt_SENSOR_path)) { s_tempjson = JSON.parse(getState(s_mqtt_SENSOR_path).val); if (b_Firmware95 == false) { // bis Tasmota Version 9.3.1 // Keine Ahnung wie das vor 9.5 aussieht, muss ich dann noch mal nachpflegen } else { // ab Tasmota Version 9.5 await setStateAsync(s_state_FullPath + ".Energy-Total", Number(s_tempjson.ENERGY.Total), true); DebugWarning("Startup: Energy-Total: " + Number(s_tempjson.ENERGY.Total)); await setStateAsync(s_state_FullPath + ".Energy-Yesterday", Number(s_tempjson.ENERGY.Yesterday), true); DebugWarning("Startup: Energy-Yesterday: " + Number(s_tempjson.ENERGY.Yesterday)); await setStateAsync(s_state_FullPath + ".Energy-Today", Number(s_tempjson.ENERGY.Today), true); DebugWarning("Startup: Energy-Today: " + Number(s_tempjson.ENERGY.Today)); await setStateAsync(s_state_FullPath + ".Energy-Power", Number(s_tempjson.ENERGY.Power), true); DebugWarning("Startup: Energy-Power: " + Number(s_tempjson.ENERGY.Power)); if (isNaN(Number(s_tempjson.ENERGY.Voltage))) { await setStateAsync(s_state_FullPath + ".Energy-Voltage", 0, true); } else { await setStateAsync(s_state_FullPath + ".Energy-Voltage", Number(s_tempjson.ENERGY.Voltage), true); } DebugWarning("Startup: Energy-Voltage: " + Number(s_tempjson.ENERGY.Voltage)); if (isNaN(Number(s_tempjson.ENERGY.Current))) { await setStateAsync(s_state_FullPath + ".Energy-Current", 0, true); } else { await setStateAsync(s_state_FullPath + ".Energy-Current", Number(s_tempjson.ENERGY.Current), true); }; DebugWarning("Startup: Energy-Current: " + Number(s_tempjson.ENERGY.Current)); if (b_Temperature == true) { await setStateAsync(s_state_FullPath + ".Temperature", Number(s_tempjson.ANALOG.Temperature), true); DebugWarning("Startup: Temperature: " + Number(s_tempjson.ANALOG.Temperature)); } } } } } catch (error) { DebugWarning(error); log(error); } } // #################################################################################################################################################### // #################################################################################################################################################### // _____ _ _ _ // | __ \ | | | | | | // | | | | __ _| |_ ___ _ __ _ __ _ _ _ __ | | _| |_ ___ // | | | |/ _` | __/ _ \ '_ \| '_ \| | | | '_ \| |/ / __/ _ \ // | |__| | (_| | || __/ | | | |_) | |_| | | | | <| || __/ // |_____/ \__,_|\__\___|_| |_| .__/ \__,_|_| |_|_|\_\\__\___| // | | // |_| // #################################################################################################################################################### // #################################################################################################################################################### // Zielpunkte anlegen falls noch nicht vorhanden //DebugWarning("Startup: Erstelle ggf. Datenpunkte ..."); // Das erstellen machen wir in einer async Funktion CreateMyStatesAndStartup(); // #################################################################################################################################################### // #################################################################################################################################################### // _____ _ _ // / ____| | | | // | (___ | |_ __ _ _ __| |_ _ _ _ __ // \___ \| __/ _` | '__| __| | | | '_ \ // ____) | || (_| | | | |_| |_| | |_) | // |_____/ \__\__,_|_| \__|\__,_| .__/ // | | // |_| // #################################################################################################################################################### // #################################################################################################################################################### // Ist nun in die Funktion CreateMyStatesAndStartup(); integriert // #################################################################################################################################################### // #################################################################################################################################################### // _____ _ _ _ _ // / ____| | | (_) | | (_) // | (___ _ _| |__ ___ ___ _ __ _ _ __ | |_ _ ___ _ __ ___ // \___ \| | | | '_ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \/ __| // ____) | |_| | |_) \__ \ (__| | | | |_) | |_| | (_) | | | \__ \ // |_____/ \__,_|_.__/|___/\___|_| |_| .__/ \__|_|\___/|_| |_|___/ // | | // |_| // #################################################################################################################################################### // #################################################################################################################################################### // Status einlesen und nach javascript.0 schreiben wenn per MQTT etwas neues reinkommt // Wird aufgerufen wenn eine MQTT-POWER Meldung reinkommt. Die wird bei jedem Ein-/Ausschalten erzeugt egal ob // ioBroker, ein Schalter, Fernbedienung oder ein Klick in der Weboberfläche das ausgelöst hat // change: "ne" sollte dafür sorgen das es nur aufgerufen wird wenn der Wert sich vom vorherigen unterscheidet //on({ id: [].concat(Array.prototype.slice.apply($('channel[state.id=mqtt.0.stat.Gosund166.POWER*]'))), change: 'ne' }, //on({ id: Array.prototype.slice.apply($("channel[state.id="+s_mqtt_POWER_path+"]")), change: "ne" }, function (obj) { if (b_hcsr04 == false) { on({ id: Array.prototype.slice.apply($("channel[state.id="+s_mqtt_POWER_path+"]")), change: "ne" }, function (obj) { //on({ id: s_mqtt_POWER_path, change: "ne" }, function (obj) { // DebugWarning("Subscription on() START: " + s_mqtt_POWER_path); DebugWarning("Subscription on() START: " + obj.id); // POWER oder POWER1..x ? Lässt sich aus dem Datenpunktnamen ermitteln, obj.id let s_powernumber = String(obj.id).slice(-1); if (s_powernumber === "R") { s_powernumber = "" } // Der aktuelle Status der gerade gekommen ist: ON oder OFF var s_value_mqtt = obj.state.val; // Wir holen den Status den wir aktuell unterhalb von JavaScript gespeichert habem var s_value_javascript = getState(s_state_power_path + s_powernumber).val; // Auswerten von ON und OFF und umsetzung on true oder false var b_helper_mqtt = false; if (s_value_mqtt == 'ON') { b_helper_mqtt = true; } else { b_helper_mqtt = false; } // prüfen ob die Werte wirklich ungleich sein sind und wir was ändern müssen if (b_helper_mqtt != s_value_javascript) { if (s_value_mqtt == 'ON') { setState(s_state_power_path, true, true); if (b_HourMeter == true) { // Aktuelle Uhrzeit wegschreiben - Einschalten i_global_unixtimeSwitchedOn = Math.floor(Date.now() / 1000); setState(s_state_FullPath + ".tmp.unixtimeSwitchedOn", i_global_unixtimeSwitchedOn, true); } // @ts-ignore if (b_UseSystemEventLog == true) { createEventlog(s_DeviceName, 'ON (per MQTT stat-POWER' + s_powernumber + ')'); } DebugWarning("Subscription on() STATUS: " + s_mqtt_POWER_path + s_powernumber + ": ON"); } else { setState(s_state_power_path, false, true); if (b_HourMeter == true) { // Aktuelle Uhrzeit wegschreiben - Ausschalten i_global_unixtimeSwitchedOff = Math.floor(Date.now() / 1000); setState(s_state_FullPath + ".tmp.unixtimeSwitchedOff", i_global_unixtimeSwitchedOff, true); CalculateSwitchedOnDuration(); // Aktuelle Einschaltzeit auf 0 setzen setState(s_state_FullPath + ".Time-CurrentPowerOnTimeSeconds", 0, true); setState(s_state_FullPath + ".Time-CurrentPowerOnTimeH", "0s", true); } if (b_UseSystemEventLog == true) { createEventlog(s_DeviceName, 'OFF (per MQTT stat-POWER)'); } DebugWarning("Subscription on() STATUS: " + s_mqtt_POWER_path + s_powernumber + ": OFF"); } } DebugWarning("Subscription on() ENDE: " + s_mqtt_POWER_path + s_powernumber); }); } // #################################################################################################################################################### // Status setzen nachdem der JavaScript-Datenpunkt geändert wurde (den, den wir z.B. für Widgets in VIS verwenden) // fromNe: o_js_Instance sorgt dafür das es NICHT angetriggert wird wenn der Datenpunkt durch diese JavaScript Instanz geändert wurde. // zusätzlich prüfen wir ob ohne Bestätigung geschrieben wurde // Wenn also eine MQTT Auswertung einer der anderen on() der Grund war wird dies hier NICHT aufgerufen // Die Variable o_js_Instance wird oben bei den Variablen-Definitionen gesetzt if (b_hcsr04 == false) { var s_state_power_path_multi = s_state_power_path; if (i_NumberOfPower > 1) { s_state_power_path_multi = s_state_power_path_multi + "*" } on({ id: Array.prototype.slice.apply($("channel[state.id="+s_state_power_path_multi+"]")), change: "ne", fromNe: o_js_Instance, ack: false }, function (obj) { // on({ id: s_state_power_path, change: "ne", fromNe: o_js_Instance, ack: false }, function (obj) { // DebugWarning("Subscription on() START: " + s_state_power_path); DebugWarning("Subscription on() START: " + obj.id); var s_value_mqtt = obj.state.val; // POWER oder POWER1..x ? Lässt sich aus dem Datenpunktnamen ermitteln, obj.id let s_powernumber = String(obj.id).slice(-1); if (s_powernumber === "R") { s_powernumber = "" } //var s_value_javascript = getState(s_state_power_path + s_powernumber).val; var b_helper_mqtt = false; // Beides nach Boolean bringen /*if (s_value_mqtt == 'ON') { b_helper_mqtt = true; } else { b_helper_mqtt = false; } */ if (s_value_mqtt == true) { //setState(s_mqtt_CMND_path + s_powernumber, 'ON', false); //DebugWarning(s_mqtt_CMND_path + s_powernumber + ': ON') sendTo(s_mqtt_Instance, 'sendMessage2Client', {topic: 'cmnd/' + s_DeviceName + '/POWER' + s_powernumber, message: 'ON'}); DebugWarning(s_mqtt_Instance + ": sendMessage2Client: " + 'cmnd/' + s_DeviceName + '/POWER' + s_powernumber + ": ON") // Quelldatenpunkt auf bestätigt setzen setState(obj.id, true, true); if (b_UseSystemEventLog == true) { createEventlog(s_DeviceName, 'ON ' + s_powernumber + '(per Datenpunkt JavaScript)'); } if (b_HourMeter == true) { // Aktuelle Uhrzeit wegschreiben - Einschalten i_global_unixtimeSwitchedOn = Math.floor(Date.now() / 1000); setState(s_state_FullPath + ".tmp.unixtimeSwitchedOn", i_global_unixtimeSwitchedOn, true); // Aktuelle Einschaltdauer auf 0 setzen setState(s_state_FullPath + ".Time-CurrentPowerOnTimeSeconds", 0, true); setState(s_state_FullPath + ".Time-CurrentPowerOnTimeH", "0s", true); } DebugWarning("Subscription on() STATUS: " + s_state_power_path + s_powernumber + ": ON"); } else { //setState(s_mqtt_CMND_path + s_powernumber, 'OFF', false); //DebugWarning(s_mqtt_CMND_path + s_powernumber + ': OFF') sendTo(s_mqtt_Instance, 'sendMessage2Client', {topic: 'cmnd/' + s_DeviceName + '/POWER' + s_powernumber, message: 'OFF'}); DebugWarning(s_mqtt_Instance + ": sendMessage2Client: " + 'cmnd/' + s_DeviceName + '/POWER' + s_powernumber + ": OFF") // Quelldatenpunkt auf bestätigt setzen setState(obj.id, false, true); if (b_UseSystemEventLog == true) { createEventlog(s_DeviceName, 'OFF ' + s_powernumber + ' (per Datenpunkt JavaScript)'); } if (b_HourMeter == true) { // Letzte Laufzeit ausrechnen und wegschreiben i_global_unixtimeSwitchedOff = Math.floor(Date.now() / 1000); setState(s_state_FullPath + ".tmp.unixtimeSwitchedOff", i_global_unixtimeSwitchedOff, true); CalculateSwitchedOnDuration(); // Aktuelle Einschaltzeit auf 0 setzen setState(s_state_FullPath + ".Time-CurrentPowerOnTimeSeconds", 0, true); setState(s_state_FullPath + ".Time-CurrentPowerOnTimeH", "0s", true); } DebugWarning("Subscription on() STATUS: " + s_state_power_path + s_powernumber + ": OFF"); } DebugWarning("Subscription on() ENDE: " + s_state_power_path + s_powernumber); }); } // #################################################################################################################################################### // Tasmota sendet seinen Status und Infos regelmäßig per MQTT als JSON, Default sind alle 300 Sekunden // das nutzen wir aus um weitere Daten zu erfassen // #################################################################################################################################################### // STATUS Meldung on({ id: s_mqtt_STATE_path, change: "ne" }, function (json) { DebugWarning("Subscription on() START: " + s_mqtt_STATE_path); try { var obj = JSON.parse(json.state.val); let myBSSId = String(obj.Wifi.BSSId); if (b_GetNameOfAccessPoints == true) { myAccessPoint = String(getState(s_AccessPoints_path + myBSSId).val); } if (b_hcsr04 == false) { if (i_NumberOfPower == 1) { var b_helper_mqtt = false; if (obj.POWER == "ON") { b_helper_mqtt = true; } else { b_helper_mqtt = false; } if (b_helper_mqtt != getState(s_state_FullPath + ".POWER").val) { setState(s_state_FullPath + ".POWER", b_helper_mqtt); if (obj.POWER == 'ON') { if (b_UseSystemEventLog == true) { createEventlog(s_DeviceName, 'ON (per MQTT tele-STATE Meldung)'); } } else { if (b_UseSystemEventLog == true) { createEventlog(s_DeviceName, 'OFF (per MQTT tele-STATE Meldung)'); } } } } } else { var b_helper_mqtt = false; for (let i = 1; i < (i_NumberOfPower + 1); i++) { b_helper_mqtt = false; if (obj["POWER" + i] == "ON") { b_helper_mqtt = true; } else { b_helper_mqtt = false; } if (b_helper_mqtt != getState(s_state_FullPath + ".POWER" + i).val) { setState(s_state_FullPath + ".POWER" + i, b_helper_mqtt); if (obj["POWER" + i] == 'ON') { if (b_UseSystemEventLog == true) { createEventlog(s_DeviceName, 'ON ' + i + ' (per MQTT tele-STATE Meldung)'); } } else { if (b_UseSystemEventLog == true) { createEventlog(s_DeviceName, 'OFF ' + i + ' (per MQTT tele-STATE Meldung)'); } } } } } setState(s_state_FullPath + ".RSII", Number(obj.Wifi.RSSI), true); setState(s_state_FullPath + ".BSSId", myBSSId, true); if (b_GetNameOfAccessPoints == true) { setState(s_state_FullPath + ".AccessPoint", myAccessPoint, true); } setState(s_state_FullPath + ".Channel", Number(obj.Wifi.Channel), true); // POWER prüfen ob die Werte wirklich ungleich sein sind und nur dann schreiben } catch (e) { DebugWarning("Subscription on() ENDE per Fehler: " + s_mqtt_STATE_path + " : " + e); return; } DebugWarning("Subscription on() ENDE: " + s_mqtt_STATE_path); }); // #################################################################################################################################################### // INFO1 Meldung (enthält Gerätetyp und Firmwareversion) on({ id: s_mqtt_INFO1_path, change: "any" }, function (json) { DebugWarning("Subscription on() START: " + s_mqtt_INFO1_path); try { var obj = JSON.parse(json.state.val); if (b_Firmware95 == false) { // bis Tasmota Version 9.3.1 setState(s_state_FullPath + ".DeviceType", String(obj.Module), true); setState(s_state_FullPath + ".Version", String(obj.Version), true); } else { // ab Tasmota Version 9.5 setState(s_state_FullPath + ".DeviceType", String(obj.Info1.Module), true); setState(s_state_FullPath + ".Version", String(obj.Info1.Version), true); } } catch (e) { DebugWarning("Subscription on() ENDE per Fehler: " + s_mqtt_INFO1_path); return; } DebugWarning("Subscription on() ENDE: " + s_mqtt_INFO1_path); }); // #################################################################################################################################################### // INFO2 Meldung (enthält die IP-Adresse) on({ id: s_mqtt_INFO2_path, change: "any" }, function (json) { DebugWarning("Subscription on() START: " + s_mqtt_INFO2_path); try { var obj = JSON.parse(json.state.val); if (b_Firmware95 == false) { // bis Tasmota Version 9.3.1 setState(s_state_FullPath + ".IPAddress", String(obj.IPAddress), true); } else { // ab Tasmota Version 9.5 setState(s_state_FullPath + ".IPAddress", String(obj.Info2.IPAddress), true); } } catch (e) { DebugWarning("Subscription on() ENDE per Fehler: " + s_mqtt_INFO2_path); return; } DebugWarning("Subscription on() ENDE: " + s_mqtt_INFO2_path); }); // #################################################################################################################################################### // stat/.../STATUS Meldung (enthält den FriendlyName) on({ id: s_mqtt_STATUS_path, change: "any" }, function (json) { DebugWarning("Subscription on() START: " + s_mqtt_STATUS_path); try { var obj = JSON.parse(json.state.val); if (b_Firmware95 == false) { // bis Tasmota Version 9.3.1 setState(s_state_FullPath + ".FriendlyName", String(obj.FriendlyName), true); } else { // ab Tasmota Version 9.5 setState(s_state_FullPath + ".FriendlyName", String(obj.Status.FriendlyName[0]), true); } } catch (e) { DebugWarning("Subscription on() ENDE per Fehler: " + s_mqtt_STATUS_path); return; } DebugWarning("Subscription on() ENDE: " + s_mqtt_STATUS_path); }); // #################################################################################################################################################### // SENSOR Meldung Stromverbrauch // Wird nur beachtet wenn der Parameter am Skriptanfang gesetzt wird // @ts-ignore if (b_Energy == true) { on({ id: s_mqtt_SENSOR_path, change: "any" }, function (json) { DebugWarning("Subscription on() START: " + s_mqtt_SENSOR_path + " (Energy)"); try { var obj = JSON.parse(json.state.val); if (b_Firmware95 == false) { // bis Tasmota Version 9.3.1 // Muss ich noch nachprüfen, hab nur noch Tasmota 10 Geräte } else { // ab Tasmota Version 9.5 setState(s_state_FullPath + ".Energy-Total", Number(obj.ENERGY.Total), true); setState(s_state_FullPath + ".Energy-Yesterday", Number(obj.ENERGY.Yesterday), true); setState(s_state_FullPath + ".Energy-Today", Number(obj.ENERGY.Today), true); setState(s_state_FullPath + ".Energy-Power", Number(obj.ENERGY.Power), true); if (isNaN(Number(obj.ENERGY.Voltage))) { setState(s_state_FullPath + ".Energy-Voltage", 0, true); } else { setState(s_state_FullPath + ".Energy-Voltage", Number(obj.ENERGY.Voltage), true); }; if (isNaN(Number(obj.ENERGY.Current))) { setState(s_state_FullPath + ".Energy-Current", 0, true); } else { setState(s_state_FullPath + ".Energy-Current", Number(obj.ENERGY.Current), true); } if (b_Temperature == true) { setState(s_state_FullPath + ".Temperature", Number(obj.ANALOG.Temperature), true); } } } catch (e) { DebugWarning("Subscription on() ENDE per Fehler: " + s_mqtt_SENSOR_path); return; } DebugWarning("Subscription on() ENDE: " + s_mqtt_SENSOR_path); }); } // #################################################################################################################################################### // SENSOR Meldung EasyMeterQ3A // @ts-ignore if (b_EasyMeterQ3A == true) { on({ id: s_mqtt_SENSOR_path, change: "any" }, function (json) { DebugWarning("Subscription on() START: " + s_mqtt_SENSOR_path + " (EasyMeterQ3A)"); /* {"Time":"2023-04-04T23:07:45", "SML":{ "Verbrauch_T1":95.4412923, "Verbrauch_T2":0.2737477, "Verbrauch_Summe":95.7150401, "Einspeisung_Summe":101.5756287, "Watt_L1":2803.85, "Watt_L2":1062.85, "Watt_L3":242.30, "Watt_Summe":4109.01, "Volt_L1":235.9, "Volt_L2":236.3, "Volt_L3":236.2}} */ try { var obj = JSON.parse(json.state.val); setState(s_state_FullPath + ".Verbrauch-Summe", Number(obj.SML.Verbrauch_Summe), true); setState(s_state_FullPath + ".Einspeisung-Summe", Number(obj.SML.Einspeisung_Summe), true); setState(s_state_FullPath + ".Watt-L1", Number(obj.SML.Watt_L1), true); setState(s_state_FullPath + ".Watt-L2", Number(obj.SML.Watt_L2), true); setState(s_state_FullPath + ".Watt-L3", Number(obj.SML.Watt_L3), true); setState(s_state_FullPath + ".Watt-Summe", Number(obj.SML.Watt_Summe), true); setState(s_state_FullPath + ".Volt-L1", Number(obj.SML.Volt_L1), true); setState(s_state_FullPath + ".Volt-L2", Number(obj.SML.Volt_L2), true); setState(s_state_FullPath + ".Volt-L3", Number(obj.SML.Volt_L3), true); } catch (e) { DebugWarning("Subscription on() ENDE per Fehler: " + s_mqtt_SENSOR_path); return; } DebugWarning("Subscription on() ENDE: " + s_mqtt_SENSOR_path); }); } // #################################################################################################################################################### // SENSOR Meldung Ultraschall Entfernungsmessung // Wird nur beachtet wenn der Parameter am Skriptanfang gesetzt wird // @ts-ignore if (b_hcsr04 == true) { on({ id: s_mqtt_SENSOR_path, change: "any" }, function (json) { DebugWarning("Subscription on() START: " + s_mqtt_SENSOR_path + " (HC-SR04)"); try { var obj = JSON.parse(json.state.val); if (b_Firmware95 == false) { // bis Tasmota Version 9.3.1 // Muss ich noch nachprüfen, hab nur noch Tasmota 10 Geräte } else { // ab Tasmota Version 9.5 setState(s_state_FullPath + ".Distance", Number(obj.SR04.Distance), true); } } catch (e) { DebugWarning("Subscription on() ENDE per Fehler: " + s_mqtt_SENSOR_path); return; } DebugWarning("Subscription on() ENDE: " + s_mqtt_SENSOR_path); }); } // #################################################################################################################################################### // ####################################################################################################################################################
Im Skript müsst Ihr oben in Zeile 2 den Namen einsetzen den Ihr beim Tasmota-Gerät als Topic eingestellt habt. Unter diesen Namen tauchen auch die Einträge in den Topics /tele etc. auf.
Das Suffix in Zeile 3 könnte ihr leer lassen, ansonsten wird es an den Namen des Gerätes angehängt bei dem Stammpfad unterhalb von0_userdata.0.tasmota.xxx
In Zeile 10 könnt Ihr die Anzahl der Schaltbaren Ausgänge einstellen, normalerweise 1// Anzahl der schaltbaren Ausgänge, 1 bis x, 1 = nur POWER, ab 2 und mehr POWER1, POWER2 usw. var i_NumberOfPower = 1;
In Zeile 23 könnte ihr ggf. die MQTT-Instanz anpassen
// Name der MQTT-Instanz var s_mqtt_Instance = "mqtt.0";
Dann startet das Skript. Beim ersten mal werden die Datenpunkte angelegt.
In Zeile 27 gibt es den Eintrag
var b_logging = false;
Wenn Ihr den auf true setzt so bekommt Ihr Statusmeldungen im Log und in der JavaScript-Konsole. Das würde ich nur zum testen anmachen und auf keinen Fall für alle Geräte.
Pro Tasmota-Gerät braucht Ihr eine neue Kopie des Skriptes!
In ioBroker sieht das dann so bei den Datenpunkten aus:
Sonderfunktionen 1: Eventlog
Es gibt eine FunktioncreateEventlog
ab Zeile 213:function createEventlog(EventType, EventText) { let tasmotaEventListDestination = "0_userdata.0.EventLog.Tasmota."; // vorhandene Einträge einlesen let EventList = getState(tasmotaEventListDestination + "EventLogTasmota").val; // Anzahl der Maximal erlaubten Einträge einlesen let maxEventCount = getState("0_userdata.0.EventLog.Tasmota.maxEventCount").val;
Um diese zu Verwenden muss man die folgenden 3 Datenpunkte von Hand erstellen:
0_userdata.0.EventLog.Tasmota.EventLogTasmota => String 0_userdata.0.EventLog.Tasmota.NextEventId => Zahl 0_userdata.0.EventLog.Tasmota.maxEventCount => Zahl => Wert 1024 oder nach Wunsch
Das Eventlogging schaltet man dann in Zeile 86 ein:
// Zentrales Log über alle Ein- und Ausschaltvorgänge führen var b_UseSystemEventLog = true;
Er führt dann eine Ereignisliste die man sich in einem HTML-Widget ausgeben lassen kann:
0008686 - 29.09.24 11:29:00 - Steckdose-2-142 - OFF (per MQTT stat-POWER) 0008685 - 29.09.24 11:29:00 - Steckdose-2-141 - OFF (per MQTT stat-POWER) 0008684 - 29.09.24 11:28:00 - Steckdose-2-141 - ON (per MQTT stat-POWER) 0008683 - 29.09.24 11:27:00 - Steckdose-2-147 - OFF (per MQTT stat-POWER) 0008682 - 29.09.24 11:27:00 - Steckdose-2-142 - ON (per MQTT stat-POWER) 0008681 - 29.09.24 11:27:00 - Steckdose-2-141 - OFF (per MQTT stat-POWER) 0008680 - 29.09.24 11:26:00 - Steckdose-2-141 - ON (per MQTT stat-POWER) 0008679 - 29.09.24 11:25:00 - Steckdose-2-141 - OFF (per MQTT stat-POWER) 0008678 - 29.09.24 11:25:00 - Steckdose-2-142 - OFF (per MQTT stat-POWER) 0008677 - 29.09.24 11:25:00 - Steckdose-2-147 - ON (per MQTT stat-POWER) 0008676 - 29.09.24 11:24:00 - Steckdose-2-142 - ON (per MQTT stat-POWER) 0008675 - 29.09.24 11:23:00 - Steckdose-2-141 - ON (per MQTT stat-POWER) 0008674 - 29.09.24 11:19:51 - Gosund166 - ON 1(per Datenpunkt JavaScript) 0008673 - 29.09.24 11:19:46 - Gosund166 - OFF 1 (per Datenpunkt JavaScript) 0008672 - 29.09.24 11:17:27 - Gosund166 - ON 1(per Datenpunkt JavaScript) 0008671 - 29.09.24 11:16:49 - Gosund166 - OFF 1 (per Datenpunkt JavaScript) 0008670 - 29.09.24 11:10:40 - Gosund166 - OFF 1 (per Datenpunkt JavaScript) 0008669 - 29.09.24 11:06:40 - Gosund166 - ON 1(per Datenpunkt JavaScript) 0008668 - 29.09.24 11:06:18 - Gosund166 - OFF 1 (per Datenpunkt JavaScript) 0008667 - 29.09.24 10:00:56 - K07-Badezimmerspiegel - OFF (per MQTT stat-POWER) 0008666 - 29.09.24 09:53:38 - K07-Badezimmerspiegel - ON (per MQTT stat-POWER) 0008665 - 29.09.24 09:50:31 - K07-Badezimmerspiegel - OFF (per MQTT stat-POWER) 0008664 - 29.09.24 09:50:31 - K06-Licht-Badezimmer - OFF (per MQTT stat-POWER) 0008663 - 29.09.24 09:46:44 - K07-Badezimmerspiegel - ON (per MQTT stat-POWER) 0008662 - 29.09.24 09:46:42 - K06-Licht-Badezimmer - ON (per MQTT stat-POWER) 0008661 - 29.09.24 09:18:10 - K07-Badezimmerspiegel - OFF (per MQTT stat-POWER) 0008660 - 29.09.24 09:04:38 - K07-Badezimmerspiegel - ON (per MQTT stat-POWER) 0008659 - 29.09.24 08:23:00 - Steckdose-2-145 - OFF (per Datenpunkt JavaScript)
Sonderfunktionen 1: AccessPoints
Ich lasse mir bei meinen Geräten anzeigen mit welchen meiner AccessPoints diese verbunden sind:
Wer das auch will muss unterhalb von
0_userdata.0.001-Konstanten.WLAN.
Seine AccessPoints mit deren BSSId als Datenpunktnamen als String anlegen, als Wert dann den Namen des AccessPoint:
Dann kann man das in Zeile 82 Einschalten:
// Private Einstellungen die nur für meine Umgebung funktionieren oder von euch zuerst die Voraussetzungen geschafft werden müssen // Soll der Name des AccessPoints ermittelt werden? // @ts-ignore var b_GetNameOfAccessPoints = true; // Pfad für das auslesen des AccessPoints. Dort gibt es für jeden AccessPoint einen Datenpunkt vom Typ String welcher die MAC als ID und den Namen als Wert hat var s_AccessPoints_path = "0_userdata.0.001-Konstanten.WLAN.";
-
@bananajoe weil ich das gerade zufällig sehe, wir hatten ja kurz das Thema in einem anderen Thread.
wenn du schreibst,
bei über 60 Geräten und für jedes Gerät ein eigenes Script,
seh ich mir das Changelog an, gehe ich von weiteren zukünftigen Änderungen(Weiterentwicklung von iobroker/tasmota) aus und muss dann jedesmal alle Scripte anpassen.
Wäre mir irgendwie zu umständlich.
OT
(meine Tasmota Geräte funktionieren übrigens wieder wie gewohnt/lag scheinbar am unifi update) -
@crunchip Jepp, da hast du recht. Leider. Eine optimale Lösung dafür ist mir noch nicht eingefallen, ich wäre aber für Vorschläge zu haben
Es unter common zu setzen halte ich auch nicht für gut (dann als Funktion).
In der Regel entwickle ich auf einem Gerät ... und dann halt Fleißarbeit. Ich muss ja nur Copy & Paste nach den ersten beiden Zeilen machen.
-
@bananajoe
Schon mal überlegt ganz von MQTT wegzugehen und ESPHome zu nutzen?
Mit meinen knapp 35 Tasmota Geräten im Sonoff Adapter habe ich zwar (noch ) keine Probleme, bin aber aus anderen Gründen interessiert auf ESPHome zu wechseln. Ich hoffe im jetzt kommenden Winter finde ich die Zeit dazu... -
@fredf bei mir ebenfalls, blick da aber noch nicht so durch mit ESPhome
-
@crunchip Geht mir ähnlich, wemos D1 mini habe ich schon hinbekommen, bei Gosund oder anderen Steckdosen hakt es...
-
@fredf Nope, ESP-Home ist keine alternative für mich. Ich mache alles mit MQTT, nicht nur die Tasmota-Geräte und finde das Protokoll und Funktionsprinzip absolut genial.
Und ich bin Tasmota-Fan, selbst mein Musik-Steuerungs LED-Display in der Küche läuft über Tasmota (und MQTT) -
@bananajoe Na klar, jeder wie er will.
-
Ich glaube @OpenSourceNomad kann zu dem ESP Thema ein wenig beitragen oder sogar ein wenig mehr
-
@haselchen
Da bin ich mir sicher -
@haselchen
Außer dass er davon überzeugt ist und auf Nachfrage gerne Links zum Thema verteilt, habe ich da auch noch nicht wirklich weitere Hilfe erhalten und wenn ich mich damit beschäftige, werden die ? nur größer, nicht kleiner. -
@haselchen sagte in Tasmota Steckdosen per MQTT + JavaScript direkt ansteuern:
oder sogar ein wenig mehr
gehört aber nicht hier in den Thread, hier gehts um mqtt und tasmota -
@bananajoe sagte in Tasmota Steckdosen per MQTT + JavaScript direkt ansteuern:
Ich habe das Script soeben bei mir angelegt - doch leider bekommen ich den Powerwert der Gosund SP1 Steckdose nicht übermittelt. Weißt du wie ich den Wert erhalte?
(alle anderen Werte sind wie bei Dir da)Vielen Dank schon einmal für einen Tipp!
-
@mcchip ich habe den ersten Post bearbeitet und dort nun meine aktuelle Version 1.18 hinterlegt.
In dieser kannst du im Setup am Anfang ein- oder ausschalten ob die Energie- und Temperaturwerte mit ausgewertet werden sollen.Zudem wird alles nun unter
0_userdate.0.tasmota
angelegt (was man im Skript einstellen kann).
die letzten 12 Versionen waren diverse Fehlerbereinigungen (Probleme mit Zahlen und Strings) aber auch Datenpunkte in denen ich sehen kann welche Skriptversion es ist und wo das Skript gespeichert ist. da dachte das es wohl eh keiner nutzt habe ich das hier nicht gepflegt.
Im Moment läuft das Skript 108 mal bei mir, inklusive Spezialversionen (2 Steckdosen, Display)Sollte es beim Start eine Warnung geben einfach nochmal neu starten, bei der nächsten Version wird auch das weg sein.
Das mit der automatischen Erkennung habe ich immer noch nicht drin wobei der Aufwand dafür überschaubar wäre.
-
@bananajoe Super Danke Dir. Werde gleich heute Abend testen!
-
@bananajoe Ich hatte das ein paar Tage später umgesetzt. Leider wird z.B. der Powerwert einmal in die Objektliste eingetragen - egal ob unter 0_userdate.0.tasmota oder im Aliasbereich.
Dann wird der Powerwert und andere nicht mehr geändert bis ich den Adapter neu starte.
Ob die Steckdose an oder aus ist (true oder false) wird immer sofort angezeigt.
Ich bin da echt etwas ratlos. -
@mcchip welche
Teleperiod
hast du eingestellt? Ab Werk sendet der nur alle 600 Sekunden.
Ich nutze zumeist 60 Sekunden, bei den Solarpanelen 15 Sekunden. -
ich hatte 100 jetzt 60 - ändert aber nichts.....
Jetzt bin ich über ein Video von Stefan "Verdrahtet" gestolpert:
"ioBroker #3 - OTA Tasmota Update auf Gosund Zwischenstecker | verdrahtet.info"und dort nimmt er nicht den ioBroker MQTT Server her sondern den Sonoff Adapter, bei einer Tasmota Steckdose.
Der Sonoff war bei mir schon installiert - ich musste in der Steckdose nur den Port ändern.
Was soll ich sagen - alles da! Die Werte ändern sich innerhalb von 10 Sekunden und es sieht so aus -
@mcchip
Der Sonoff Adapter ist ein abgespeckter und auf Tasmota zugeschnittener MQTT, somit wesentlich einfacher in der Handhabung, da eh alles schon drin was man dafür braucht
Sonoff heißt der Adapter nur, weil Tasmota zu Beginn auf Sonoff Geräten lief und da den Namen quasi adaptiert hatte. -
@jan1
Vielen Dank für deine Antwort.ABER - ich hab nie verstanden warum bei dem MQTT Adapter die Werte unter "Objekte" immer mit Anführungszeichen, hintereinander ankommen. Beim Sonoff-Adapter habe ich jetzt für jeden Wert einen Eintrag und kann die leicht ohne Javaskript dazwischen verwenden. Mag ja sein dass der "kastriert" ist - aber so ist es einfacher.