Hallo an alle,
durch die Diskussion mit honk0504, in diesem Thread, habe ich das Script komplett neu überarbeitet. Dank an Ihn für den Beta Test.
Vorraussetzung ist IPS-Version ab 2.7
-neu: Automatisches Anlegen aller im Datensatz übergebenen Variablen, unter einem Dummy Modul.
-neu: Variablen werden über einen eindeutigen IDENT angesprochen.
-neu: Unterstützung aller RESOL-Regler.
-neu: Bekannte Variablenprofile werden ausgewählt.
-fix: Negative Werte werden richtig berrechnet.
Aufgebaut habe ich das Script auf einer XML Datei die in der RESOL Service Center Software enthalten ist.
Diese Software kann auf der Resol Seite kostenlos heruntergeladen werden.
LINK
EDIT 01.05.2020
Ich habe das Script nochmalig überarbeitet.
-neu: IPS Version muss mindestens 2.7 statt 2.5 sein
-neu: Automatisches Erstellen von I/O Instance, Cutter, RegisterVariable (Installer)
-neu: Einstellbarer ScriptTimer
-neu: TCP oder RS232 Schnittstelle
-neu: Unterstützte BitSize 31 und 32
-neu: Variablen Info wird mit „Common Usage“ beschrieben
-neu: Englische Variablennamen per Option auswählbar
Installation:
- die angehängte ZIP Datei entpacken und die enthaltenen XML Datei ins Script Verzeichnis kopieren.
- das Script anlegen
- Inhalt hineinkopieren
- Konfiguration anpassen
- Einmalig manuell ausführen, nur dann werden alle nötigen Instanzen angelegt
- Fertig
<?
/*
WICHTIG !! Zur Verarbeitung ist die Datei "VBusSpecificationResol.xml" im Scripts Verzeichnis nötig !!
WICHTIG !! mindestens IPS_Version 2.7 ist notwendig!!
Dieses Script dient zum Empfang von Daten über den "V-Bus".
Die Daten werden entsprechend ihrer Bedeutung aufbereitet und in IPS Variablen abgelegt.
Die Variablennamen können umbennant werden, müssen aber unter dem angelegtem Dummymodul bleiben.
Bekannte Formate bekommen automatisch ein Variablenprofil, alle anderen müssen manuell eines zugewiesen bekommen.
Protokollinformationen sind unter : http://goo.gl/HP6ZY zu finden.
Weitere Infos : http://groups.google.com/group/resol-vbus/
Copyright (c) 2010-2020 Attain
Link http://www.ip-symcon.de/forum/f23/vbus-protokoll-resol-solarregler-11700/
Version 1.2.2
Datum 13.05.2020
Changelog:
V1.0 01.10.2010
first release
V1.1 11.02.2012
auslesen der spezifischen reglerdaten aus der XML Datei
automatisches Variablen erstellen, per Ident angesprochen
Dummy Modul wird erstellt
Automatisches Anlegen von Varprofilen
V1.2 01.05.2020
IPS Version muss mindestens 2.7 statt 2.5 sein
Automatisches Erstellen von I/O Instance, Cutter, RegisterVariable(Installer)
TCP oder RS232 Schnittstelle
Unterstützte BitSize 31 und 32
Variablen Info wird mit "Common Usage" beschrieben
Englische Variablennamen per Option auswählbar
V1.2.1 03.05.2020
fix Varprofil Zuordnung
V1.2.2 13.05.2020
fix Varprofil Sonderzeichen
ToDo PHP Modul erstellen
+----------------------------------------------------------------------+
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
+----------------------------------------------------------------------+
*/
########## Konfigurationsteil #####################
$debug = false; // zur Fehlersuche auf TRUE setzen
$socket = "TCP"; // Art des Adapter, TCP oder RS232
$timer = 0; // Abstand in sekunden, in der Daten empfangen werden sollen | 0 = Timer deaktiviert, Port bleibt immer offen, Alle Daten werden verarbeitet
$language = 0; // Variablennamen | 0 = Deutsch | 1 = English
//nur TCP
$ip_address = "192.168.123.110"; // IP Adresse des LAN Adapter
$ip_port = 7053; // Kommunikationsport
$passwort = "vbus"; // passwort zur Abfrage der Daten mit dem LAN Adapter, standart: vbus
// nur RS232
$com_port = "COM4"; // Serieller Port
########## Installer ###########################
if ($socket == "TCP") $IOid = ATN_GetInstanceIDbyIdent("{3CFF0FD9-E306-41DB-9B5A-9D06D38576C3}","RESOL_IO");
elseif ($socket == "RS232") $IOid = ATN_GetInstanceIDbyIdent("{3CFF0FD9-E306-41DB-9B5A-9D06D38576C3}","RESOL_IO");
else IPS_LogMessage("RESOL-VBUS-SCRIPT ".$_IPS['SELF'], $socket . " ist keine gültige Schnittstelle");
if ($_IPS['SENDER'] == "Execute")
{
if (IPS_GetKernelVersion()<2.7)
{
IPS_LogMessage("RESOL-VBUS-SCRIPT ".$_IPS['SELF'], "Script ist erst ab Version 2.7 lauffähig");
return;
}
if ($socket == "TCP")
{
if (!$IOid) // client socket instance does not exist -> create
{
$IOid = IPS_CreateInstance("{3CFF0FD9-E306-41DB-9B5A-9D06D38576C3}");
IPS_SetIdent($IOid,"RESOL_IO");
IPS_SetName($IOid,"Client Socket (Resol)");
}
IPS_SetConfiguration($IOid,'{"Open":true,"Host":"' . $ip_address . '","Port":'. $ip_port . '}');
IPS_ApplyChanges($IOid);
CSCK_SendText($IOid,"PASS " . $passwort . CHR(13));
CSCK_SendText($IOid,"DATA".CHR(13));
}
elseif($socket == "RS232")
{
if (!$IOid) // serial instance does not exist -> create
{
$IOid = IPS_CreateInstance("{6DC3D946-0D31-450F-A8C6-C42DB8D7D4F1}");
IPS_SetIdent($IOid,"RESOL_IO");
IPS_SetName($IOid,"Serial Port (Resol)");
}
IPS_SetConfiguration($IOid,'{"Open":true,"Port":"' . $com_port . '","BaudRate":"9600","DataBits":"8","StopBits":"1","Parity":"None"}');
IPS_ApplyChanges($IOid);
}
// Cutter
$Cutterid = ATN_GetInstanceIDbyIdent("{AC6C6E74-C797-40B3-BA82-F135D941D1A2}","RESOL_CUTTER");
if (!$Cutterid) // nicht vorhanden, anlegen
{
$Cutterid = IPS_CreateInstance("{AC6C6E74-C797-40B3-BA82-F135D941D1A2}");
IPS_SetName($Cutterid,"Cutter (Resol)");
IPS_SetIdent($Cutterid,"RESOL_CUTTER");
}
IPS_SetConfiguration($Cutterid,'{"ParseType":0,"LeftCutChar":"AA 10","LeftCutCharAsHex":true,"RightCutChar":"AA","RightCutCharAsHex":true,"DeleteCutChars":false,"InputLength":0,"SyncChar":"","SyncCharAsHex":false,"Timeout":1000}');
If (IPS_GetInstance($Cutterid)['ConnectionID'] != $IOid)
{
@IPS_DisconnectInstance ($Cutterid);
IPS_ApplyChanges($Cutterid);
}
@IPS_ConnectInstance($Cutterid, $IOid);
IPS_ApplyChanges($Cutterid);
// Register Variable
$Registerid = ATN_GetInstanceIDbyIdent("{F3855B3C-7CD6-47CA-97AB-E66D346C037F}","RESOL_REGISTER_VARIABLE");
if(!$Registerid) // nicht vorhanden, anlegen
{
$Registerid = IPS_CreateInstance("{F3855B3C-7CD6-47CA-97AB-E66D346C037F}");
IPS_SetName($Registerid,"RegisterVariable (Resol)");
IPS_SetIdent($Registerid,"RESOL_REGISTER_VARIABLE");
IPS_SetParent($Registerid,$_IPS['SELF']);
}
IPS_SetConfiguration($Registerid,'{"RXObjectID":' . $_IPS['SELF'] . '}');
If (IPS_GetInstance($Registerid)['ConnectionID'] != $Cutterid)
{
@IPS_DisconnectInstance ($Registerid);
IPS_ApplyChanges($Registerid);
}
@IPS_ConnectInstance($Registerid, $Cutterid);
IPS_ApplyChanges($Registerid);
IPS_SetScriptTimer($_IPS['SELF'],$timer);
return;
} // End Execute
################ Timer #############################
if ($_IPS['SENDER'] == "TimerEvent")
{
if (!IPS_GetProperty($IOid,"Open")) // Port geschlossen ?
{
IPS_SetProperty($IOid,"Open",true); // Datenport einschalten
IPS_ApplyChanges($IOid);
}
if ($socket == "TCP")
{
CSCK_SendText($IOid,"PASS " . $passwort . CHR(13));
CSCK_SendText($IOid,"DATA".CHR(13));
}
return;
}
################ Datenempfang #####################################
if ($_IPS['SENDER'] == "RegisterVariable")
{
########## Definition von Konstanten ##############
define('ANZAHL_FRAMES', ord($_IPS['VALUE']{6}));
define('HEADER_CHECKSUMME', ord($_IPS['VALUE']{7}));
define('REGLER_TYP', "0x" . dechex(ord($_IPS['VALUE']{2})) . dechex(ord($_IPS['VALUE']{1} )));
define('SCRIPT_KENNUNG', 'V-Bus-Script ID : ' . $_IPS['SELF']);
define('XML_DATEI', 'VBusSpecificationResol.xml');
if ($debug) IPS_LogMessage(SCRIPT_KENNUNG,REGLER_TYP);
############ Scriptteil ###########################
$cs = 16; // durch den Cutter wird das erste Byte (0x10 Hex) abgeschnitten, hier wird der Wert wieder dazu genommen
for ($i=00; $i<=06; $i++)
{
$cs += ord($_IPS['VALUE']{$i}); //Headerbytes zur Checksumme zusammenaddieren
}
$cs = ~$cs; //Checksumme invertieren
$cs &= 127; //MSB aus Checksumme entfernen
if ($debug) IPS_LogMessage(SCRIPT_KENNUNG,"Berrechnete Checksumme Header: $cs , Empfangene Checksumme: " . HEADER_CHECKSUMME);
if ( $cs == HEADER_CHECKSUMME) // Checksumme ok?
{
if ($debug) IPS_LogMessage(SCRIPT_KENNUNG,"HeaderChecksumme OK!");
$byte_array = array();
$k = 0; // array Index
if ($debug) IPS_LogMessage(SCRIPT_KENNUNG,"Anzahl der ermittelten Frames: " . ANZAHL_FRAMES);
for ($i=01; $i<=ANZAHL_FRAMES; $i++) // Schleife für alle Datenframes
{
$cs = 0;
$septet = ord($_IPS['VALUE']{$i * 6 + 6});
for ($j=00; $j<=03; $j++)
{ // es sind immer 4 Bytes in einem Frame
$payload_byte = ord($_IPS['VALUE']{$i * 6 + 2 + $j});
$byte_array[$k] = $payload_byte + 128 * (($septet >> $j) & 1); //das komplette Datenbyte aus dem Byte und dem Teil des Septet zusammenfügen
$k++; //Array Index erhöhen
$cs += $payload_byte;// Bytes zur Checksumme addieren
} // End payload Byte Schleife
$cs += $septet; // septet dazuaddieren
$cs = ~$cs; //Checksumme invertieren
$cs &= 127; //MSB aus Checksumme entfernen
if ($debug) IPS_LogMessage(SCRIPT_KENNUNG,"Berrechnete Checksumme Frame $i: $cs , Empfangene Checksumme: ".ord($_IPS['VALUE']{$i * 6 + 7}));
if ($cs != ord($_IPS['VALUE']{$i * 6 + 7})) // Checksumme Frame not ok?
{
IPS_LogMessage(SCRIPT_KENNUNG,"Checksummenfehler im Frame $i >> ermittelte Summe: $cs empfangene Summe: ".ord($_IPS['VALUE']{$i * 6 + 7}));
return;
}
} // end for frameschleife
}
else // Checksumme Head not ok
{
IPS_LogMessage(SCRIPT_KENNUNG,"Checksummenfehler Header >>Checksumme berrechnet: $cs Checksumme soll: ".ord($_IPS['VALUE']{7}));
return;
} // end else
if ($debug) IPS_LogMessage(SCRIPT_KENNUNG,print_r($byte_array));
########################################################################
if (file_exists(XML_DATEI))
{
$xml = simplexml_load_file(XML_DATEI);
// print_r($xml);
### Regler Typ in der XML Datei suchen ###
foreach($xml->device as $master)
{
if ($master->address == REGLER_TYP)
{
$regler_name = (string)$master->name;
if ($debug) IPS_LogMessage(SCRIPT_KENNUNG,$regler_name);
break; // end foreach
} // end if
} //end foreach
if (!isset($regler_name))
{
IPS_LogMessage(SCRIPT_KENNUNG,REGLER_TYP . " wurde nicht in der XML Datei gefunden!");
}
### dummy instance ### ggf. anlegen ###
$parentobject = IPS_GetObject($_IPS['SELF']);
$parentID = $parentobject['ParentID'];
if (IPS_GetObject($parentID)['ObjectType'] !== 1)
{
$parentID = IPS_CreateInstance("{485D0419-BE97-4548-AA9C-C083EB82E61E}");
IPS_SetParent($parentID, $parentobject['ParentID']);
IPS_SetParent($_IPS['SELF'], $parentID);
IPS_SetHidden($_IPS['SELF'], true);
IPS_SetName ($parentID, $regler_name);
IPS_SetIcon ($parentID, "Sun");
}
### Regler
foreach($xml->packet as $master)
{
if ($master->source == REGLER_TYP) // passenden Regler in der Datei gefunden
{
//print_r($master);
foreach($master->field as $field)
{
$field_name = (string)($field->name[$language]); // 0 = deutsch 1 = englisch
$field_info = (string)$field['commonUsage'][0];
$field_unit = (string)$field->unit;
$field_bit_size = (int)$field->bitSize;
$var_profil = "";
if ($field_bit_size == 1)
{
$var_type = 0; // 0 ^ bool
}
elseif ((float)$field->factor < 1 && (float)$field->factor > 0)
{
$var_type = 2; // ^ float
}
else // kein factor oder factor >= 1
{
$var_type = 1; // ^ integer
}
if (isset($field->field->offset)) // es gibt mehrere unterwerte
{
$var_value = 0;
foreach($field->field as $child_field)
{
$field_offset = (int)$child_field->offset;
$field_factor = (float)$child_field->factor;
$var_value += ($byte_array[$field_offset] + 256 * $byte_array[$field_offset+1])* $field_factor;
}
}
else // nur 1 unterwert
{
$field_offset = (int)$field->offset;
if (isset($field->factor))
{
$field_factor = (float)$field->factor;
}
else // wenn kein factor angegeben ist
{
$field_factor = 1;
}
switch ($field_bit_size)
{
case 32:
$var_value = $byte_array[$field_offset] + (2**8) * $byte_array[$field_offset+1] + (2**16) * $byte_array[$field_offset+2] + (2**24) * $byte_array[$field_offset+3];
$var_value *= $field_factor;
break;
case 31:
$var_value = $byte_array[$field_offset] + (2**8) * $byte_array[$field_offset+1] + (2**16) * $byte_array[$field_offset+2] + (2**24) * $byte_array[$field_offset+3];
$var_value -= ((2**32)*($var_value >> 31)); // wenn bit 31 == true , Wert ist negativ
$var_value *= $field_factor;
break;
case 16:
$var_value = $byte_array[$field_offset] + (2**8) * $byte_array[$field_offset+1];
$var_value *= $field_factor;
break;
case 15:
$var_value = $byte_array[$field_offset] + 2**8 * $byte_array[$field_offset+1];
$var_value -= ((2**16)*($var_value >> 15)); // wenn bit 15 == true , Wert ist negativ
$var_value *= $field_factor;
break;
case 8:
$var_value = $byte_array[$field_offset];
break;
case 7:
$var_value = $byte_array[$field_offset];
$var_value -= ((2**8)*($var_value >> 7)); // wenn bit 7 == true , Wert ist negativ
break;
case 1:
$field_bit = $field->bitPos;
$var_value = (($byte_array[$field_offset] >> $field_bit) & 1);
$var_profil = "~Switch";
break;
} // END Switch
} //end else
if ((string)$field->format == "t") // Systemzeit
{
$var_value = mktime(0,$var_value,0);
$var_profil = "~UnixTimestamp";
}
if ((string) $field_unit == " °C") // Temperaturen
{
$var_profil = "~Temperature";
}
if ($field_unit == " %") // Drehzahlen
{
$var_profil = "~Intensity.100";
}
if ($debug) echo "|" .$var_profil . "|" . $field_unit . "|
";
if ($var_profil == "" && $field_unit != "") {$var_profil = ATN_CreateVariableProfile($var_type, $field_unit, $field_bit_size);}
$var_ident = REGLER_TYP . $field_offset . (string)$field->bitPos; // eindeutigen IDENT erzeugen
$position = (int) $field_offset . (string)$field->bitPos;
if ($debug) IPS_LogMessage(SCRIPT_KENNUNG,$field_name . " " . $field_offset . " ".$var_value . " ".$field_unit);
$var_id = CreateVariableByName($parentID, $field_name, $var_type, $var_ident, $var_profil, $position, $field_info);
if (GetValue($var_id) != $var_value) SetValue($var_id,$var_value); // Wert in Variable abspeichern. Nur neue.
}
break; //foreach beenden
} // end if
} //end foreach
} //end if
else
{
IPS_LogMessage(SCRIPT_KENNUNG,'Konnte Datei ' . XML_DATEI . ' nicht laden.');
}
if ($timer) // nur wenn timer aktiv, port schliessen
{
IPS_SetProperty($IOid, "Open", false); // Datenport ausschalten
IPS_ApplyChanges($IOid);
}
}
// Geguttenbergt by paresy
function CreateVariableByName($id, $name, $type, $ident, $profile = "", $position = 0, $info = "")
{
$vid = @IPS_GetObjectIDByIdent ($ident, $id);
if($vid === false)
{
$vid = IPS_CreateVariable($type);
IPS_SetParent($vid, $id);
IPS_SetName($vid, $name);
IPS_SetIdent($vid, $ident);
IPS_SetPosition($vid, $position);
IPS_SetInfo($vid, $info);
if($profile !== "") IPS_SetVariableCustomProfile($vid, $profile);
}
return $vid;
}
function ATN_GetInstanceIDbyIdent($guid,$ident) // check if instance already exist
{
$Instance = IPS_GetInstanceListByModuleID($guid);
foreach ($Instance as $IOid)
{
$object = IPS_GetObject($IOid);
if ($object['ObjectIdent'] == $ident)
{
return ($IOid); // found instance with ident
}
}
return(false); //instance does not exist
}
function ATN_CreateVariableProfile($var_type, $field_unit, $field_bit_size)
{
$Maximalwert = 2** (int)$field_bit_size;
$profil_name = "Resol" . $field_unit;
// keine Sonderzeichen im Var-Profilname zulässig
$profil_name = preg_replace ( '/[^a-z0-9]/i', '_', $profil_name );
if (!@IPS_GetVariableProfile($profil_name))
{
IPS_CreateVariableProfile($profil_name, $var_type);
IPS_SetVariableProfileText($profil_name, "", $field_unit);
IPS_SetVariableProfileValues ($profil_name, 0, $Maximalwert, 1);
}
return $profil_name;
}
?>
EDIT 11.05.2020
XML Datei war fehlerhaft - erneuert
Gruß und Danke
Attain
VBusSpecificationResol.zip (28.4 KB)