Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
manuals:symcon:mqtt-integration [2017/08/04 17:16] paulg4hmanuals:symcon:mqtt-integration [2018/09/23 19:15] (aktuell) paulg4h
Zeile 1: Zeile 1:
 ====== MQTT in Symcon Einbinden ====== ====== MQTT in Symcon Einbinden ======
 +
 +<WRAP center round info 60%>
 +Stand September 2018, IPS 4.4
 +</WRAP>
 +
  
 Diese Anleitung zeigt wie man auf einem Raspberry PI 3 das MQTT Protokoll über Mosquitto und mqttwarn in Symcon schreibend und per Modul auch Beschreibbar ist. Also in beide Richtungen Ereigniss Basierend kommuniziert so wie ich es schon seit einem halben Jahr Produktiv mit diversen Arduinos und ESP8266 (PubSub Library) einsetze. Diese Anleitung zeigt wie man auf einem Raspberry PI 3 das MQTT Protokoll über Mosquitto und mqttwarn in Symcon schreibend und per Modul auch Beschreibbar ist. Also in beide Richtungen Ereigniss Basierend kommuniziert so wie ich es schon seit einem halben Jahr Produktiv mit diversen Arduinos und ESP8266 (PubSub Library) einsetze.
Zeile 8: Zeile 13:
 **Auch müssen alle Werte in <spitzen> Klammern durch die Eigenen ersetzt werden!** **Auch müssen alle Werte in <spitzen> Klammern durch die Eigenen ersetzt werden!**
 </WRAP> </WRAP>
 +
  
 ===== Grund Installation am PI Einrichten ===== ===== Grund Installation am PI Einrichten =====
Zeile 35: Zeile 41:
  
 ===== Pakete Installieren ===== ===== Pakete Installieren =====
 +Einen MQTT Broker z.B. das Paket mosquitto Installieren
 +  aptitude install mosquitto mosquitto_pub mosquitto_sub
 +  
 +===== Symcon Vorbereiten =====
 +
 +==== MQTT Client zum Senden in Symcon Installieren ====
 +Zum Senden von Daten per MQTT_Publish aus jedem script:
 +  https://github.com/mkretzschmar/SymconMQTT
 +
 +
 +==== Mosquitto an Symcon Anbinden ====
 +
 +Eine Kategorie anlegen 
 +  Datenpunkte/MQTT/devices
 +  
 +In diesem Knoten werden dann alle Geräte und Datenpunkte Automatisch erstellt / Aktualisiert, nun gehen wir aber wieder zu 
 +  Datenpunkte/MQTT
 +und erstellen das Script "mqtt_switch_relais", damit sind "boolean" Datenpunkte (einfach "True" oder "False" beim ersten schreiben in dem mqtt broker erstellt die Variable in Symcon und verlinkt diese mit dem Script und ist somit sofort Bedienbar.
 +
 +Die Datei:
 +  Datenpunkte/MQTT/mqtt_switch_relais"
 +
 +mit folgendem Inhalt:
 +<code php><?
 + include_once(IPS_GetScript(42011 )["ScriptFile"]);
 +
 + $d = true; $msg = "";
 + $value = ""; $run = true;
 +
 + if ($d){
 + $msg .= "Sender: ".$_IPS['SENDER']."\n";
 + $msg .= print_r($_IPS, true);
 + }
 +
 + if ($_IPS['SENDER'] == "Execute"){
 + //On Manual Execute check child events and set Event Trigger to "On Change"
 + foreach (IPS_GetChildrenIDs($_IPS['SELF']) as $key => $value){
 + if (IPS_GetObject($value)['ObjectType'] == 4){
 + IPS_SetEventTrigger($value, 1, IPS_GetEvent($value)['TriggerVariableID']);
 + }
 + }
 + } else {
 + if (($_IPS['SENDER'] == "WebFront") or ($_IPS['SENDER'] == "Variable")){
 + if ($_IPS['SENDER'] == "Variable"){
 + //$value = (GetValueBoolean($_IPS['VARIABLE'])?"true":"false");
 + $value = ($_IPS['VALUE']=="1"?"true":"false");
 + }
 + if (($_IPS['SENDER'] == "WebFront")){
 + $value = ($_IPS['VALUE']=="1"?"true":"false");
 + }
 +
 + if (($value == (GetValueBoolean($_IPS['VARIABLE'])?"true":"false")) and ($_IPS['SENDER'] != "Variable")){
 + if($d){ $msg .= "  Aktuell: >".$value."< alt: >".(GetValueBoolean($_IPS['VARIABLE'])?"true":"false")."<\n"; }
 + $run = false;
 + }
 +
 + if ($d){ 
 + $msg .= "  run: ".($run?"Ja":"Nein")."\n";
 + }
 +
 + $topic = explode(";",IPS_GetObject($_IPS['VARIABLE'])['ObjectInfo'])[1];
 +
 + if((strlen($topic) > 3) and ($run)){
 + if ($d){
 + $msg .= "  Veröffentliche: ".$value."\n"; 
 + $msg .= "    Variable: ".IPS_GetName($_IPS['VARIABLE'])."\n";
 + $msg .= "    Topic: ".$topic."\n";
 + $msg .= "    Value: ".$value."\n";
 + }
 + MQTT_Publish($idMQTTBroker , $topic ,$value ,1 , true);
 + }
 + }
 + }
 +   if(strlen($msg) > 0){
 +  IPS_LogMessage("mqtt_switch_relais", $msg);
 +  }
 +
 +?></code>
 +
 +
 +Das Eigentliche Script welces die Daten per RPC vom mqttwarn Daemon entgegennimmt und ablegt, in dem nicht Vergessen die ID's in den ersten Zeilen durch die Eigenen ersetzen:
 +
 +<code php> <?
 +$d = true; $msg = "";
 +//sample value: devices/terminal/helligkeit;319
 +// mqtt topic to symcon variable id mapping
 +$idParent = IPS_GetParent($_IPS['SELF']);
 +$archiveId = 32289;
 +$relaisScriptId = 17676; //Relais Script ID
 +
 +// get value from mqtt variable
 +if( array_key_exists("payload", $_IPS)){
 + $topic = $_IPS['topic']; 
 + $topics = explode("/", $topic);
 + $payload = $_IPS['payload'];
 + 
 + $payload = str_replace(array("\r", "\n"), '', $payload);
 + 
 + if ($d){ $msg .= "topic: $topic\npayload: $payload\n"; }
 + 
 + // Datentyp der payload herausfinden und ins Format für IPS Übersetzen
 + $contType = 99;
 + if (is_float($payload+0)){
 +   //Float
 + $contType = 2;
 + }
 + if (($contType == 99) and (is_numeric($payload))){
 +   //Integer
 + $contType = 1;
 + }
 + if (($contType == 99) and (is_string($payload))){
 + if ((strtolower($payload) == "true") or (strtolower($payload) == "false")){
 +    //Boolean
 +  $contType = 0;
 + } else {
 +    //String
 +  $contType = 3;
 + }
 + }
 + $idf = $idParent;
 + //Pfad durchlaufen und Prüfen ob die Kategorien / Variablen vorhanden sind und bei bedarf Anlegen
 + for($i = 0; $i < count($topics); $i++){
 + if ($i == (count($topics) -1)){
 +  $type = 2;
 + } else {
 +  $type = 0;
 + }
 + $idf = checkIfElementExists($idf, $type, $topics[$i], $contType);
 + }
 + 
 + if($d){
 +   $msg .= "Variablen Type. ".$contType."\n";
 +   $msg .= "Set Itend to: "."mqtt_".str_replace("/", "_", $topic)."\n";
 + }
 + 
 + IPS_SetIdent($idf, "mqtt_".str_replace("/", "_", $topic));
 + 
 + //mqset($idf, $payload);
 + SetValue($idf, $payload);
 +}
 +if ((strlen($msg) > 0) and ($d)){
 +   if($_IPS['SENDER'] == "Execute"){
 +      print $msg;
 +
 + IPS_LogMessage("mqtt-read-run", $msg);
 +}
 +
 +function isTrueFloat($val){
 +    $pattern = '/^[-+]?(((\\\\d+)\\\\.?(\\\\d+)?)|\\\\.\\\\d+)([eE]?[+-]?\\\\d+)?$/';
 +
 +    return (!is_bool($val) && (is_float($val) || preg_match($pattern, trim($val))));
 +}
 +
 +function mqset($id, $value){
 + Global $msg, $d;
 + if(GetValue($id) != $value){
 + switch(IPS_GetVariable($id)["VariableType"]){
 + case 0: // boolean
 + $val = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
 + if($d){ $msg .= "val: ".$val."\n"; }
 + SetValue($id, $val);
 + break;
 + case 1: // integer
 + $val = intval($value);
 + SetValue($id, $val);
 + break;
 + case 2: //  float
 + $val = floatval($value);
 + SetValue($id, $val);
 + break;
 + case 3: // string
 + SetValue($id, $value);
 + break;
 + }
 + }
 +}
 +
 +
 +function checkIfElementExists($varid, $type, $name, $contType ){
 + Global $archiveId, $topic, $relaisScriptId;
 + $exists = false;
 + if (IPS_HasChildren($varid)){
 + // Wenn Childs da sind alle durchlaufen
 + foreach (IPS_GetChildrenIDs($varid) as $key){
 + if (IPS_GetObject($key)["ObjectType"] == $type){
 + // Prüfen ob schon ein Objekt mit genau dem Namen existiert
 + if (IPS_GetObject($key)["ObjectName"] == $name){
 + // Dann nicht erstellen und die id merken
 + $exists = true;
 + $id = $key;
 + }
 + }
 + }
 + }
 + if (!$exists){
 +    if($type == 2){
 + //Wenn es eine Variable sein soll
 +    $id = IPS_CreateVariable($contType);
 + } else {
 + //Sonst ist es eine Kategorie
 +    $id = IPS_CreateCategory();
 + }
 + IPS_SetName($id, $name);
 +  IPS_SetParent($id, $varid);
 +  if($type == 2){ // Variable
 +   if ($contType == 0){ // Boolean
 +    if (strpos("   ".strtolower($name), "licht") > 0){
 +       //Wenn der Variablen Name das wort "licht" enthält das Profil Licht zuweisen
 +       IPS_SetVariableCustomProfile($id, "Licht");
 +       IPS_SetVariableCustomAction($id, $relaisScriptId);
 +    } elseif(strpos("   ".strtolower($name), "motion") > 0){
 +       IPS_SetVariableCustomProfile($id, "Motion");
 +    } elseif ($name == "connected"){
 +       IPS_SetVariableCustomProfile($id, "Connected");
 +    } else {
 +     //Wenn es eine Boolean Variable ist das Profile ~Switch zuweisen
 +     IPS_SetVariableCustomProfile($id, "~Switch");
 +     IPS_SetVariableCustomAction($id, $relaisScriptId);
 +     checkCreateEvent($id, $relaisScriptId);
 +    }
 +   }
 +   if (strpos("   ".strtolower($name), "temp") > 0){
 +      IPS_SetVariableCustomProfile($id, "~Temperature");
 +   }
 +   if (strpos("   ".strtolower($name), "humidity") > 0){
 +      IPS_SetVariableCustomProfile($id, "~Humidity");
 +   }
 +   if (strpos("   ".strtolower($name), "rssi") > 0){
 +      IPS_SetVariableCustomProfile($id, "rssi");
 +   }
 + IPS_SetInfo($id, "mqtt;$topic");
 + //Archivierung aktivieren
 +   AC_SetLoggingStatus($archiveId, $id, true);
 +   IPS_ApplyChanges($archiveId);
 + }
 +
 + return $id;
 +}
 +
 +function checkCreateEvent($varid , $scriptId){
 + $create = true;
 + if (IPS_HasChildren($varid)){
 + // Wenn Childs da sind alle durchlaufen
 +    foreach (IPS_GetChildrenIDs($varid) as $key){
 +       // Wenn diese Events sind
 +       if (IPS_GetObject($key)["ObjectType"] == 4){
 +          // Prüfen ob schon ein Event mit genau dem script existiert
 +          if (IPS_GetEvent($key)["TriggerVariableID"] == $script){
 +             // Sonst erstellen
 +             $create = false;
 +          }
 +       }
 +    }
 + } else {
 +    // Sonst erstellen
 +    $create = true;
 + }
 + if ($create){
 +  //Event Anlegen
 +  $eid = IPS_CreateEvent(0);                   //Ausgelöstes Ereignis
 + IPS_SetEventTrigger($eid, 1, $varid);        //Bei Variablenaktualisierung
 + IPS_SetParent($eid, $scriptId);              //Ereignis zuordnen
 + IPS_SetEventActive($eid, true);              //Ereignis aktivieren
 + }
 +}
 +?></code>
  
-==== Mosquitto (MQTT Broker) ==== +==== MQTT Broker (Mosquitto) ==== 
-  aptitude install mosquitto -y+  aptitude install mosquitto mosquitto-clients python-pip git -y
      
 ==== mqttwarn (mqtt daemon der alle Ereignisse zu Symcon weiterleitet) ==== ==== mqttwarn (mqtt daemon der alle Ereignisse zu Symcon weiterleitet) ====
 [[https://github.com/jpmens/mqttwarn/wiki/Setup|Installation aus der Wiki von hier]] [[https://github.com/jpmens/mqttwarn/wiki/Setup|Installation aus der Wiki von hier]]
 Abhängige Pakete Installieren: Abhängige Pakete Installieren:
-  pip install paho-mqtt+  pip install paho-mqtt jinja2
 Verzeichniss erstellen Verzeichniss erstellen
   cd /opt/   cd /opt/
Zeile 113: Zeile 385:
  
 [devices/#] [devices/#]
-targets = http:postIPS+targets = log:info, http:postIPS
 template = ipsrpc.json template = ipsrpc.json
 </code> </code>
Zeile 127: Zeile 399:
   vi ipsrpc.json    vi ipsrpc.json 
 mit folgendem Inhalt erstellen: mit folgendem Inhalt erstellen:
-<code>{% +<code>{% set data = { 
-    set data = { +                'method': "IPS_RunScriptEx", 
-        'method': "IPS_RunScriptEx", +                'params': [33107, { 'topic': topic, 'payload': payload } ], 
-        'params': [<id des verarbeitungs scriptes>, { 'payload': topic +";"payload } ], +                'jsonrpc': "2.0", 
-        'jsonrpc': "2.0", +                'id': '0' 
-        'id': '0' +        }
-    }+
 %} %}
 {{ data | jsonify }}</code> {{ data | jsonify }}</code>
Zeile 163: Zeile 434:
 2016-11-30 21:26:19,685 DEBUG [mqttwarn] Subscribing to devices/# (qos=0)</code> 2016-11-30 21:26:19,685 DEBUG [mqttwarn] Subscribing to devices/# (qos=0)</code>
  
-===== Symcon ===== 
-Nach der Installation von IPS dort in einer Kategorie z.b. Datenpunlte/MQTT/ ein neues Script mit folgendem Inhalt anlegen: 
-<code php><? 
-$d = false; $msg = ""; 
-//sample value: devices/terminal/helligkeit;319 
-// mqtt topic to symcon variable id mapping 
-$idParent = IPS_GetParent($_IPS['SELF']); 
-$archiveId = <archiv id> /*[Archive]*/; 
-$relaisScriptId = <id des Relais scripts> /*[Datenpunkte\MQTT\mqtt_switch_relais]*/; //Relais Script ID 
- 
- 
-// get value from mqtt variable 
-$var = $_IPS['payload'];  
-$varsplit = explode(";", $var); 
- 
-if(count($varsplit)>1){ 
- $topics = explode("/", $varsplit[0]); 
- $topic=$varsplit[0]; 
- $payload=$varsplit[1]; 
- $payload = str_replace(array("\r", "\n"), '', $payload); 
- 
- if ($d){ $msg .= "topic: $topic\npayload: $payload\n"; } 
- 
- // Datentyp der payload herausfinden und ins Format für IPS Übersetzen 
- $contType = 99; 
- if (is_float($payload+0)){ 
-    //Float 
- $contType = 2; 
- } 
- if (($contType == 99) and (is_numeric($payload))){ 
-    //Integer 
- $contType = 1; 
- } 
- if (($contType == 99) and (is_string($payload))){ 
- if ((strtolower($payload) == "true") or (strtolower($payload) == "false")){ 
-    //Boolean 
- $contType = 0; 
- } else { 
-    //String 
- $contType = 3; 
- } 
- } 
- $idf = $idParent; 
- //Pfad durchlaufen und Prüfen ob die Kategorien / Variablen vorhanden sind und bei bedarf Anlegen 
- for($i = 0; $i < count($topics); $i++){ 
- if ($i == (count($topics) -1)){ 
-         $type = 2; 
- } else { 
- $type = 0; 
- } 
- $idf = checkIfElementExists($idf, $type, $topics[$i], $contType); 
- } 
-  
- if($d){ 
-    $msg .= "Variablen Type. ".$contType."\n"; 
-    $msg .= "Set Itend to: "."mqtt_".str_replace("/", "_", $topic)."\n"; 
- } 
-  
- //IPS_SetIdent($idf, "mqtt;".$topic); 
- IPS_SetIdent($idf, "mqtt_".str_replace("/", "_", $topic)); 
-  
- //Wert Setzen 
- mqset($idf, $payload); 
-  
-} 
-if (strlen($msg) > 0){ 
-   if($_IPS['SENDER'] == "Execute"){ 
-      print $msg; 
- } else { 
- IPS_LogMessage("mqtt-read-run", $msg); 
- } 
-} 
-  
-function isTrueFloat($val){ 
-    $pattern = '/^[-+]?(((\\\\d+)\\\\.?(\\\\d+)?)|\\\\.\\\\d+)([eE]?[+-]?\\\\d+)?$/'; 
- 
-    return (!is_bool($val) && (is_float($val) || preg_match($pattern, trim($val)))); 
-} 
- 
-function mqset($id, $value){ 
- switch(IPS_GetVariable($id)["VariableType"]){ 
- case 0: // boolean 
- $val = filter_var($value, FILTER_VALIDATE_BOOLEAN); 
- SetValue($id, $val); 
- break; 
- case 1: // integer 
- $val = intval($value); 
- SetValue($id, $val); 
- break; 
- case 2: //  float 
- $val = floatval($value); 
- SetValue($id, $val); 
- break; 
- case 3: // string 
- SetValue($id, $value); 
- break; 
- } 
-} 
- 
- 
-function checkIfElementExists($varid, $type, $name, $contType ){ 
- Global $archiveId, $topic, $relaisScriptId; 
- $exists = false; 
- if (IPS_HasChildren($varid)){ 
- // Wenn Childs da sind alle durchlaufen 
- foreach (IPS_GetChildrenIDs($varid) as $key){ 
- if (IPS_GetObject($key)["ObjectType"] == $type){ 
- // Prüfen ob schon ein Objekt mit genau dem Namen existiert 
- if (IPS_GetObject($key)["ObjectName"] == $name){ 
- // Dann nicht erstellen und die id merken 
- $exists = true; 
- $id = $key; 
- } 
- } 
- } 
- } 
- if (!$exists){ 
-    if($type == 2){ 
- //Wenn es eine Variable sein soll 
-    $id = IPS_CreateVariable($contType); 
- } else { 
- //Sonst ist es eine Kategorie 
-    $id = IPS_CreateCategory(); 
- } 
- IPS_SetName($id, $name); 
-    IPS_SetParent($id, $varid); 
-    if($type == 2){ // Variable 
-       if ($contType == 0){ // Boolean 
-          if (strpos("   ".strtolower($name), "licht") > 0){ 
-             //Wenn der Variablen Name das wort "licht" enthält das Profil Licht zuweisen 
-             IPS_SetVariableCustomProfile($id, "Licht"); 
-             IPS_SetVariableCustomAction($id, $relaisScriptId); 
- } elseif(strpos("   ".strtolower($name), "motion") > 0){ 
-    IPS_SetVariableCustomProfile($id, "Motion"); 
- } elseif ($name == "connected"){ 
-    IPS_SetVariableCustomProfile($id, "Connected"); 
-          } else { 
- //Wenn es eine Boolean Variable ist das Profile ~Switch zuweisen 
-           IPS_SetVariableCustomProfile($id, "~Switch"); 
-           IPS_SetVariableCustomAction($id, $relaisScriptId); 
- checkCreateEvent($id, $relaisScriptId); 
- } 
- } 
-    if (strpos("   ".strtolower($name), "temp") > 0){ 
-       IPS_SetVariableCustomProfile($id, "~Temperature"); 
-    } 
-    if (strpos("   ".strtolower($name), "humidity") > 0){ 
-       IPS_SetVariableCustomProfile($id, "~Humidity"); 
-    } 
-    if (strpos("   ".strtolower($name), "rssi") > 0){ 
-       IPS_SetVariableCustomProfile($id, "rssi"); 
-    } 
- IPS_SetInfo($id, "mqtt;$topic"); 
- //Archivierung aktivieren 
-       AC_SetLoggingStatus($archiveId, $id, true); 
-    IPS_ApplyChanges($archiveId); 
- } 
- 
- return $id; 
-} 
- 
-function checkCreateEvent($varid , $scriptId){ 
- $create = true; 
- if (IPS_HasChildren($varid)){ 
- // Wenn Childs da sind alle durchlaufen 
-    foreach (IPS_GetChildrenIDs($varid) as $key){ 
-       // Wenn diese Events sind 
-       if (IPS_GetObject($key)["ObjectType"] == 4){ 
-          // Prüfen ob schon ein Event mit genau dem script existiert 
-          if (IPS_GetEvent($key)["TriggerVariableID"] == $script){ 
-             // Sonst erstellen 
-             $create = false; 
-          } 
-       } 
-    } 
- } else { 
-    // Sonst erstellen 
-    $create = true; 
- } 
- if ($create){ 
-    //Event Anlegen 
-      $eid = IPS_CreateEvent(0);                   //Ausgelöstes Ereignis 
- IPS_SetEventTrigger($eid, 0, $varid);        //Bei Änderung von Variable 
- IPS_SetParent($eid, $scriptId);                 //Ereignis zuordnen 
- IPS_SetEventActive($eid, true);              //Ereignis aktivieren 
- } 
-} 
-?></code> 
- 
-hier noch das switch Script damit sind "boolean" Datenpunkte (einfach "True" oder "False" beim ersten schreiben in dem mqtt broker erstellt die Variable in Symcon und verlinkt diese mit dem Script und ist somit sofort Bedienbar. 
- 
-<code php><? 
- $d = false; $msg = ""; 
- $value = ""; $run = true; 
- if ($d){ $msg .= "Sender: ".$_IPS['SENDER']."\n"; } 
- //if (($_IPS['SENDER'] == "Variable") or ($_IPS['SENDER'] == "WebFront")){ 
- if ($_IPS['SENDER'] == "Variable"){ 
-    $value = GetValue($_IPS['VARIABLE']); 
-    if ($value == $_IPS['OLDVALUE']){ 
-       $msg .= "Value: X".$value."X old: X".$_IPS['OLDVALUE']."X\n"; 
-       $run = false; 
-    } 
- } 
- if (($_IPS['SENDER'] == "WebFront")){ 
-    $value = $_IPS['VALUE']; 
- } 
- if ($d){ $msg .= "Value: ".$value."\n"; } 
- $id = $_IPS['VARIABLE']; 
- $topic = explode(";",IPS_GetObject($id)['ObjectInfo'])[1]; 
- if((strlen($topic) > 3) and ($run)){ 
- switch(IPS_GetVariable($id)['VariableType']){ 
-    case 0: //boolean 
-       if($value == 1){ $value = "true"; } else { $value = "false"; } 
-       break; 
- case 1: //Integer 
- 
-    break; 
- case 2: //float 
- 
-    break; 
- case 3: //string 
- 
-    break; 
- } 
- if($d){ $msg .= "veröffentliche: ".$value."\n"; } 
- MQTT_Publish(50729 /*[MQTT_Localhost]*/, $topic ,$value ,1 , true); 
- } 
- 
-  if ($d){ $msg .= "Variable: ".IPS_GetName($id)."\nTopic: ".$topic."\n Value: ".$value."\n"; } 
-   
-   if(strlen($msg) > 0){ 
-  IPS_LogMessage("mqtt_switch_relais", $msg); 
-  } 
- 
-?></code> 
  
Recent changes RSS feed Creative Commons License Donate Minima Template by Wikidesign Driven by DokuWiki