diff --git a/fhem/CHANGED b/fhem/CHANGED
index d8ed52345..841a055ca 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
+ - change: 88_HMCCU: New features and bug fixes
- feature: 36_WMBUS: initial support for mode 7 encryption (mostly untested)
Digest::CMAC must be installed
- feature: 72_XiaomiDevice: added S1 vacuum states
diff --git a/fhem/FHEM/88_HMCCU.pm b/fhem/FHEM/88_HMCCU.pm
index a51ac5eea..dcbc21104 100755
--- a/fhem/FHEM/88_HMCCU.pm
+++ b/fhem/FHEM/88_HMCCU.pm
@@ -4,7 +4,7 @@
#
# $Id$
#
-# Version 4.3.016
+# Version 4.3.017
#
# Module for communication between FHEM and Homematic CCU2/3.
#
@@ -52,7 +52,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version
-my $HMCCU_VERSION = '4.3.015';
+my $HMCCU_VERSION = '4.3.017';
# Constants and default values
my $HMCCU_MAX_IOERRORS = 100;
@@ -202,12 +202,13 @@ sub HMCCU_AggregateReadings ($$);
sub HMCCU_AggregationRules ($$);
# Handling of default attributes
+sub HMCCU_DetectDefaults ($$);
sub HMCCU_ExportDefaults ($$);
sub HMCCU_ExportDefaultsCSV ($$);
sub HMCCU_ImportDefaults ($);
sub HMCCU_FindDefaults ($$);
-sub HMCCU_SetDefaults ($);
sub HMCCU_GetDefaults ($$);
+sub HMCCU_SetDefaults ($);
# Status and logging functions
sub HMCCU_Trace ($$$$);
@@ -229,7 +230,8 @@ sub HMCCU_SubstVariables ($$$);
# Update client device readings
sub HMCCU_BulkUpdate ($$$$);
sub HMCCU_GetUpdate ($$$);
-sub HMCCU_UpdateClients ($$$$$);
+sub HMCCU_UpdateCB ($$$);
+sub HMCCU_UpdateClients ($$$$$$);
sub HMCCU_UpdateInternalValues ($$$$);
sub HMCCU_UpdateMultipleDevices ($$);
sub HMCCU_UpdatePeers ($$$$);
@@ -251,6 +253,7 @@ sub HMCCU_RPCDeRegisterCallback ($);
sub HMCCU_RPCRegisterCallback ($);
sub HMCCU_RPCGetConfig ($$$$);
sub HMCCU_RPCSetConfig ($$$);
+sub HMCCU_RPCRequest ($$$$$;$);
sub HMCCU_StartExtRPCServer ($);
sub HMCCU_StartIntRPCServer ($);
sub HMCCU_StopExtRPCServer ($);
@@ -261,6 +264,7 @@ sub HMCCU_ParseObject ($$$);
sub HMCCU_IsDevAddr ($$);
sub HMCCU_IsChnAddr ($$);
sub HMCCU_SplitChnAddr ($);
+sub HMCCU_SplitDatapoint ($;$);
# FHEM device handling functions
sub HMCCU_AssignIODevice ($$$);
@@ -270,6 +274,7 @@ sub HMCCU_GetHash ($@);
sub HMCCU_GetAttribute ($$$$);
sub HMCCU_GetFlags ($);
sub HMCCU_GetAttrReadingFormat ($$);
+sub HMCCU_GetAttrStripNumber ($);
sub HMCCU_GetAttrSubstitute ($$);
sub HMCCU_IODeviceStates ();
sub HMCCU_IsFlag ($$);
@@ -308,8 +313,9 @@ sub HMCCU_GetSpecialDatapoints ($$$$$);
sub HMCCU_GetSwitchDatapoint ($$$);
sub HMCCU_GetValidDatapoints ($$$$$);
sub HMCCU_IsValidDatapoint ($$$$$);
-sub HMCCU_SetDatapoint ($$$);
+# sub HMCCU_SetDatapoint ($$$);
sub HMCCU_SetMultipleDatapoints ($$);
+sub HMCCU_SetMultipleParameters ($$$);
# Internal RPC server functions
sub HMCCU_ResetRPCQueue ($$);
@@ -321,7 +327,7 @@ sub HMCCU_GetVariables ($$);
sub HMCCU_HMCommand ($$$);
sub HMCCU_HMCommandCB ($$$);
sub HMCCU_HMCommandNB ($$$);
-sub HMCCU_HMScriptExt ($$$);
+sub HMCCU_HMScriptExt ($$$$$);
sub HMCCU_SetVariable ($$$$$);
sub HMCCU_UpdateVariables ($);
@@ -388,8 +394,9 @@ sub HMCCU_Initialize ($)
" ccudef-hmstatevals:textField-long ccudef-substitute:textField-long".
" ccudef-readingname:textField-long ccudef-readingfilter:textField-long".
" ccudef-readingformat:name,namelc,address,addresslc,datapoint,datapointlc".
+ " ccudef-stripnumber".
" ccuflags:multiple-strict,extrpc,intrpc,procrpc,dptnocheck,noagg,nohmstate,".
- "logEvents,noEvents,noReadings,nonBlocking,reconnect,logPong,trace".
+ "logEvents,noEvents,noInitialUpdate,noReadings,nonBlocking,reconnect,logPong,trace".
" ccuReqTimeout ccuGetVars rpcinterval:2,3,5,7,10 rpcqueue rpcPingCCU".
" rpcport:multiple-strict,".join(',',sort keys %HMCCU_RPC_NUMPORT).
" rpcserver:on,off rpcserveraddr rpcserverport rpctimeout rpcevtimeout parfile substitute".
@@ -1090,6 +1097,17 @@ sub HMCCU_GetDefaults ($$)
return $result;
}
+######################################################################
+# Try to detect default attributes
+######################################################################
+
+sub HMCCU_DetectDefaults ($$)
+{
+ my ($hash, $object) = @_;
+
+ my $response = HMCCU_GetDeviceInfo ($hash, $object, 'Value');
+}
+
######################################################################
# Handle FHEM events
######################################################################
@@ -1375,9 +1393,12 @@ sub HMCCU_Set ($@)
my ($hash, $a, $h) = @_;
my $name = shift @$a;
my $opt = shift @$a;
- my $options = "avar clear delete execute hmscript cleardefaults:noArg defaults:noArg ".
+ my $options = "avar clear delete execute hmscript cleardefaults:noArg datapoint defaults:noArg ".
"importdefaults rpcregister:all rpcserver:on,off,restart ackmessages:noArg authentication ".
"prgActivate prgDeactivate";
+
+ return "No set command specified" if (!defined ($opt));
+
my @ifList = HMCCU_GetRPCInterfaceList ($hash);
if (scalar (@ifList) > 0) {
my $ifStr = join (',', @ifList);
@@ -1487,7 +1508,56 @@ sub HMCCU_Set ($@)
return HMCCU_SetState ($hash, "OK");
}
elsif ($opt eq 'datapoint') {
- return HMCCU_SetError ($hash, "Command set datapoint is no longer supported by I/O device");
+ $usage = "set $name $opt FHEM-Device[.Channel].Datapoint=Value [...]";
+ return HMCCU_SetError ($hash, $usage) if (scalar (keys %$h) < 1);
+
+ my $cmd = 1;
+ my %dpValues;
+
+ foreach my $dptSpec (keys %$h) {
+ my $adr;
+ my $chn;
+ my $dpt;
+ my ($devName, $t1, $t2) = split (/\./, $dptSpec);
+
+ return HMCCU_SetError ($hash, "FHEM device $devName not defined")
+ if (!exists ($defs{$devName}));
+
+ my $dh = $defs{$devName};
+ my $ccuif = $dh->{ccuif};
+
+ if ($dh->{TYPE} eq 'HMCCUCHN') {
+ return HMCCU_SetError ($hash, "Channel number not allowed for FHEM device $devName")
+ if (defined ($t2));
+ ($adr, $chn) = HMCCU_SplitChnAddr ($dh->{ccuaddr});
+ $dpt = $t1;
+ }
+ elsif ($dh->{TYPE} eq 'HMCCUDEV') {
+ return HMCCU_SetError ($hash, "Missing channel number for device $devName")
+ if (!defined ($t2));
+ return HMCCU_SetError ($hash, "Invalid channel number specified for device $devName")
+ if ($t1 !~ /^[0-9]+$/ || $t1 > $dh->{channels});
+ $adr = $dh->{ccuaddr};
+ $chn = $t1;
+ $dpt = $t2;
+ }
+ else {
+ return HMCCU_SetError ($hash, "FHEM device $devName has illegal type");
+ }
+
+ return HMCCU_SetError ($hash, "Invalid datapoint $dpt specified for device $devName")
+ if (!HMCCU_IsValidDatapoint ($dh, $dh->{ccutype}, $chn, $dpt, 2));
+
+ my $statevals = AttrVal ($dh->{NAME}, 'statevals', '');
+
+ my $no = sprintf ("%03d", $cmd);
+ $dpValues{"$no.$ccuif.$devName:$chn.$dpt"} = HMCCU_Substitute ($h->{$dptSpec}, $statevals, 1, undef, '');
+ $cmd++;
+ }
+
+ my $rc = HMCCU_SetMultipleDatapoints ($hash, \%dpValues);
+ return HMCCU_SetError ($hash, $rc) if ($rc < 0);
+ return HMCCU_SetState ($hash, "OK");
}
elsif ($opt eq 'delete') {
my $objname = shift @$a;
@@ -1498,7 +1568,8 @@ sub HMCCU_Set ($@)
return HMCCU_SetError ($hash, $usage)
if (!defined ($objname) || $objtype !~ /^(OT_VARDP|OT_DEVICE)$/);
- $result = HMCCU_HMScriptExt ($hash, "!DeleteObject", { name => $objname, type => $objtype });
+ $result = HMCCU_HMScriptExt ($hash, "!DeleteObject", { name => $objname, type => $objtype },
+ undef, undef);
return HMCCU_SetError ($hash, -2) if ($result =~ /^ERROR:.*/);
return HMCCU_SetState ($hash, "OK");
@@ -1524,7 +1595,8 @@ sub HMCCU_Set ($@)
return HMCCU_SetError ($hash, $usage) if (!defined ($program));
- $result = HMCCU_HMScriptExt ($hash, "!ActivateProgram", { name => $program, mode => $mode });
+ $result = HMCCU_HMScriptExt ($hash, "!ActivateProgram", { name => $program, mode => $mode },
+ undef, undef);
return HMCCU_SetError ($hash, -2) if ($result =~ /^ERROR:.*/);
return HMCCU_SetState ($hash, "OK");
@@ -1553,13 +1625,13 @@ sub HMCCU_Set ($@)
return HMCCU_SetError ($hash, $usage) if (defined ($dump) && $dump ne 'dump');
# Execute script
- $response = HMCCU_HMScriptExt ($hash, $script, $h);
+ $response = HMCCU_HMScriptExt ($hash, $script, $h, undef, undef);
return HMCCU_SetError ($hash, -2, $response) if ($response =~ /^ERROR:/);
HMCCU_SetState ($hash, "OK");
return $response if (! $ccureadings || defined ($dump));
- foreach my $line (split /\n/, $response) {
+ foreach my $line (split /[\n\r]+/, $response) {
my @tokens = split /=/, $line;
next if (@tokens != 2);
my $reading;
@@ -1646,7 +1718,7 @@ sub HMCCU_Set ($@)
return HMCCU_SetState ($hash, "OK");
}
elsif ($opt eq 'ackmessages') {
- my $response = HMCCU_HMScriptExt ($hash, "!ClearUnreachable", undef);
+ my $response = HMCCU_HMScriptExt ($hash, "!ClearUnreachable", undef, undef, undef);
return HMCCU_SetError ($hash, -2, $response) if ($response =~ /^ERROR:/);
return HMCCU_SetState ($hash, "OK", "Unreach errors in CCU cleared");
}
@@ -1690,7 +1762,9 @@ sub HMCCU_Get ($@)
my ($hash, $a, $h) = @_;
my $name = shift @$a;
my $opt = shift @$a;
-
+
+ return "No get command specified" if (!defined ($opt));
+
my $options = "defaults:noArg exportdefaults devicelist dump dutycycle:noArg vars update".
" updateccu parfile configdesc firmware rpcevents:noArg rpcstate:noArg deviceinfo".
" ccumsg:alarm,service";
@@ -1763,11 +1837,10 @@ sub HMCCU_Get ($@)
my $ccuget = shift @$a;
$ccuget = 'Attr' if (!defined ($ccuget));
return HMCCU_SetError ($hash, $usage) if ($ccuget !~ /^(Attr|State|Value)$/);
+ my $nonBlocking = HMCCU_IsFlag ($name, 'nonBlocking') ? 1 : 0;
- my ($co, $ce) = HMCCU_UpdateClients ($hash, $devexp, $ccuget, ($opt eq 'updateccu') ? 1 : 0, undef);
-
- return HMCCU_SetState ($hash, "OK",
- "$co client devices successfully updated. Update for $ce client devices failed");
+ HMCCU_UpdateClients ($hash, $devexp, $ccuget, ($opt eq 'updateccu') ? 1 : 0, undef, 0);
+ return HMCCU_SetState ($hash, "OK");
}
elsif ($opt eq 'parfile') {
my $par_parfile = shift @$a;
@@ -1973,7 +2046,7 @@ sub HMCCU_Get ($@)
}
elsif ($opt eq 'dutycycle') {
my $dc = HMCCU_GetDutyCycle ($hash);
- return HMCCU_SetState ($hash, "OK", "Read $dc duty cycle values");
+ return HMCCU_SetState ($hash, "OK");
}
elsif ($opt eq 'firmware') {
my $devtype = shift @$a;
@@ -2069,12 +2142,12 @@ sub HMCCU_Get ($@)
return HMCCU_SetError ($hash, $usage) if (!defined ($msgtype));
my $script = ($msgtype eq 'service') ? "!GetServiceMessages" : "!GetAlarms";
- my $res = HMCCU_HMScriptExt ($hash, $script, undef);
+ my $res = HMCCU_HMScriptExt ($hash, $script, undef, undef, undef);
return HMCCU_SetError ($hash, "Error") if ($res eq '' || $res =~ /^ERROR:.*/);
# Generate event for each message
- foreach my $msg (split /\n/, $res) {
+ foreach my $msg (split /[\n\r]+/, $res) {
next if ($msg =~ /^[0-9]+$/);
DoTrigger ($name, $msg);
}
@@ -2419,14 +2492,19 @@ sub HMCCU_GetReadingName ($$$$$$$)
foreach my $rr (@rules) {
my ($rold, $rnew) = split (':', $rr);
next if (!defined ($rnew));
+ my @rnewList = split (',', $rnew);
+ next if (scalar (@rnewList) < 1);
if ($rnlist[0] =~ /$rold/) {
- if ($rnew =~ /^\+(.+)$/) {
- my $radd = $1;
- $radd =~ s/$rold/$radd/;
- push (@rnlist, $radd);
- }
- else {
- $rnlist[0] =~ s/$rold/$rnew/;
+ foreach my $rnew (@rnewList) {
+ if ($rnew =~ /^\+(.+)$/) {
+ my $radd = $1;
+ $radd =~ s/$rold/$radd/;
+ push (@rnlist, $radd);
+ }
+ else {
+ $rnlist[0] =~ s/$rold/$rnew/;
+ last;
+ }
}
}
}
@@ -2454,26 +2532,35 @@ sub HMCCU_GetReadingName ($$$$$$$)
sub HMCCU_FormatReadingValue ($$$)
{
my ($hash, $value, $dpt) = @_;
+ my $name = $hash->{NAME};
+ my $fnc = "FormatReadingValue";
- my $stripnumber = AttrVal ($hash->{NAME}, 'stripnumber', 'null');
- return $value if ($stripnumber eq 'null' || $value !~ /^[+-]?\d*\.?\d+(?:(?:e|E)\d+)?$/);
+ my $stripnumber = HMCCU_GetAttrStripNumber ($hash);
- my $isint = $value =~ /^[+-]?[0-9]+$/ ? 1 : 0;
+ if ($stripnumber ne 'null' && $value =~ /^[+-]?\d*\.?\d+(?:(?:e|E)\d+)?$/) {
+ my $isint = $value =~ /^[+-]?[0-9]+$/ ? 1 : 0;
- foreach my $sr (split (';', $stripnumber)) {
- my ($d, $s) = split ('!', $sr);
- if (defined ($s)) {
- next if ($d eq '' || $dpt !~ /$d/);
- }
- else {
- $s = $sr;
- }
+ foreach my $sr (split (';', $stripnumber)) {
+ my ($d, $s) = split ('!', $sr);
+ if (defined ($s)) {
+ next if ($d eq '' || $dpt !~ /$d/);
+ }
+ else {
+ $s = $sr;
+ }
- if ($s eq '0' && !$isint) { return sprintf ("%d", $value); }
- elsif ($s eq '1' && !$isint) { return sprintf ("%.1f", $value); }
- elsif ($s eq '2' && !$isint) { return sprintf ("%g", $value); }
- elsif ($s =~ /^-([0-9])$/ && !$isint) { my $f = '%.'.$1.'f'; return sprintf ($f, $value); }
- elsif ($s =~ /^%.+$/) { return sprintf ($s, $value); }
+ if ($s eq '0' && !$isint) { return sprintf ("%d", $value); }
+ elsif ($s eq '1' && !$isint) { return sprintf ("%.1f", $value); }
+ elsif ($s eq '2' && !$isint) { return sprintf ("%g", $value); }
+ elsif ($s =~ /^-([0-9])$/ && !$isint) { my $f = '%.'.$1.'f'; return sprintf ($f, $value); }
+ elsif ($s =~ /^%.+$/) { return sprintf ($s, $value); }
+ }
+
+ HMCCU_Trace ($hash, 2, $fnc, "sn = $stripnumber, dpt=$dpt, isint=$isint, value $value not changed");
+ }
+ else {
+ my $h = unpack "H*", $value;
+ HMCCU_Trace ($hash, 2, $fnc, "sn = $stripnumber, Value $value $h not changed");
}
return $value;
@@ -2494,7 +2581,7 @@ sub HMCCU_Trace ($$$$)
return if (!HMCCU_IsFlag ($name, "trace"));
foreach my $m (split ("
", $msg)) {
- $m = "$fnc: $m" if (defined ($fnc) && $fnc ne '');
+ $m = "[$name] $fnc: $m" if (defined ($fnc) && $fnc ne '');
Log3 $name, $level, "$type: $m";
}
}
@@ -2562,7 +2649,8 @@ sub HMCCU_SetError ($@)
-17 => 'Cannot detect or create external RPC device',
-18 => 'Type of system variable not supported',
-19 => 'Device not initialized',
- -20 => 'Invalid or unknown device interface'
+ -20 => 'Invalid or unknown device interface',
+ -21 => 'Device disabled'
);
$msg = exists ($errlist{$text}) ? $errlist{$text} : $text;
@@ -2621,8 +2709,7 @@ sub HMCCU_SetRPCState ($@)
HMCCU_Log ($hash, 1, "All RPC servers $state", undef);
DoTrigger ($name, "RPC server $state");
if ($state eq 'running') {
- my ($c_ok, $c_err) = HMCCU_UpdateClients ($hash, '.*', 'Attr', 0, $filter);
- HMCCU_Log ($hash, 2, "Updated devices. Success=$c_ok Failed=$c_err", undef);
+ HMCCU_UpdateClients ($hash, '.*', 'Value', 0, $filter, 1);
}
}
}
@@ -2638,7 +2725,7 @@ sub HMCCU_SetRPCState ($@)
foreach my $i (@iflist) {
my $st = $hash->{hmccu}{interfaces}{$i}{state};
$stc{$st}++ if (exists ($stc{$st}));
- if ($hash->{hmccu}{interfaces}{$i}{manager} eq 'HMCCU') {
+ if ($hash->{hmccu}{interfaces}{$i}{manager} eq 'HMCCU' && $ccuflags !~ /noInitialUpdate/) {
my $rpcFlags = AttrVal ($hash->{hmccu}{interfaces}{$i}{device}, 'ccuflags', 'null');
if ($rpcFlags !~ /noInitialUpdate/) {
$filter = defined ($filter) ? "$filter|$i" : $i;
@@ -2661,8 +2748,7 @@ sub HMCCU_SetRPCState ($@)
HMCCU_Log ($hash, 1, "All RPC servers $rpcstate", undef);
DoTrigger ($name, "RPC server $rpcstate");
if ($rpcstate eq 'running' && defined ($filter)) {
- my ($c_ok, $c_err) = HMCCU_UpdateClients ($hash, '.*', 'Attr', 0, $filter);
- HMCCU_Log ($hash, 2, "Updated devices for interface filter $filter. Success=$c_ok Failed=$c_err", undef);
+ HMCCU_UpdateClients ($hash, '.*', 'Value', 0, $filter, 1);
}
}
}
@@ -2841,15 +2927,18 @@ sub HMCCU_SubstVariables ($$$)
# only devices belonging to interface ifname are updated.
######################################################################
-sub HMCCU_UpdateClients ($$$$$)
+sub HMCCU_UpdateClients ($$$$$$)
{
- my ($hash, $devexp, $ccuget, $fromccu, $ifname) = @_;
+ my ($hash, $devexp, $ccuget, $fromccu, $ifname, $nonBlock) = @_;
my $fhname = $hash->{NAME};
- my $c_ok = 0;
- my $c_err = 0;
+ my $c = 0;
my $filter = "ccudevstate=active";
$filter .= ",ccuif=$ifname" if (defined ($ifname));
+ $ccuget = AttrVal ($fhname, 'ccuget', 'Value') if ($ccuget eq 'Attr');
+ my $list = '';
+ HMCCU_Log ($hash, 2, "Updating devices for filter $filter", 0);
+
if ($fromccu) {
foreach my $name (sort keys %{$hash->{hmccu}{adr}}) {
next if ($name !~ /$devexp/ || !($hash->{hmccu}{adr}{$name}{valid}));
@@ -2860,49 +2949,41 @@ sub HMCCU_UpdateClients ($$$$$)
my $ch = $defs{$d};
next if (!defined ($ch->{IODev}) || !defined ($ch->{ccuaddr}));
next if ($ch->{ccuaddr} ne $hash->{hmccu}{adr}{$name}{address});
-
- my $rc = HMCCU_GetUpdate ($ch, $hash->{hmccu}{adr}{$name}{address}, $ccuget);
- if ($rc <= 0) {
- if ($rc == -10) {
- Log3 $fhname, 3, "HMCCU: Device $name has no readable datapoints";
- }
- else {
- Log3 $fhname, 2, "HMCCU: Update of device $name failed";
- }
- $c_err++;
- }
- else {
- $c_ok++;
- }
+ next if ($ch->{ccuif} eq 'fhem');
+ next if (!HMCCU_IsValidDeviceOrChannel ($hash, $ch->{ccuaddr}, $HMCCU_FL_ADDRESS));
+ $list .= ($list eq '') ? $name : ",$name";
+ $c++;
}
}
}
else {
my @devlist = HMCCU_FindClientDevices ($hash, "(HMCCUDEV|HMCCUCHN)", $devexp, $filter);
- Log3 $fhname, 2, "HMCCU: No client devices matching $devexp" if (scalar (@devlist) == 0);
+ Log3 $fhname, 2, "HMCCU: Found ".scalar(@devlist)." client devices matching $devexp";
foreach my $d (@devlist) {
my $ch = $defs{$d};
- next if (!defined ($ch->{IODev}) || !defined ($ch->{ccuaddr}));
-
- my $rc = HMCCU_GetUpdate ($ch, $ch->{ccuaddr}, $ccuget);
- if ($rc <= 0) {
- if ($rc == -10) {
- Log3 $fhname, 3, "HMCCU: Device ".$ch->{ccuaddr}." has no readable datapoints";
- }
- else {
- Log3 $fhname, 2, "HMCCU: Update of device ".$ch->{ccuaddr}." failed"
- if ($ch->{ccuif} ne 'VirtualDevices' && $ch->{ccuif} ne 'fhem');
- }
- $c_err++;
- }
- else {
- $c_ok++;
- }
+ next if (!defined ($ch->{IODev}) || !defined ($ch->{ccuaddr}) || $ch->{ccuif} eq 'fhem');
+ next if (!HMCCU_IsValidDeviceOrChannel ($hash, $ch->{ccuaddr}, $HMCCU_FL_ADDRESS));
+ my $name = HMCCU_GetDeviceName ($hash, $ch->{ccuaddr}, '');
+ next if ($name eq '');
+ $list .= ($list eq '') ? $name : ",$name";
+ $c++;
}
}
+
+ if (HMCCU_IsFlag ($fhname, 'nonBlocking') || $nonBlock) {
+ HMCCU_HMScriptExt ($hash, '!GetDatapointsByDevice', { list => $list, ccuget => $ccuget },
+ \&HMCCU_UpdateCB, { logCount => 1, devCount => $c });
+ return 1;
+ }
+ else {
+ my $response = HMCCU_HMScriptExt ($hash, '!GetDatapointsByDevice',
+ { list => $list, ccuget => $ccuget }, undef, undef);
+ return -2 if ($response eq '' || $response =~ /^ERROR:.*/);
- return ($c_ok, $c_err);
+ HMCCU_UpdateCB ({ ioHash => $hash, logCount => 1, devCount => $c }, undef, $response);
+ return 1;
+ }
}
##########################################################################
@@ -3237,7 +3318,7 @@ sub HMCCU_UpdateSingleDevice ($$$$)
my $peer = AttrVal ($cltname, 'peer', 'null');
my $crf = HMCCU_GetAttrReadingFormat ($clthash, $ccuhash);
my $substitute = HMCCU_GetAttrSubstitute ($clthash, $ccuhash);
- my ($sc, $st, $cc, $cd) = HMCCU_GetSpecialDatapoints ($clthash, '', 'STATE', '', '');
+ my ($sc, $st, $cc, $cd, $ss, $cs) = HMCCU_GetSpecialDatapoints ($clthash, '', 'STATE', '', '');
# Virtual device flag
my $vg = 0;
@@ -3310,7 +3391,7 @@ sub HMCCU_UpdateSingleDevice ($$$$)
if ($cd ne '' && $dpt eq $cd && $chnnum eq $cc);
HMCCU_BulkUpdate ($clthash, 'state', $fvalue, $cvalue)
if ($dpt eq $st && ($sc eq '' || $sc eq $chnnum));
-
+
# Update peers
HMCCU_UpdatePeers ($clthash, "$chnnum.$dpt", $cvalue, $peer) if (!$vg && $peer ne 'null');
}
@@ -3379,6 +3460,10 @@ sub HMCCU_UpdateMultipleDevices ($$)
"ccudevstate=active");
foreach my $d (@devlist) {
my $ch = $defs{$d};
+ if (!defined ($ch)) {
+ HMCCU_Log ($name, 2, "Can't find hash for device $d", 0);
+ next;
+ }
my @addrlist = HMCCU_GetAffectedAddresses ($ch);
next if (scalar (@addrlist) == 0);
foreach my $addr (@addrlist) {
@@ -4152,7 +4237,7 @@ sub HMCCU_GetDeviceInfo ($$$)
}
$response .= HMCCU_HMScriptExt ($hmccu_hash, "!GetDeviceInfo",
- { devname => $devname, ccuget => $ccuget });
+ { devname => $devname, ccuget => $ccuget }, undef, undef);
HMCCU_Trace ($hash, 2, undef,
"Device=$devname Devname=$devname
".
"Script response = \n".$response."
".
@@ -4280,10 +4365,10 @@ sub HMCCU_GetDevice ($$)
my $devtype;
my %objects = ();
- my $response = HMCCU_HMScriptExt ($hash, "!GetDevice", { name => $name });
+ my $response = HMCCU_HMScriptExt ($hash, "!GetDevice", { name => $name }, undef, undef);
return (-1, -1) if ($response eq '' || $response =~ /^ERROR:.*/);
- my @scrlines = split /\n/,$response;
+ my @scrlines = split /[\n\r]+/,$response;
foreach my $hmdef (@scrlines) {
my @hmdata = split /;/,$hmdef;
next if (scalar (@hmdata) == 0);
@@ -4348,9 +4433,9 @@ sub HMCCU_GetDeviceList ($)
my %objects = ();
# Read devices, channels, interfaces and groups from CCU
- my $response = HMCCU_HMScriptExt ($hash, "!GetDeviceList", undef);
+ my $response = HMCCU_HMScriptExt ($hash, "!GetDeviceList", undef, undef, undef);
return (-1, -1, -1, -1, -1) if ($response eq '' || $response =~ /^ERROR:.*/);
- my $groups = HMCCU_HMScriptExt ($hash, "!GetGroupDevices", undef);
+ my $groups = HMCCU_HMScriptExt ($hash, "!GetGroupDevices", undef, undef, undef);
# CCU is reachable
$hash->{ccustate} = 'active';
@@ -4377,7 +4462,7 @@ sub HMCCU_GetDeviceList ($)
# {address}{rxmode} := Transmit mode
# {address}{chndir} := Channel direction: 1=sensor 2=actor 0=none
- my @scrlines = split /\n/,$response;
+ my @scrlines = split /[\n\r]+/,$response;
foreach my $hmdef (@scrlines) {
my @hmdata = split /;/,$hmdef;
next if (scalar (@hmdata) == 0);
@@ -4602,14 +4687,14 @@ sub HMCCU_GetDatapointList ($$$)
my $devlist = join (',', @devunique);
my $response = HMCCU_HMScriptExt ($hash, "!GetDatapointList",
- { list => $devlist });
+ { list => $devlist }, undef, undef);
if ($response eq '' || $response =~ /^ERROR:.*/) {
Log3 $name, 2, "HMCCU: Cannot get datapoint list";
return 0;
}
my $c = 0;
- foreach my $dpspec (split /\n/,$response) {
+ foreach my $dpspec (split /[\n\r]+/,$response) {
my ($iface, $chna, $devt, $devc, $dptn, $dptt, $dpto) = split (";", $dpspec);
$devt = "CUX-".$devt if ($iface eq 'CUxD');
$devt = "HVL-".$devt if ($iface eq 'HVL');
@@ -4656,28 +4741,43 @@ sub HMCCU_IsValidDevice ($$$)
# Address
if ($mode & $HMCCU_FL_STADDRESS) {
+ my $i;
+ my $a = 'null';
+
# Address with interface
if (HMCCU_IsDevAddr ($param, 1)) {
- my ($i, $a) = split (/\./, $param);
- return 0 if (! exists ($hash->{hmccu}{dev}{$a}));
- return $hash->{hmccu}{dev}{$a}{valid};
+ ($i, $a) = split (/\./, $param);
+ }
+ elsif (HMCCU_IsDevAddr ($param, 0)) {
+ $a = $param;
+ }
+ else {
+ HMCCU_Log ($hash, 3, "$param is not a valid address", 0);
}
- # Address without interface
- if (HMCCU_IsDevAddr ($param, 0)) {
- return 0 if (! exists ($hash->{hmccu}{dev}{$param}));
- return $hash->{hmccu}{dev}{$param}{valid};
+ if (exists ($hash->{hmccu}{dev}{$a})) {
+ return $hash->{hmccu}{dev}{$a}{valid};
+ }
+ else {
+ HMCCU_Log ($hash, 3, "Address $param not found", 0);
}
# Special address for Non-Homematic devices
if (($mode & $HMCCU_FL_EXADDRESS) && exists ($hash->{hmccu}{dev}{$param})) {
return $hash->{hmccu}{dev}{$param}{valid} && $hash->{hmccu}{dev}{$param}{addtype} eq 'dev' ? 1 : 0;
}
+
+ HMCCU_Log ($hash, 3, "Invalid address $param", 0);
}
# Name
- if (($mode & 2) && exists ($hash->{hmccu}{adr}{$param})) {
- return $hash->{hmccu}{adr}{$param}{valid} && $hash->{hmccu}{adr}{$param}{addtype} eq 'dev' ? 1 : 0;
+ if (($mode & $HMCCU_FL_NAME)) {
+ if (exists ($hash->{hmccu}{adr}{$param})) {
+ return $hash->{hmccu}{adr}{$param}{valid} && $hash->{hmccu}{adr}{$param}{addtype} eq 'dev' ? 1 : 0;
+ }
+ else {
+ HMCCU_Log ($hash, 3, "Device $param not found", 0);
+ }
}
return 0;
@@ -4715,7 +4815,7 @@ sub HMCCU_IsValidChannel ($$$)
}
# Name
- if (($mode & 2) && exists ($hash->{hmccu}{adr}{$param})) {
+ if (($mode & $HMCCU_FL_NAME) && exists ($hash->{hmccu}{adr}{$param})) {
return $hash->{hmccu}{adr}{$param}{valid} && $hash->{hmccu}{adr}{$param}{addtype} eq 'chn' ? 1 : 0;
}
@@ -5204,6 +5304,15 @@ sub HMCCU_SplitChnAddr ($)
return ($dev, $chn);
}
+sub HMCCU_SplitDatapoint ($;$)
+{
+ my ($dpt, $defchn) = @_;
+
+ my @t = split ('.', $dpt);
+
+ return (scalar (@t) > 1) ? @t : ($defchn, $t[0]);
+}
+
######################################################################
# Get list of client devices matching the specified criteria.
# If no criteria is specified all device names will be returned.
@@ -5621,6 +5730,35 @@ sub HMCCU_GetAttrReadingFormat ($$)
return AttrVal ($clname, 'ccureadingformat', $rfdef);
}
+######################################################################
+# Get number format considering default attribute ccudef-stripnumber,
+# Default is null
+######################################################################
+
+sub HMCCU_GetAttrStripNumber ($)
+{
+ my ($hash) = @_;
+ my $fnc = "GetAttrStripNumber";
+
+ my $snDef = 'null';
+
+ if ($hash->{TYPE} ne 'HMCCU') {
+ my $ioHash = HMCCU_GetHash ($hash);
+ if (defined ($ioHash)) {
+ $snDef = AttrVal ($ioHash->{NAME}, 'ccudef-stripnumber', 'null');
+ }
+ }
+ else {
+ $snDef = AttrVal ($hash->{NAME}, 'ccudef-stripnumber', 'null');
+ }
+
+ my $stripnumber = AttrVal ($hash->{NAME}, 'stripnumber', $snDef);
+
+ HMCCU_Trace ($hash, 2, $fnc, "stripnumber = $stripnumber");
+
+ return $stripnumber;
+}
+
######################################################################
# Get attributes substitute and substexcl considering default
# attribute ccudef-substitute defined in I/O device.
@@ -6102,9 +6240,9 @@ sub HMCCU_HMCommandCB ($$$)
# Return script output or error message starting with "ERROR:".
######################################################################
-sub HMCCU_HMScriptExt ($$$)
+sub HMCCU_HMScriptExt ($$$$$)
{
- my ($hash, $hmscript, $params) = @_;
+ my ($hash, $hmscript, $params, $cbFunc, $cbParam) = @_;
my $name = $hash->{NAME};
my $code = $hmscript;
my $scrname = '';
@@ -6113,6 +6251,9 @@ sub HMCCU_HMScriptExt ($$$)
my $host = $hash->{host};
my $ccureqtimeout = AttrVal ($hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
+# if (!defined ($nonBlocking)) {
+# $nonBlocking = HMCCU_IsFlag ($name, 'nonBlocking') ? 1 : 0;
+# }
if ($hmscript =~ /^!(.*)$/) {
# Internal script
@@ -6159,27 +6300,36 @@ sub HMCCU_HMScriptExt ($$$)
$HMCCU_SCRIPTS->{$scrname}{syntax};
}
}
-
+
# Execute script on CCU
my $url = HMCCU_BuildURL ($hash, 'rega');
- my $param = { url => $url, timeout => $ccureqtimeout, data => $code, method => "POST" };
- $param->{sslargs} = { SSL_verify_mode => 0 };
- my ($err, $response) = HttpUtils_BlockingGet ($param);
-
-# my $ua = new LWP::UserAgent ();
-# my $response = $ua->post($url, Content => $code);
-# if ($response->is_success ()) {
-# my $output = $response->content;
- if ($err eq '') {
- my $output = $response;
- $output =~ s/.*<\/xml>//;
- $output =~ s/\r//g;
- return $output;
+ if (defined ($cbFunc)) {
+ my $param = { url => $url, timeout => $ccureqtimeout, data => $code, method => "POST",
+ callback => $cbFunc, ioHash => $hash };
+ if (defined ($cbParam)) {
+ foreach my $p (keys %{$cbParam}) {
+ $param->{$p} = $cbParam->{$p};
+ }
+ }
+ $param->{sslargs} = { SSL_verify_mode => 0 };
+ HttpUtils_NonblockingGet ($param);
+ return ''
}
else {
-# my $msg = $response->status_line();
- HMCCU_Log ($hash, 2, "HMScript failed. $err", undef);
- return "ERROR: HMScript failed. $err";
+ my $param = { url => $url, timeout => $ccureqtimeout, data => $code, method => "POST" };
+ $param->{sslargs} = { SSL_verify_mode => 0 };
+ my ($err, $response) = HttpUtils_BlockingGet ($param);
+
+ if ($err eq '') {
+ my $output = $response;
+ $output =~ s/.*<\/xml>//;
+ $output =~ s/\r//g;
+ return $output;
+ }
+ else {
+ HMCCU_Log ($hash, 2, "HMScript failed. $err", undef);
+ return "ERROR: HMScript failed. $err";
+ }
}
}
@@ -6272,67 +6422,111 @@ sub HMCCU_GetDatapoint ($@)
}
}
+######################################################################
+# Set multiple values of parameter set.
+# Parameter params is a hash reference. Keys are datapoint names.
+# Parameter address must be a channel address.
+######################################################################
+
+sub HMCCU_SetMultipleParameters ($$$)
+{
+ my ($clHash, $address, $params) = @_;
+
+ my ($add, $chn) = HMCCU_SplitChnAddr ($address);
+ return -1 if (!defined ($chn));
+
+ foreach my $p (sort keys %$params) {
+ return -8 if (!HMCCU_IsValidDatapoint ($clHash, $clHash->{ccutype}, $chn, $p, 2));
+ $params->{$p} = HMCCU_ScaleValue ($clHash, $chn, $p, $params->{$p}, 1);
+ }
+
+ return HMCCU_RPCRequest ($clHash, "putParamset", $address, 'VALUES', $params);
+}
+
######################################################################
# Set multiple datapoints on CCU in a single request.
# Parameter params is a hash reference. Keys are full qualified CCU
# datapoint specifications in format:
-# no.interface.address:channelno.datapoint
+# no.interface.{address|fhemdev}:channelno.datapoint
# Parameter no defines the command order.
######################################################################
sub HMCCU_SetMultipleDatapoints ($$) {
- my ($cl_hash, $params) = @_;
+ my ($clHash, $params) = @_;
my $fnc = "SetMultipleDatapoints";
- my $type = $cl_hash->{TYPE};
+ my $mdFlag = $clHash->{TYPE} eq 'HMCCU' ? 1 : 0;
+ my $ioHash;
- my $io_hash = HMCCU_GetHash ($cl_hash);
- return -3 if (!defined ($io_hash));
- return -4 if (exists ($cl_hash->{ccudevstate}) && $cl_hash->{ccudevstate} eq 'deleted');
- my $io_name = $io_hash->{NAME};
- my $cl_name = $cl_hash->{NAME};
+ if ($mdFlag) {
+ $ioHash = $clHash;
+ }
+ else {
+ $ioHash = HMCCU_GetHash ($clHash);
+ return -3 if (!defined ($ioHash));
+ }
- my $ccureqtimeout = AttrVal ($io_name, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
- my $ccuflags = HMCCU_GetFlags ($io_name);
- my $readingformat = HMCCU_GetAttrReadingFormat ($cl_hash, $io_hash);
- my $ccuverify = AttrVal ($cl_name, 'ccuverify', 0);
- my $ccuchange = AttrVal ($cl_name, 'ccuSetOnChange', 'null');
- my $ccutype = $cl_hash->{ccutype};
+ my $ioName = $ioHash->{NAME};
+ my $clName = $clHash->{NAME};
+ my $ccuFlags = HMCCU_GetFlags ($ioName);
# Build Homematic script
- my @addrlist = $cl_hash->{ccuif} eq 'fhem' ? split (',', $cl_hash->{ccugroup}) : ($cl_hash->{ccuaddr});
my $cmd = '';
- foreach my $a (@addrlist) {
- foreach my $p (sort keys %$params) {
- my $v = $params->{$p};
+ foreach my $p (sort keys %$params) {
+ my $v = $params->{$p};
- HMCCU_Trace ($cl_hash, 2, $fnc, "dpt=$p, value=$v");
+ # Check address. dev is either a device address or a FHEM device name
+ my ($no, $int, $addchn, $dpt) = split (/\./, $p);
+ return -1 if (!defined ($dpt));
+ my ($dev, $chn) = split (':', $addchn);
+ return -1 if (!defined ($chn));
+ my $add = $dev;
+
+ # Get hash of FHEM device
+ if ($mdFlag) {
+ return -1 if (!exists ($defs{$dev}));
+ $clHash = $defs{$dev};
+ ($add, undef) = HMCCU_SplitChnAddr ($clHash->{ccuaddr});
+ }
- # Check address
- my ($no, $int, $addchn, $dpt) = split (/\./, $p);
- return -1 if (!defined ($dpt));
- my ($add, $chn) = split (/:/, $addchn);
- return -1 if (!defined ($chn));
- return -8 if (!HMCCU_IsValidDatapoint ($cl_hash, $ccutype, $chn, $dpt, 2));
+ # Device has been deleted or is disabled
+ return -4 if (exists ($clHash->{ccudevstate}) && $clHash->{ccudevstate} eq 'deleted');
+ return -21 if (IsDisabled ($clHash->{NAME}));
+
+ HMCCU_Trace ($clHash, 2, $fnc, "dpt=$p, value=$v");
- # Override device interface and address if device is virtual
- if ($cl_hash->{ccuif} eq 'fhem') {
- $add = $a;
- $int = HMCCU_GetDeviceInterface ($io_hash, $add, '');
+ # Check client device type and datapoint
+ my $clType = $clHash->{TYPE};
+ my $ccuType = $clHash->{ccutype};
+ return -1 if ($clType ne 'HMCCUCHN' && $clType ne 'HMCCUDEV');
+ return -8 if (!HMCCU_IsValidDatapoint ($clHash, $ccuType, $chn, $dpt, 2));
+
+ my $ccuVerify = AttrVal ($clName, 'ccuverify', 0);
+ my $ccuChange = AttrVal ($clName, 'ccuSetOnChange', 'null');
+
+ # Build device address list considering group devices
+ my @addrList = $clHash->{ccuif} eq 'fhem' ? split (',', $clHash->{ccugroup}) : ($add);
+ return -1 if (scalar (@addrList) < 1);
+
+ foreach my $a (@addrList) {
+ # Override address and interface of group device with address of group members
+ if ($clHash->{ccuif} eq 'fhem') {
+ ($add, undef) = HMCCU_SplitChnAddr ($a);
+ $int = HMCCU_GetDeviceInterface ($ioHash, $a, '');
return -20 if ($int eq '');
}
- if ($ccutype eq 'HM-Dis-EP-WM55' && $dpt eq 'SUBMIT') {
+ if ($ccuType eq 'HM-Dis-EP-WM55' && $dpt eq 'SUBMIT') {
$v = HMCCU_EncodeEPDisplay ($v);
}
else {
- $v = HMCCU_ScaleValue ($cl_hash, $chn, $dpt, $v, 1);
+ $v = HMCCU_ScaleValue ($clHash, $chn, $dpt, $v, 1);
}
-
- my $dpttype = HMCCU_GetDatapointAttr ($io_hash, $ccutype, $chn, $dpt, 'type');
- $v = "'".$v."'" if (defined ($dpttype) && $dpttype == $HMCCU_TYPE_STRING);
+
+ my $dptType = HMCCU_GetDatapointAttr ($ioHash, $ccuType, $chn, $dpt, 'type');
+ $v = "'".$v."'" if (defined ($dptType) && $dptType == $HMCCU_TYPE_STRING);
my $c = '(datapoints.Get("'.$int.'.'.$add.':'.$chn.'.'.$dpt.'")).State('.$v.");\n";
- if ($dpt =~ /$ccuchange/) {
+ if ($dpt =~ /$ccuChange/) {
$cmd .= 'if((datapoints.Get("'.$int.'.'.$add.':'.$chn.'.'.$dpt.'")).Value() != '.$v.") {\n$c}\n";
}
else {
@@ -6342,13 +6536,13 @@ sub HMCCU_SetMultipleDatapoints ($$) {
}
# Execute command (non blocking)
- if ($ccuflags =~ /nonBlocking/) {
- HMCCU_HMCommandNB ($cl_hash, $cmd, undef);
+ if ($ccuFlags =~ /nonBlocking/) {
+ HMCCU_HMCommandNB ($clHash, $cmd, undef);
return 0;
}
# Execute command (blocking)
- my $response = HMCCU_HMCommand ($cl_hash, $cmd, 1);
+ my $response = HMCCU_HMCommand ($clHash, $cmd, 1);
return -2 if (!defined ($response));
# Datapoint verification ???
@@ -6365,101 +6559,101 @@ sub HMCCU_SetMultipleDatapoints ($$) {
# hmccu:hmccuchn_name.datapoint
######################################################################
-sub HMCCU_SetDatapoint ($$$)
-{
- my ($hash, $param, $value) = @_;
- my $fnc = "SetDatapoint";
- my $type = $hash->{TYPE};
-
- my $hmccu_hash = HMCCU_GetHash ($hash);
- return -3 if (!defined ($hmccu_hash));
- return -4 if (exists ($hash->{ccudevstate}) && $hash->{ccudevstate} eq 'deleted');
- my $name = $hmccu_hash->{NAME};
- my $cdname = $hash->{NAME};
-
- my $ccureqtimeout = AttrVal ($name, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
- my $ccuflags = HMCCU_GetFlags ($name);
- my $readingformat = HMCCU_GetAttrReadingFormat ($hash, $hmccu_hash);
- my $ccuverify = AttrVal ($cdname, 'ccuverify', 0);
-
- HMCCU_Trace ($hash, 2, $fnc, "param=$param, value=$value");
-
- if ($param =~ /^hmccu:.+$/) {
- my @t = split (/\./, $param);
- return -1 if (scalar (@t) < 2 || scalar (@t) > 3);
- my $fhdpt = pop @t;
- my ($fhadd, $fhchn) = HMCCU_GetAddress ($hmccu_hash, $t[0], '', '');
- $fhchn = $t[1] if (scalar (@t) == 2);
- return -1 if ($fhadd eq '' || $fhchn eq '');
- $param = "$fhadd:$fhchn.$fhdpt";
- }
- elsif ($param =~ /^ccu:(.+)$/) {
- $param = $1;
- }
-
- my $cmd = '';
- my ($int, $add, $chn, $dpt, $nam, $flags) = HMCCU_ParseObject ($hmccu_hash, $param,
- $HMCCU_FLAG_INTERFACE);
- return -1 if ($flags != $HMCCU_FLAGS_IACD && $flags != $HMCCU_FLAGS_NCD);
-
- if ($hash->{ccutype} eq 'HM-Dis-EP-WM55' && $dpt eq 'SUBMIT') {
- $value = HMCCU_EncodeEPDisplay ($value);
- }
- else {
- $value = HMCCU_ScaleValue ($hash, $chn, $dpt, $value, 1);
- }
-
- my $dpttype = HMCCU_GetDatapointAttr ($hmccu_hash, $hash->{ccutype}, $chn, $dpt, 'type');
- if (defined ($dpttype) && $dpttype == $HMCCU_TYPE_STRING) {
- $value = "'".$value."'";
- }
-
- if ($flags == $HMCCU_FLAGS_IACD) {
-# $cmd = '(datapoints.Get("'.$int.'.'.$add.':'.$chn.'.'.$dpt.'")).State('.$value.')';
- $nam = HMCCU_GetChannelName ($hmccu_hash, $add.":".$chn, '');
- }
- elsif ($flags == $HMCCU_FLAGS_NCD) {
-# $cmd = '(dom.GetObject(ID_CHANNELS)).Get("'.$nam.'").DPByHssDP("'.$dpt.'").State('.$value.')';
- ($add, $chn) = HMCCU_GetAddress ($hmccu_hash, $nam, '', '');
- }
-
- if ($type eq 'HMCCUDEV' && $hash->{ccuif} eq 'fhem' && $hash->{ccutype} ne 'n/a' && exists ($hash->{ccugroup})) {
- foreach my $gaddr (split (',', $hash->{ccugroup})) {
- $cmd .= '(datapoints.Get("'.$int.'.'.$gaddr.':'.$chn.'.'.$dpt.'")).State('.$value.");\n";
- }
- }
- else {
- $cmd = '(datapoints.Get("'.$int.'.'.$add.':'.$chn.'.'.$dpt.'")).State('.$value.')';
- }
-
- my $addr = $add.":".$chn;
-
- if ($ccuflags =~ /nonBlocking/) {
- HMCCU_HMCommandNB ($hash, $cmd, undef);
- return 0;
- }
-
- # Execute command (blocking)
- my $response = HMCCU_HMCommand ($hash, $cmd, 1);
- HMCCU_Trace ($hash, 2, $fnc,
- "Addr=$addr Name=$nam
".
- "Script response = \n".(defined ($response) ? $response: 'undef')."
".
- "Script = \n".$cmd);
- return -2 if (!defined ($response));
-
- # Verify setting of datapoint value or update reading with new datapoint value
- if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $addr, $dpt, 1)) {
- if ($ccuverify == 1) {
- my ($rc, $result) = HMCCU_GetDatapoint ($hash, $param, 0);
- return $rc;
- }
- elsif ($ccuverify == 2) {
- HMCCU_UpdateSingleDatapoint ($hash, $chn, $dpt, $value);
- }
- }
-
- return 0;
-}
+# sub HMCCU_SetDatapoint ($$$)
+# {
+# my ($hash, $param, $value) = @_;
+# my $fnc = "SetDatapoint";
+# my $type = $hash->{TYPE};
+#
+# my $hmccu_hash = HMCCU_GetHash ($hash);
+# return -3 if (!defined ($hmccu_hash));
+# return -4 if (exists ($hash->{ccudevstate}) && $hash->{ccudevstate} eq 'deleted');
+# my $name = $hmccu_hash->{NAME};
+# my $cdname = $hash->{NAME};
+#
+# my $ccureqtimeout = AttrVal ($name, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
+# my $ccuflags = HMCCU_GetFlags ($name);
+# my $readingformat = HMCCU_GetAttrReadingFormat ($hash, $hmccu_hash);
+# my $ccuverify = AttrVal ($cdname, 'ccuverify', 0);
+#
+# HMCCU_Trace ($hash, 2, $fnc, "param=$param, value=$value");
+#
+# if ($param =~ /^hmccu:.+$/) {
+# my @t = split (/\./, $param);
+# return -1 if (scalar (@t) < 2 || scalar (@t) > 3);
+# my $fhdpt = pop @t;
+# my ($fhadd, $fhchn) = HMCCU_GetAddress ($hmccu_hash, $t[0], '', '');
+# $fhchn = $t[1] if (scalar (@t) == 2);
+# return -1 if ($fhadd eq '' || $fhchn eq '');
+# $param = "$fhadd:$fhchn.$fhdpt";
+# }
+# elsif ($param =~ /^ccu:(.+)$/) {
+# $param = $1;
+# }
+#
+# my $cmd = '';
+# my ($int, $add, $chn, $dpt, $nam, $flags) = HMCCU_ParseObject ($hmccu_hash, $param,
+# $HMCCU_FLAG_INTERFACE);
+# return -1 if ($flags != $HMCCU_FLAGS_IACD && $flags != $HMCCU_FLAGS_NCD);
+#
+# if ($hash->{ccutype} eq 'HM-Dis-EP-WM55' && $dpt eq 'SUBMIT') {
+# $value = HMCCU_EncodeEPDisplay ($value);
+# }
+# else {
+# $value = HMCCU_ScaleValue ($hash, $chn, $dpt, $value, 1);
+# }
+#
+# my $dpttype = HMCCU_GetDatapointAttr ($hmccu_hash, $hash->{ccutype}, $chn, $dpt, 'type');
+# if (defined ($dpttype) && $dpttype == $HMCCU_TYPE_STRING) {
+# $value = "'".$value."'";
+# }
+#
+# if ($flags == $HMCCU_FLAGS_IACD) {
+# # $cmd = '(datapoints.Get("'.$int.'.'.$add.':'.$chn.'.'.$dpt.'")).State('.$value.')';
+# $nam = HMCCU_GetChannelName ($hmccu_hash, $add.":".$chn, '');
+# }
+# elsif ($flags == $HMCCU_FLAGS_NCD) {
+# # $cmd = '(dom.GetObject(ID_CHANNELS)).Get("'.$nam.'").DPByHssDP("'.$dpt.'").State('.$value.')';
+# ($add, $chn) = HMCCU_GetAddress ($hmccu_hash, $nam, '', '');
+# }
+#
+# if ($type eq 'HMCCUDEV' && $hash->{ccuif} eq 'fhem' && $hash->{ccutype} ne 'n/a' && exists ($hash->{ccugroup})) {
+# foreach my $gaddr (split (',', $hash->{ccugroup})) {
+# $cmd .= '(datapoints.Get("'.$int.'.'.$gaddr.':'.$chn.'.'.$dpt.'")).State('.$value.");\n";
+# }
+# }
+# else {
+# $cmd = '(datapoints.Get("'.$int.'.'.$add.':'.$chn.'.'.$dpt.'")).State('.$value.')';
+# }
+#
+# my $addr = $add.":".$chn;
+#
+# if ($ccuflags =~ /nonBlocking/) {
+# HMCCU_HMCommandNB ($hash, $cmd, undef);
+# return 0;
+# }
+#
+# # Execute command (blocking)
+# my $response = HMCCU_HMCommand ($hash, $cmd, 1);
+# HMCCU_Trace ($hash, 2, $fnc,
+# "Addr=$addr Name=$nam
".
+# "Script response = \n".(defined ($response) ? $response: 'undef')."
".
+# "Script = \n".$cmd);
+# return -2 if (!defined ($response));
+#
+# # Verify setting of datapoint value or update reading with new datapoint value
+# if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $addr, $dpt, 1)) {
+# if ($ccuverify == 1) {
+# my ($rc, $result) = HMCCU_GetDatapoint ($hash, $param, 0);
+# return $rc;
+# }
+# elsif ($ccuverify == 2) {
+# HMCCU_UpdateSingleDatapoint ($hash, $chn, $dpt, $value);
+# }
+# }
+#
+# return 0;
+# }
######################################################################
# Scale, spread and/or shift datapoint value.
@@ -6510,7 +6704,6 @@ sub HMCCU_ScaleValue ($$$$$)
# Do not scale if value out of range or interval wrong
return $value if ($a[1] > $a[2] || $a[3] > $a[4]);
return $value if ($mode == 0 && ($value < $a[1] || $value > $a[2]));
-# return $value if ($mode == 1 && ($value >= $a[1] && $value <= $a[2]));
return $value if ($mode == 1 && ($value < $a[3] || $value > $a[4]));
# Reverse value
@@ -6545,12 +6738,12 @@ sub HMCCU_GetVariables ($$)
my $ccureadings = AttrVal ($name, 'ccureadings', HMCCU_IsFlag ($name, "noReadings") ? 0 : 1);
- my $response = HMCCU_HMScriptExt ($hash, "!GetVariables", undef);
+ my $response = HMCCU_HMScriptExt ($hash, "!GetVariables", undef, undef, undef);
return (-2, $response) if ($response eq '' || $response =~ /^ERROR:.*/);
readingsBeginUpdate ($hash) if ($ccureadings);
- foreach my $vardef (split /\n/, $response) {
+ foreach my $vardef (split /[\n\r]+/, $response) {
my @vardata = split /=/, $vardef;
next if (@vardata != 3);
next if ($vardata[0] !~ /$pattern/);
@@ -6619,7 +6812,7 @@ sub HMCCU_SetVariable ($$$$$)
$params->{valtrue} = "ist wahr" if ($vartype eq 'bool' && !exists ($params->{valtrue}));
$params->{valfalse} = "ist falsch" if ($vartype eq 'bool' && !exists ($params->{valfalse}));
- my $rc = HMCCU_HMScriptExt ($hash, $varfnc{$vartype}, $params);
+ my $rc = HMCCU_HMScriptExt ($hash, $varfnc{$vartype}, $params, undef, undef);
return HMCCU_Log ($hash, 1, $rc, -2) if ($rc =~ /^ERROR:.*/);
}
@@ -6630,6 +6823,7 @@ sub HMCCU_SetVariable ($$$$$)
# Update all datapoints / readings of device or channel considering
# attribute ccureadingfilter.
# Parameter $ccuget can be 'State', 'Value' or 'Attr'.
+# Return 1 on success, <= 0 on error
######################################################################
sub HMCCU_GetUpdate ($$$)
@@ -6680,32 +6874,42 @@ sub HMCCU_GetUpdate ($$$)
return -1;
}
- my $response = HMCCU_HMScriptExt ($hmccu_hash, $script,
- { list => $list, ccuget => $ccuget });
- HMCCU_Trace ($cl_hash, 2, $fnc, "Addr=$addr Name=$nam Script=$script
".
- "Script response = \n".$response);
- return -2 if ($response eq '' || $response =~ /^ERROR:.*/);
-
- my @dpdef = split /\n/, $response;
- my $count = pop (@dpdef);
- return -10 if (!defined ($count) || $count == 0);
-
- my %events = ();
- foreach my $dp (@dpdef) {
- my ($chnname, $dpspec, $value) = split /=/, $dp;
- next if (!defined ($value));
- my ($iface, $chnadd, $dpt) = split /\./, $dpspec;
- next if (!defined ($dpt));
- my ($add, $chn) = ('', '');
- if ($iface eq 'sysvar' && $chnadd eq 'link') {
- ($add, $chn) = HMCCU_GetAddress ($hmccu_hash, $chnname, '', '');
- }
- else {
- ($add, $chn) = HMCCU_SplitChnAddr ($chnadd);
- }
- next if ($chn eq '');
- $events{$add}{$chn}{$dpt} = $value;
+ if (HMCCU_IsFlag ($hmccu_hash->{NAME}, 'nonBlocking')) {
+ HMCCU_HMScriptExt ($hmccu_hash, $script, { list => $list, ccuget => $ccuget },
+ \&HMCCU_UpdateCB, undef);
+ return 1;
}
+ else {
+ my $response = HMCCU_HMScriptExt ($hmccu_hash, $script,
+ { list => $list, ccuget => $ccuget }, undef, undef);
+ HMCCU_Trace ($cl_hash, 2, $fnc, "Addr=$addr Name=$nam Script=$script
".
+ "Script response = \n".$response);
+ return -2 if ($response eq '' || $response =~ /^ERROR:.*/);
+
+ HMCCU_UpdateCB ({ ioHash => $hmccu_hash }, undef, $response);
+ return 1;
+ }
+
+# my @dpdef = split /\n/, $response;
+# my $count = pop (@dpdef);
+# return -10 if (!defined ($count) || $count == 0);
+#
+# my %events = ();
+# foreach my $dp (@dpdef) {
+# my ($chnname, $dpspec, $value) = split /=/, $dp;
+# next if (!defined ($value));
+# my ($iface, $chnadd, $dpt) = split /\./, $dpspec;
+# next if (!defined ($dpt));
+# my ($add, $chn) = ('', '');
+# if ($iface eq 'sysvar' && $chnadd eq 'link') {
+# ($add, $chn) = HMCCU_GetAddress ($hmccu_hash, $chnname, '', '');
+# }
+# else {
+# ($add, $chn) = HMCCU_SplitChnAddr ($chnadd);
+# }
+# next if ($chn eq '');
+# $events{$add}{$chn}{$dpt} = $value;
+# }
# if ($cl_hash->{ccuif} eq 'fhem') {
# # Calculate datapoints of virtual group device
@@ -6722,11 +6926,61 @@ sub HMCCU_GetUpdate ($$$)
# }
# }
- HMCCU_UpdateMultipleDevices ($hmccu_hash, \%events);
+# HMCCU_UpdateMultipleDevices ($hmccu_hash, \%events);
return 1;
}
+######################################################################
+# Generic reading update callback function for non blocking HTTP
+# requests.
+# Format of $data: Newline separated list of datapoint values.
+# ChannelName=Interface.ChannelAddress.Datapoint=Value
+# Optionally last line can contain the number of datapoint lines.
+######################################################################
+
+sub HMCCU_UpdateCB ($$$)
+{
+ my ($param, $err, $data) = @_;
+
+ if (!exists ($param->{ioHash})) {
+ Log3 1, undef, "HMCCU: Missing parameter ioHash in update callback";
+ return;
+ }
+
+ my $hash = $param->{ioHash};
+ my $logcount = 0;
+ $logcount = 1 if (exists ($param->{logCount}) && $param->{logCount} == 1);
+
+ my $count = 0;
+ my @dpdef = split /[\n\r]+/, $data;
+ my $lines = scalar (@dpdef);
+ $count = ($lines > 0 && $dpdef[$lines-1] =~ /^[0-9]+$/) ? pop (@dpdef) : $lines;
+ return if ($count == 0);
+
+ my %events = ();
+ foreach my $dp (@dpdef) {
+ my ($chnname, $dpspec, $value) = split /=/, $dp;
+ next if (!defined ($value));
+ my ($iface, $chnadd, $dpt) = split /\./, $dpspec;
+ next if (!defined ($dpt));
+ my ($add, $chn) = ('', '');
+ if ($iface eq 'sysvar' && $chnadd eq 'link') {
+ ($add, $chn) = HMCCU_GetAddress ($hash, $chnname, '', '');
+ }
+ else {
+ ($add, $chn) = HMCCU_SplitChnAddr ($chnadd);
+ }
+ next if ($chn eq '');
+ $events{$add}{$chn}{$dpt} = $value;
+ }
+
+ my $c_ok = HMCCU_UpdateMultipleDevices ($hash, \%events);
+ my $c_err = 0;
+ $c_err = max($param->{devCount}-$c_ok, 0) if (exists ($param->{devCount}));
+ HMCCU_Log ($hash, 2, "Update success=$c_ok failed=$c_err", 0) if ($logcount);
+}
+
######################################################################
# Get multiple datapoints of channels and update readings of client
# devices.
@@ -6770,11 +7024,11 @@ sub HMCCU_GetChannel ($$)
return (0, $result) if ($chnlist eq '');
my $response = HMCCU_HMScriptExt ($hash, "!GetChannel",
- { list => $chnlist, ccuget => $ccuget });
+ { list => $chnlist, ccuget => $ccuget }, undef, undef);
return (-2, $result) if ($response eq '' || $response =~ /^ERROR:.*/);
# Output format is Channelname=Interface.Channeladdress.Datapoint=Value
- foreach my $dpdef (split /\n/, $response) {
+ foreach my $dpdef (split /[\n\r]+/, $response) {
my ($chnname, $dptaddr, $value) = split /=/, $dpdef;
next if (!defined ($value));
my ($iface, $chnaddr, $dpt) = split /\./, $dptaddr;
@@ -6796,6 +7050,107 @@ sub HMCCU_GetChannel ($$)
return ($count, $result);
}
+sub HMCCU_RPCRequest ($$$$$;$)
+{
+ my ($clHash, $method, $address, $key, $parref, $filter) = @_;
+ my $name = $clHash->{NAME};
+ my $type = $clHash->{TYPE};
+ my $fnc = "RPCRequest";
+
+ my $reqMethod = $method eq 'listParamset' ? 'getParamset' : $method;
+ $filter = '.*' if (!defined ($filter));
+ my $addr = '';
+ my $result = '';
+
+ my $ioHash = HMCCU_GetHash ($clHash);
+ return (-3, $result) if (!defined ($ioHash));
+ return (-4, $result) if ($type ne 'HMCCU' && $clHash->{ccudevstate} eq 'deleted');
+
+ # Get flags and attributes
+ my $ioFlags = HMCCU_GetFlags ($ioHash->{NAME});
+ my $clFlags = HMCCU_GetFlags ($name);
+ my $ccureadings = AttrVal ($name, 'ccureadings', $clFlags =~ /noReadings/ ? 0 : 1);
+ my $readingformat = HMCCU_GetAttrReadingFormat ($clHash, $ioHash);
+ my $substitute = HMCCU_GetAttrSubstitute ($clHash, $ioHash);
+
+ # Parse address, complete address information
+ my ($int, $add, $chn, $dpt, $nam, $flags) = HMCCU_ParseObject ($ioHash, $address,
+ $HMCCU_FLAG_FULLADDR);
+ return (-1, $result) if (!($flags & $HMCCU_FLAG_ADDRESS));
+ $addr = $add;
+ $addr .= ':'.$chn if ($flags & $HMCCU_FLAG_CHANNEL);
+
+ # Get RPC type and port for interface of device address
+ my ($rpcType, $rpcPort) = HMCCU_GetRPCServerInfo ($ioHash, $int, 'type,port');
+ return (-9, '') if (!defined ($rpcType) || !defined ($rpcPort));
+
+ # Search RPC device, do not create one
+ my ($rpcDevice, $save) = HMCCU_GetRPCDevice ($ioHash, 0, $int);
+ return (-17, $result) if ($rpcDevice eq '');
+ my $rpcHash = $defs{$rpcDevice};
+
+ # Build parameter array
+ my @parArray = ($addr, $key);
+ if (defined ($parref)) {
+ foreach my $k (keys %{$parref}) { push @parArray, "$k=$parref->{$k}"; };
+ }
+
+ # Submit RPC request
+ my $reqResult = HMCCURPCPROC_SendRequest ($rpcHash, $reqMethod, @parArray);
+ return (-5, "Function not available") if (!defined ($reqResult));
+
+ HMCCU_Trace ($clHash, 2, $fnc,
+ "Dump of RPC request $method $addr. Result type=".ref($reqResult)."
".
+ HMCCU_RefToString ($reqResult));
+
+ my $parCount = 0;
+
+ if (ref ($reqResult) eq 'HASH') {
+ if (exists ($reqResult->{faultString})) {
+ HMCCU_Log ($rpcHash, 1, $reqResult->{faultString}, 0);
+ return (-2, $reqResult->{faultString});
+ }
+ else {
+ $parCount = keys %{$reqResult};
+ }
+ }
+# else {
+# return (-2, defined ($RPC::XML::ERROR) ? $RPC::XML::ERROR : 'RPC request failed');
+# }
+
+ if ($method eq 'listParamset') {
+ $result = join ("\n", map { $_ =~ /$filter/ ? $_.'='.$reqResult->{$_} : () } keys %$reqResult);
+ }
+ elsif ($method eq 'getParamsetDescription') {
+ my @operFlags = ('', 'R', 'W', 'RW', 'E', 'RE', 'WE', 'RWE');
+ $result = join ("\n",
+ map { $_.': '.$reqResult->{$_}->{TYPE}." [".$operFlags[$reqResult->{$_}->{OPERATIONS}]."]" } keys %$reqResult);
+ }
+ elsif ($method eq 'getParamset') {
+ readingsBeginUpdate ($clHash) if ($ccureadings);
+
+ foreach my $key (sort keys %$reqResult) {
+ next if ($key !~ /$filter/);
+ my $value = $reqResult->{$key};
+ $result .= "$key=$value\n";
+ if ($ccureadings) {
+ $value = HMCCU_FormatReadingValue ($clHash, $value, $key);
+ $value = HMCCU_Substitute ($value, $substitute, 0, $chn, $key);
+ my @readings = HMCCU_GetReadingName ($clHash, $int, $add, $chn, $key, $nam, $readingformat);
+ foreach my $rn (@readings) {
+ next if ($rn eq '');
+ $rn = "R-".$rn;
+ readingsBulkUpdate ($clHash, $rn, $value);
+ }
+ }
+ }
+
+ readingsEndUpdate ($clHash, 1) if ($ccureadings);
+ }
+
+ return (0, $result);
+}
+
######################################################################
# Get RPC paramSet or paramSetDescription
######################################################################
@@ -6844,7 +7199,7 @@ sub HMCCU_RPCGetConfig ($$$$)
}
}
else {
- $res = HMCCURPCPROC_SendRequest ($rpchash, $method, $addr, "MASTER");
+ $res = HMCCURPCPROC_SendRequest ($rpchash, $method, "$addr:STRING", "MASTER:STRING");
}
return (-5, "Function not available") if (!defined ($res));
@@ -8165,6 +8520,10 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
set <name> cleardefaults
Clear default attributes imported from file.
+ set <name> datapoint <FHEM-Device>[.<channel-number>].<datapoint>=<value>
+ Set datapoint values on multiple devices. If FHEM-Device is of type HMCCUDEV
+ a channel-number must be specified.
+
set <name> defaults
Set default attributes for I/O device.
@@ -8382,6 +8741,11 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
Set global rules for reading name substitution. These rules are added to the rules
specified by client device attribute 'ccureadingname'.
+ ccudef-stripnumber [<datapoint-expr>!]{0|1|2|-n|%fmt}[;...]
+ Set global formatting rules for numeric datapoint or config parameter values.
+ Default value is 2 (strip trailing zeroes).
+ For details see description of attribute stripnumber in HMCCUCHN.
+
ccudef-substitute <subst-rule>[;...]
Set global substitution rules for datapoint value. These rules are added to the rules
specified by client device attribute 'substitute'.
@@ -8401,6 +8765,8 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
logEvents - Write events from CCU into FHEM logfile
logPong - Write log message when receiving pong event if verbose level is at least 3.
noEvents - Ignore events / device updates sent by CCU. No readings will be updated!
+ noInitialUpdate - Do not update datapoints of devices after RPC server start. Overrides
+ settings in RPC devices.
nonBlocking - Use non blocking (asynchronous) CCU requests
noReadings - Do not create or update readings
procrpc - Use external RPC server provided by module HMCCPRPCPROC. During first RPC
diff --git a/fhem/FHEM/88_HMCCUCHN.pm b/fhem/FHEM/88_HMCCUCHN.pm
index a7ee42942..84946e794 100644
--- a/fhem/FHEM/88_HMCCUCHN.pm
+++ b/fhem/FHEM/88_HMCCUCHN.pm
@@ -4,7 +4,7 @@
#
# $Id$
#
-# Version 4.3.006
+# Version 4.3.007
#
# (c) 2019 zap (zap01 t-online de)
#
@@ -205,7 +205,10 @@ sub HMCCUCHN_Set ($@)
my $name = shift @$a;
my $opt = shift @$a;
- my $rocmds = "clear config defaults:noArg";
+ return "No set command specified" if (!defined ($opt));
+
+ my $rocmds = "clear defaults:noArg";
+ my $rwcmds = "clear config control datapoint defaults:noArg devstate rpcParameter";
# Get I/O device, check device state
return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
@@ -415,7 +418,20 @@ sub HMCCUCHN_Set ($@)
if (defined ($par) && $par eq 'device') {
($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr);
}
- my $rc = HMCCU_RPCSetConfig ($hash, $ccuobj, $h);
+ my ($rc, $res) = HMCCU_RPCRequest ($hash, "putParamset", $ccuobj, "MASTER", $h);
+# my $rc = HMCCU_RPCSetConfig ($hash, $ccuobj, $h);
+ return HMCCU_SetError ($hash, $rc) if ($rc < 0);
+ return HMCCU_SetState ($hash, "OK");
+ }
+ elsif ($opt eq 'rpcParameter') {
+ return HMCCU_SetError ($hash, "Usage: set $name rpcParameter [MASTER|VALUES] {parameter}={value} [...]")
+ if ((scalar keys %{$h}) < 1);
+ my $key = shift @$a;
+ $key = 'VALUES' if (!defined ($key));
+ return HMCCU_SetError ($hash, "Key must be MASTER or VALUES")
+ if ($key ne 'MASTER' && $key ne 'VALUES');
+
+ my ($rc, $res) = HMCCU_RPCRequest ($hash, "putParamset", $ccuaddr, $key, $h);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
}
@@ -425,14 +441,13 @@ sub HMCCUCHN_Set ($@)
return HMCCU_SetState ($hash, "OK");
}
else {
- return "HMCCUCHN: Unknown argument $opt, choose one of ".$rocmds
+ return "HMCCUCHN: Unknown argument $opt, choose one of $rocmds"
if ($hash->{statevals} eq 'readonly');
-
- my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of clear config control datapoint defaults:noArg devstate";
+ my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of $rwcmds";
if ($hash->{statevals} ne '') {
my @cmdlist = split /\|/,$hash->{statevals};
shift @cmdlist;
- $retmsg .= ':'.join(',',@cmdlist) if (@cmdlist > 0);
+ $retmsg .= ':'.join(',',@cmdlist) if (scalar(@cmdlist) > 0);
foreach my $sv (@cmdlist) {
$retmsg .= ' '.$sv.':noArg';
}
@@ -457,6 +472,8 @@ sub HMCCUCHN_Get ($@)
my $name = shift @$a;
my $opt = shift @$a;
+ return "No get command specified" if (!defined ($opt));
+
return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
!defined ($hash->{IODev}));
@@ -533,7 +550,8 @@ sub HMCCUCHN_Get ($@)
}
$par = '.*' if (!defined ($par));
- my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset", $par);
+ my ($rc, $res) = HMCCU_RPCRequest ($hash, "getParamset", $ccuobj, "MASTER", undef, $par);
+# my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset", $par);
return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0);
return $ccureadings ? undef : $res;
}
@@ -548,7 +566,8 @@ sub HMCCUCHN_Get ($@)
}
$par = '.*' if (!defined ($par));
- my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "listParamset", $par);
+ my ($rc, $res) = HMCCU_RPCRequest ($hash, "listParamset", $ccuobj, "MASTER", undef, $par);
+# my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "listParamset", $par);
return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0);
return $res;
}
@@ -559,7 +578,8 @@ sub HMCCUCHN_Get ($@)
($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr);
}
- my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription", undef);
+ my ($rc, $res) = HMCCU_RPCRequest ($hash, "getParamsetDescription", $ccuobj, "MASTER", undef);
+# my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription", undef);
return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0);
return $res;
}
@@ -827,7 +847,7 @@ sub HMCCUCHN_Get ($@)
channel-name.datapoint. If set to 'datapoint' format is channel-number.datapoint. With
suffix 'lc' reading names are converted to lowercase.
- ccureadingname <old-readingname-expr>:[+]<new-readingname>[;...]
+ ccureadingname <old-readingname-expr>:[+]<new-readingname>[,...];[;...]
Set alternative or additional reading names or group readings. Only part of old reading
name matching old-readingname-exptr is substituted by new-readingname.
If new-readingname is preceded by '+' an additional reading is created. If
diff --git a/fhem/FHEM/88_HMCCUDEV.pm b/fhem/FHEM/88_HMCCUDEV.pm
index 7352d208c..b2798f93e 100644
--- a/fhem/FHEM/88_HMCCUDEV.pm
+++ b/fhem/FHEM/88_HMCCUDEV.pm
@@ -4,7 +4,7 @@
#
# $Id$
#
-# Version 4.3.008
+# Version 4.3.009
#
# (c) 2019 zap (zap01 t-online de)
#
@@ -340,6 +340,8 @@ sub HMCCUDEV_Set ($@)
my $name = shift @$a;
my $opt = shift @$a;
+ return "No set command specified" if (!defined ($opt));
+
# Valid commands for read only devices
my $rocmds = "clear config defaults:noArg";
@@ -593,11 +595,36 @@ sub HMCCUDEV_Set ($@)
$objname .= ':'.$1;
}
- my $rc = HMCCU_RPCSetConfig ($hash, $objname, $h);
+ my ($rc, $res) = HMCCU_RPCRequest ($hash, "putParamset", $objname, "MASTER", $h);
+# my $rc = HMCCU_RPCSetConfig ($hash, $objname, $h);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
}
+ elsif ($opt eq 'rpcParameter') {
+ return HMCCU_SetError ($hash, "Usage: set $name rpcParameter [channel] [MASTER|VALUES] {parameter}={value} [...]")
+ if ((scalar keys %{$h}) < 1);
+
+ my $key;
+ my $addr;
+
+ while (my $p = shift @$a) {
+ if ($p =~ /^(MASTER|VALUES)$/ && !defined ($key)) {
+ $key = $p;
+ }
+ elsif ($p =~ /^([0-9]+)$/ && !defined ($addr)) {
+ HMCCU_SetError ($hash, -7) if ($p >= $hash->{channels});
+ $addr = $p;
+ }
+ }
+
+ $key = 'VALUES' if (!defined ($key));
+ $addr = defined ($addr) ? "$ccuaddr:$addr" : $ccuaddr;
+
+ my ($rc, $res) = HMCCU_RPCRequest ($hash, "putParamset", $addr, $key, $h);
+ return HMCCU_SetError ($hash, $rc) if ($rc < 0);
+ return HMCCU_SetState ($hash, "OK");
+ }
elsif ($opt eq 'defaults') {
my $rc = HMCCU_SetDefaults ($hash);
return HMCCU_SetError ($hash, "HMCCU: No default attributes found") if ($rc == 0);
@@ -640,6 +667,8 @@ sub HMCCUDEV_Get ($@)
my $name = shift @$a;
my $opt = shift @$a;
+ return "No get command specified" if (!defined ($opt));
+
# Get I/O device
return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
!defined ($hash->{IODev}));
@@ -739,7 +768,6 @@ sub HMCCUDEV_Get ($@)
return HMCCU_FormatDeviceInfo ($result);
}
elsif ($opt eq 'config') {
- my $channel = undef;
my $ccuobj = $ccuaddr;
my $par = shift @$a;
if (defined ($par)) {
@@ -751,13 +779,13 @@ sub HMCCUDEV_Get ($@)
}
$par = '.*' if (!defined ($par));
- my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset", $par);
+ my ($rc, $res) = HMCCU_RPCRequest ($hash, "getParamset", $ccuobj, "MASTER", undef, $par);
+# my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset", $par);
return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $ccureadings ? undef : $res;
}
elsif ($opt eq 'configlist') {
- my $channel = undef;
my $ccuobj = $ccuaddr;
my $par = shift @$a;
if (defined ($par)) {
@@ -769,13 +797,13 @@ sub HMCCUDEV_Get ($@)
}
$par = '.*' if (!defined ($par));
- my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "listParamset", $par);
+ my ($rc, $res) = HMCCU_RPCRequest ($hash, "listParamset", $ccuobj, "MASTER", undef, $par);
+# my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "listParamset", $par);
return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $res;
}
elsif ($opt eq 'configdesc') {
- my $channel = undef;
my $ccuobj = $ccuaddr;
my $par = shift @$a;
if (defined ($par)) {
@@ -788,7 +816,8 @@ sub HMCCUDEV_Get ($@)
}
}
- my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription", undef);
+ my ($rc, $res) = HMCCU_RPCRequest ($hash, "getParamsetDescription", $ccuobj, "MASTER", undef);
+# my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription", undef);
return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $res;
diff --git a/fhem/FHEM/88_HMCCURPCPROC.pm b/fhem/FHEM/88_HMCCURPCPROC.pm
index e9b20a468..c68fae913 100755
--- a/fhem/FHEM/88_HMCCURPCPROC.pm
+++ b/fhem/FHEM/88_HMCCURPCPROC.pm
@@ -4,7 +4,7 @@
#
# $Id$
#
-# Version 1.7.002
+# Version 1.8
#
# Subprocess based RPC Server module for HMCCU.
#
@@ -35,7 +35,7 @@ use SetExtensions;
######################################################################
# HMCCURPC version
-my $HMCCURPCPROC_VERSION = '1.7.001';
+my $HMCCURPCPROC_VERSION = '1.8';
# Maximum number of events processed per call of Read()
my $HMCCURPCPROC_MAX_EVENTS = 100;
@@ -97,6 +97,26 @@ my $BINRPC_RESPONSE = 0x42696E01;
my $BINRPC_REQUEST_HEADER = 0x42696E40;
my $BINRPC_ERROR = 0x42696EFF;
+# BinRPC datatype mapping
+my %BINRPC_TYPE_MAPPING = (
+ "BOOL" => $BINRPC_BOOL,
+ "INTEGER" => $BINRPC_INTEGER,
+ "STRING" => $BINRPC_STRING,
+ "FLOAT" => $BINRPC_DOUBLE,
+ "DOUBLE" => $BINRPC_DOUBLE,
+ "BASE64" => $BINRPC_BASE64,
+ "ARRAY" => $BINRPC_ARRAY,
+ "STRUCT" => $BINRPC_STRUCT
+);
+
+# Read/Write flags for RPC methods (0=Read, 1=Write)
+my %RPC_METHODS = (
+ 'putParamset' => 1,
+ 'getParamset' => 0,
+ 'getParamsetDescription' => 0,
+ 'setValue' => 1,
+ 'getValue' => 0
+);
######################################################################
# Functions
@@ -157,8 +177,8 @@ sub HMCCURPCPROC_ReaddDevicesCB ($$$);
sub HMCCURPCPROC_EventCB ($$$$$);
sub HMCCURPCPROC_ListDevicesCB ($$);
-# Binary RPC encoding functions
-sub HMCCURPCPROC_RPCNewValue ($$);
+# RPC encoding functions
+sub HMCCURPCPROC_EncValue ($$);
sub HMCCURPCPROC_EncInteger ($);
sub HMCCURPCPROC_EncBool ($);
sub HMCCURPCPROC_EncString ($);
@@ -497,6 +517,8 @@ sub HMCCURPCPROC_Set ($@)
my $name = shift @$a;
my $opt = shift @$a;
+ return "No set command specified" if (!defined ($opt));
+
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
my $options = $ccuflags =~ /expert/ ?
"cleanup:noArg deregister:noArg register:noArg rpcrequest rpcserver:on,off" : "";
@@ -576,6 +598,8 @@ sub HMCCURPCPROC_Get ($@)
my $name = shift @$a;
my $opt = shift @$a;
+ return "No get command specified" if (!defined ($opt));
+
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
my $options = "rpcevents:noArg rpcstate:noArg";
@@ -1080,13 +1104,7 @@ sub HMCCURPCPROC_RegisterCallback ($$)
$hash->{hmccu}{rpc}{cburl} = $cburl;
Log3 $name, 2, "HMCCURPCPROC: [$name] Registering callback $cburl of type $rpctype with ID $clkey at $clurl";
- my $rc;
- if ($rpctype eq 'A') {
- $rc = HMCCURPCPROC_SendRequest ($hash, "init", $cburl, $clkey);
- }
- else {
- $rc = HMCCURPCPROC_SendRequest ($hash, "init", $BINRPC_STRING, $cburl, $BINRPC_STRING, $clkey);
- }
+ my $rc = HMCCURPCPROC_SendRequest ($hash, "init", "$cburl:STRING", "$clkey:STRING");
if (defined ($rc)) {
return (1, $ccuflags !~ /ccuInit/ ? 'running' : 'registered');
@@ -1126,13 +1144,7 @@ sub HMCCURPCPROC_DeRegisterCallback ($$)
# Deregister up to 2 times
for (my $i=0; $i<2; $i++) {
- my $rc;
- if (HMCCU_IsRPCType ($hmccu_hash, $port, 'A')) {
- $rc = HMCCURPCPROC_SendRequest ($hash, "init", $cburl);
- }
- else {
- $rc = HMCCURPCPROC_SendRequest ($hash, "init", $BINRPC_STRING, $cburl);
- }
+ my $rc = HMCCURPCPROC_SendRequest ($hash, "init", "$cburl:STRING");
if (defined ($rc)) {
HMCCURPCPROC_SetRPCState ($hash, $force == 0 ? 'deregistered' : $rpchash->{state},
@@ -1389,8 +1401,8 @@ sub HMCCURPCPROC_RPCServerStarted ($)
# Update client devices if interface is managed by HMCCURPCPROC device.
# Normally interfaces are managed by HMCCU device.
if ($hmccu_hash->{hmccu}{interfaces}{$ifname}{manager} eq 'HMCCURPCPROC') {
- my ($c_ok, $c_err) = HMCCU_UpdateClients ($hmccu_hash, '.*', 'Attr', 0, $ifname);
- Log3 $name, 2, "HMCCURPCPROC: [$name] Updated devices. Success=$c_ok Failed=$c_err";
+ HMCCU_UpdateClients ($hmccu_hash, '.*', 'Attr', 0, $ifname, 1);
+# Log3 $name, 2, "HMCCURPCPROC: [$name] Updated devices. Success=$c_ok Failed=$c_err";
}
RemoveInternalTimer ($hash, "HMCCURPCPROC_IsRPCServerRunning");
@@ -1633,6 +1645,25 @@ sub HMCCURPCPROC_StopRPCServer ($$)
######################################################################
# Send RPC request to CCU.
# Supports XML and BINRPC requests.
+# Parameter $request contains the RPC command (i.e. "init" or
+# "putParamset"). If RPC command is a parameter set command, two
+# additional parameters address and key (MASTER or VALUE) must be
+# specified.
+# If RPC command is putParamset or setValue, the remaining elements
+# in array @param contains the request parameters in format:
+# ParameterName=Value[:ParameterType]
+# For other RPC command the array @param contains the parameters in
+# format:
+# Value[:ParameterType]
+# For BINRPC interfaces ParameterType is mapped as follows:
+# "INTEGER" = $BINRPC_INTEGER
+# "BOOL" = $BINRPC_BOOL
+# "STRING" = $BINRPC_STRING
+# "FLOAT" = $BINRPC_DOUBLE
+# "DOUBLE" = $BINRPC_DOUBLE
+# "BASE64" = $BINRPC_BASE64
+# "ARRAY" = $BINRPC_ARRAY
+# "STRUCT" = $BINRPC_STRUCT
# Return response or undef on error.
######################################################################
@@ -1640,35 +1671,89 @@ sub HMCCURPCPROC_SendRequest ($@)
{
my ($hash, $request, @param) = @_;
my $name = $hash->{NAME};
- my $hmccu_hash = $hash->{IODev};
+ my $ioHash = $hash->{IODev};
my $port = $hash->{rpcport};
my $rc;
- return HMCCU_Log ($hash, 2, "I/O device not found", undef) if (!defined ($hmccu_hash));
+ return HMCCU_Log ($hash, 2, "I/O device not found", undef) if (!defined ($ioHash));
- if (HMCCU_IsRPCType ($hmccu_hash, $port, 'A')) {
+ my $re = ':('.join('|', keys(%BINRPC_TYPE_MAPPING)).')';
+
+ if (HMCCU_IsRPCType ($ioHash, $port, 'A')) {
# Use XMLRPC
- my $clurl = HMCCU_BuildURL ($hmccu_hash, $port);
+ my $clurl = HMCCU_BuildURL ($ioHash, $port);
return HMCCU_Log ($hash, 2, "Can't get client URL for port $port", undef)
if (!defined ($clurl));
- Log3 $name, 4, "HMCCURPCPROC: [$name] Send ASCII RPC request $request to $clurl";
+ HMCCU_Log ($hash, 4, "Send ASCII RPC request $request to $clurl", undef);
my $rpcclient = RPC::XML::Client->new ($clurl, useragent => [
ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0 } ]);
- $rc = $rpcclient->simple_request ($request, @param);
- Log3 $name, 2, "HMCCURPCPROC: [$name] RPC request error ".$RPC::XML::ERROR if (!defined ($rc));
+
+ if (exists ($RPC_METHODS{$request})) {
+ # Read or write parameter sets
+ my $address = shift @param;
+ my $key = shift @param;
+ return HMCCU_Log ($hash, 2, "Missing address or key in RPC request $request", undef)
+ if (!defined ($key));
+
+ my %hparam;
+
+ # Write requests have at least one parameters
+ if ($RPC_METHODS{$request} == 1) {
+ # Build a parameter hash
+ while (my $p = shift @param) {
+ my $pt = "STRING";
+ if ($p =~ /${re}/) {
+ $pt = $1;
+ $p =~ s/${re}//;
+ }
+ my ($pn, $pv) = split ('=', $p, 2);
+ next if (!defined ($pv));
+ $hparam{$pn} = HMCCURPCPROC_EncValue ($pv, $pt);
+ }
+
+ return HMCCU_Log ($hash, 2, "Missing parameter in RPC request $request", undef)
+ if (!keys %hparam);
+
+ # Submit write paramset request
+ $rc = $rpcclient->simple_request ($request, $address, $key, \%hparam);
+ }
+ else {
+ # Submit read paramset request
+ $rc = $rpcclient->simple_request ($request, $address, $key);
+ }
+ }
+ else {
+ # RPC commands
+ my @aparam = ();
+
+ # Build a parameter array
+ while (my $p = shift @param) {
+ my $pt = "STRING";
+ if ($p =~ /${re}/) {
+ $pt = $1;
+ $p =~ s/${re}//;
+ }
+ push (@aparam, HMCCURPCPROC_EncValue ($p, $pt));
+ }
+
+ # Submit RPC command
+ $rc = $rpcclient->simple_request ($request, @aparam);
+ }
+
+ HMCCU_Log ($hash, 2, "RPC request error ".$RPC::XML::ERROR, undef) if (!defined ($rc));
}
- elsif (HMCCU_IsRPCType ($hmccu_hash, $port, 'B')) {
+ elsif (HMCCU_IsRPCType ($ioHash, $port, 'B')) {
# Use BINRPC
- my ($serveraddr) = HMCCU_GetRPCServerInfo ($hmccu_hash, $port, 'host');
- return HMCCU_Log ($hash, 2, "Can't get server address for port $port", undef)
+ my ($serveraddr) = HMCCU_GetRPCServerInfo ($ioHash, $port, 'host');
+ return HMCCU_Log ($ioHash, 2, "Can't get server address for port $port", undef)
if (!defined ($serveraddr));
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
my $verbose = GetVerbose ($name);
- Log3 $name, 4, "HMCCURPCPROC: [$name] Send binary RPC request $request to $serveraddr:$port";
+ HMCCU_Log ($hash, 4, "Send binary RPC request $request to $serveraddr:$port", undef);
my $encreq = HMCCURPCPROC_EncodeRequest ($request, \@param);
return HMCCU_Log ($hash, 2, "Error encoding binary request", undef) if ($encreq eq '');
@@ -1687,7 +1772,7 @@ sub HMCCURPCPROC_SendRequest ($@)
if (defined ($encresp)) {
if ($ccuflags =~ /logEvents/ && $verbose >= 4) {
- Log3 $name, 4, "HMCCURPCPROC: [$name] Response";
+ HMCCU_Log ($hash, 4, "Response", undef);
HMCCURPCPROC_HexDump ($name, $encresp);
}
my ($response, $err) = HMCCURPCPROC_DecodeResponse ($encresp);
@@ -1701,7 +1786,7 @@ sub HMCCURPCPROC_SendRequest ($@)
$socket->close ();
}
else {
- Log3 $name, 2, "HMCCURPCPROC: [$name] Unknown RPC server type";
+ HMCCU_Log ($hash, 2, "Unknown RPC server type", undef);
}
return $rc;
@@ -1723,7 +1808,7 @@ sub HMCCURPCPROC_RPCPing ($)
if ($ping > 0) {
if ($init_done && HMCCURPCPROC_CheckProcessState ($hash, 'running')) {
my $clkey = 'CB'.$hash->{rpcport}.$hash->{rpcid};
- HMCCURPCPROC_SendRequest ($hash, "ping", $clkey);
+ HMCCURPCPROC_SendRequest ($hash, "ping", "$clkey:STRING");
}
InternalTimer (gettimeofday()+$ping, "HMCCURPCPROC_RPCPing", $hash, 0);
}
@@ -2253,6 +2338,10 @@ sub HMCCURPCPROC_ListDevicesCB ($$)
return RPC::XML::array->new ();
}
+######################################################################
+# RPC encoding functions
+######################################################################
+
######################################################################
# Convert value to RPC data type
# Valid types are bool, boolean, int, integer, float, double, string.
@@ -2260,7 +2349,7 @@ sub HMCCURPCPROC_ListDevicesCB ($$)
# value is returned as is.
######################################################################
-sub HMCCURPCPROC_RPCNewValue ($$)
+sub HMCCURPCPROC_EncValue ($$)
{
my ($value, $type) = @_;
@@ -2300,10 +2389,6 @@ sub HMCCURPCPROC_RPCNewValue ($$)
return $value;
}
-######################################################################
-# Binary RPC encoding functions
-######################################################################
-
######################################################################
# Encode integer (type = 1)
######################################################################
@@ -2448,6 +2533,8 @@ sub HMCCURPCPROC_EncType ($$)
{
my ($t, $v) = @_;
+ return '' if (!defined ($t));
+
if ($t == $BINRPC_INTEGER) {
return HMCCURPCPROC_EncInteger ($v);
}
@@ -2478,7 +2565,8 @@ sub HMCCURPCPROC_EncType ($$)
# Encode RPC request with method and optional parameters.
# Headers are not supported.
# Input is method name and reference to parameter array.
-# Array must contain (type, value) pairs
+# Array must contain parameters in format value[:type]. Default for
+# type is STRING.
# Return encoded data or empty string on error
######################################################################
@@ -2490,14 +2578,19 @@ sub HMCCURPCPROC_EncodeRequest ($$)
my $m = HMCCURPCPROC_EncName ($method);
# Encode parameters
+ my $re = ':('.join('|', keys(%BINRPC_TYPE_MAPPING)).')';
my $r = '';
my $s = 0;
-
+
if (defined ($args)) {
- while (my $t = shift @$args) {
- my $e = shift @$args;
- last if (!defined ($e));
- $r .= HMCCURPCPROC_EncType ($t, $e);
+ while (my $p = shift @$args) {
+ my $pt = "STRING";
+ if ($p =~ /${re}/) {
+ $pt = $1;
+ $p =~ s/${re}//;
+ }
+ my ($e, $t) = split (':', $p);
+ $r .= HMCCURPCPROC_EncType ($BINRPC_TYPE_MAPPING{uc($pt)}, $p);
$s++;
}
}
diff --git a/fhem/FHEM/HMCCUConf.pm b/fhem/FHEM/HMCCUConf.pm
index fac305cfb..7a3b8dccd 100644
--- a/fhem/FHEM/HMCCUConf.pm
+++ b/fhem/FHEM/HMCCUConf.pm
@@ -4,7 +4,7 @@
#
# $Id$
#
-# Version 4.6
+# Version 4.6.002
#
# Configuration parameters for HomeMatic devices.
#
@@ -168,6 +168,17 @@ use vars qw(%HMCCU_SCRIPTS);
webCmd => "control:on:off",
widgetOverride => "control:slider,0,10,100"
},
+ "HmIP-FCI6" => {
+ _description => "IP Kontaktschnittstelle Unterputz 6-fach",
+ _channels => "1,2,3,4,5,6",
+ ccureadingfilter => "STATE",
+ controldatapoint => "STATE",
+ statedatapoint => "STATE",
+ statevals => "on:true,off:false",
+ substitute => "STATE!(0|false):off,(1|true):on",
+ webCmd => "devstate",
+ widgetOverride => "devstate:uzsuToggle,off,on"
+ },
"HM-PB-2-FM" => {
_description => "Funk-Wandtaster 2-fach",
_channels => "1,2",
@@ -297,7 +308,7 @@ use vars qw(%HMCCU_SCRIPTS);
webCmd => "control:up:stop:down",
widgetOverride => "control:slider,0,10,100"
},
- "HmIP-BROLL" => {
+ "HmIP-BROLL|HmIP-FROLL" => {
_description => "Rollladenaktor",
_channels => "4",
ccureadingfilter => "(ERROR_CODE|ERROR_OVERHEAT|ACTUAL_TEMPERATURE|LEVEL|ACTIVITY_STATE)",
@@ -336,7 +347,7 @@ use vars qw(%HMCCU_SCRIPTS);
stripnumber => 1,
substitute => "RAINING,RAIN_COUNTER_OVERFLOW,SUNSHINEDURATION_OVERFLOW,SUNSHINE_THRESHOLD_OVERRUN,WIND_THRESHOLD_OVERRUN!(0|false):no,(1|true):yes"
},
- "HM-Sec-MD|HM-Sec-MDIR|HM-Sec-MDIR-2|HM-Sec-MDIR-3" => {
+ "HM-Sec-MD|HM-Sec-MDIR|HM-Sec-MDIR-2|HM-Sec-MDIR-3|Hm-Sen-MDIR-O-3" => {
_description => "Bewegungsmelder",
_channels => "1",
ccureadingfilter => "(BRIGHTNESS|MOTION)",
@@ -348,9 +359,13 @@ use vars qw(%HMCCU_SCRIPTS);
_description => "Bewegungsmelder",
_channels => "1",
ccureadingfilter => "(ILLUMINATION|MOTION)",
- eventMap => "/datapoint MOTION_DETECTION_ACTIVE 1:detection-on/datapoint MOTION_DETECTION_ACTIVE 0:detection-off/",
+ controldatapoint => "MOTION_DETECTION_ACTIVE",
+ eventMap => "/datapoint RESET_MOTION 1:reset/datapoint MOTION_DETECTION_ACTIVE 1:detection-on/datapoint MOTION_DETECTION_ACTIVE 0:detection-off/",
+ hmstatevals => "SABOTAGE!(1|true):sabotage",
statedatapoint => "MOTION",
- substitute => "MOTION!(0|false):no,(1|true):yes"
+ substitute => "MOTION!(0|false):no,(1|true):yes;MOTION_DETECTION_ACTIVE!(0|false):off,(1|true):on",
+ webCmd => "control",
+ widgetOverride => "control:uzsuToggle,off,on"
},
"HmIP-SPI" => {
_description => "Anwesenheitssensor",
@@ -712,16 +727,16 @@ use vars qw(%HMCCU_SCRIPTS);
webCmd => "control:up:stop:down",
widgetOverride => "control:slider,0,10,100"
},
- "HmIP-BROLL" => {
+ "HmIP-BROLL|HmIP-FROLL" => {
_description => "Rollladenaktor",
- ccureadingfilter => "(ERROR_CODE|ERROR_OVERHEAT|ACTUAL_TEMPERATURE|LEVEL|ACTIVITY_STATE|SELF_CALIBRATION_RESULT)",
- ccureadingname => "LEVEL:+pct",
+ ccureadingfilter => "3.LEVEL;(ERROR_CODE|ERROR_OVERHEAT|ACTUAL_TEMPERATURE|ACTIVITY_STATE|SELF_CALIBRATION_RESULT)",
+ ccureadingname => "3.LEVEL$:+control,+pct",
ccuscaleval => "LEVEL:0:1:0:100",
cmdIcon => "up:fts_shutter_up stop:fts_shutter_manual down:fts_shutter_down",
controldatapoint => "4.LEVEL",
hmstatevals => "ACTUAL_TEMPERATURE_STATUS!2:tempOverflow,3:tempUnderflow;ERROR_OVERHEAT!(1|true):overheat",
eventMap => "/datapoint 4.STOP true:stop/datapoint 4.LEVEL 0:down/datapoint 4.LEVEL 100:up/datapoint 3.SELF_CALIBRATION 0:stopCalibration/datapoint 3.SELF_CALIBRATION 1:startCalibration/",
- statedatapoint => "4.LEVEL",
+ statedatapoint => "3.LEVEL",
stripnumber => 1,
substexcl => "control|pct",
substitute => "LEVEL!#0-0:closed,#100-100:open;ACTIVITY_STATE!0:unknown,1:up,2:down,3:stop;ERROR_OVERHEAT!(0|false):no,(1|true):yes;ACTUAL_TEMPERATURE_STATUS!0:normal,1:unknown,2:overflow,3:underflow;SELF_CALIBRATION_RESULT!(0|false):failed,(1|true):ok",
@@ -763,7 +778,7 @@ use vars qw(%HMCCU_SCRIPTS);
ccureadingname => "1.LEVEL:valve_position",
ccuscaleval => "LEVEL:0:1:0:100",
controldatapoint => "1.SET_POINT_TEMPERATURE",
- eventMap => "/datapoint 1.BOOST_MODE true:Boost/datapoint 1.CONTROL_MODE 0:Auto/datapoint 1.CONTROL_MODE 1:Manual/datapoint 1.CONTROL_MODE 2:Holiday/datapoint 1.SET_POINT_TEMPERATURE 4.5:off/datapoint 1.SET_POINT_TEMPERATURE 30.5:on/",
+ eventMap => "/datapoint 1.BOOST_MODE true:Boost/datapoint 1.CONTROL_MODE 0:Auto/datapoint 1.CONTROL_MODE 1:Manual/datapoint 1.CONTROL_MODE 2:Holiday/datapoint 1.CONTROL_MODE 1 1.SET_POINT_TEMPERATURE 4.5:off/datapoint 1.CONTROL_MODE 0 1.SET_POINT_TEMPERATURE 30.5:on/",
genericDeviceType => "thermostat",
statedatapoint => "1.SET_POINT_TEMPERATURE",
stripnumber => 1,
@@ -833,7 +848,7 @@ use vars qw(%HMCCU_SCRIPTS);
webCmd => "control:Auto:Manu:Boost:on:off",
widgetOverride => "control:slider,4.5,0.5,30.5,1"
},
- "HM-Sec-MD|HM-Sec-MDIR|HM-Sec-MDIR-2|HM-Sec-MDIR-3" => {
+ "HM-Sec-MD|HM-Sec-MDIR|HM-Sec-MDIR-2|HM-Sec-MDIR-3|Hm-Sen-MDIR-O-3" => {
_description => "Bewegungsmelder",
ccureadingfilter => "(BRIGHTNESS|MOTION)",
hmstatevals => "ERROR!1:sabotage",
@@ -843,9 +858,13 @@ use vars qw(%HMCCU_SCRIPTS);
"HmIP-SMI" => {
_description => "Bewegungsmelder",
ccureadingfilter => "(ILLUMINATION|MOTION)",
- eventMap => "/datapoint 1.MOTION_DETECTION_ACTIVE 1:detection-on/datapoint 1.MOTION_DETECTION_ACTIVE 0:detection-off/",
+ controldatapoint => "1.MOTION_DETECTION_ACTIVE",
+ eventMap => "/datapoint 1.RESET_MOTION 1:reset/datapoint 1.MOTION_DETECTION_ACTIVE 1:detection-on/datapoint 1.MOTION_DETECTION_ACTIVE 0:detection-off/",
+ hmstatevals => "SABOTAGE!(1|true):sabotage",
statedatapoint => "1.MOTION",
- substitute => "MOTION!(0|false):no,(1|true):yes"
+ substitute => "MOTION!(0|false):no,(1|true):yes;MOTION_DETECTION_ACTIVE!(0|false):off,(1|true):on",
+ webCmd => "control",
+ widgetOverride => "control:uzsuToggle,off,on"
},
"HmIP-SMI55" => {
_description => "Bewegungsmelder",