<?php
class GeneralData {
public function __construct($data) {
$this->{'va_rating'} = trim(substr($data, 21, 6));
$this->{'model'} = trim(substr($data, 27, 14));
$this->{'producer'} = trim(str_replace('\x00', ' ', substr($data, 41, 49)));
$this->{'serial_number'} = trim(str_replace('\x00', ' ', substr($data, 90, 32)));
$this->{'soft_ver_com'} = trim(str_replace('\x00', ' ', substr($data, 122, 6)));
$this->{'soft_ver_master_cpu'} = trim(str_replace('\x00', ' ', substr($data, 128, 6)));
$this->{'soft_ver_slave_cpu'} = trim(str_replace('\x00', ' ', substr($data, 134, 6)));
}
}
class StatusData {
public function __construct($data) {
$unp = unpack('nNNnnCnnnnNNnnnnnnNNnN', substr($data, 10));
$this->{'counter'} = unpack("n", substr($data, 10, 2))[1];
$this->{'today_generation'} = unpack("n", substr($data, 61, 2))[1];
$this->{'pv_ampere1'} = unpack("n", substr($data, 25, 2))[1];
$this->{'pv_ampere2'} = unpack("n", substr($data, 27, 2))[1];
$this->{'pv_input1'} = unpack("n", substr($data, 29, 2))[1];
$this->{'pv_input2'} = unpack("n", substr($data, 31, 2))[1];
$this->{'grid_voltage'} = unpack("n", substr($data, 43, 2))[1];
$this->{'grid_frequency'} = unpack("n", substr($data, 45, 2))[1];
$this->{'grid_current'} = unpack("n", substr($data, 47, 2))[1];
$this->{'amb_temp'} = unpack("n", substr($data, 51, 2))[1];
$this->{'total_generation'} = unpack("N", substr($data, 53, 4))[1];
$this->{'running_time'} = unpack("N", substr($data, 57, 4))[1];
$this->{'output_power'} = unpack("N", substr($data, 63, 4))[1];
}
}
function _sum($data) {
$res = 0;
for($i = 0, $len=strlen($data); $i < $len; $i++) $res += ord($data[$i]);
return $res;
}
function validate_checksum($msg) {
$data_len = strlen($msg);
$msg_sum = unpack("n", substr($msg, $data_len - 2, 2))[1];
$actual_sum = _sum(substr($msg, 0, $data_len - 2));
return $msg_sum == $actual_sum;
}
function interpret_general_data($data) {
if(unpack("n" ,$data)[1] != 0x55aa) return "INVALID GENERAL DATA";
if($data && validate_checksum($data)) return new GeneralData($data);
return null;
}
function interpret_status_data($data) {
if(unpack("n" ,$data)[1] != 0x55aa) return "INVALID STATUS DATA";
if($data && validate_checksum($data)) return new StatusData($data);
return null;
}
function broadcast_message($port, $msg) {
$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($s, SOL_SOCKET, SO_BROADCAST, 1);
socket_sendto($s, $msg, strlen($msg), 0, '255.255.255.255', $port);
socket_close($s);
}
function request_general_data($conn) {
$data=hex2bin("55AA001101000000000000000280010000007A020E");
socket_send($conn, $data, strlen($data), 0);
time_nanosleep(0, 250000000);
return socket_read($conn, 1024, PHP_BINARY_READ);
}
function request_status_data($conn){
$data=hex2bin("55AA0011010000000000000102800103E8004A02CA");
socket_send($conn, $data, strlen($data), 0);
time_nanosleep(0, 250000000);
return socket_read($conn, 1024, PHP_BINARY_READ);
}
function collect_data($verbose = false){
$TCP_PORT = 60001 /*[Objekt #60001 existiert nicht]*/;
$UDP_PORT1 = 1300;
$UDP_PORT2 = 60000 /*[Objekt #60000 existiert nicht]*/;
$s = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($s, '0', $TCP_PORT);
socket_set_option($s, SOL_SOCKET, SO_RCVTIMEO, ["sec" => 5, "usec" => 0]);
broadcast_message($UDP_PORT1, hex2bin("55aa004002000b4920414d20534552564552043a"));
broadcast_message($UDP_PORT2, hex2bin("55aa000c010000000007000000000113"));
if(socket_listen($s, 1)) {
$retries = 10;
socket_set_nonblock($s);
if($verbose) IPS_LogMessage('SolarSystem', "waiting for connection...");
for(;;){
if(!$conn = socket_accept($s)) {
if($retries == 0) {
break;
}
$retries--;
time_nanosleep(0, 900000000);
if($verbose) IPS_LogMessage('SolarSystem', "sleep 1 sec");
continue;
}
else {
socket_set_block($conn);
$general_data = interpret_general_data(request_general_data($conn));
sleep(1);
$status_data = interpret_status_data(request_status_data($conn));
// if everything is ok, then at this point you have $general_data and $status_data that holds your data
// the classes are defined at the top of the script
//var_dump($general_data);
SetValueInteger(22892 /*[Energie\SolarSystem\Max DC Power]*/, $general_data->va_rating);
SetValueString(47748 /*[Energie\SolarSystem\Model name]*/, $general_data->model);
SetValueString(33669 /*[Energie\SolarSystem\Manufacturer]*/, $general_data->producer);
SetValueString(52120 /*[Energie\SolarSystem\Serial number]*/, $general_data->serial_number);
SetValueString(27809 /*[Energie\SolarSystem\Software version [COM]]*/, $general_data->soft_ver_com);
SetValueString(31265 /*[Energie\SolarSystem\Software version [Master CPU]]*/, $general_data->soft_ver_master_cpu);
SetValueString(42070 /*[Energie\SolarSystem\Software version [Slave CPU]]*/, $general_data->soft_ver_slave_cpu);
//var_dump($status_data);
SetValueInteger(16847 /*[Energie\SolarSystem\Running time]*/, $status_data->running_time);
SetValueFloat(56533 /*[Energie\SolarSystem\Output Power]*/, $status_data->output_power);
SetValueFloat(49228 /*[Energie\SolarSystem\Today generation]*/, $status_data->today_generation*0.01);
SetValueFloat(23825 /*[Energie\SolarSystem\PV1 current]*/, $status_data->pv_ampere1 *0.1);
SetValueFloat(20956 /*[Energie\SolarSystem\PV2 current]*/, $status_data->pv_ampere2 *0.1);
//SetValueFloat(49541 /*[Energie\SolarSystem\PV1 voltage]*/, $status_data->pv_input1);
//SetValueFloat(21275 /*[Energie\SolarSystem\PV2 voltage]*/, $status_data->pv_input2);
SetValueFloat(18456 /*[Energie\SolarSystem\PV1 input power]*/, $status_data->pv_input1);
SetValueFloat(14381 /*[Energie\SolarSystem\PV2 input power]*/, $status_data->pv_input2);
//SetValueFloat(49228 /*[Energie\SolarSystem\Today generation]*/, $status_data->grid_voltage);
//SetValueFloat(49228 /*[Energie\SolarSystem\Today generation]*/, $status_data->grid_frequency);
//SetValueFloat(49228 /*[Energie\SolarSystem\Today generation]*/, $status_data->grid_current);
//SetValueFloat(49228 /*[Energie\SolarSystem\Today generation]*/, $status_data->amb_temp);
SetValueFloat(34316 /*[Energie\SolarSystem\Total generation]*/, $status_data->total_generation* 0.1);
//Gesamtstrom mit Solar
SetvalueFloat(29015 /*[Energie\Gesamtstrom mit Solar]*/, Getvalue(13659 /*[Energie\EKM-868 (Gesamtstrom)\Current]*/)-Getvalue(56533 /*[Energie\SolarSystem\Output Power]*/));
// cleanup accepted socket
socket_shutdown($conn, 2);
socket_close($conn);
break;
}
}
IPS_LogMessage('SolarSystem', "No one connected");
}
else IPS_LogMessage('SolarSystem', "listen returned error: ".socket_strerror(socket_getlast_error($s))."
");
// close listening socket
socket_close($s);
}
$DECODE_TEST = false;
if($DECODE_TEST) {
// test data
$TEST_STATUS_DATA = hex2bin("55AA005B010000000003000103800103E8004A01E00D7A11A7001E0008040E01820172001508CA1386001508CE1386001408D5138600007B21000005690067000004FA00010000000000000000000000000000000000000000000000000D64");
$TEST_GENERAL_DATA = hex2bin("55AA008B01000000000300000380010000007A0032202037303030534C20202037303030544C2D504D20202020202020202020202020202020002053616D696C506F77657200202020202020202020202020202020202020202020543032313435433037310000000000000000000000000000000000000000000056322E30302056322E30302056322E3030201585");
//echo validate_checksum($TEST_STATUS_DATA);
//echo validate_checksum($TEST_GENERAL_DATA);
var_dump(interpret_general_data($TEST_GENERAL_DATA));
var_dump(interpret_status_data($TEST_STATUS_DATA));
}
else
collect_data();
?>