2012-04-24 11:03:38 +00:00
|
|
|
|
################################################################
|
|
|
|
|
#
|
|
|
|
|
# Copyright notice
|
|
|
|
|
#
|
|
|
|
|
# (c) 2012 Torsten Poitzsch (torsten.poitzsch@gmx.de)
|
2012-04-29 18:11:46 +00:00
|
|
|
|
# (c) 2012 Jan-Hinrich Fessel (oskar@fessel.org)
|
2012-04-24 11:03:38 +00:00
|
|
|
|
#
|
|
|
|
|
# This script is free software; you can redistribute it and/or modify
|
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
# (at your option) any later version.
|
|
|
|
|
#
|
|
|
|
|
# The GNU General Public License can be found at
|
|
|
|
|
# http://www.gnu.org/copyleft/gpl.html.
|
|
|
|
|
# A copy is found in the textfile GPL.txt and important notices to the license
|
|
|
|
|
# from the author is found in LICENSE.txt distributed with these scripts.
|
|
|
|
|
#
|
|
|
|
|
# This script is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
|
#
|
|
|
|
|
# This copyright notice MUST APPEAR in all copies of the script!
|
|
|
|
|
#
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
##############################################
|
|
|
|
|
package main;
|
|
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
|
use warnings;
|
|
|
|
|
use IO::Socket;
|
|
|
|
|
|
2012-04-29 18:11:46 +00:00
|
|
|
|
my $cc; # The Itmes Changed Counter
|
|
|
|
|
|
2012-04-24 11:03:38 +00:00
|
|
|
|
sub
|
|
|
|
|
LUXTRONIK2_Initialize($)
|
|
|
|
|
{
|
|
|
|
|
my ($hash) = @_;
|
|
|
|
|
|
|
|
|
|
$hash->{DefFn} = "LUXTRONIK2_Define";
|
|
|
|
|
$hash->{AttrList} = "loglevel:0,1,2,3,4,5,6";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub
|
|
|
|
|
LUXTRONIK2_Define($$)
|
|
|
|
|
{
|
|
|
|
|
my ($hash, $def) = @_;
|
|
|
|
|
my $name=$hash->{NAME};
|
|
|
|
|
my @a = split("[ \t][ \t]*", $def);
|
|
|
|
|
|
|
|
|
|
return "Wrong syntax: use define <name> LUXTRONIK2 <ip-address> [<poll-interval>]" if(int(@a) <3 || int(@a) >4);
|
|
|
|
|
$hash->{Host} = $a[2];
|
|
|
|
|
$hash->{INTERVAL}=$a[3] || 300;
|
2012-04-29 10:35:10 +00:00
|
|
|
|
|
|
|
|
|
#Get first data after 5 seconds
|
|
|
|
|
InternalTimer(gettimeofday() + 5, "LUXTRONIK2_GetStatus", $hash, 0);
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
|
|
|
|
return undef;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-29 18:11:46 +00:00
|
|
|
|
sub
|
|
|
|
|
LUXTRONIK2_TempValueMerken($$$)
|
|
|
|
|
{
|
|
|
|
|
my ($hash, $param, $paramName) = @_;
|
|
|
|
|
|
|
|
|
|
$param /= 10;
|
|
|
|
|
if($hash->{READINGS}{$paramName}{VAL} != $param) {
|
|
|
|
|
$hash->{READINGS}{$paramName}{TIME} = TimeNow();
|
|
|
|
|
$hash->{READINGS}{$paramName}{VAL} = $param;
|
|
|
|
|
$hash->{READINGS}{$paramName}{UNIT} = "Degree Celsius";
|
|
|
|
|
$hash->{CHANGED}[$cc++] = $paramName .": ". $param;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-24 11:03:38 +00:00
|
|
|
|
#####################################
|
|
|
|
|
|
|
|
|
|
sub
|
|
|
|
|
LUXTRONIK2_GetStatus($)
|
|
|
|
|
{
|
|
|
|
|
my ($hash) = @_;
|
|
|
|
|
my $err_log='';
|
|
|
|
|
my @heatpump_values;
|
|
|
|
|
my @heatpump_parameters;
|
|
|
|
|
my $result='';
|
|
|
|
|
my $switch=0;
|
|
|
|
|
my $value='';
|
2012-04-29 18:11:46 +00:00
|
|
|
|
my $count=0;
|
|
|
|
|
# my $i=0;
|
2012-04-24 11:03:38 +00:00
|
|
|
|
my $name = $hash->{NAME};
|
|
|
|
|
my $host = $hash->{Host};
|
|
|
|
|
my $sensor = '';
|
2012-04-29 10:35:10 +00:00
|
|
|
|
my $state = '';
|
2012-04-29 18:11:46 +00:00
|
|
|
|
|
|
|
|
|
$cc = 0; #initialize counter
|
|
|
|
|
|
2012-04-24 11:03:38 +00:00
|
|
|
|
InternalTimer(gettimeofday() + $hash->{INTERVAL}, "LUXTRONIK2_GetStatus", $hash, 0);
|
|
|
|
|
|
|
|
|
|
my $socket = new IO::Socket::INET ( PeerAddr => $host,
|
2012-04-29 18:11:46 +00:00
|
|
|
|
PeerPort => 8888,
|
|
|
|
|
# Type => SOCK_STREAM, # probably needed on some systems
|
|
|
|
|
Proto => 'tcp'
|
|
|
|
|
);
|
|
|
|
|
if (!$socket) {
|
|
|
|
|
$hash->{STATE} = "error opening device";
|
|
|
|
|
Log 1,"$name: Error opening Connection to $host";
|
|
|
|
|
return "Can't Connect to $host -> $@ ( $!)\n";
|
|
|
|
|
}
|
2012-04-24 11:03:38 +00:00
|
|
|
|
$socket->autoflush(1);
|
|
|
|
|
|
2012-04-29 10:35:10 +00:00
|
|
|
|
#Read operational values
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$socket->send(pack("N", 3004));
|
|
|
|
|
$socket->send(pack("N", 0));
|
|
|
|
|
|
|
|
|
|
# read response, should be 3004, status, number of parameters, and the parameters...
|
2012-04-24 11:03:38 +00:00
|
|
|
|
$socket->recv($result,4);
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$count = unpack("N", $result);
|
|
|
|
|
if($count != 3004) {
|
|
|
|
|
Log 2, "LUXTRONIK2_GetStatus: $name $host 3004 Status problem 1: ".length($result)." -> ".$count;
|
|
|
|
|
return "3004 != 3004";
|
|
|
|
|
}
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
|
|
|
|
$socket->recv($result,4);
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$count = unpack("N", $result);
|
|
|
|
|
if($count != 0) {
|
|
|
|
|
Log 2, "LUXTRONIK2_GetStatus: $name $host ".length($result)." -> ".$count;
|
|
|
|
|
return "0 != 0";
|
|
|
|
|
}
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
|
|
|
|
$socket->recv($result,4);
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$count = unpack("N", $result);
|
|
|
|
|
if($count == 0) {
|
|
|
|
|
Log 2, "LUXTRONIK2_GetStatus: $name $host 0 Paramters read".length($result)." -> ".$count;
|
|
|
|
|
return "0 Paramters read";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$socket->recv($result, $count*4+4);
|
|
|
|
|
if(length($result) != $count*4) {
|
|
|
|
|
Log 1, "LUXTRONIK2_GetStatus status report length check: $name $host ".length($result)." should have been ". $count * 4;
|
|
|
|
|
return "Value read mismatch Lux2 ( $!)\n";
|
|
|
|
|
}
|
|
|
|
|
@heatpump_values = unpack("N$count", $result);
|
|
|
|
|
if(scalar(@heatpump_values) != $count) {
|
|
|
|
|
Log 2, "LUXTRONIK2_GetStatus10: $name $host ".scalar(@heatpump_values)." -> ".$heatpump_values[10];
|
|
|
|
|
return "Value unpacking problem";
|
|
|
|
|
}
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
|
|
|
|
# Parametereinstellung lesen
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$socket->send(pack("N", 3003));
|
|
|
|
|
$socket->send(pack("N", 0));
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
|
|
|
|
$socket->recv($result,4);
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$count = unpack("N", $result);
|
|
|
|
|
$count = unpack("N", $result);
|
|
|
|
|
if($count != 3003) {
|
|
|
|
|
Log 2, "LUXTRONIK2_GetStatus: $name $host 3003 Status problem 1: ".length($result)." -> ".$count;
|
|
|
|
|
return "3003 != 3003";
|
|
|
|
|
}
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$socket->recv($result,4);
|
|
|
|
|
$count = unpack("N", $result);
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$socket->recv($result, $count*4+4);
|
|
|
|
|
if(length($result) != $count*4) {
|
|
|
|
|
Log 1, "LUXTRONIK2_GetStatus parameter settings length check: $name $host ".length($result)." should have been ". $count * 4;
|
|
|
|
|
# return "Value read mismatch Lux2 ( $!)\n";
|
|
|
|
|
}
|
|
|
|
|
@heatpump_parameters = unpack("N$count", $result);
|
|
|
|
|
if(scalar(@heatpump_parameters) != $count) {
|
|
|
|
|
Log 2, "LUXTRONIK2_GetStatus: $name $host pump parameter problem: received parameter count ("
|
|
|
|
|
. scalar(@heatpump_parameters) .
|
|
|
|
|
") is not equal to announced parameter count(" . $count . ")!";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$socket->close();
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
|
|
|
|
if($err_log ne "")
|
|
|
|
|
{
|
2012-04-29 18:11:46 +00:00
|
|
|
|
Log GetLogLevel($name,2), "LUXTRONIK2 ".$err_log;
|
|
|
|
|
return("");
|
2012-04-24 11:03:38 +00:00
|
|
|
|
}
|
2012-04-29 10:35:10 +00:00
|
|
|
|
|
|
|
|
|
my %wpOpStat1 = ( 0 => "Waermepumpe laeuft",
|
|
|
|
|
1 => "Waermepumpe steht",
|
|
|
|
|
2 => "Waermepumpe kommt",
|
|
|
|
|
3 => "Fehler",
|
|
|
|
|
4 => "Abtauen" );
|
|
|
|
|
my %wpOpStat2 = ( 0 => "Heizbetrieb",
|
|
|
|
|
1 => "Keine Anforderung",
|
|
|
|
|
2 => "Netz Einschaltverzögerung",
|
|
|
|
|
3 => "Schaltspielzeit",
|
|
|
|
|
4 => "EVU Sperrzeit",
|
|
|
|
|
5 => "Brauchwasser",
|
|
|
|
|
6 => "Stufe",
|
|
|
|
|
7 => "Abtauen",
|
|
|
|
|
8 => "Pumpenvorlauf",
|
|
|
|
|
9 => "Thermische Desinfektion",
|
|
|
|
|
10 => "Kühlbetrieb",
|
|
|
|
|
12 => "Schwimmbad",
|
|
|
|
|
13 => "Heizen_Ext_En",
|
|
|
|
|
14 => "Brauchw_Ext_En",
|
|
|
|
|
16 => "Durchflussueberwachung",
|
|
|
|
|
17 => "Elektrische Zusatzheizung" );
|
|
|
|
|
my %wpMode = ( 0 => "Automatik",
|
|
|
|
|
1 => "Zusatzheizung",
|
|
|
|
|
2 => "Party",
|
|
|
|
|
3 => "Ferien",
|
|
|
|
|
4 => "Aus" );
|
2012-04-29 18:11:46 +00:00
|
|
|
|
|
2012-04-29 10:35:10 +00:00
|
|
|
|
# Erst die operativen Stati und Parameterenstellungen
|
2012-04-29 18:11:46 +00:00
|
|
|
|
|
2012-04-24 11:03:38 +00:00
|
|
|
|
$sensor = "currentOperatingStatus1";
|
|
|
|
|
$switch = $heatpump_values[117];
|
2012-04-29 10:35:10 +00:00
|
|
|
|
$value = $wpOpStat1{$switch};
|
|
|
|
|
$value = "unbekannt (".$switch.")" unless $value;
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
2012-04-29 20:22:45 +00:00
|
|
|
|
if($hash->{READINGS}{$sensor}{VAL} ne $value) {
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$hash->{READINGS}{$sensor}{TIME} = TimeNow();
|
|
|
|
|
$hash->{READINGS}{$sensor}{VAL} = $value;
|
|
|
|
|
$hash->{CHANGED}[$cc++] = $sensor.": ".$value;
|
|
|
|
|
}
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
2012-04-29 10:35:10 +00:00
|
|
|
|
$state = $value;
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
|
|
|
|
$sensor = "currentOperatingStatus2";
|
|
|
|
|
$switch = $heatpump_values[119];
|
2012-04-29 10:35:10 +00:00
|
|
|
|
$value = $wpOpStat2{$switch};
|
2012-04-29 18:11:46 +00:00
|
|
|
|
|
|
|
|
|
# Sonderfaelle behandeln:
|
2012-04-29 10:35:10 +00:00
|
|
|
|
if ($switch==6) { $value = "Stufe ".$heatpump_values[121]." ".($heatpump_values[122] / 10)." °C "; }
|
|
|
|
|
elsif ($switch==7) {
|
|
|
|
|
if ($heatpump_values[44]==1) {$value = "Abtauen (Kreisumkehr)";}
|
|
|
|
|
else {$value = "Luftabtauen";}
|
|
|
|
|
}
|
|
|
|
|
$value = "unbekannt (".$switch.")" unless $value;
|
2012-04-29 18:11:46 +00:00
|
|
|
|
|
2012-04-29 20:22:45 +00:00
|
|
|
|
if($hash->{READINGS}{$sensor}{VAL} ne $value) {
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$hash->{READINGS}{$sensor}{TIME} = TimeNow();
|
|
|
|
|
$hash->{READINGS}{$sensor}{VAL} = $value;
|
|
|
|
|
$hash->{CHANGED}[$cc++] = $sensor.": ".$value;
|
|
|
|
|
}
|
|
|
|
|
#
|
|
|
|
|
# TODO: STATE ändern nach Developer-Wiki.
|
|
|
|
|
#
|
2012-04-24 11:03:38 +00:00
|
|
|
|
$state = $state." - ".$value;
|
|
|
|
|
$hash->{STATE} = $state;
|
2012-04-29 10:35:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$sensor = "hotWaterOperatingMode";
|
|
|
|
|
$switch = $heatpump_parameters[4];
|
|
|
|
|
|
|
|
|
|
$value = $wpMode{$switch};
|
|
|
|
|
$value = "unbekannt (".$switch.")" unless $value;
|
|
|
|
|
|
2012-04-29 20:22:45 +00:00
|
|
|
|
if($hash->{READINGS}{$sensor}{VAL} ne $value) {
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$hash->{READINGS}{$sensor}{TIME} = TimeNow();
|
|
|
|
|
$hash->{READINGS}{$sensor}{VAL} = $value;
|
|
|
|
|
$hash->{CHANGED}[$cc++] = $sensor.": ".$value;
|
|
|
|
|
}
|
2012-04-29 10:35:10 +00:00
|
|
|
|
|
|
|
|
|
$sensor = "heatingOperatingMode";
|
|
|
|
|
$switch = $heatpump_parameters[3];
|
|
|
|
|
|
|
|
|
|
$value = $wpMode{$switch};
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$value = "unbekannt (" . $switch . ")" unless $value;
|
2012-04-29 10:35:10 +00:00
|
|
|
|
|
2012-04-29 20:22:45 +00:00
|
|
|
|
if($hash->{READINGS}{$sensor}{VAL} ne $value) {
|
2012-04-29 18:11:46 +00:00
|
|
|
|
$hash->{READINGS}{$sensor}{TIME} = TimeNow();
|
|
|
|
|
$hash->{READINGS}{$sensor}{VAL} = $value;
|
|
|
|
|
$hash->{CHANGED}[$cc++] = $sensor.": ".$value;
|
|
|
|
|
}
|
2012-04-29 10:35:10 +00:00
|
|
|
|
|
2012-04-29 18:11:46 +00:00
|
|
|
|
#####################
|
|
|
|
|
# Jetzt die aktuellen Betriebswerte auswerten.
|
|
|
|
|
#####################
|
|
|
|
|
|
|
|
|
|
# is ambient temperature the correct wording for the outside temperature?
|
|
|
|
|
# Wikipedia:
|
|
|
|
|
# Ambient temperature simply means "the temperature of the surroundings" and will be the same as room temperature indoors.
|
|
|
|
|
LUXTRONIK2_TempValueMerken($hash,$heatpump_values[15],"ambientTemperature");
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
2012-04-29 18:11:46 +00:00
|
|
|
|
LUXTRONIK2_TempValueMerken($hash,$heatpump_values[16],"averageAmbientTemperature");
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
|
|
|
|
Log GetLogLevel($name,4), $sensor.": ".$value;
|
2012-04-29 18:11:46 +00:00
|
|
|
|
# Log 4, "LUXTRONIK2_GetStatus: $name $host ".$hash->{STATE}." -> ".$state;
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
2012-04-29 18:11:46 +00:00
|
|
|
|
LUXTRONIK2_TempValueMerken($hash,$heatpump_values[17],"hotWaterTemperature");
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
2012-04-29 18:11:46 +00:00
|
|
|
|
# Wert 10 gibt die Vorlauftemperatur an, die
|
|
|
|
|
# korrekte Übersetzung ist flow temperature.
|
|
|
|
|
LUXTRONIK2_TempValueMerken($hash,$heatpump_values[10],"flowTemperature");
|
|
|
|
|
# Rücklauftempereatur
|
|
|
|
|
LUXTRONIK2_TempValueMerken($hash,$heatpump_values[11],"returnTemperature");
|
|
|
|
|
# Rücklauftemperatur Sollwert
|
|
|
|
|
LUXTRONIK2_TempValueMerken($hash,$heatpump_values[12],"returnTemperatureTarget");
|
|
|
|
|
# Rücklauftemperatur am externen Sensor.
|
|
|
|
|
LUXTRONIK2_TempValueMerken($hash,$heatpump_values[13],"returnTemperatureExtern");
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
2012-04-29 18:11:46 +00:00
|
|
|
|
# Durchfluss Wärmemengenzähler
|
2012-04-29 10:35:10 +00:00
|
|
|
|
# Durchfluss W<>rmemengenz<6E>hler
|
2012-04-24 11:03:38 +00:00
|
|
|
|
$sensor = "flowRate";
|
|
|
|
|
$value = $heatpump_values[155];
|
2012-04-29 18:11:46 +00:00
|
|
|
|
if($hash->{READINGS}{$sensor}{VAL} != $value) {
|
|
|
|
|
$hash->{READINGS}{$sensor}{TIME} = TimeNow();
|
|
|
|
|
$hash->{READINGS}{$sensor}{VAL} = $value;
|
|
|
|
|
$hash->{READINGS}{$sensor}{UNIT} = "l/h";
|
|
|
|
|
$hash->{CHANGED}[$cc++] = $sensor.": ".$value;
|
|
|
|
|
}
|
2012-04-24 11:03:38 +00:00
|
|
|
|
|
|
|
|
|
DoTrigger($name, undef) if($init_done);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
1;
|