NEWS
MQTT get und set anlegen für zigbee2mqtt
-
Hallo ich versuche mit einem Javascript die get und set Datenpunkte für meine zigbee2mqtt geräte anzulegen so das ich ich dann über diese Datenpunkte meine Geräte steuern kann.
Versucht habe ich folgendes:
const mqtt = "mqtt.0"; const topic = "zigbee2mqtt"; const zigbee2mqtt = mqtt +"."+ topic; var devices = JSON.parse(getState(zigbee2mqtt +".bridge.devices").val); devices.forEach(device => { if (device.type == "EndDevice" && device.friendly_name.length > 0 && existsState(zigbee2mqtt +"."+ device.friendly_name) ) { if (!existsState(zigbee2mqtt +"."+ device.friendly_name +".set")) { sendTo(mqtt, 'sendMessage2Client', {topic: '/'+ topic +'/'+ device.friendly_name +'/set', message: '{}'}); } if (!existsState(zigbee2mqtt +"."+ device.friendly_name +".get")) { sendTo(mqtt, 'sendMessage2Client', {topic: '/'+ topic +'/'+ device.friendly_name +'/get', message: '{}'}); } } });
Hiermit werden leider keine Datenpunkte angelegt.
Nächster versuch:
const mqtt = "mqtt.0"; const topic = "zigbee2mqtt"; const zigbee2mqtt = mqtt +"."+ topic; var devices = JSON.parse(getState(zigbee2mqtt +".bridge.devices").val); devices.forEach(device => { if (device.type == "EndDevice" && device.friendly_name.length > 0 && existsState(zigbee2mqtt +"."+ device.friendly_name) ) { if (!existsState(zigbee2mqtt +"."+ device.friendly_name +".set")) { setState(zigbee2mqtt +'.'+ device.friendly_name +'.set', '{}'); } if (!existsState(zigbee2mqtt +"."+ device.friendly_name +".get")) { setState(zigbee2mqtt +'.'+ device.friendly_name +'.get', '{}'); } } });
Auch hier keine Datenpunkte.
Jemand eine Idee wie ich das machen muss um die Datenpunkte anzulegen?
Gruß Alina
-
@eistee Nun wenn der Adapter ein Broker ist, dann wirst Du die Datenpunkte manuell anlegen müssen oder Du nutzt NodeRed oder einen anderen mqtt-Client.
Dein Script ist kein mqtt-Client und mqtt-Nachrichten an einen Broker darf nur ein mqtt Client schicken.
Bei dem 2. kannst Du versuchen, ob Du mit createState was erreichst, bin mir aber nicht sicher. setState geht dachte ich nur bei existierenden States - habe ich aber nie entwickelt. https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#createstate
Ich bin mir auch immer nicht sicher, ob das zulässig ist, dass man in den Hoheitsraum eines Adapters schreiben darf, ausser über den Admin manuell anlegen.
-
@mickym sagte: ob Du mit createState was erreichst
createState() funktioniert nur für "javascript.N" und "0_userdata.0". Alle anderen Objekte müssen mittels setObject() erstellt werden.
-
@mickym sagte in MQTT get und set anlegen für zigbee2mqtt:
achte ich nur bei e
Also ich habe einen mosquitto server laufen. iobroker ist als client dort angemeldet. Wenn ich manuell ein get oder ein set am mosquitto publishe legt iobroker den Datenpunkt ja an und ich kann ihn ab da nutzen. Ich möchte diese Datenpunkte nun automatisch anlegen lassen da ich nicht manuell für alle geräte diese publishen kann. Es muss ja eine Möglichkeit geben in iobroker Datenpunkte anzulegen. Ich kenne nur den passenden Befehl scheinbar nicht.
-
@eistee Na das war mir ja nicht klar, wie Deine Umgebung aussieht - wird halt immer nur ein Bruchteil von Informationen gepostet. Jetzt kenne ich die Umgebung und im Prinzip müsste das Senden zum Adapter tun. Dann liegst vielleicht daran, dass Du ein leeres Objekt anstatt eines leeren Strings schickst und die Syntax laut Beschriebung musst Du die Instanz des Adapters ja angeben:
sendTo('mqtt.0', 'sendMessage2Client', {topic: '/'+ topic +'/'+ device.friendly_name +'/set', message: ''});
Wobei ich persönlich die manuelle Vorgehensweise bevorzugen würde. Es macht keinen Sinn, wenn Sensoren set Punkte bekommen, die eh nicht verwendet werden können.
In dem Fall filterst Du mE auch noch den falschen Typ, nämlich EndDevice, was in der Regel nur batteriebetriebene Sensoren sind. Du müsstest, wenn schon nach dem Typ "Router", filtern. So machts ja mal doppelt keinen Sinn. -
Hi,
hab es hinbekommen was ich erreichen wollte. setObject muss in den Instanzeinstellungen vom Javascript aktiv sein.
Für die Nachwelt hier meine Lösung:const mqtt = "mqtt.0"; const topic = "zigbee2mqtt"; const zigbee2mqtt = mqtt +"."+ topic; var devices = JSON.parse(getState(zigbee2mqtt +".bridge.devices").val); devices.forEach(device => { if (device.friendly_name.length > 0 && existsObject(zigbee2mqtt +"."+ device.friendly_name) ) { if (!existsObject(zigbee2mqtt +"."+ device.friendly_name +".set")) { setObject(zigbee2mqtt +'.'+ device.friendly_name +'.set', { "common": { "name": topic +'/'+ device.friendly_name +"/set", "desc": topic +'/'+ device.friendly_name +"/set", "role": "json", "type": "json", "read": true, "write": true }, "type": "state" }); } if (!existsObject(zigbee2mqtt +"."+ device.friendly_name +".get")) { setObject(zigbee2mqtt +'.'+ device.friendly_name +'.get', { "common": { "name": topic +'/'+ device.friendly_name +"/get", "desc": topic +'/'+ device.friendly_name +"/get", "role": "json", "type": "json", "read": true, "write": true }, "type": "state" }); } } });
-
-
da ich bei mir die einzelnen attribute und kein komplettes json ausgeben lasse, hat mir das hier nicht wirklich weitergeholfen, aber schon ein wenig inspiriert. hier mal mein erster schnellschuss - bisher funktioniert alles, kann aber sicher noch etwas verbessert werden (datentyp, min/max-werte):
const mqtt = "mqtt.0"; const topic = "zigbee2mqtt"; const zigbee2mqtt = mqtt +"."+ topic; const doNotGenerateSetStates = ["update-state", "availability", "linkquality"] const doNotOverwriteExistingObjects = false; var devices = JSON.parse(getState(zigbee2mqtt +".bridge.devices").val); devices.forEach(device => { if (device.friendly_name.length > 0) { var device_name = device.friendly_name.replaceAll("/", ".") console.log(device_name) //console.log({device}) if (device.type.toLowerCase() === "router") { console.log("ist router") var datapointBase = zigbee2mqtt + "." + device_name; if (existsObject(datapointBase)) { console.log(datapointBase + " existiert") var getPoints = $('[state.id=' + datapointBase + '.*]') //console.log({getPoints}) getPoints.each(function (id, i) { if (existsObject(id)) { var attribute = id.split('.').pop(); if (doNotGenerateSetStates.includes(attribute.toLocaleLowerCase())) { console.log("--ABBRUCH: " + attribute) return; } var setMqttPath = topic + "/" + device.friendly_name + "/set/" + attribute; var setId = datapointBase + ".set." + attribute; if (existsObject(setId) && doNotOverwriteExistingObjects) { console.log("--ABBRUCH (existiert bereits): " + attribute) return; } var attributeSpecs = device.definition.exposes.find(data => data.hasOwnProperty('features')).features.find(data => data.name === attribute); if (attributeSpecs === undefined) { attributeSpecs = device.definition.exposes.find(data => data.name === attribute); } //console.log(attributeSpecs) var getObj = getObject(id); getObj._id = setId; getObj.common.name = setMqttPath; getObj.native.topic = setMqttPath; if (attributeSpecs?.value_min != undefined) { getObj.common.min = attributeSpecs.value_min; } if (attributeSpecs?.value_max != undefined) { getObj.common.max = attributeSpecs.value_max; } if (attributeSpecs?.unit != undefined) { getObj.common.unit = attributeSpecs.unit; } setObject(setId, getObj, function (err) { if (err) console.error('Cannot write object: ' + err); }); console.log(setId) } }); } } } })
und das ergebnis:
edit: ich war etwas ungehalten und habe min, max und unit schon hinzugeügt. mehr werte kann man ja bei bedarf analog dazu auslesen.
als nächstes kommt dann noch ein alias datenpunkt, der entsprechend read und write datenpunkte vereint.