2014-01-25 12:21:18 +00:00
|
|
|
|
###############################################################
|
2013-01-01 14:21:40 +00:00
|
|
|
|
#
|
|
|
|
|
# Copyright notice
|
|
|
|
|
#
|
2014-01-16 18:17:49 +00:00
|
|
|
|
# (c) 2012,2014 Torsten Poitzsch (torsten.poitzsch@gmx.de)
|
2014-01-18 15:12:15 +00:00
|
|
|
|
# (c) 2012-2013 Jan-Hinrich Fessel (oskar@fessel.org)
|
2013-01-01 14:21:40 +00:00
|
|
|
|
#
|
2014-01-24 18:21:30 +00:00
|
|
|
|
# The modul reads and writes parameters of the heat pump controller Luxtronik 2.0
|
|
|
|
|
#
|
2013-01-01 14:21:40 +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;
|
2014-01-16 18:17:49 +00:00
|
|
|
|
use Blocking;
|
2013-01-01 14:21:40 +00:00
|
|
|
|
use IO::Socket;
|
2014-01-18 15:12:15 +00:00
|
|
|
|
use Time::HiRes qw/ time /;
|
|
|
|
|
use POSIX;
|
2014-01-24 18:21:30 +00:00
|
|
|
|
use Net::Telnet;
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# Modul Version for remote debugging
|
2014-02-08 10:32:49 +00:00
|
|
|
|
my $modulVersion = "2014-02-08";
|
2014-01-25 12:21:18 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
#List of firmware versions that are known to be compatible with this modul
|
|
|
|
|
my $testedFirmware = "#V1.54C#V1.60#V1.69#";
|
|
|
|
|
my $compatibleFirmware = "#V1.54C#V1.60#V1.69#";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2013-01-01 14:21:40 +00:00
|
|
|
|
LUXTRONIK2_Initialize($)
|
|
|
|
|
{
|
|
|
|
|
my ($hash) = @_;
|
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$hash->{DefFn} = "LUXTRONIK2_Define";
|
|
|
|
|
$hash->{UndefFn} = "LUXTRONIK2_Undefine";
|
2014-02-02 14:10:15 +00:00
|
|
|
|
$hash->{NotifyFn} = "LUXTRONIK2_Notify";
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$hash->{SetFn} = "LUXTRONIK2_Set";
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$hash->{AttrFn} = "LUXTRONIK2_Attr";
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$hash->{AttrList} = "disable:0,1 ".
|
2014-01-24 18:21:30 +00:00
|
|
|
|
"allowSetParameter:0,1 ".
|
|
|
|
|
"autoSynchClock:slider,10,5,300 ".
|
2014-02-02 14:10:15 +00:00
|
|
|
|
"doStatistics:0,1 ".
|
2014-01-24 18:21:30 +00:00
|
|
|
|
"ignoreFirmwareCheck:0,1 ".
|
2014-01-16 18:17:49 +00:00
|
|
|
|
"statusHTML ".
|
|
|
|
|
$readingFnAttributes;
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2013-01-01 14:21:40 +00:00
|
|
|
|
LUXTRONIK2_Define($$)
|
|
|
|
|
{
|
|
|
|
|
my ($hash, $def) = @_;
|
|
|
|
|
my @a = split("[ \t][ \t]*", $def);
|
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
return "Usage: define <name> LUXTRONIK2 <ip-address> [poll-interval]" if(@a <3 || @a >4);
|
|
|
|
|
|
|
|
|
|
my $name = $a[0];
|
|
|
|
|
my $host = $a[2];
|
|
|
|
|
|
|
|
|
|
my $interval = 5*60;
|
|
|
|
|
$interval = $a[3] if(int(@a) == 4);
|
2014-01-25 18:44:12 +00:00
|
|
|
|
$interval = 30 if( $interval < 30 );
|
2014-01-16 18:17:49 +00:00
|
|
|
|
|
|
|
|
|
$hash->{NAME} = $name;
|
|
|
|
|
|
|
|
|
|
$hash->{STATE} = "Initializing";
|
|
|
|
|
$hash->{HOST} = $host;
|
|
|
|
|
$hash->{INTERVAL} = $interval;
|
2014-02-08 10:30:40 +00:00
|
|
|
|
$hash->{NOTIFYDEV} = "global";
|
2014-01-16 18:17:49 +00:00
|
|
|
|
|
|
|
|
|
RemoveInternalTimer($hash);
|
|
|
|
|
#Get first data after 10 seconds
|
|
|
|
|
InternalTimer(gettimeofday() + 10, "LUXTRONIK2_GetUpdate", $hash, 0);
|
2014-01-18 15:12:15 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
#Reset temporary values
|
2014-01-18 15:12:15 +00:00
|
|
|
|
$hash->{fhem}{durationFetchReadingsMin} = 0;
|
|
|
|
|
$hash->{fhem}{durationFetchReadingsMax} = 0;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
$hash->{fhem}{alertFirmware} = 0;
|
2014-02-08 10:30:40 +00:00
|
|
|
|
$hash->{fhem}{statBoilerHeatUpStep} = 0;
|
|
|
|
|
$hash->{fhem}{statBoilerCoolDownStep} = 0;
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
$hash->{fhem}{modulVersion} = $modulVersion;
|
|
|
|
|
Log3 $hash,5,"$name: LUXTRONIK2.pm version is $modulVersion.";
|
|
|
|
|
|
2013-01-01 14:21:40 +00:00
|
|
|
|
return undef;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2014-01-16 18:17:49 +00:00
|
|
|
|
LUXTRONIK2_Undefine($$)
|
2013-01-01 14:21:40 +00:00
|
|
|
|
{
|
2014-01-16 18:17:49 +00:00
|
|
|
|
my ($hash, $arg) = @_;
|
|
|
|
|
|
|
|
|
|
RemoveInternalTimer($hash);
|
|
|
|
|
|
|
|
|
|
BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID}));
|
|
|
|
|
|
|
|
|
|
return undef;
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
sub ########################################
|
|
|
|
|
LUXTRONIK2_Notify(@) {
|
|
|
|
|
my ($hash,$dev) = @_;
|
|
|
|
|
my $name = $hash->{NAME};
|
|
|
|
|
|
2014-02-08 10:30:40 +00:00
|
|
|
|
if ($dev->{NAME} eq "global" && grep (m/^INITIALIZED|REREADCFG$/,@{$dev->{CHANGED}})){
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# housekeeping
|
|
|
|
|
my %cleanUp = (
|
|
|
|
|
delayDeviceTime => "delayDeviceTimeCalc",
|
|
|
|
|
deviceTimeStartReadings => "deviceTimeCalc",
|
|
|
|
|
heatingSummerMode => "heatingLimit",
|
|
|
|
|
thresholdTemperatureSummerMode => "thresholdHeatingLimit",
|
|
|
|
|
lastDeviceClockSynch => "deviceTimeLastSync",
|
|
|
|
|
operatingHoursHeatPump => "counterHoursHeatPump",
|
|
|
|
|
operatingHoursSecondHeatSource1 => "counterHours2ndHeatSource1",
|
|
|
|
|
operatingHoursSecondHeatSource2 => "counterHours2ndHeatSource2",
|
|
|
|
|
operatingHoursSecondHeatSource3 => "counterHours2ndHeatSource3",
|
|
|
|
|
operatingHoursHeating => "counterHoursHeating",
|
|
|
|
|
operatingHoursHotWater => "counterHoursHotWater",
|
|
|
|
|
heatQuantityHeating => "counterHeatQHeating",
|
|
|
|
|
heatQuantityHotWater => "counterHeatQHotWater",
|
|
|
|
|
heatQuantityTotal => "counterHeatQTotal",
|
|
|
|
|
currentOperatingStatus1 => "opStateHeatPump1",
|
|
|
|
|
currentOperatingState1 => "opStateHeatPump1",
|
|
|
|
|
currentOperatingStatus2 => "opStateHeatPump3",
|
|
|
|
|
currentOperatingState2 => "opStateHeatPump2",
|
|
|
|
|
currentOperatingState3 => "opStateHeatPump3",
|
|
|
|
|
heatingOperatingMode => "opModeHeating",
|
|
|
|
|
heatingOperatingState => "opStateHeating",
|
|
|
|
|
hotWaterOperatingMode => "opModeHotWater",
|
|
|
|
|
hotWaterStatus => "opStateHotWater",
|
|
|
|
|
hotWaterState => "opStateHotWater",
|
|
|
|
|
heatingSystemCirculationPump => "heatingSystemCircPump",
|
2014-02-08 10:30:40 +00:00
|
|
|
|
hotWaterCirculationPumpExtern => "hotWaterCircPumpExtern",
|
|
|
|
|
statGradientBoilerTempLoss => "statBoilerGradientHeatUp' and 'statBoilerGradientCoolDown" );
|
2014-02-02 14:10:15 +00:00
|
|
|
|
my $oldReading;
|
|
|
|
|
my $newReading;
|
|
|
|
|
while (($oldReading, $newReading) = each(%cleanUp)) {
|
|
|
|
|
if ( exists( $hash->{READINGS}{$oldReading} ) ) {
|
|
|
|
|
delete($hash->{READINGS}{$oldReading});
|
|
|
|
|
Log3 $name,2,"$name: !!! Change/fix in LUXTRONIK2-Modul: '$oldReading' is now '$newReading'";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2014-01-16 18:17:49 +00:00
|
|
|
|
LUXTRONIK2_Set($$@)
|
|
|
|
|
{
|
2014-01-18 15:12:15 +00:00
|
|
|
|
my ($hash, $name, $cmd, $val) = @_;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
my $resultStr = "";
|
2014-01-18 15:12:15 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
if($cmd eq 'statusRequest') {
|
|
|
|
|
$hash->{LOCAL} = 1;
|
|
|
|
|
LUXTRONIK2_GetUpdate($hash);
|
|
|
|
|
$hash->{LOCAL} = 0;
|
|
|
|
|
return undef;
|
|
|
|
|
}
|
2014-02-08 10:30:40 +00:00
|
|
|
|
elsif ($cmd eq 'resetStatistics') {
|
|
|
|
|
if ( ($val eq "all" || $val eq "statBoilerGradientCoolDownMin")
|
|
|
|
|
&& exists($defs{$name}{READINGS}{statBoilerGradientCoolDownMin})) {
|
|
|
|
|
delete $defs{$name}{READINGS}{statBoilerGradientCoolDownMin};
|
|
|
|
|
$resultStr .= " statBoilerGradientCoolDownMin";
|
2014-02-02 14:10:15 +00:00
|
|
|
|
}
|
|
|
|
|
if ( $resultStr eq "" ) {
|
2014-02-08 10:30:40 +00:00
|
|
|
|
$resultStr = "$name: No statistics to reset";
|
2014-02-02 14:10:15 +00:00
|
|
|
|
} else {
|
|
|
|
|
$resultStr = "$name: Statistic value(s) deleted:" . $resultStr;
|
|
|
|
|
}
|
|
|
|
|
Log3 $hash, 3, $resultStr;
|
|
|
|
|
return $resultStr;
|
|
|
|
|
}
|
2014-01-18 15:12:15 +00:00
|
|
|
|
elsif($cmd eq 'INTERVAL' && int(@_)==4 ) {
|
2014-01-25 18:44:12 +00:00
|
|
|
|
$val = 30 if( $val < 30 );
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$hash->{INTERVAL}=$val;
|
|
|
|
|
return "Polling interval set to $val seconds.";
|
2014-01-18 15:12:15 +00:00
|
|
|
|
}
|
2014-01-24 18:21:30 +00:00
|
|
|
|
|
|
|
|
|
#Check Firmware and Set-Paramter-lock
|
|
|
|
|
if ($cmd eq 'synchronizeClockHeatPump' ||
|
2014-01-18 15:12:15 +00:00
|
|
|
|
$cmd eq 'hotWaterTemperatureTarget' ||
|
2014-02-02 14:10:15 +00:00
|
|
|
|
$cmd eq 'opModeHotWater')
|
2014-01-24 18:21:30 +00:00
|
|
|
|
{
|
|
|
|
|
my $firmware = ReadingsVal($name,"firmware","");
|
|
|
|
|
my $firmwareCheck = LUXTRONIK2_checkFirmware($firmware);
|
|
|
|
|
# stop in case of incompatible firmware
|
|
|
|
|
if ($firmwareCheck eq "fwNotCompatible") {
|
|
|
|
|
Log3 $name, 3, $name." Error: Host firmware '$firmware' not compatible for parameter setting.";
|
|
|
|
|
return "Firmware '$firmware' not compatible for parameter setting. ";
|
|
|
|
|
# stop in case of untested firmware and firmware check enabled
|
|
|
|
|
} elsif (AttrVal($name, "ignoreFirmwareCheck", 0)!= 1 &&
|
|
|
|
|
$firmwareCheck eq "fwNotTested") {
|
2014-02-02 14:10:15 +00:00
|
|
|
|
Log3 $name, 3, $name." Error: Host firmware '$firmware' not tested for parameter setting. To test set attribute 'ignoreFirmwareCheck' to 1";
|
|
|
|
|
return "Firmware '$firmware' not compatible for parameter setting. To test set attribute 'ignoreFirmwareCheck' to 1.";
|
2014-01-24 18:21:30 +00:00
|
|
|
|
# stop in case setting of parameters is not enabled
|
|
|
|
|
} elsif ( AttrVal($name, "allowSetParameter", 0) != 1) {
|
|
|
|
|
Log3 $name, 3, $name." Error: Setting of parameters not allowed. Please set attribut 'allowSetParameter' to 1";
|
|
|
|
|
return "Setting of parameters not allowed. To unlock, please set attribut 'allowSetParameter' to 1.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($cmd eq 'synchronizeClockHeatPump') {
|
|
|
|
|
$hash->{LOCAL} = 1;
|
|
|
|
|
$resultStr = LUXTRONIK2_synchronizeClock($hash);
|
|
|
|
|
$hash->{LOCAL} = 0;
|
|
|
|
|
Log3 $name, 3, "$name - $resultStr";
|
|
|
|
|
return $resultStr;
|
|
|
|
|
} elsif(int(@_)==4 &&
|
2014-02-02 14:10:15 +00:00
|
|
|
|
($cmd eq 'hotWaterTemperatureTarget'
|
|
|
|
|
|| $cmd eq 'opModeHotWater')) {
|
2014-01-18 15:12:15 +00:00
|
|
|
|
$hash->{LOCAL} = 1;
|
|
|
|
|
$resultStr = LUXTRONIK2_SetParameter ($hash, $cmd, $val);
|
|
|
|
|
$hash->{LOCAL} = 0;
|
|
|
|
|
return $resultStr;
|
2014-01-24 18:21:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-18 15:12:15 +00:00
|
|
|
|
my $list = "statusRequest:noArg".
|
2014-02-08 10:30:40 +00:00
|
|
|
|
" resetStatistics:all,statBoilerGradientCoolDownMin".
|
2014-01-18 15:12:15 +00:00
|
|
|
|
" hotWaterTemperatureTarget:slider,30.0,0.5,65.0".
|
2014-02-02 14:10:15 +00:00
|
|
|
|
" opModeHotWater:Auto,Party,Off".
|
2014-01-24 18:21:30 +00:00
|
|
|
|
" synchronizeClockHeatPump:noArg".
|
2014-02-02 14:10:15 +00:00
|
|
|
|
" INTERVAL:slider,30,30,1800";
|
2014-01-16 18:17:49 +00:00
|
|
|
|
return "Unknown argument $cmd, choose one of $list";
|
|
|
|
|
}
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2014-01-24 18:21:30 +00:00
|
|
|
|
LUXTRONIK2_Attr(@)
|
|
|
|
|
{
|
|
|
|
|
my ($cmd,$name,$aName,$aVal) = @_;
|
|
|
|
|
# $cmd can be "del" or "set"
|
|
|
|
|
# $name is device name
|
|
|
|
|
# aName and aVal are Attribute name and value
|
|
|
|
|
if ($cmd eq "set") {
|
|
|
|
|
if ($aName eq "1allowSetParameter") {
|
|
|
|
|
eval { qr/$aVal/ };
|
|
|
|
|
if ($@) {
|
|
|
|
|
Log3 $name, 3, "LUXTRONIK2: Invalid allowSetParameter in attr $name $aName $aVal: $@";
|
|
|
|
|
return "Invalid allowSetParameter $aVal";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-02 14:10:15 +00:00
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
return undef;
|
|
|
|
|
}
|
2014-01-18 15:12:15 +00:00
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2014-01-16 18:17:49 +00:00
|
|
|
|
LUXTRONIK2_GetUpdate($)
|
2013-01-01 14:21:40 +00:00
|
|
|
|
{
|
|
|
|
|
my ($hash) = @_;
|
|
|
|
|
my $name = $hash->{NAME};
|
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
if(!$hash->{LOCAL}) {
|
|
|
|
|
RemoveInternalTimer($hash);
|
|
|
|
|
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "LUXTRONIK2_GetUpdate", $hash, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
my $host = $hash->{HOST};
|
|
|
|
|
|
|
|
|
|
if( !$hash->{LOCAL} ) {
|
|
|
|
|
return undef if( AttrVal($name, "disable", 0 ) == 1 );
|
|
|
|
|
}
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
$hash->{helper}{RUNNING_PID} = BlockingCall("LUXTRONIK2_DoUpdate", $name."|".$host, "LUXTRONIK2_UpdateDone", 25, "LUXTRONIK2_UpdateAborted", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
|
2014-01-16 18:17:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-18 15:12:15 +00:00
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2014-01-16 18:17:49 +00:00
|
|
|
|
LUXTRONIK2_DoUpdate($)
|
|
|
|
|
{
|
|
|
|
|
my ($string) = @_;
|
|
|
|
|
my ($name, $host) = split("\\|", $string);
|
|
|
|
|
|
|
|
|
|
my @heatpump_values;
|
|
|
|
|
my @heatpump_parameters;
|
2014-01-24 18:21:30 +00:00
|
|
|
|
my @heatpump_visibility;
|
2014-01-16 18:17:49 +00:00
|
|
|
|
my $count=0;
|
|
|
|
|
my $result="";
|
|
|
|
|
my $readingStartTime = time();
|
|
|
|
|
|
|
|
|
|
Log3 $name, 5, "$name: Opening connection to host ".$host;
|
2013-01-01 14:21:40 +00:00
|
|
|
|
my $socket = new IO::Socket::INET ( PeerAddr => $host,
|
|
|
|
|
PeerPort => 8888,
|
2014-01-24 18:21:30 +00:00
|
|
|
|
# Type = SOCK_STREAM, # probably needed on some systems
|
2013-01-01 14:21:40 +00:00
|
|
|
|
Proto => 'tcp'
|
|
|
|
|
);
|
|
|
|
|
if (!$socket) {
|
2014-01-16 18:17:49 +00:00
|
|
|
|
Log3 $name, 1, "$name Error: Could not open connection to host ".$host;
|
|
|
|
|
return "$name|0|Can't connect to $host";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
|
|
|
|
$socket->autoflush(1);
|
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
############################
|
|
|
|
|
#Fetch operational values (FOV)
|
|
|
|
|
############################
|
|
|
|
|
Log3 $name, 5, "$name: Ask host for operational values";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
$socket->send(pack("N", 3004));
|
|
|
|
|
$socket->send(pack("N", 0));
|
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
Log3 $name, 5, "$name: Start to receive operational values";
|
2014-01-24 18:21:30 +00:00
|
|
|
|
#(FOV) read first 4 bytes of response -> should be request_echo = 3004
|
2013-01-01 14:21:40 +00:00
|
|
|
|
$socket->recv($result,4);
|
|
|
|
|
$count = unpack("N", $result);
|
|
|
|
|
if($count != 3004) {
|
2014-01-16 18:17:49 +00:00
|
|
|
|
Log3 $name, 2, "$name LUXTRONIK2_DoUpdate-Error: Fetching operational values - wrong echo of request 3004: ".length($result)." -> ".$count;
|
|
|
|
|
$socket->close();
|
2014-01-24 18:21:30 +00:00
|
|
|
|
return "$name|0|3004 != $count";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
#(FOV) read next 4 bytes of response -> should be status = 0
|
2013-01-01 14:21:40 +00:00
|
|
|
|
$socket->recv($result,4);
|
|
|
|
|
$count = unpack("N", $result);
|
2014-01-16 18:17:49 +00:00
|
|
|
|
if($count > 0) {
|
2014-02-02 14:10:15 +00:00
|
|
|
|
Log3 $name, 4, "$name: Parameter on target changed, restart parameter reading after 5 seconds";
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|2|Status = $count - parameter on target changed, restart device reading after 5 seconds";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
#(FOV) read next 4 bytes of response -> should be count_calc_values > 0
|
2013-01-01 14:21:40 +00:00
|
|
|
|
$socket->recv($result,4);
|
2014-02-02 14:10:15 +00:00
|
|
|
|
my $count_calc_values = unpack("N", $result);
|
|
|
|
|
if($count_calc_values == 0) {
|
|
|
|
|
Log3 $name, 2, "$name LUXTRONIK2_DoUpdate-Error: Fetching operational values - 0 values announced: ".length($result)." -> ".$count_calc_values;
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|0|0 values read";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#(FOV) read remaining response -> should be previous number of parameters
|
|
|
|
|
my $i=1;
|
|
|
|
|
$result="";
|
|
|
|
|
my $buf="";
|
2014-02-02 14:10:15 +00:00
|
|
|
|
while($i<=$count_calc_values) {
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$socket->recv($buf,4);
|
|
|
|
|
$result.=$buf;
|
|
|
|
|
$i++;
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
2014-02-02 14:10:15 +00:00
|
|
|
|
if(length($result) != $count_calc_values*4) {
|
|
|
|
|
Log3 $name, 1, "$name LUXTRONIK2_DoUpdate-Error: operational values length check: ".length($result)." should have been ". $count_calc_values * 4;
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|0|Number of values read mismatch ( $!)\n";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
2014-01-16 18:17:49 +00:00
|
|
|
|
|
|
|
|
|
#(FOV) unpack response in array
|
2014-02-02 14:10:15 +00:00
|
|
|
|
@heatpump_values = unpack("N$count_calc_values", $result);
|
|
|
|
|
if(scalar(@heatpump_values) != $count_calc_values) {
|
|
|
|
|
Log3 $name, 2, "$name LUXTRONIK2_DoUpdate-Error: unpacking problem by operation values: ".scalar(@heatpump_values)." instead of ".$count_calc_values;
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|0|Unpacking problem of operational values";
|
2014-01-24 18:21:30 +00:00
|
|
|
|
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
2014-01-16 18:17:49 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
Log3 $name, 5, "$name: $count_calc_values operational values received";
|
2014-01-16 18:17:49 +00:00
|
|
|
|
|
|
|
|
|
############################
|
|
|
|
|
#Fetch set parameters (FSP)
|
|
|
|
|
############################
|
|
|
|
|
Log3 $name, 5, "$name: Ask host for set parameters";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
$socket->send(pack("N", 3003));
|
|
|
|
|
$socket->send(pack("N", 0));
|
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
Log3 $name, 5, "$name: Start to receive set parameters";
|
2014-01-24 18:21:30 +00:00
|
|
|
|
#(FSP) read first 4 bytes of response -> should be request_echo=3003
|
2013-01-01 14:21:40 +00:00
|
|
|
|
$socket->recv($result,4);
|
|
|
|
|
$count = unpack("N", $result);
|
|
|
|
|
if($count != 3003) {
|
2014-01-16 18:17:49 +00:00
|
|
|
|
Log3 $name, 2, "$name LUXTRONIK2_DoUpdate-Error: wrong echo of request 3003: ".length($result)." -> ".$count;
|
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|0|3003 != 3003";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
#(FSP) read next 4 bytes of response -> should be number_of_parameters > 0
|
2013-01-01 14:21:40 +00:00
|
|
|
|
$socket->recv($result,4);
|
2014-02-02 14:10:15 +00:00
|
|
|
|
my $count_set_parameter = unpack("N", $result);
|
|
|
|
|
if($count_set_parameter == 0) {
|
|
|
|
|
Log3 $name, 2, "$name LUXTRONIK2_DoUpdate-Error: 0 parameter read: ".length($result)." -> ".$count_set_parameter;
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|0|0 parameter read";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#(FSP) read remaining response -> should be previous number of parameters
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$i=1;
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$result="";
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$buf="";
|
2014-02-02 14:10:15 +00:00
|
|
|
|
while($i<=$count_set_parameter) {
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$socket->recv($buf,4);
|
|
|
|
|
$result.=$buf;
|
|
|
|
|
$i++;
|
|
|
|
|
}
|
2014-02-02 14:10:15 +00:00
|
|
|
|
if(length($result) != $count_set_parameter*4) {
|
|
|
|
|
Log3 $name, 1, "$name LUXTRONIK2_DoUpdate-Error: parameter length check: ".length($result)." should have been ". $count_set_parameter * 4;
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|0|Number of parameters read mismatch ( $!)\n";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
2014-01-16 18:17:49 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
@heatpump_parameters = unpack("N$count_set_parameter", $result);
|
|
|
|
|
if(scalar(@heatpump_parameters) != $count_set_parameter) {
|
|
|
|
|
Log3 $name, 2, "$name LUXTRONIK2_DoUpdate-Error: unpacking problem by set parameter: ".scalar(@heatpump_parameters)." instead of ".$count_set_parameter;
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|0|Unpacking problem of set parameters";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
Log3 $name, 5, "$name: $count_set_parameter set values received";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
goto SKIP_VISIBILITY_READING;
|
|
|
|
|
|
|
|
|
|
############################
|
|
|
|
|
#Fetch Visibility Attributes (FVA)
|
|
|
|
|
############################
|
|
|
|
|
Log3 $name, 5, "$name: Ask host for visibility attributes";
|
|
|
|
|
$socket->send(pack("N", 3005));
|
|
|
|
|
$socket->send(pack("N", 0));
|
|
|
|
|
|
|
|
|
|
Log3 $name, 5, "$name: Start to receive visibility attributes";
|
|
|
|
|
#(FVA) read first 4 bytes of response -> should be request_echo=3005
|
|
|
|
|
$socket->recv($result,4);
|
|
|
|
|
$count = unpack("N", $result);
|
|
|
|
|
if($count != 3005) {
|
|
|
|
|
Log3 $name, 2, "$name LUXTRONIK2_DoUpdate-Error: wrong echo of request 3005: ".length($result)." -> ".$count;
|
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|0|3005 != $count";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#(FVA) read next 4 bytes of response -> should be number_of_Visibility_Attributes > 0
|
|
|
|
|
$socket->recv($result,4);
|
|
|
|
|
$count = unpack("N", $result);
|
|
|
|
|
if($count == 0) {
|
|
|
|
|
Log3 $name, 2, "$name LUXTRONIK2_DoUpdate-Error: 0 visibility attributes announced: ".length($result)." -> ".$count;
|
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|0|0 visibility attributes announced";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#(FVA) read remaining response bytewise -> should be previous number of parameters
|
|
|
|
|
$i=1;
|
|
|
|
|
$result="";
|
|
|
|
|
$buf="";
|
|
|
|
|
while($i<=$count) {
|
|
|
|
|
$socket->recv($buf,1);
|
|
|
|
|
$result.=$buf;
|
|
|
|
|
$i++;
|
|
|
|
|
}
|
|
|
|
|
if(length($result) != $count) {
|
|
|
|
|
Log3 $name, 1, "$name LUXTRONIK2_DoUpdate-Error: Visibility attributes length check: ".length($result)." should have been ". $count;
|
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|0|Number of Visibility attributes read mismatch ( $!)\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@heatpump_visibility = unpack("C$count", $result);
|
|
|
|
|
if(scalar(@heatpump_visibility) != $count) {
|
|
|
|
|
Log3 $name, 2, "$name LUXTRONIK2_DoUpdate-Error: Unpacking problem by visibility attributes: ".scalar(@heatpump_visibility)." instead of ".$count;
|
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name|0|Unpacking problem of visibility attributes";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log3 $name, 5, "$name: $count visibility attributs received";
|
|
|
|
|
|
|
|
|
|
####################################
|
|
|
|
|
|
|
|
|
|
SKIP_VISIBILITY_READING:
|
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
Log3 $name, 5, "$name: Closing connection to host $host";
|
|
|
|
|
$socket->close();
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
my $readingEndTime = time();
|
|
|
|
|
|
|
|
|
|
#return certain readings for further processing
|
|
|
|
|
# 0 - name
|
|
|
|
|
my $return_str="$name";
|
|
|
|
|
# 1 - no error = 1
|
|
|
|
|
$return_str .= "|1";
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 2 - opStateHeatPump1
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[117];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 3 - opStateHeatPump3
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[119];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 4 - Stufe - ID_WEB_HauptMenuAHP_Stufe
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[121];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 5 - Temperature Value - ID_WEB_HauptMenuAHP_Temp
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[122];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 6 - Compressor1
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[44];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 7 - opModeHotWater
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_parameters[4];
|
|
|
|
|
# 8 - hotWaterMonitoring
|
|
|
|
|
$return_str .= "|".$heatpump_values[124];
|
|
|
|
|
# 9 - hotWaterBoilerValve
|
|
|
|
|
$return_str .= "|".$heatpump_values[38];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 10 - opModeHeating
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_parameters[3];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 11 - heatingLimit
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_parameters[699];
|
|
|
|
|
# 12 - ambientTemperature
|
|
|
|
|
$return_str .= "|".$heatpump_values[15];
|
|
|
|
|
# 13 - averageAmbientTemperature
|
|
|
|
|
$return_str .= "|".$heatpump_values[16];
|
|
|
|
|
# 14 - hotWaterTemperature
|
|
|
|
|
$return_str .= "|".$heatpump_values[17];
|
|
|
|
|
# 15 - flowTemperature
|
|
|
|
|
$return_str .= "|".$heatpump_values[10];
|
|
|
|
|
# 16 - returnTemperature
|
|
|
|
|
$return_str .= "|".$heatpump_values[11];
|
|
|
|
|
# 17 - returnTemperatureTarget
|
|
|
|
|
$return_str .= "|".$heatpump_values[12];
|
|
|
|
|
# 18 - returnTemperatureExtern
|
|
|
|
|
$return_str .= "|".$heatpump_values[13];
|
|
|
|
|
# 19 - flowRate
|
|
|
|
|
$return_str .= "|".$heatpump_values[155];
|
|
|
|
|
# 20 - firmware
|
|
|
|
|
my $fwvalue = "";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
for(my $fi=81; $fi<91; $fi++) {
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$fwvalue .= chr($heatpump_values[$fi]) if $heatpump_values[$fi];
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$fwvalue;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 21 - thresholdHeatingLimit
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_parameters[700];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 22 - rawDeviceTimeCalc
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[134];
|
|
|
|
|
# 23 - heatSourceIN
|
|
|
|
|
$return_str .= "|".$heatpump_values[19];
|
|
|
|
|
# 24 - heatSourceOUT
|
|
|
|
|
$return_str .= "|".$heatpump_values[20];
|
|
|
|
|
# 25 - hotWaterTemperatureTarget
|
|
|
|
|
$return_str .= "|".$heatpump_values[18];
|
|
|
|
|
# 26 - hotGasTemperature
|
|
|
|
|
$return_str .= "|".$heatpump_values[14];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 27 - heatingSystemCircPump
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[39];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 28 - hotWaterCircPumpExtern
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[46];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 29 - readingFhemStartTime
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$readingStartTime;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 30 - readingFhemEndTime
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$return_str .= "|".$readingEndTime;
|
2014-01-24 18:21:30 +00:00
|
|
|
|
# 31 - typeHeatpump
|
|
|
|
|
$return_str .= "|".$heatpump_values[78];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 32 - counterHours2ndHeatSource1
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[60];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 33 - counterHoursHeatpump
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[63];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 34 - counterHoursHeating
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[64];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 35 - counterHoursHotWater
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[65];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 36 - counterHeatQHeating
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[151];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 37 - counterHeatQHeating
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[152];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 38 - counterHours2ndHeatSource2
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[61];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 39 - counterHours2ndHeatSource3
|
2014-01-24 18:21:30 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[62];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 40 - opStateHeatPump2
|
2014-01-25 12:21:18 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[118];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 41 - opStateHeatPump2Duration
|
2014-01-25 12:21:18 +00:00
|
|
|
|
$return_str .= "|".$heatpump_values[120];
|
|
|
|
|
# 42 - timeError0
|
|
|
|
|
$return_str .= "|".$heatpump_values[95];
|
2014-01-25 18:44:12 +00:00
|
|
|
|
# 43 - bivalentLevel
|
|
|
|
|
$return_str .= "|".$heatpump_values[79];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# 44 - Number of calculated values
|
|
|
|
|
$return_str .= "|".$count_calc_values;
|
|
|
|
|
# 45 - Number of set parameters
|
|
|
|
|
$return_str .= "|".$count_set_parameter;
|
|
|
|
|
# 46 - opStateHeating
|
|
|
|
|
$return_str .= "|".$heatpump_values[125];
|
|
|
|
|
# 47 - deltaHeatingReduction
|
|
|
|
|
$return_str .= "|".$heatpump_parameters[13];
|
|
|
|
|
# 48 - thresholdTemperatureSetBack
|
|
|
|
|
$return_str .= "|".$heatpump_parameters[111];
|
2014-02-08 10:30:40 +00:00
|
|
|
|
# 49 - hotWaterTemperatureHysterese
|
|
|
|
|
$return_str .= "|".$heatpump_parameters[74];
|
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
return $return_str;
|
|
|
|
|
}
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-18 15:12:15 +00:00
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2014-01-16 18:17:49 +00:00
|
|
|
|
LUXTRONIK2_UpdateDone($)
|
|
|
|
|
{
|
|
|
|
|
my ($string) = @_;
|
|
|
|
|
my $value = "";
|
|
|
|
|
my $state = "";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
return unless(defined($string));
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
my @a = split("\\|",$string);
|
|
|
|
|
my $hash = $defs{$a[0]};
|
|
|
|
|
my $name = $a[0];
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
delete($hash->{helper}{RUNNING_PID});
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
return if($hash->{helper}{DISABLED});
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
Log3 $hash, 5, "$name: LUXTRONIK2_UpdateDone: $string";
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
#Define Status Messages
|
|
|
|
|
my %wpOpStat1 = ( 0 => "Waermepumpe laeuft",
|
|
|
|
|
1 => "Waermepumpe steht",
|
|
|
|
|
2 => "Waermepumpe kommt",
|
|
|
|
|
4 => "Fehler",
|
2014-02-08 10:30:40 +00:00
|
|
|
|
5 => "Abtauen",
|
|
|
|
|
6 => "Warte auf LIN-Verbindung",
|
|
|
|
|
7 => "Verdichter heizt auf");
|
2014-01-16 18:17:49 +00:00
|
|
|
|
my %wpOpStat2 = ( 0 => "Heizbetrieb",
|
|
|
|
|
1 => "Keine Anforderung",
|
2014-01-25 18:44:12 +00:00
|
|
|
|
2 => "Netz Einschaltverzoegerung",
|
2014-01-16 18:17:49 +00:00
|
|
|
|
3 => "Schaltspielzeit",
|
|
|
|
|
4 => "EVU Sperrzeit",
|
|
|
|
|
5 => "Brauchwasser",
|
|
|
|
|
6 => "Stufe",
|
|
|
|
|
7 => "Abtauen",
|
|
|
|
|
8 => "Pumpenvorlauf",
|
|
|
|
|
9 => "Thermische Desinfektion",
|
|
|
|
|
10 => "Kuehlbetrieb",
|
2014-02-08 10:30:40 +00:00
|
|
|
|
12 => "Schwimmbad/Photovoltaik",
|
2014-01-16 18:17:49 +00:00
|
|
|
|
13 => "Heizen_Ext_En",
|
|
|
|
|
14 => "Brauchw_Ext_En",
|
|
|
|
|
16 => "Durchflussueberwachung",
|
|
|
|
|
17 => "Elektrische Zusatzheizung" );
|
|
|
|
|
my %wpMode = ( 0 => "Automatik",
|
2014-02-02 14:10:15 +00:00
|
|
|
|
1 => "Zusatzheizung",
|
|
|
|
|
2 => "Party",
|
|
|
|
|
3 => "Ferien",
|
|
|
|
|
4 => "Aus" );
|
|
|
|
|
my %heatingState = ( 0 => "Abgesenkt",
|
|
|
|
|
1 => "Normal",
|
|
|
|
|
3 => "Aus");
|
2014-01-24 18:21:30 +00:00
|
|
|
|
my %wpType = ( 0 => "ERC", 1 => "SW1",
|
2014-02-02 14:10:15 +00:00
|
|
|
|
2 => "SW2", 3 => "WW1",
|
|
|
|
|
4 => "WW2", 5 => "L1I",
|
|
|
|
|
6 => "L2I", 7 => "L1A",
|
|
|
|
|
8 => "L2A", 9 => "KSW",
|
|
|
|
|
10 => "KLW", 11 => "SWC",
|
|
|
|
|
12 => "LWC", 13 => "L2G",
|
|
|
|
|
14 => "WZS", 15 => "L1I407",
|
|
|
|
|
16 => "L2I407", 17 => "L1A407",
|
|
|
|
|
18 => "L2A407", 19 => "L2G407",
|
|
|
|
|
20 => "LWC407", 21 => "L1AREV",
|
|
|
|
|
22 => "L2AREV", 23 => "WWC1",
|
|
|
|
|
24 => "WWC2", 25 => "L2G404",
|
|
|
|
|
26 => "WZW", 27 => "L1S",
|
|
|
|
|
28 => "L1H", 29 => "L2H",
|
|
|
|
|
30 => "WZWD", 31 => "ERC",
|
|
|
|
|
40 => "WWB_20", 41 => "LD5",
|
|
|
|
|
42 => "LD7", 43 => "SW 37_45",
|
|
|
|
|
44 => "SW 58_69", 45 => "SW 29_56",
|
|
|
|
|
46 => "LD5 (230V)", 47 => "LD7 (230 V)",
|
|
|
|
|
48 => "LD9", 49 => "LD5 REV",
|
|
|
|
|
50 => "LD7 REV", 51 => "LD5 REV 230V",
|
|
|
|
|
52 => "LD7 REV 230V", 53 => "LD9 REV 230V",
|
|
|
|
|
54 => "SW 291", 55 => "LW SEC" );
|
2014-01-24 18:21:30 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
my $counterRetry = $hash->{fhem}{counterRetry};
|
|
|
|
|
$counterRetry++;
|
|
|
|
|
|
|
|
|
|
if ($a[1]==0 ) {
|
|
|
|
|
readingsSingleUpdate($hash,"state","Error: ".$a[2],1);
|
|
|
|
|
$counterRetry = 0;
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
2014-01-16 18:17:49 +00:00
|
|
|
|
elsif ($a[1]==2 ) {
|
|
|
|
|
if ($counterRetry <=3) {
|
|
|
|
|
InternalTimer(gettimeofday() + 5, "LUXTRONIK2_GetUpdate", $hash, 0);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
readingsSingleUpdate($hash,"state","Error: Reading skipped after $counterRetry tries",1);
|
|
|
|
|
Log3 $hash, 2, "$name Error: Device reading skipped after $counterRetry tries with parameter change on target";
|
|
|
|
|
}
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
2014-01-16 18:17:49 +00:00
|
|
|
|
elsif ($a[1]==1 ) {
|
|
|
|
|
$counterRetry = 0;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
readingsBeginUpdate($hash);
|
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# Temporary storage of values because needed several times
|
|
|
|
|
my $ambientTemperature = LUXTRONIK2_CalcTemp($a[12]);
|
|
|
|
|
my $averageAmbientTemperature = LUXTRONIK2_CalcTemp($a[13]);
|
|
|
|
|
my $hotWaterTemperature = LUXTRONIK2_CalcTemp($a[14]);
|
2014-02-08 10:30:40 +00:00
|
|
|
|
my $hotWaterTemperatureTarget = LUXTRONIK2_CalcTemp($a[25]);
|
|
|
|
|
my $hotWaterTemperatureThreshold = LUXTRONIK2_CalcTemp($a[25] - $a[49]);
|
2014-02-02 14:10:15 +00:00
|
|
|
|
my $thresholdHeatingLimit = LUXTRONIK2_CalcTemp($a[21]);
|
|
|
|
|
my $thresholdTemperatureSetBack = LUXTRONIK2_CalcTemp($a[48]);
|
|
|
|
|
my $flowTemperature = LUXTRONIK2_CalcTemp($a[15]);
|
|
|
|
|
my $returnTemperature = LUXTRONIK2_CalcTemp($a[16]);
|
2014-02-08 10:30:40 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# if selected, do all the statistic calculations
|
2014-02-08 10:30:40 +00:00
|
|
|
|
if ( AttrVal($name,"doStatistics",0) == 1) {
|
|
|
|
|
#LUXTRONIK2_doStatisticBoilerHeatUp $hash, $currOpHours, $currHQ, $currTemp, $opState, $target
|
|
|
|
|
$value = LUXTRONIK2_doStatisticBoilerHeatUp ($hash, $a[35], $a[37]/10, $hotWaterTemperature, $a[3],$hotWaterTemperatureTarget);
|
2014-02-02 14:10:15 +00:00
|
|
|
|
if ($value ne "") {
|
2014-02-08 10:30:40 +00:00
|
|
|
|
readingsBulkUpdate($hash,"statBoilerGradientHeatUp",$value);
|
|
|
|
|
Log3 $name,3,"$name: statBoilerGradientHeatUp set to $value";
|
|
|
|
|
}
|
|
|
|
|
#LUXTRONIK2_doStatisticBoilerCoolDown $hash, $time, $currTemp, $opState, $target, $threshold
|
|
|
|
|
$value = LUXTRONIK2_doStatisticBoilerCoolDown ($hash, $a[22], $hotWaterTemperature, $a[3], $hotWaterTemperatureTarget, $hotWaterTemperatureThreshold);
|
|
|
|
|
if ($value ne "") {
|
|
|
|
|
readingsBulkUpdate($hash,"statBoilerGradientCoolDown",$value);
|
|
|
|
|
Log3 $name,3,"$name: statBoilerGradientCoolDown set to $value";
|
|
|
|
|
if ( exists( $hash->{READINGS}{statBoilerGradientCoolDownMin} ) ) {
|
|
|
|
|
my @new = split / /, $value;
|
|
|
|
|
my @old = split / /, $hash->{READINGS}{statBoilerGradientCoolDownMin};
|
|
|
|
|
if ($new[5]>6 && $new[0]<$old[0]) {
|
|
|
|
|
readingsBulkUpdate($hash,"statBoilerGradientCoolDownMin",$value);
|
|
|
|
|
Log3 $name,3,"$name: statBoilerGradientCoolDownMin set to $value";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
readingsBulkUpdate($hash,"statBoilerGradientCoolDownMin",$value);
|
|
|
|
|
Log3 $name,3,"$name: statBoilerGradientCoolDownMin set to $value";
|
|
|
|
|
}
|
2014-02-02 14:10:15 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
#Operating status of heat pump
|
2014-02-02 14:10:15 +00:00
|
|
|
|
my $opStateHeatPump1 = $wpOpStat1{$a[2]}; ##############
|
|
|
|
|
$opStateHeatPump1 = "unbekannt (".$a[2].")" unless $opStateHeatPump1;
|
|
|
|
|
readingsBulkUpdate($hash,"opStateHeatPump1",$opStateHeatPump1);
|
2014-01-25 18:44:12 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
my $opStateHeatPump2 = "unknown ($a[40])"; ##############
|
2014-01-25 12:21:18 +00:00
|
|
|
|
my $prefix = "";
|
|
|
|
|
if ($a[40] == 0 || $a[40] == 2) { $prefix = "seit ";}
|
|
|
|
|
elsif ($a[40] == 1) { $prefix = "in ";}
|
|
|
|
|
if ($a[40] == 2) { #Sonderbehandlung bei WP-Fehlern
|
2014-02-02 14:10:15 +00:00
|
|
|
|
$opStateHeatPump2 = $prefix . strftime "%d.%m.%Y %H:%M:%S", localtime($a[42]);
|
2014-01-25 12:21:18 +00:00
|
|
|
|
} else {
|
2014-02-02 14:10:15 +00:00
|
|
|
|
$opStateHeatPump2 = $prefix . LUXTRONIK2_FormatDuration($a[41]);
|
2014-01-25 12:21:18 +00:00
|
|
|
|
}
|
2014-02-02 14:10:15 +00:00
|
|
|
|
readingsBulkUpdate($hash,"opStateHeatPump2",$opStateHeatPump2);
|
2014-01-25 18:44:12 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
my $opStateHeatPump3 = $wpOpStat2{$a[3]}; ##############
|
2014-01-25 12:21:18 +00:00
|
|
|
|
# refine text of third state
|
2014-01-16 18:17:49 +00:00
|
|
|
|
if ($a[3]==6) {
|
2014-02-02 14:10:15 +00:00
|
|
|
|
$opStateHeatPump3 = "Stufe ".$a[4]." ".LUXTRONIK2_CalcTemp($a[5])." C ";
|
2014-01-16 18:17:49 +00:00
|
|
|
|
}
|
|
|
|
|
elsif ($a[3]==7) {
|
2014-02-02 14:10:15 +00:00
|
|
|
|
if ($a[6]==1) {$opStateHeatPump3 = "Abtauen (Kreisumkehr)";}
|
|
|
|
|
else {$opStateHeatPump3 = "Luftabtauen";}
|
2014-01-16 18:17:49 +00:00
|
|
|
|
}
|
2014-02-02 14:10:15 +00:00
|
|
|
|
$opStateHeatPump3 = "unbekannt (".$a[3].")" unless $opStateHeatPump3;
|
|
|
|
|
readingsBulkUpdate($hash,"opStateHeatPump3",$opStateHeatPump3);
|
2014-01-25 12:21:18 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
# Hot water operating mode
|
|
|
|
|
$value = $wpMode{$a[7]};
|
|
|
|
|
$value = "unbekannt (".$a[7].")" unless $value;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
readingsBulkUpdate($hash,"opModeHotWater",$value);
|
|
|
|
|
# opStateHotWater
|
2014-01-18 15:12:15 +00:00
|
|
|
|
if ($a[8]==0) {$value="Sperrzeit";}
|
2014-01-16 18:17:49 +00:00
|
|
|
|
elsif ($a[8]==1 && $a[9]==1) {$value="Aufheizen";}
|
2014-02-02 14:10:15 +00:00
|
|
|
|
elsif ($a[8]==1 && $a[9]==0) {$value="Temp. OK";}
|
2014-01-18 15:12:15 +00:00
|
|
|
|
elsif ($a[8]==3) {$value="Aus";}
|
2014-01-16 18:17:49 +00:00
|
|
|
|
else {$value = "unbekannt (".$a[8]."/".$a[9].")";}
|
2014-02-02 14:10:15 +00:00
|
|
|
|
readingsBulkUpdate($hash,"opStateHotWater",$value);
|
|
|
|
|
|
|
|
|
|
# Heating operating mode
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$value = $wpMode{$a[10]};
|
2014-02-02 14:10:15 +00:00
|
|
|
|
$value = "unbekannt (".$a[10].")" unless $value;
|
|
|
|
|
readingsBulkUpdate($hash,"opModeHeating",$value);
|
|
|
|
|
# Heating operating state
|
|
|
|
|
# Consider also heating limit
|
2014-01-16 18:17:49 +00:00
|
|
|
|
if ($a[10] == 0
|
|
|
|
|
&& $a[11] == 1
|
2014-02-02 14:10:15 +00:00
|
|
|
|
&& $averageAmbientTemperature >= $thresholdHeatingLimit) {
|
|
|
|
|
$value = "Heizungsgrenze (Aus)";
|
|
|
|
|
} else {
|
|
|
|
|
$value = $heatingState{$a[46]};
|
|
|
|
|
$value = "unbekannt (".$a[46].")" unless $value;
|
|
|
|
|
# Consider heating reduction limit
|
|
|
|
|
if ($a[46] == 0) {
|
|
|
|
|
if ($thresholdTemperatureSetBack <= $ambientTemperature) {
|
|
|
|
|
$value .= " ".LUXTRONIK2_CalcTemp($a[47])." C";
|
|
|
|
|
} else {
|
|
|
|
|
$value = "Normal da < $thresholdTemperatureSetBack C";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
readingsBulkUpdate($hash,"opStateHeating",$value);
|
|
|
|
|
|
|
|
|
|
# Device and reading times, delays and durations
|
|
|
|
|
$value = strftime "%Y-%m-%d %H:%M:%S", localtime($a[22]);
|
|
|
|
|
readingsBulkUpdate($hash, "deviceTimeCalc", $value);
|
|
|
|
|
my $delayDeviceTimeCalc=floor($a[29]-$a[22]+0.5);
|
|
|
|
|
readingsBulkUpdate($hash, "delayDeviceTimeCalc", $delayDeviceTimeCalc);
|
|
|
|
|
my $durationFetchReadings = floor(($a[30]-$a[29]+0.005)*100)/100;
|
|
|
|
|
readingsBulkUpdate($hash, "durationFetchReadings", $durationFetchReadings);
|
|
|
|
|
#Remember min and max reading durations, will be reset when initializing the device
|
|
|
|
|
if ($hash->{fhem}{durationFetchReadingsMin} == 0 || $hash->{fhem}{durationFetchReadingsMin} > $durationFetchReadings) {
|
|
|
|
|
$hash->{fhem}{durationFetchReadingsMin} = $durationFetchReadings;
|
|
|
|
|
}
|
|
|
|
|
if ($hash->{fhem}{durationFetchReadingsMax} < $durationFetchReadings) {
|
|
|
|
|
$hash->{fhem}{durationFetchReadingsMax} = $durationFetchReadings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Temperatures and flow rate
|
|
|
|
|
readingsBulkUpdate( $hash, "ambientTemperature", $ambientTemperature);
|
|
|
|
|
readingsBulkUpdate( $hash, "averageAmbientTemperature", $averageAmbientTemperature);
|
|
|
|
|
readingsBulkUpdate( $hash, "heatingLimit",$a[11]?"on":"off");
|
|
|
|
|
readingsBulkUpdate( $hash, "thresholdHeatingLimit", $thresholdHeatingLimit);
|
|
|
|
|
readingsBulkUpdate( $hash, "thresholdTemperatureSetBack", $thresholdTemperatureSetBack);
|
|
|
|
|
readingsBulkUpdate( $hash, "hotWaterTemperature", $hotWaterTemperature);
|
2014-02-08 10:30:40 +00:00
|
|
|
|
readingsBulkUpdate( $hash, "hotWaterTemperatureTarget",$hotWaterTemperatureTarget);
|
2014-02-02 14:10:15 +00:00
|
|
|
|
readingsBulkUpdate( $hash, "flowTemperature", $flowTemperature);
|
|
|
|
|
readingsBulkUpdate( $hash, "returnTemperature", $returnTemperature);
|
|
|
|
|
readingsBulkUpdate( $hash, "returnTemperatureTarget",LUXTRONIK2_CalcTemp($a[17]));
|
|
|
|
|
readingsBulkUpdate( $hash, "returnTemperatureExtern",LUXTRONIK2_CalcTemp($a[18]));
|
|
|
|
|
readingsBulkUpdate( $hash, "flowRate",$a[19]);
|
|
|
|
|
readingsBulkUpdate( $hash, "heatSourceIN",LUXTRONIK2_CalcTemp($a[23]));
|
|
|
|
|
readingsBulkUpdate( $hash, "heatSourceOUT",LUXTRONIK2_CalcTemp($a[24]));
|
|
|
|
|
readingsBulkUpdate( $hash, "hotGasTemperature",LUXTRONIK2_CalcTemp($a[26]));
|
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
|
|
|
|
|
# Input / Output status
|
2014-02-02 14:10:15 +00:00
|
|
|
|
readingsBulkUpdate($hash,"heatingSystemCircPump",$a[27]?"on":"off");
|
|
|
|
|
readingsBulkUpdate($hash,"hotWaterCircPumpExtern",$a[28]?"on":"off");
|
2014-01-16 18:17:49 +00:00
|
|
|
|
readingsBulkUpdate($hash,"hotWaterSwitchingValve",$a[9]?"on":"off");
|
2014-01-25 18:44:12 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# bivalentLevel
|
2014-01-25 18:44:12 +00:00
|
|
|
|
readingsBulkUpdate($hash,"bivalentLevel",$a[43]);
|
2014-01-16 18:17:49 +00:00
|
|
|
|
|
|
|
|
|
# Firmware
|
2014-01-24 18:21:30 +00:00
|
|
|
|
my $firmware = $a[20];
|
|
|
|
|
readingsBulkUpdate($hash,"firmware",$firmware);
|
|
|
|
|
my $firmwareCheck = LUXTRONIK2_checkFirmware($firmware);
|
2014-01-16 18:17:49 +00:00
|
|
|
|
# if unknown firmware, ask at each startup to inform comunity
|
2014-01-24 18:21:30 +00:00
|
|
|
|
if ($hash->{fhem}{alertFirmware} != 1 && $firmwareCheck eq "fwNotTested") {
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$hash->{fhem}{alertFirmware} = 1;
|
2014-01-24 18:21:30 +00:00
|
|
|
|
Log3 $hash, 2, "$name Alert: Host uses untested Firmware '$a[20]'. Please inform FHEM comunity about compatibility.";
|
2014-01-16 18:17:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
# Type of Heatpump
|
|
|
|
|
$value = $wpType{$a[31]};
|
|
|
|
|
$value = "unbekannt (".$a[31].")" unless $value;
|
|
|
|
|
readingsBulkUpdate($hash,"typeHeatpump",$value);
|
2014-01-25 18:44:12 +00:00
|
|
|
|
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# Operating hours (seconds->hours) and heat quantities, write/create readings only if >0
|
|
|
|
|
if ($a[32]>0) {readingsBulkUpdate($hash,"counterHours2ndHeatSource1",floor($a[32]/360+0.5)/10);}
|
|
|
|
|
if ($a[38]>0) {readingsBulkUpdate($hash,"counterHours2ndHeatSource2",floor($a[38]/360+0.5)/10);}
|
|
|
|
|
if ($a[39]>0) {readingsBulkUpdate($hash,"counterHours2ndHeatSource3",floor($a[39]/360+0.5)/10);}
|
|
|
|
|
if ($a[33]>0) {readingsBulkUpdate($hash,"counterHoursHeatPump",floor($a[33]/360+0.5)/10);}
|
|
|
|
|
if ($a[34]>0) {readingsBulkUpdate($hash,"counterHoursHeating",floor($a[34]/360+0.5)/10);}
|
|
|
|
|
if ($a[35]>0) {readingsBulkUpdate($hash,"counterHoursHotWater",floor($a[35]/360+0.5)/10);}
|
|
|
|
|
if ($a[36]>0) {readingsBulkUpdate($hash,"counterHeatQHeating",$a[36]/10);}
|
|
|
|
|
if ($a[37]>0) {readingsBulkUpdate($hash,"counterHeatQHotWater",$a[37]/10);}
|
|
|
|
|
if ($a[36]+$a[37]>0) {readingsBulkUpdate($hash,"counterHeatQTotal",($a[36]+$a[37])/10);}
|
2014-02-08 10:30:40 +00:00
|
|
|
|
#WM[kW] = delta_Temp [K] * Durchfluss [l/h] / ( 3.600 [kJ/kWh] / ( 4,179 [kJ/(kg*K)] (H2O W<>rmekapazit<69>t bei 30 & 40<34>C) * 0,994 [kg/l] (H2O Dichte bei 35<33>C) )
|
|
|
|
|
$value = ($flowTemperature-$returnTemperature) * $a[19] / 866.65;
|
|
|
|
|
readingsBulkUpdate( $hash, "currentThermalOutput", sprintf("%.1f", $value));
|
2014-02-02 14:10:15 +00:00
|
|
|
|
|
|
|
|
|
# HTML for floorplan
|
|
|
|
|
if(AttrVal($name, "statusHTML", "none") ne "none") {
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$value = "<div class=fp_" . $a[0] . "_title>" . $a[0] . "</div>";
|
2014-02-02 14:10:15 +00:00
|
|
|
|
$value .= "$opStateHeatPump1<br>";
|
|
|
|
|
$value .= "$opStateHeatPump2<br>";
|
|
|
|
|
$value .= "$opStateHeatPump3<br>";
|
|
|
|
|
$value .= "Brauchwasser: $hotWaterTemperature °C";
|
2014-01-16 18:17:49 +00:00
|
|
|
|
readingsBulkUpdate($hash,"floorplanHTML",$value);
|
|
|
|
|
}
|
2014-02-02 14:10:15 +00:00
|
|
|
|
# State update
|
|
|
|
|
readingsBulkUpdate($hash,"state","$opStateHeatPump1 $opStateHeatPump2 - $opStateHeatPump3");
|
2014-01-16 18:17:49 +00:00
|
|
|
|
|
|
|
|
|
readingsEndUpdate($hash,1);
|
2014-02-02 14:10:15 +00:00
|
|
|
|
|
|
|
|
|
$hash->{helper}{fetched_calc_values} = $a[44];
|
|
|
|
|
$hash->{helper}{fetched_parameters} = $a[45];
|
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
############################
|
|
|
|
|
#Auto Synchronize Device Clock
|
|
|
|
|
my $autoSynchClock = AttrVal($name, "autoSynchClock", 0);
|
|
|
|
|
$autoSynchClock = 10 unless ($autoSynchClock >= 10 || $autoSynchClock == 0);
|
|
|
|
|
$autoSynchClock = 600 unless $autoSynchClock <= 600;
|
|
|
|
|
if ($autoSynchClock != 0 and abs($delayDeviceTimeCalc) > $autoSynchClock ) {
|
|
|
|
|
Log3 $name, 3, $name." - autoSynchClock triggered (delayDeviceTimeCalc ".abs($delayDeviceTimeCalc)." > $autoSynchClock).";
|
|
|
|
|
# Firmware not tested and Firmware Check not ignored
|
|
|
|
|
if ($firmwareCheck eq "fwNotTested" && AttrVal($name, "ignoreFirmwareCheck", 0)!= 1) {
|
|
|
|
|
Log3 $name, 1, $name." Error: Host firmware '$firmware' not tested for clock synchronization. To test set 'ignoreFirmwareCheck' to 1.";
|
|
|
|
|
$attr{$name}{autoSynchClock} = 0;
|
|
|
|
|
Log3 $name, 3, $name." Attribute 'autoSynchClock' set to 0.";
|
|
|
|
|
#Firmware not compatible
|
|
|
|
|
} elsif ($firmwareCheck eq "fwNotCompatible") {
|
|
|
|
|
Log3 $name, 1, $name." Error: Host firmware '$firmware' not compatible for host clock synchronization.";
|
|
|
|
|
$attr{$name}{autoSynchClock} = 0;
|
|
|
|
|
Log3 $name, 3, $name." Attribute 'autoSynchClock' set to 0.";
|
|
|
|
|
#Firmware OK -> Synchronize Clock
|
|
|
|
|
} else {
|
|
|
|
|
$value = LUXTRONIK2_synchronizeClock($hash, 600);
|
|
|
|
|
Log3 $hash, 3, "$name ".$value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#End of Auto Synchronize Device Clock
|
|
|
|
|
############################
|
2014-01-16 18:17:49 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Log3 $hash, 5, "$name LUXTRONIK2_DoUpdate-Error: Status = $a[1]";
|
|
|
|
|
}
|
|
|
|
|
$hash->{fhem}{counterRetry} = $counterRetry;
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-16 18:17:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-18 15:12:15 +00:00
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2014-01-16 18:17:49 +00:00
|
|
|
|
LUXTRONIK2_UpdateAborted($)
|
|
|
|
|
{
|
|
|
|
|
my ($hash) = @_;
|
|
|
|
|
delete($hash->{helper}{RUNNING_PID});
|
|
|
|
|
my $name = $hash->{NAME};
|
2014-02-02 14:10:15 +00:00
|
|
|
|
my $host = $hash->{HOST};
|
|
|
|
|
Log3 $hash, 1, "$name Error: Timeout when connecting to host $host";
|
2014-01-16 18:17:49 +00:00
|
|
|
|
}
|
2013-01-01 14:21:40 +00:00
|
|
|
|
|
2014-01-18 15:12:15 +00:00
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2014-01-16 18:17:49 +00:00
|
|
|
|
LUXTRONIK2_CalcTemp($)
|
|
|
|
|
{
|
|
|
|
|
my ($temp) = @_;
|
2014-01-24 18:21:30 +00:00
|
|
|
|
#change unsigned into signed
|
|
|
|
|
if ($temp > 2147483648) {$temp = $temp-4294967296;}
|
2014-01-16 18:17:49 +00:00
|
|
|
|
$temp /= 10;
|
|
|
|
|
return $temp;
|
2013-01-01 14:21:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
|
|
|
|
LUXTRONIK2_FormatDuration($)
|
|
|
|
|
{
|
|
|
|
|
my ($value) = @_;
|
|
|
|
|
my $returnstr = sprintf "%02d:", int($value/3600);
|
|
|
|
|
$value %= 3600;
|
|
|
|
|
$returnstr .= sprintf "%02d:", int($value/60);
|
|
|
|
|
$value %= 60;
|
|
|
|
|
$returnstr .= sprintf "%02d", $value;
|
|
|
|
|
|
|
|
|
|
return $returnstr;
|
|
|
|
|
}
|
2014-01-18 15:12:15 +00:00
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2014-01-18 15:12:15 +00:00
|
|
|
|
LUXTRONIK2_SetParameter($$$)
|
|
|
|
|
{
|
|
|
|
|
my ($hash, $parameterName, $realValue) = @_;
|
|
|
|
|
my $setParameter = 0;
|
|
|
|
|
my $setValue = 0;
|
|
|
|
|
my $result;
|
|
|
|
|
my $buffer;
|
|
|
|
|
my $host = $hash->{HOST};
|
|
|
|
|
my $name = $hash->{NAME};
|
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
my %opMode = ( "Auto" => 0,
|
2014-01-18 15:12:15 +00:00
|
|
|
|
"Party" => 2,
|
|
|
|
|
"Off" => 4);
|
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
if(AttrVal($name, "allowSetParameter", 0) != 1) {
|
|
|
|
|
return $name." Error: Setting of parameters not allowed. Please set attribut 'allowSetParameter' to 1";
|
2014-01-18 15:12:15 +00:00
|
|
|
|
}
|
|
|
|
|
if ($parameterName eq "hotWaterTemperatureTarget") {
|
|
|
|
|
#parameter number
|
|
|
|
|
$setParameter = 2;
|
|
|
|
|
#limit temperature range
|
|
|
|
|
$realValue = 30 if( $realValue < 30 );
|
|
|
|
|
$realValue = 65 if( $realValue > 65 );
|
|
|
|
|
#Allow only integer temperature or with decimal .5
|
|
|
|
|
$setValue = int($realValue * 2) * 5;
|
|
|
|
|
$realValue = $setValue / 10;
|
|
|
|
|
}
|
2014-02-02 14:10:15 +00:00
|
|
|
|
elsif ($parameterName eq "opModeHotWater") {
|
2014-01-18 15:12:15 +00:00
|
|
|
|
if (! exists($opMode{$realValue})) {
|
2014-02-02 14:10:15 +00:00
|
|
|
|
return "$name Error: Wrong parameter given for opModeHotWater, use Automatik,Party,Off"
|
2014-01-18 15:12:15 +00:00
|
|
|
|
}
|
|
|
|
|
$setParameter = 4;
|
|
|
|
|
$setValue = $opMode{$realValue};
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return "$name LUXTRONIK2_SetParameter-Error: unknown parameter $parameterName";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
############################
|
|
|
|
|
# Send new parameter to host
|
|
|
|
|
############################
|
|
|
|
|
if ($setParameter !=0) {
|
|
|
|
|
Log3 $name, 5, "$name: Opening connection to host ".$host;
|
|
|
|
|
my $socket = new IO::Socket::INET ( PeerAddr => $host,
|
|
|
|
|
PeerPort => 8888,
|
|
|
|
|
Proto => 'tcp'
|
|
|
|
|
);
|
|
|
|
|
if (!$socket) {
|
|
|
|
|
Log3 $name, 1, "$name LUXTRONIK2_SetParameter-Error: Could not open connection to host ".$host;
|
|
|
|
|
return "$name Error: Could not open connection to host ".$host;
|
|
|
|
|
}
|
|
|
|
|
$socket->autoflush(1);
|
|
|
|
|
|
|
|
|
|
Log3 $name, 5, "$name: Set parameter $parameterName ($setParameter) = $realValue ($setValue)";
|
|
|
|
|
$socket->send(pack("N", 3002));
|
|
|
|
|
$socket->send(pack("N", $setParameter));
|
|
|
|
|
$socket->send(pack("N", $setValue));
|
|
|
|
|
|
|
|
|
|
Log3 $name, 5, "$name: Receive confirmation";
|
2014-01-24 18:21:30 +00:00
|
|
|
|
#read first 4 bytes of response -> should be request_echo = 3002
|
2014-01-18 15:12:15 +00:00
|
|
|
|
$socket->recv($buffer,4);
|
|
|
|
|
$result = unpack("N", $buffer);
|
|
|
|
|
if($result != 3002) {
|
|
|
|
|
Log3 $name, 2, "$name LUXTRONIK2_SetParameter-Error: Set parameter $parameterName - wrong echo of request: $result instead of 3002";
|
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name Error: Host did not confirm parameter setting";
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
#Read next 4 bytes of response -> should be setParameter
|
2014-01-18 15:12:15 +00:00
|
|
|
|
$socket->recv($buffer,4);
|
|
|
|
|
$result = unpack("N", $buffer);
|
|
|
|
|
if($result !=$setParameter) {
|
|
|
|
|
Log3 $name, 2, "$name LUXTRONIK2_SetParameter-Error: Set parameter $parameterName - missing confirmation: $result instead of $setParameter";
|
|
|
|
|
$socket->close();
|
|
|
|
|
return "$name Error: Host did not confirm parameter setting";
|
|
|
|
|
}
|
|
|
|
|
Log3 $name, 5, "$name: Parameter setting confirmed";
|
|
|
|
|
|
|
|
|
|
$socket->close();
|
|
|
|
|
|
|
|
|
|
readingsSingleUpdate($hash,$parameterName,$realValue,1);
|
|
|
|
|
|
|
|
|
|
return "$name: Parameter $parameterName set to $realValue";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
2014-01-24 18:21:30 +00:00
|
|
|
|
LUXTRONIK2_synchronizeClock (@)
|
|
|
|
|
{
|
|
|
|
|
my ($hash,$maxDelta) = @_;
|
|
|
|
|
my $host = $hash->{HOST};
|
|
|
|
|
my $name = $hash->{NAME};
|
|
|
|
|
my $delay = 0;
|
|
|
|
|
my $returnStr = "";
|
|
|
|
|
|
|
|
|
|
$maxDelta = 60 unless $maxDelta >= 0;
|
|
|
|
|
$maxDelta = 600 unless $maxDelta <= 600;
|
|
|
|
|
|
|
|
|
|
Log3 $name, 5, "$name: Open telnet connection to $host";
|
|
|
|
|
my $telnet = new Net::Telnet ( Host=>$host, Port => 23, Timeout=>10, Errmode=>'return');
|
|
|
|
|
if (!$telnet) {
|
|
|
|
|
Log3 $name, 1, "$name LUXTRONIK2_synchronizeClock-Error: ".$telnet->errmsg;
|
|
|
|
|
return "$name synchronizeDeviceClock-Error: ".$telnet->errmsg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log3 $name, 5, "$name: Log into $host";
|
|
|
|
|
if (!$telnet->login('root', '')) {
|
|
|
|
|
Log3 $name, 1, "$name LUXTRONIK2_synchronizeClock-Error: ".$telnet->errmsg;
|
|
|
|
|
return "$name synchronizeDeviceClock-Error: ".$telnet->errmsg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log3 $name, 5, "$name: Read current time of host";
|
|
|
|
|
my @output = $telnet->cmd('date +%s');
|
|
|
|
|
$delay = floor(time()) - $output[0];
|
|
|
|
|
Log3 $name, 5, "$name: Current time is ".localtime($output[0])." Delay is $delay seconds.";
|
|
|
|
|
|
|
|
|
|
if (abs($delay)>$maxDelta && $maxDelta!=0) {
|
|
|
|
|
$returnStr = "Do not dare to synchronize. Device clock of host $host differs by $delay seconds (max. is $maxDelta).";
|
|
|
|
|
} elsif ($delay == 0) {
|
|
|
|
|
$returnStr = "Internal clock of host $host has no delay. -> not synchronized";
|
|
|
|
|
} else {
|
|
|
|
|
my $newTime = strftime "%m%d%H%M%Y.%S", localtime();
|
|
|
|
|
Log3 $name, 5, "$name: Run command 'date ".$newTime."'";
|
|
|
|
|
@output=$telnet->cmd('date '.$newTime);
|
|
|
|
|
$returnStr = "Internal clock of host $host corrected by $delay seconds. -> ".$output[0];
|
2014-02-02 14:10:15 +00:00
|
|
|
|
readingsSingleUpdate($hash,"deviceTimeLastSync",TimeNow,1);
|
2014-01-24 18:21:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log3 $name, 5, "$name: Close telnet connection.";
|
|
|
|
|
$telnet->close;
|
|
|
|
|
|
|
|
|
|
return $returnStr;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-25 12:21:18 +00:00
|
|
|
|
sub ########################################
|
|
|
|
|
LUXTRONIK2_checkFirmware ($)
|
2014-01-24 18:21:30 +00:00
|
|
|
|
{
|
|
|
|
|
my ($myFirmware) = @_;
|
|
|
|
|
|
|
|
|
|
#Firmware not tested
|
2014-02-02 14:10:15 +00:00
|
|
|
|
if (index($testedFirmware,"#".$myFirmware."#") == -1) {
|
2014-01-24 18:21:30 +00:00
|
|
|
|
return "fwNotTested";
|
|
|
|
|
#Firmware tested but not compatible
|
2014-02-02 14:10:15 +00:00
|
|
|
|
} elsif (index($compatibleFirmware,"#".$myFirmware."#") == -1) {
|
2014-01-24 18:21:30 +00:00
|
|
|
|
return "fwNotCompatible";
|
|
|
|
|
#Firmware compatible
|
|
|
|
|
} else {
|
|
|
|
|
return "fwCompatible";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-08 10:30:40 +00:00
|
|
|
|
# Calculate heat-up gradients of boiler based on hotWaterTemperature and counterHeatQHeating
|
2014-02-02 14:10:15 +00:00
|
|
|
|
sub ########################################
|
2014-02-08 10:30:40 +00:00
|
|
|
|
LUXTRONIK2_doStatisticBoilerHeatUp ($$$$$$)
|
2014-02-02 14:10:15 +00:00
|
|
|
|
{
|
|
|
|
|
|
2014-02-08 10:30:40 +00:00
|
|
|
|
my ($hash, $currOpHours, $currHQ, $currTemp, $opState, $target) = @_;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
my $name = $hash->{NAME};
|
2014-02-08 10:30:40 +00:00
|
|
|
|
my $step = $hash->{fhem}{statBoilerHeatUpStep};
|
|
|
|
|
my $minTemp = $hash->{fhem}{statBoilerHeatUpMin};
|
|
|
|
|
my $maxTemp = $hash->{fhem}{statBoilerHeatUpMax};
|
|
|
|
|
my $lastHQ = $hash->{fhem}{statBoilerHeatUpHQ};
|
|
|
|
|
my $lastOpHours = $hash->{fhem}{statBoilerHeatUpOpHours};
|
|
|
|
|
my $value1 = 0;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
my $value2 = 0;
|
|
|
|
|
my $value3 = 0;
|
2014-02-08 10:30:40 +00:00
|
|
|
|
my $returnStr = "";
|
|
|
|
|
|
|
|
|
|
# step 0 = Initialize - if hot water preparation is off
|
|
|
|
|
if ($step == 0) {
|
|
|
|
|
if ($opState != 5) { # wait till hot water preparation stopped
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Heat-Up step 0->1: Initializing Measurment";
|
|
|
|
|
$step = 1;
|
|
|
|
|
$lastOpHours = $currOpHours;
|
|
|
|
|
$lastHQ = $currHQ;
|
|
|
|
|
$minTemp = $currTemp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# step 1 = wait till hot water preparation starts -> monitor Tmin, take previous HQ and previous operating hours
|
|
|
|
|
} elsif ($step == 1) {
|
|
|
|
|
if ($currTemp < $minTemp) { # monitor minimum temperature
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Heat-Up step 1: Monitor minimum temperature ($minTemp -> $currTemp)";
|
|
|
|
|
$minTemp = $currTemp;
|
|
|
|
|
}
|
|
|
|
|
if ($opState != 5) { # wait -> update operating hours and HQ to be used as start value in calculations
|
|
|
|
|
$lastOpHours = $currOpHours;
|
|
|
|
|
$lastHQ = $currHQ;
|
|
|
|
|
} else { # go to step 2 - if hot water preparation running
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Heat-Up step 1->2: Hot water preparation started ".($currOpHours-$lastOpHours)." s ago";
|
|
|
|
|
$step = 2;
|
|
|
|
|
$maxTemp = $currTemp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# step 2 = wait till hot water preparation done and target reached
|
|
|
|
|
} elsif ($step == 2) {
|
|
|
|
|
if ($currTemp < $minTemp) { # monitor minimal temperature
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Heat-Up step 2: Boiler temperature still decreasing ($minTemp -> $currTemp)";
|
|
|
|
|
$minTemp = $currTemp;
|
|
|
|
|
}
|
|
|
|
|
if ($currTemp > $maxTemp) { # monitor maximal temperature
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Heat-Up step 2: Boiler temperature increasing ($maxTemp -> $currTemp)";
|
|
|
|
|
$maxTemp = $currTemp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($opState != 5) { # wait till hot water preparation stopped
|
|
|
|
|
if ($currTemp >= $target) {
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Heat-Up step 2->3: Hot water preparation stopped";
|
|
|
|
|
$step = 3;
|
|
|
|
|
} else {
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Heat-Up step 2->1: Measurement cancelled (hot water preparation stopped but target not reached, $currTemp < $target)";
|
|
|
|
|
$step = 1;
|
|
|
|
|
$lastOpHours = $currOpHours;
|
|
|
|
|
$lastHQ = $currHQ;
|
|
|
|
|
$minTemp = $currTemp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# step 3 = wait with calculation till temperature maximum reached once
|
|
|
|
|
} elsif ($step == 3) {
|
|
|
|
|
# cancel measurement - if hot water preparation has restarted
|
|
|
|
|
if ($opState == 5) {
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Heat-Up step 3->0: Measurement cancelled (hot water preparation restarted before maximum reached)";
|
|
|
|
|
$step = 0;
|
|
|
|
|
# monitor maximal temperature
|
|
|
|
|
} elsif ($currTemp > $maxTemp) {
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Heat-Up step 3: Temperature still increasing ($maxTemp -> $currTemp)";
|
|
|
|
|
$maxTemp = $currTemp;
|
|
|
|
|
# else calculate temperature gradient
|
|
|
|
|
} else {
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Heat-Up step 3->1: Boiler heat-up measurement finished";
|
|
|
|
|
$value1 = ( int(10 * $maxTemp) - int(10 * $minTemp) ) / 10; # delta hot water temperature
|
|
|
|
|
$value2 = ( $currOpHours - $lastOpHours ) / 60; # delta time (minutes)
|
|
|
|
|
# $value3 = floor(100 * $value1 / $value2 + 0.5) / 100; # Temperature gradient over time rounded to 1/100th
|
|
|
|
|
# $value2 = floor(100 * $value2 + 0.5) / 100; # rounded to 1/100th
|
|
|
|
|
$returnStr = "DT/min: ".sprintf("%.2f", $value1/$value2)." DT: ".sprintf("%.2f", $value1)." Dmin: ".sprintf("%.0f", $value2);
|
|
|
|
|
|
|
|
|
|
$value2 = $currHQ - $lastHQ; # delta heat quantity
|
|
|
|
|
# $value2 = floor(10*($currHQ - $lastHQ)+0.5)/10; # delta heat quantity
|
|
|
|
|
# $value3 = floor(100 * $value2 / $value1 + 0.5) / 100; # heat gradient over temperature rounded to 1/100th
|
|
|
|
|
$returnStr .= " DQ/T: ".sprintf("%.2f",$value2/$value1)." DQ: ".sprintf("%.1f",$value2);
|
|
|
|
|
|
|
|
|
|
#Volumen [l] = W<>rmemenge [kWh] / (delta T) [K] * ( 3.600 [kJ/kWh] / ( 4,179 [kJ/(kg*K)] (H2O W<>rmekapazit<69>t bei 40<34>C) * 0,992 [kg/l] (H2O Dichte bei 40<34>C) ) [K/(kWh*l)] )
|
|
|
|
|
$value3 = 868.4 * $value2 / $value1 ; # heated water volume in liter
|
|
|
|
|
$returnStr .= " DV: ".sprintf("%.0f",$value3);
|
|
|
|
|
|
|
|
|
|
$step = 1;
|
|
|
|
|
$lastOpHours = $currOpHours;
|
|
|
|
|
$lastHQ = $currHQ;
|
|
|
|
|
$minTemp = $currTemp;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$hash->{fhem}{statBoilerHeatUpStep} = $step;
|
|
|
|
|
$hash->{fhem}{statBoilerHeatUpMin} = $minTemp;
|
|
|
|
|
$hash->{fhem}{statBoilerHeatUpMax} = $maxTemp;
|
|
|
|
|
$hash->{fhem}{statBoilerHeatUpHQ} = $lastHQ;
|
|
|
|
|
$hash->{fhem}{statBoilerHeatUpOpHours} = $lastOpHours;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
|
2014-02-08 10:30:40 +00:00
|
|
|
|
return $returnStr;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
|
2014-02-08 10:30:40 +00:00
|
|
|
|
}
|
2014-02-02 14:10:15 +00:00
|
|
|
|
|
2014-02-08 10:30:40 +00:00
|
|
|
|
# Calculate heat loss gradients of boiler based on hotWaterTemperature and counterHeatQHeating
|
|
|
|
|
sub ########################################
|
|
|
|
|
LUXTRONIK2_doStatisticBoilerCoolDown ($$$$$$)
|
|
|
|
|
{
|
|
|
|
|
my ($hash, $time, $currTemp, $opState, $target, $threshold) = @_;
|
|
|
|
|
my $name = $hash->{NAME};
|
|
|
|
|
my $step = $hash->{fhem}{statBoilerCoolDownStep};
|
|
|
|
|
my $maxTemp = $hash->{fhem}{statBoilerCoolDownMax};
|
|
|
|
|
my $startTime = $hash->{fhem}{statBoilerCoolDownStartTime};
|
|
|
|
|
my $value1 = 0;
|
|
|
|
|
my $value2 = 0;
|
|
|
|
|
my $value3 = 0;
|
|
|
|
|
my $returnStr = "";
|
|
|
|
|
|
|
|
|
|
# step 0 = Initialize - if hot water preparation is off and target reached,
|
|
|
|
|
if ($step == 0) {
|
|
|
|
|
if ($opState == 5 || $currTemp < $target) { # -> stay step 0
|
|
|
|
|
# Log3 $name, 4, "$name: Statistic Boiler Cool-Down step 0: Wait till hot water preparation stops and target is reached ($currTemp < $target)";
|
2014-02-02 14:10:15 +00:00
|
|
|
|
} else {
|
2014-02-08 10:30:40 +00:00
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Cool-Down step 0->1: Initializing, target reached ($currTemp >= $target)";
|
|
|
|
|
$step = 1;
|
|
|
|
|
$startTime = $time;
|
|
|
|
|
$maxTemp = $currTemp;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
}
|
2014-02-08 10:30:40 +00:00
|
|
|
|
# step 1 = wait till threshold is reached -> do calculation, monitor maximal temperature
|
|
|
|
|
} elsif ($step == 1) {
|
|
|
|
|
if ($currTemp > $maxTemp) { # monitor maximal temperature
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Cool-Down step 1: Temperature still increasing ($currTemp > $maxTemp)";
|
|
|
|
|
$maxTemp = $currTemp;
|
|
|
|
|
$startTime = $time;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
}
|
2014-02-08 10:30:40 +00:00
|
|
|
|
if ($opState == 5) {
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Cool-Down step 1: Measurement cancelled (restart of hot water preparation)";
|
|
|
|
|
$step = 0;
|
|
|
|
|
} elsif ($currTemp <= $threshold) {
|
|
|
|
|
Log3 $name, 4, "$name: Statistic Boiler Cool-Down step 2->1: Measurement finished, threshold reached ($currTemp <= $threshold)";
|
|
|
|
|
$value1 = ( int(10 * $currTemp) - int(10 * $maxTemp) ) / 10; # delta hot water temperature
|
|
|
|
|
$value2 = ( $time - $startTime ) / 3600; # delta time (hours)
|
|
|
|
|
$value3 = floor(100 * $value1 / $value2 + 0.5) / 100; # Temperature gradient over time rounded to 1/100th
|
|
|
|
|
$value2 = floor(100 * $value2 + 0.5) / 100; # rounded to 1/100th
|
|
|
|
|
$returnStr = "DT/h: $value3 DT: $value1 Dh: $value2";
|
|
|
|
|
|
|
|
|
|
$step = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$hash->{fhem}{statBoilerCoolDownStep} = $step;
|
|
|
|
|
$hash->{fhem}{statBoilerCoolDownMax} = $maxTemp;
|
|
|
|
|
$hash->{fhem}{statBoilerCoolDownStartTime} = $startTime;
|
|
|
|
|
|
|
|
|
|
return $returnStr;
|
2014-02-02 14:10:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-01-01 14:21:40 +00:00
|
|
|
|
1;
|
|
|
|
|
|
|
|
|
|
=pod
|
|
|
|
|
=begin html
|
|
|
|
|
|
|
|
|
|
<a name="LUXTRONIK2"></a>
|
|
|
|
|
<h3>LUXTRONIK2</h3>
|
|
|
|
|
<ul>
|
2014-02-08 10:30:40 +00:00
|
|
|
|
Luxtronik 2.0 is a heating controller used in Alpha Innotec and Siemens Novelan (WPR NET) heat pumps.<br>
|
2014-01-24 18:21:30 +00:00
|
|
|
|
It has a built-in ethernet port, so it can be directly integrated into a local area network (LAN).
|
2014-01-25 12:21:18 +00:00
|
|
|
|
<br>
|
2014-02-02 14:10:15 +00:00
|
|
|
|
<i>The modul is reported to work with firmware: V1.54C, V1.60, V1.69.</i>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
<br>
|
2013-01-01 14:21:40 +00:00
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
<a name="LUXTRONIK2define"></a>
|
|
|
|
|
<b>Define</b>
|
|
|
|
|
<ul>
|
2014-01-16 18:17:49 +00:00
|
|
|
|
<code>define <name> LUXTRONIK2 <IP-address> [poll-interval]</code>
|
2013-01-01 14:21:40 +00:00
|
|
|
|
<br>
|
2014-01-25 18:44:12 +00:00
|
|
|
|
If the pool interval is omitted, it is set to 300 (seconds). Smallest possible value is 30.
|
2013-01-01 14:21:40 +00:00
|
|
|
|
<br>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
Example: <code>define Heizung LUXTRONIK2 192.168.0.12 600</code>
|
2013-01-01 14:21:40 +00:00
|
|
|
|
</ul>
|
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
<a name="LUXTRONIK2set"></a>
|
2014-01-24 18:21:30 +00:00
|
|
|
|
<b>Set</b><br>
|
2014-01-24 18:35:10 +00:00
|
|
|
|
<ul>A firmware check assures before each set operation that a heat pump with untested firmware is not damaged accidently.
|
2014-02-08 10:30:40 +00:00
|
|
|
|
<li><code>opModeHotWater <Mode></code><br>
|
|
|
|
|
Operating Mode of domestic hot water boiler (Auto | Party | Off)</li>
|
|
|
|
|
<li><code>hotWaterTemperatureTarget <temperature></code><br>
|
|
|
|
|
Target temperature of domestic hot water boiler in °C</li>
|
|
|
|
|
<li><code>INTERVAL <polling interval></code><br>
|
|
|
|
|
Polling interval in seconds</li>
|
|
|
|
|
<li><code>statusRequest</code><br>
|
|
|
|
|
Update device information</li>
|
|
|
|
|
<li><code>synchClockHeatPump</code><br>
|
|
|
|
|
Synchronizes controller clock with FHEM time. <b>!! This change is lost in case of controller power off!!</b></li>
|
2014-01-24 18:35:10 +00:00
|
|
|
|
</ul>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
<br>
|
2013-01-01 14:21:40 +00:00
|
|
|
|
<a name="LUXTRONIK2get"></a>
|
|
|
|
|
<b>Get</b>
|
|
|
|
|
<ul>
|
|
|
|
|
No get implemented yet ...
|
|
|
|
|
</ul>
|
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
<a name="LUXTRONIK2attr"></a>
|
|
|
|
|
<b>Attributes</b>
|
|
|
|
|
<ul>
|
2014-02-08 10:30:40 +00:00
|
|
|
|
<li><code>statusHTML</code><br>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
If set, a HTML-formatted reading named "floorplanHTML" is created. It can be used with the <a href="#FLOORPLAN">FLOORPLAN</a> module.<br>
|
2014-01-24 18:21:30 +00:00
|
|
|
|
Currently, if the value of this attribute is not NULL, the corresponding reading consists of the current status of the heat pump and the temperature of the water.</li>
|
2014-02-08 10:30:40 +00:00
|
|
|
|
<li><code>doStatistics < 0 | 1 ></code><br>
|
|
|
|
|
Calculates statistic values: <i>statBoilerGradientHeatUp, statBoilerGradientCoolDown, statBoilerGradientCoolDownMin (boiler heat loss)</i></li>
|
|
|
|
|
<li><code>allowSetParameter < 0 | 1 ></code><br>
|
2014-01-24 18:21:30 +00:00
|
|
|
|
The <a href="#LUXTRONIK2set">parameters</a> of the heat pump controller can only be changed if this attribut is set to 1.</li>
|
2014-02-08 10:30:40 +00:00
|
|
|
|
<li><code>autoSynchClock <delay></code><br>
|
2014-02-02 14:10:15 +00:00
|
|
|
|
Corrects the clock of the heatpump automatically if a certain <i>delay</i> (10 s - 600 s) against the FHEM time is exeeded. Does a firmware check before.<br>
|
|
|
|
|
<i>(A 'delayDeviceTimeCalc' <= 2 s can be caused by the internal calculation interval of the heat pump controller.)</i></li>
|
2014-02-08 10:30:40 +00:00
|
|
|
|
<li><code>ignoreFirmwareCheck < 0 | 1 ></code><br>
|
2014-02-02 14:10:15 +00:00
|
|
|
|
A firmware check assures before each set operation that a heatpump controller with untested firmware is not damaged accidently.<br>
|
|
|
|
|
If this attribute is set to 1, the firmware check is ignored and new firmware can be tested for compatibility.</li>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
|
|
|
|
|
</ul>
|
2013-01-01 14:21:40 +00:00
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
=end html
|
2014-01-24 18:21:30 +00:00
|
|
|
|
|
|
|
|
|
=begin html_DE
|
2014-01-25 12:21:18 +00:00
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
<a name="LUXTRONIK2"></a>
|
|
|
|
|
<h3>LUXTRONIK2</h3>
|
|
|
|
|
<ul>
|
2014-02-02 14:10:15 +00:00
|
|
|
|
Die Luxtronik 2.0 ist eine Heizungssteuerung, welche in Wärmepumpen von Alpha Innotec und Siemens Novelan (WPR NET) verbaut ist.<br>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
Sie besitzt einen Ethernet Anschluss, so dass sie direkt in lokale Netzwerke (LAN) integriert werden kann.<br>
|
2014-02-02 14:10:15 +00:00
|
|
|
|
<i>Das Modul wurde bisher mit folgender Steuerungs-Firmware getestet: V1.54C, V1.60, V1.69.</i>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
<br>
|
2014-01-24 18:21:30 +00:00
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
<a name="LUXTRONIK2define"></a>
|
|
|
|
|
<b>Define</b>
|
|
|
|
|
<ul>
|
|
|
|
|
<code>define <name> LUXTRONIK2 <IP-Adresse> [Abfrage-Interval]</code>
|
|
|
|
|
<br>
|
2014-01-25 18:44:12 +00:00
|
|
|
|
Wenn das Abfrage-Interval nicht angegeben ist, wird es auf 300 (Sekunden) gesetzt. Der kleinste mögliche Wert ist 30.
|
2014-01-24 18:21:30 +00:00
|
|
|
|
<br>
|
2014-01-24 18:35:10 +00:00
|
|
|
|
Beispiel: <code>define Heizung LUXTRONIK2 192.168.0.12 600</code>
|
|
|
|
|
|
2014-01-24 18:21:30 +00:00
|
|
|
|
</ul>
|
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
<a name="LUXTRONIK2set"></a>
|
|
|
|
|
<b>Set</b><br>
|
2014-01-24 18:35:10 +00:00
|
|
|
|
<ul>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
Durch einen Firmware-Test wird vor jeder Set-Operation sichergestellt, dass Wärmepumpen mit ungetester Firmware nicht unabsichtlich beschädigt werden.
|
2014-02-02 14:10:15 +00:00
|
|
|
|
<li>opModeHotWater <Betriebsmodus> - Betriebsmodus des Heißwasserboilers ( Auto | Party | Off )</l>
|
|
|
|
|
<li>hotWaterTemperatureTarget <Temperatur> - Soll-Temperatur des Heißwasserboilers in °C</li>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
<li>INTERVAL <Abfrageinterval> - Abfrageinterval in Sekunden</li>
|
2014-02-02 14:10:15 +00:00
|
|
|
|
<li>statusRequest - Aktualisieren der Gerätewerte</li>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
<li>synchClockHeatPump - Abgleich der Uhr der Steuerung mit der FHEM Zeit. <br>
|
2014-02-02 14:10:15 +00:00
|
|
|
|
<b>!! Diese Änderung geht verloren, sobald die Steuerung ausgeschaltet wird!!</b></li>
|
2014-01-24 18:35:10 +00:00
|
|
|
|
</ul>
|
2014-01-24 18:21:30 +00:00
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
<a name="LUXTRONIK2get"></a>
|
|
|
|
|
<b>Get</b>
|
|
|
|
|
<ul>
|
|
|
|
|
Es wurde noch kein "get" implementiert ...
|
|
|
|
|
</ul>
|
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
<a name="LUXTRONIK2attr"></a>
|
|
|
|
|
<b>Attribute</b>
|
|
|
|
|
<ul>
|
|
|
|
|
<li>statusHTML<br>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
wenn gesetzt, dann wird ein HTML-formatierter Wert "floorplanHTML" erzeugt, welcher vom Modul <a href="#FLOORPLAN">FLOORPLAN</a> genutzt werden kann.<br>
|
2014-01-24 18:21:30 +00:00
|
|
|
|
Momentan wird nur geprüft, ob der Wert dieses Attributes ungleich NULL ist, der entsprechende Gerätewerte besteht aus dem aktuellen Wärmepumpenstatus und der Heizwassertemperatur.</li>
|
2014-02-02 14:10:15 +00:00
|
|
|
|
<li>doStatistics < 0 | 1 ><br>
|
2014-02-08 10:30:40 +00:00
|
|
|
|
Berechnet statistische Werte: <i>statBoilerGradientHeatUp, statBoilerGradientCoolDown, statBoilerGradientCoolDownMin (W<EFBFBD>rmeverlust des Boilers)</i></li>
|
2014-02-02 14:10:15 +00:00
|
|
|
|
<li>allowSetParameter < 0 | 1 ><br>
|
2014-01-24 18:21:30 +00:00
|
|
|
|
Die internen <a href="#LUXTRONIK2set">Parameter</a> der Wärmepumpensteuerung können nur geändert werden, wenn dieses Attribut auf 1 gesetzt ist.</li>
|
2014-01-24 18:35:10 +00:00
|
|
|
|
<li>autoSynchClock <Zeitunterschied><br>
|
2014-01-25 12:21:18 +00:00
|
|
|
|
Die Uhr der Wärmepumpe wird automatisch korrigiert, wenn ein gewisser <i>Zeitunterschied</i> (10 s - 600 s) gegenüber der FHEM Zeit erreicht ist. Zuvor wird die Kompatibilität der Firmware überprüft.<br>
|
|
|
|
|
<i>(Ein Gerätewert 'delayDeviceTimeCalc' <= 2 s ist auf die internen Berechnungsintervale der Wärmepumpensteuerung zurückzuführen.)</i></li>
|
|
|
|
|
<li>ignoreFirmwareCheck < 0 | 1 ><br>
|
|
|
|
|
Durch einen Firmware-Test wird vor jeder Set-Operation sichergestellt, dass Wärmepumpen mit ungetester Firmware nicht unabsichtlich beschädigt werden. Wenn dieses Attribute auf 1 gesetzt ist, dann wird der Firmware-Test ignoriert und neue Firmware kann getestet werden. Dieses Attribut wird jedoch ignoriert, wenn die Steuerungs-Firmware bereits als nicht kompatibel berichtet wurde.</li>
|
|
|
|
|
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
|
2014-01-24 18:21:30 +00:00
|
|
|
|
</ul>
|
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
=end html_DE
|
2013-01-01 14:21:40 +00:00
|
|
|
|
=cut
|
2014-01-16 18:17:49 +00:00
|
|
|
|
|