@apollon77 hat einen Artikel verfasst (c't 20-2021, Seiten 162 - 165).
NEWS

Best posts made by paul53
-
c't 20-2021
-
[Vorlage] Alias per Skript erzeugen
Im folgenden Skript wird ein Alias zu einem Datenpunkt mit dessen common-Eigenschaften erstellt. Bei gewollten Abweichungen von common-Eigenschaften des Alias zum Original muss man die zugehörigen // (Kommentar) entfernen und den gewünschten Wert zuweisen.
// Original-Datenpunkt const idOrigin = 'mqtt.0.switch.status'; // Optional: Status-Datenpunkt, wenn Kommando und Status getrennt. // Bei Nicht-Verwendung Leerstring '' zuweisen const idRead = ''; // Alias-Datenpunkt const idAlias = 'Pool.Pumpe.Schalter'; var typeAlias, read, write, nameAlias, role, desc, min, max, unit, states, custom, raum, gewerk; // Folgende kommentieren, wenn keine Änderung der Eigenschaft erforderlich nameAlias = 'Poolpumpe Ein'; desc = 'per Script erstellt'; // typeAlias = 'boolean'; // oder 'number' // read = "val < 0 ? -val : 0"; // Erkennung "Aus" --> false erfolgt automatisch // write = "val ? String(1) : String(0)"; // role = 'value'; // min = 0; // nur Zahlen // max = 100; // nur Zahlen // unit = '%'; // nur für Zahlen // states = {0: 'Aus', 1: 'Auto', 2: 'Ein'}; // Zahlen (Multistate) oder Logikwert (z.B. Aus/Ein) custom = {}; // verhindert doppelte Ausführung von history, ... // raum = 'EG_Flur'; // Groß-/Kleinschreibung in der ID beachten ! // gewerk = 'Licht'; // Groß-/Kleinschreibung in der ID beachten ! // Ab hier nichts ändern !! function createAlias(idDst, idSrc, idRd) { if(existsState(idDst)) log(idDst + ' schon vorhanden !', 'warn'); else { var obj = {}; obj.type = 'state'; obj.common = getObject(idSrc).common; obj.common.alias = {}; if(idRd) { obj.common.alias.id = {}; obj.common.alias.id.read = idRd; obj.common.alias.id.write = idSrc; obj.common.read = true; } else obj.common.alias.id = idSrc; if(typeAlias) obj.common.type = typeAlias; if(obj.common.read !== false && read) obj.common.alias.read = read; if(obj.common.write !== false && write) obj.common.alias.write = write; if(nameAlias) obj.common.name = nameAlias; if(role) obj.common.role = role; if(desc) obj.common.desc = desc; if(obj.common.type == 'number') { if(min !== undefined) obj.common.min = min; if(max !== undefined) obj.common.max = max; if(unit) obj.common.unit = unit; } else { if(obj.common.min !== undefined) delete obj.common.min; if(obj.common.max !== undefined) delete obj.common.max; if(obj.common.unit) delete obj.common.unit; } if(states) obj.common.states = states; if(custom && obj.common.custom) obj.common.custom = custom; obj.native = {}; setObject(idDst, obj, function() { if(idRd) setState(idRd, getState(idRd).val, true); else setState(idSrc, getState(idSrc).val, true); }); if(raum && existsObject('enum.rooms.' + raum)) { let obj = getObject('enum.rooms.' + raum) obj.common.members.push(idDst); setObject('enum.rooms.' + raum, obj); } if(gewerk && existsObject('enum.functions.' + gewerk)) { let obj = getObject('enum.functions.' + gewerk) obj.common.members.push(idDst); setObject('enum.functions.' + gewerk, obj); } } } createAlias('alias.0.' + idAlias, idOrigin, idRead);
Beispiele für Konvertierung (write);
write = "val ? 1 : 0"; // boolean --> binary write = "val ? 'On' : 'Off'"; // boolean --> string write = "val.toString()"; // number --> string dezimal write = "val.toFixed(2)"; // number --> string mit 2 Nachkommastellen
EDIT(20.12.2019): obj.native ergänzt.
EDIT(16.01.2020): Abfrage (Zeile 20) geändert
EDIT(06.02.2020): obj.common.custom ergänztEDIT(17.02.2020): Da man Raum und Gewerk in die Struktur der Alias-ID einbringen kann, sind enums für Raum und Gewerk oftmals nicht erforderlich. Für diejenigen, die den erzeugten Alias-Datenpunkt zu enum.rooms und/oder enum.functions hinzufügen wollen, wurde das Skript erweitert.
EDIT(21.04.2020): Erweiterung für getrennte Kommando- und Status-Datenpunkte ab js-controller 3.x.
EDIT(05.12.2020): Wenn Alias-Typ keine Zahl ist, werden min, max und unit gelöscht, falls vorhanden
EDIT(16.02.2021): Zeile 23 geändert von leerem Array in leeres Objekt
-
[Vorlage] Skript: Erstellen von User-Datenpunkten
// Datenpunkt unter 0_userdata.0 erstellen const idUser = 'EG_Kueche.Rollo.Schaltzeit2'; const commonUser = { // nicht benötigte Attribute auskommentieren type: 'number', read: true, write: true, name: 'Rollo Küche Schaltzeit 2', desc: 'Laufzeit Rollo', def: 60, min: 0, // nur bei Zahlen max: 200, // nur bei Zahlen unit: 's', // nur bei Zahlen // states: { // nur bei Zahlen, Logikwerten // 0: 'Aus', // 1: 'Auto', // 2: 'Ein' // }, role: 'level.timer' }; function createDp(id, common) { if(existsState(id)) log('Datenpunkt ' + id + ' existiert bereits !', 'warn'); else { var obj = {}; obj.type = 'state'; obj.common = common; obj.native = {}; setObject(id, obj, function (err) { if (err) log('Cannot write object: ' + err) else { var init = null; if(common.def === undefined) { if(common.type === 'number') init = 0; if(common.type === 'boolean') init = false; if(common.type === 'string') init = ''; } else init = common.def; setState(id, init, true); } }); } } createDp('0_userdata.0.' + idUser, commonUser);
EDIT: Abfrage geändert, ob Datenpunkt schon vorhanden ist.
-
[Vorlage] Wechselseitige Aktualisierung und Bedienung von Datenpunkten
In Fällen, in denen der Wert von einem Gerät auf ein anderes Gerät (und umgekehrt) übertragen werden soll, muss man ein endloses Hin- und Her vermeiden. Damit ein Triggern auf das setState() verhindert wird, kann im Trigger die Quelle (from) ausgewertet werden.
// Wechselseitige Aktualisierung von Datenpunkten const id1 = '...'; // Datenpunkt-ID vom Gerät 1 const id2 = '...'; // Datenpunkt-ID vom Gerät 2 const js = 'system.adapter.javascript.' + instance; on({id: id1, change: 'ne', fromNe: js}, function(dp) { setState(id2, dp.state.val); }); on({id: id2, change: 'ne', fromNe: js}, function(dp) { setState(id1, dp.state.val); });
In Blockly muss die aktuelle JS-Instanz fest eingetragen werden.
-
RE: einfacher Timer, nach x Min Aus
@maddin77 sagte: wenn ich während den 30min den Schalter drücke ignoriere den Schalter erst wenn Zeit abgelaufen wieder Aktiv
-
RE: Variable einmal Pro Monat Protokollieren
@codierknecht sagte: Dann läuft der Kram 30x im Monat ohne etwas zu tun.
Das kann man im CRON eingrenzen. Es ist weniger aufwändig und funktioniert auch nach einem Skript-Neustart.
-
RE: braucht Pi4 8GB ein Gehäuse mit Lüfter?
@tt-tom sagte: wenn man die Kiste mal festhalten muss
Topflappen?
-
RE: Device von einem State abfragen
@Daniel-R sagte:
benötige ich nun den Device Namen
Vorschlag:
function deviceName(id) { // id = Datenpunkt-ID id = id.substring(0, id.lastIndexOf('.')); if(existsObject(id) && getObject(id).type == 'device') return getObject(id).common.name; id = id.substring(0, id.lastIndexOf('.')); if(existsObject(id) && getObject(id).type == 'device') return getObject(id).common.name; }
-
RE: Datenpunkte in Ordner verschieben?
@saeft_2003 sagte:
Wann würdest du zu einem Skript kommen?
Jetzt.
// Kopieren von Datenpunkten nach 0_userdata.0 // Pfade anpassen ! const pathSrc = 'meineDP.0.'; // abschließenden Punkt angeben const pathDst = '0_userdata.0.'; const idsSrc = $(pathSrc + '*'); idsSrc.each(function(id, i) { // Schleife über alle Datenpunkte im Pfad let idDst = pathDst + id.substring(pathSrc.length); if(existsObject(idDst)) log('Datenpunkt ' + idDst + ' existiert bereits !', 'warn'); else { let obj = getObject(id); setObject(idDst, obj, function (err) { if (err) log('Cannot write object: ' + err) else { let init = null; if(existsState(id)) init = getState(id).val; else { let common = obj.common; if(common.def === undefined) { if(common.type === 'number') init = 0; if(common.type === 'boolean') init = false; if(common.type === 'string') init = ''; if(common.type === 'array') init = []; } else init = common.def; } setStateDelayed(idDst, init, true, 20 * i + 50); } }); } });
Falls ioBroker.linkeddevices verwendet wird: Vorher die Instanz deaktivieren !
Vor dem manuellen Löschen der alten Datenpunkte (Ordner) sollten alle Scripte angepasst werden, da man sonst viele Warnungen und Fehlermeldungen riskiert.
Latest posts made by paul53
-
RE: [erl] fritzdect warnung Bereichsüberschreitung DP
@martinp sagte: Datenpunkte werden frisch und für 2.6.2 verdaulich wieder angelegt...
Ja, die beiden DP werden in der letzten Version ohne common.max erzeugt (siehe auch).
-
RE: [gelöst] Fritz-DECT Adapter und AVM Energy 250
@wcag22 sagte: max "2147483648"
Das sollte auch behoben sein: common.max wird nicht mehr erzeugt (siehe Zeilen 4280 bis 4292). Du kannst common.max auch aus den OBJEKTDATEN des DP löschen.
-
RE: [gelöst] Fritz-DECT Adapter und AVM Energy 250
@wcag22 sagte: Kann Jemand damit etwas anfangen?
Es gibt ein Github-Issue.
-
RE: [erl] fritzdect warnung Bereichsüberschreitung DP
@martinp sagte: max "2147483648"
Das sind offenbar Sekunden (2^31). Es gibt dazu ein Github-Issue.
"window open active end time" scheint Minuten zu enthalten (1.1.1970). Rechne es per Alias in ms um. -
RE: Ansteuerung für Zeit X
@mika-0 sagte: nicht nur 30min angesteuert wird, sondern ununterbrochen
Man muss einen Mehrfachstart des Intervalls verhindern, z.B. so:
-
RE: (Gelöst)Frage zu JS Funktion
@docsnyder7 sagte: muss ich eine 2. JS Funktion einbauen
Inzwischen benötigt man die JS-Funktion für den DP-Namen nicht mehr.
@docsnyder7 sagte in Frage zu JS Funktion:
Kann ich dieses um eine weitere Schleife für Türen ergänzen
Du meinst, mit einem weiteren Selektor? Ja, da die Schleifen nacheinander ausgeführt werden, kann wieder die gleiche Variable id verwendet werden.
EDIT: Etwa so: -
RE: Smart-Home mit ioBroker – Zigbee, Z-Wave, DECT, Matter?
@itoss sagte: Z-Wave funkt nicht auf 2,4 GHz, was gut ist
Neben Z-Wave funken noch weitere Protokolle auf 868 MHz:
- Homematic (IP)
- Enocean
- LoRaWan
-
RE: E-Mail Benachrichtigung nach Datenpunktänderung
@martinp sagte: Eine Hysterese sollte man aber einbauen
Mit Hysterese ohne Timeout würde ich es so realisieren:
-
RE: E-Mail Benachrichtigung nach Datenpunktänderung
@perladd sagte: Das Script sieht zu Zeit so aus!
Wenn auf zwei Datenpunkte getriggert wird, benötigt man für jeden DP einen eigenen Timeout.
Dann kann die Nachricht auch den betreffenden Akku nennen.