NEWS
[gelöst] Generischen Datenpunkt via Blockly (openHasp)
-
Hallo,
ich bein gerade dabei ein openHasp-Display via ioBroker anzusprechen. Da funktioniert nur der MQTT-Client Adapter vernünftig.
Man muss für jeden Button, Slider etc. 2 separate Datenpunkte mit MQTT-Verknüpfung manuell erstellen (1 mal subscribe und einmal publish). Das muss doch einfacher und fehlerfreier gehen. Zumal ich demnächst ein 2. Display einbinden muss.Ich dachte an ein Blockly, welchem ich die Variablem übergeben und ein Javascript erstellt mir das dann generisch. Hab schonmal gestartet, da tut sich aber nix. Könnt ihr mir bitte den Anstoss in die richtige Richtung geben?
Mein vorhandenes Blockly (mit JS):
var host_name, button_id, name2, adapter, type, role; // Beschreibe diese Funktion … async function createIoBrokerDataPoint() { function createIoBrokerDataPoint(adapter, button_id, name, type) { // Überprüfen, ob die notwendigen Parameter vorhanden sind if (!adapter || !button_id || !name || !type) { console.error('Bitte alle Parameter übergeben: adapter, button_id, name, type.'); return; } // Datenpunkt erstellen const objDefinition = { type: 'state', common: { name: name, type: type, role: 'state', read: true, write: true, }, native: {}, }; } // Beispielaufruf der Funktion // Angenommen, "adapter" ist dein ioBroker-Adapter createIoBrokerDataPoint(adapter, button_id, name2, type); } host_name = ''; button_id = 'p1b1'; name2 = 'beschreibung'; adapter = 'mqtt-client.0'; type = 'string'; role = ''; on({ id: '0_userdata.0.create_openHasp_object' /* create_openHasp_object */, change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; if ((obj.state ? obj.state.val : '')) { setState('0_userdata.0.create_openHasp_object' /* create_openHasp_object */, false); await createIoBrokerDataPoint(); console.info('createIoBrokerDataPoint'); } });
Der Datenpunkt soll dann später auch die MQTT-Sachen enthalten, automatisch. Hier ein Beispiel:
{ "common": { "name": "p7b46_Power_Sofalampe_Mitte", "desc": "Manuell erzeugt", "role": "state", "type": "string", "read": true, "write": true, "def": "", "custom": { "mqtt-client.0": { "enabled": true, "publish": false, "pubChangesOnly": false, "pubAsObject": false, "qos": false, "retain": false, "subscribe": true, "subChangesOnly": false, "subAsObject": false, "subQos": false, "setAck": false, "topic": "hasp/buero_sofa/state/p7b46" } } }, "type": "state", "native": {}, "_id": "mqtt-client.0.buero_sofa.state.p7b46_Power_Sofalampe_Mitte", "acl": { "object": 1636, "state": 1636, "owner": "system.user.admin", "ownerGroup": "system.group.administrator" }, "from": "system.adapter.admin.0", "user": "system.user.admin", "ts": 1742849606787 }
p7b46 - ist der Button (button_id) des Displays und Teil des Topics.
Sofalampe wäre hier Beispielsweise der Name.
buero_sofa ist der hostname in diesem Fall.Wenn ich das schonmal hinbekomme, dann könnte ich relativ leicht auch den 2. Datenpunkt zum publishen gleich miterstellen...
"topic": "hasp/buero_sofa/command/p7b46.val" -
@oberfragger
Zunächst wäre es wohl hilfreich, der Funktion auch ein paar Parameter mitzugeben -
@codierknecht sagte in Generischen Datenpunkt via Blockly erstellen:
@oberfragger
Zunächst wäre es wohl hilfreich, der Funktion auch ein paar Parameter mitzugebenOh. Vielen Dank. Logisch.
Sorry, nächste Frage...
Ich hab mal bisschen mit dem Copilot gespielt (bestehenden Datenpunkt genommen und einfach mal ID verändert. So wollte ich mal via JS das alles anlegen.const datapoint = { common: { name: "p7b77_Power_Sofalampe_Mitte", desc: "Manuell erzeugt", role: "state", type: "string", read: true, write: true, def: "", custom: { "mqtt-client.0": { enabled: true, publish: false, pubChangesOnly: false, pubAsObject: false, qos: false, retain: false, subscribe: true, subChangesOnly: false, subAsObject: false, subQos: false, setAck: false, topic: "hasp/buero_sofa/state/p7b77" } } }, type: "state", native: {}, acl: { object: 1636, state: 1636, owner: "system.user.admin", ownerGroup: "system.group.administrator" } }; const id = "mqtt-client.0.buero_sofa.state.p7b77_Power_Sofalampe_Mitte"; createState(id, datapoint.common, true, (err) => { if (err) { console.error(`Fehler beim Anlegen des Datenpunkts: ${err}`); } else { console.log(`Datenpunkt "${id}" erfolgreich angelegt.`); } });
Ich erhalte auch nach dem starten die Ausgabe:
javascript.0 12:11:15.701 info script.js.common.openHasp_Datenpunkt_JS: Datenpunkt "mqtt-client.0.buero_sofa.state.p7b77_Power_Sofalampe_Mitte" erfolgreich angelegt.
Aber leider ist kein derartiger datenpunkt zu sehen...!?! Hab auch oben auf "refresh" geklickt.
Irgendwo ein Denkfehler drin? -
@oberfragger sagte: Irgendwo ein Denkfehler drin?
Wenn man den MQTT-Client Adapter verwendet, erstellt man die Datenpunkte unter "0_userdata.0" und unter common.custom wird der Bezug zur MQTT-Client-Instanz hergestellt.
createState() kann nur unter "javascript.N" und "0_userdata.0" Datenpunkte erstellen.EDIT: Beispiel:
const common = { name: "Power Sofalampe Mitte", role: "state", type: "string", read: true, write: false, def: "", custom: { "mqtt-client.0": { enabled: true, publish: false, pubChangesOnly: false, pubAsObject: false, qos: false, retain: false, subscribe: true, subChangesOnly: false, subAsObject: false, subQos: false, setAck: false, topic: "hasp/buero_sofa/state/p7b77" } } }; const id = "0_userdata.0.buero_sofa.Sofalampe_Mitte.Power.state"; createState(id, '', common);
-
@paul53 Danke.
Das werde ich probieren. Ich poste ein Update.Wenn ich das so wie gewünscht hinbekomme, kann es meines Erachtens die Benutzung von openHasp-Devices für alle enorm vereinfachen, da leider mit normalem MQTT keine zurückgegeben Werte ausgewertet werden können.
-
@oberfragger
Etwas flexibler durch Auswertung des Topic:const topic = 'hasp/buero_sofa/state/p7b77'; const Name = 'Power Sofalampe_Mitte'; const def = ''; // Typ muss übereinstimmen const arrTop = topic.split('/'); const arrName = Name.split(' '); const id = '0_userdata.0.' + arrTop[1] + '.' + arrName[1] + '.' + arrName[0] + '.' + arrTop[2]; const common = { name: Name.replace('_', ' '), role: "state", type: typeof def, read: arrTop[2] == 'state', write: arrTop[2] == 'command', def: def, custom: { "mqtt-client.0": { enabled: true, publish: arrTop[2] == 'command', pubChangesOnly: false, pubAsObject: false, qos: false, retain: false, subscribe: arrTop[2] == 'state', subChangesOnly: false, subAsObject: false, subQos: false, setAck: false, topic: topic } } }; createState(id, def, common);
EDIT: Mittels Alias lassen sich "state" und "command" zu einem DP verbinden.
-
@paul53 Ich hab gerade den von mir generierten Datenpunkt gefunden- der wurde unter javascript.0 erstellt. So wie du geschrieben hast. Das ist natürlich nicht so schön. Userdata.0 ist ebsser.
Mit dem vorletzten Script von dir, erstellt er mir leider garnix. Ich möchte mich da halt langtasten und sukzessive verstehen was ich da mache -> dann kann ich das auch mal selbst machen.
Hier ist das Blockly (wie gesagt- ich möchte später mal einfach die Werte wie Button etc. eintragen und somit schnell erstellen können. Die Idee mit dem Alias finde ich super. Aber Schritt für Schritt.
Warum wird bei Aktivierung (ich setze da einfach den Datenpunkt auf "true" um das Script dann auszuführen...) der Datenpunkt unter userdata.0 nicht erstellt?
-
@oberfragger sagte: Mit dem vorletzten Script von dir, erstellt er mir leider garnix.
Bei Skriptstart sollte der DP "0_userdata.0.buero_sofa.Sofalampe_Mitte.Power.state" erstellt werden.
Bei mir erfolgt es mit dem zuletzt geposteten Skript:
-
@paul53 Keine Ahnung- jetzt klappts bei mir auch.
Ich hangel mich gerade durch. Muss noch bisschen frickeln, so dass ich die notwendigen Sachen aus dem blockly an die Funktion übergeben bekomme.
Danke auf jeden Fall für deine Mühe.
Nach ein bisschen grübeln habe ich auch verstanden was du hier machst:
Mein Ziel ist es primär, die notwendigen Variablen an die Funktion zu übergeben (zum Beispiel Button "p7b77") und dann legt er mir für jeden Button sowohl einen state, als auch command an. Somit kann ich dann bequem für jeden Button auf dem openHasp-Display die Sachen eingeben und beide Datenpunkte automatisch generieren lassen. Und wenn das klappt, dann schaue ich mir mal die Alias-Geschichte an. -
Kurzes Update.
Das Script & Blockly scheint fertig. Damit kann ich nun recht generisch Datenpunkte für openHasp-Displays erstellen bzw. für die diversen Buttons.@paul53 hat Starthilfe gegeben. Danke nochmal.
Den Rest dann mit chatgpt beendet. Waren noch paar kleine Stolpersteine drin.Wenn ich auch passende Scripte fertig und alles getestet habe, dann schreibe ich mal eine Anleitung für openHasp.
<xml xmlns="https://developers.google.com/blockly/xml"> <variables> <variable id="t]mHQ2(O[i~,~{Z1[+%!">button_id</variable> <variable id="mPT5a/ZZM;ltIo{jt;]v">buttonfunktion</variable> <variable id="O5fjg~@mC^kh:.OT[4tI">speicherpfad</variable> <variable id="r2OFNb5JSoE#g];#4K3Y">pretopic</variable> <variable id="5gtZow7y)14]oqV=GyN|">hostname</variable> <variable id="`wmra-.jA.[a)@dMnQN7">type</variable> </variables> <block type="procedures_defcustomnoreturn" id="@UFkkX.yv%])Ff}F2;|j" x="238" y="163"> <mutation statements="false"> <arg name="button_id" varid="t]mHQ2(O[i~,~{Z1[+%!"></arg> <arg name="buttonfunktion" varid="mPT5a/ZZM;ltIo{jt;]v"></arg> <arg name="speicherpfad" varid="O5fjg~@mC^kh:.OT[4tI"></arg> <arg name="pretopic" varid="r2OFNb5JSoE#g];#4K3Y"></arg> <arg name="hostname" varid="5gtZow7y)14]oqV=GyN|"></arg> <arg name="type" varid="`wmra-.jA.[a)@dMnQN7"></arg> </mutation> <field name="NAME">paul53</field> <field name="SCRIPT">Y29uc3QgY3JlYXRlVG9waWMgPSAoYWN0aW9uKSA9PiBgJHtwcmV0b3BpY30vJHtob3N0bmFtZX0vJHthY3Rpb259LyR7YnV0dG9uX2lkfWA7DQpjb25zdCBjcmVhdGVJRCA9IChhY3Rpb24pID0+IGAwX3VzZXJkYXRhLjAuJHtzcGVpY2hlcnBmYWR9LiR7aG9zdG5hbWV9LiR7YWN0aW9ufS4ke2J1dHRvbl9pZH1gOw0KDQpjb25zdCBzdGF0ZXRvcGljID0gY3JlYXRlVG9waWMoJ3N0YXRlJyk7DQpjb25zdCBjb21tYW5kdG9waWMgPSBjcmVhdGVUb3BpYygnY29tbWFuZCcpICsgKHR5cGUudG9Mb3dlckNhc2UoKSA9PT0gJ251bWJlcicgPyAnLnZhbCcgOiAnJyk7DQoNCmNvbnN0IHN0YXRlX2lkID0gY3JlYXRlSUQoJ3N0YXRlJyk7DQpjb25zdCBjb21tYW5kX2lkID0gY3JlYXRlSUQoJ2NvbW1hbmQnKTsNCg0KLy8gU3RhbmRhcmR3ZXJ0IGbDvHIgZGVmDQpjb25zdCBnZXREZWZhdWx0VmFsdWUgPSAodCkgPT4gKHQgPT09ICdudW1iZXInID8gMCA6IHQgPT09ICdib29sZWFuJyA/IGZhbHNlIDogJycpOw0KDQpjb25zdCBzdGF0ZV9jb21tb24gPSB7DQogICAgbmFtZTogYnV0dG9uZnVua3Rpb24sDQogICAgcm9sZTogInN0YXRlIiwNCiAgICB0eXBlOiAic3RyaW5nIiwNCiAgICByZWFkOiB0cnVlLA0KICAgIHdyaXRlOiBmYWxzZSwNCiAgICBkZWY6ICcnLA0KICAgIGN1c3RvbTogew0KICAgICAgICAibXF0dC1jbGllbnQuMCI6IHsgZW5hYmxlZDogdHJ1ZSwgcHVibGlzaDogZmFsc2UsIHN1YnNjcmliZTogdHJ1ZSwgdG9waWM6IHN0YXRldG9waWMgfQ0KICAgIH0NCn07DQoNCmNvbnN0IGNvbW1hbmRfY29tbW9uID0gew0KICAgIG5hbWU6IGJ1dHRvbmZ1bmt0aW9uLA0KICAgIHJvbGU6ICJzdGF0ZSIsDQogICAgdHlwZSwNCiAgICByZWFkOiB0cnVlLA0KICAgIHdyaXRlOiB0cnVlLA0KICAgIGRlZjogZ2V0RGVmYXVsdFZhbHVlKHR5cGUpLA0KICAgIGN1c3RvbTogew0KICAgICAgICAibXF0dC1jbGllbnQuMCI6IHsgZW5hYmxlZDogdHJ1ZSwgcHVibGlzaDogdHJ1ZSwgc3Vic2NyaWJlOiBmYWxzZSwgdG9waWM6IGNvbW1hbmR0b3BpYyB9DQogICAgfQ0KfTsNCg0KY3JlYXRlU3RhdGUoc3RhdGVfaWQsICcnLCBzdGF0ZV9jb21tb24pOw0KY3JlYXRlU3RhdGUoY29tbWFuZF9pZCwgZ2V0RGVmYXVsdFZhbHVlKHR5cGUpLCBjb21tYW5kX2NvbW1vbik7</field> <comment pinned="false" h="80" w="160">Beschreibe diese Funktion …</comment> </block> <block type="comment" id="$RQ:rwIC/g6xPOV+A1Ss" x="237" y="212"> <field name="COMMENT">Adapter: mqtt-client.0&#10;button_id: Den Button angeben&#10;buttonfunktion: Was soll durch den Button ausgelöst werden&#10;speicherpfad: hinter userdata_0.0&#10;pretopic: siehe mqtt-setting des hasp devices&#10;hostname des hasp-devices&#10;typ des Buttons (bool, string, number)</field> <next> <block type="on" id="V?L;5Nr}OxT)BT]~^#Jc"> <field name="OID">0_userdata.0.test</field> <field name="CONDITION">ne</field> <field name="ACK_CONDITION"></field> <statement name="STATEMENT"> <block type="controls_if" id="0),V(RPzI|S:?3|,7W]!"> <value name="IF0"> <block type="on_source" id="3z%t2xus(;q~YGyZh}SN"> <field name="ATTR">state.val</field> </block> </value> <statement name="DO0"> <block type="procedures_callcustomnoreturn" id="=gS(Blp?cNt|^k7%1[k%"> <mutation name="paul53"> <arg name="button_id"></arg> <arg name="buttonfunktion"></arg> <arg name="speicherpfad"></arg> <arg name="pretopic"></arg> <arg name="hostname"></arg> <arg name="type"></arg> </mutation> <value name="ARG0"> <block type="text" id="E~iotn9wF;Let({7%t2E"> <field name="TEXT">p1b7</field> </block> </value> <value name="ARG1"> <block type="text" id="FAP!atq!u%WrvXl^R2ts"> <field name="TEXT">Lampe Ecke Helligkeit</field> </block> </value> <value name="ARG2"> <block type="text" id="umuTAU1|5gG|sv/$[=6a"> <field name="TEXT">Büro</field> </block> </value> <value name="ARG3"> <block type="text" id="f{Ht+f@lncWjnT7EMvY7"> <field name="TEXT">hasp</field> </block> </value> <value name="ARG4"> <block type="text" id="Jr_osU%Iy/{u}}oP=Os3"> <field name="TEXT">buero_sofa</field> </block> </value> <value name="ARG5"> <block type="text" id="||K]*]sydI[Jq6;7:*O|"> <field name="TEXT">number</field> </block> </value> <next> <block type="control" id="I@W^acpevmW@{].wv{Cb"> <mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation> <field name="OID">0_userdata.0.test</field> <field name="WITH_DELAY">FALSE</field> <value name="VALUE"> <block type="logic_boolean" id="S=gT0|j);wtj0Jsc1Maa"> <field name="BOOL">FALSE</field> </block> </value> </block> </next> </block> </statement> </block> </statement> </block> </next> </block> </xml>
const createTopic = (action) => `${pretopic}/${hostname}/${action}/${button_id}`; const createID = (action) => `0_userdata.0.${speicherpfad}.${hostname}.${action}.${button_id}`; const statetopic = createTopic('state'); const commandtopic = createTopic('command') + (type.toLowerCase() === 'number' ? '.val' : ''); const state_id = createID('state'); const command_id = createID('command'); // Standardwert für def const getDefaultValue = (t) => (t === 'number' ? 0 : t === 'boolean' ? false : ''); const state_common = { name: buttonfunktion, role: "state", type: "string", read: true, write: false, def: '', custom: { "mqtt-client.0": { enabled: true, publish: false, subscribe: true, topic: statetopic } } }; const command_common = { name: buttonfunktion, role: "state", type, read: true, write: true, def: getDefaultValue(type), custom: { "mqtt-client.0": { enabled: true, publish: true, subscribe: false, topic: commandtopic } } }; createState(state_id, '', state_common); createState(command_id, getDefaultValue(type), command_common);