2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-21 07:56:03 +00:00

HMCCU: Update for version 4.4 beta

git-svn-id: https://svn.fhem.de/fhem/trunk@22102 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2020-06-03 17:31:41 +00:00
parent d5d226b682
commit 10037472af
5 changed files with 1832 additions and 2011 deletions

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
# #
# $Id: 88_HMCCUCHN.pm 18552 2019-02-10 11:52:28Z zap $ # $Id: 88_HMCCUCHN.pm 18552 2019-02-10 11:52:28Z zap $
# #
# Version 4.4.016 # Version 4.4.019
# #
# (c) 2020 zap (zap01 <at> t-online <dot> de) # (c) 2020 zap (zap01 <at> t-online <dot> de)
# #
@ -39,22 +39,22 @@ sub HMCCUCHN_Initialize ($)
{ {
my ($hash) = @_; my ($hash) = @_;
$hash->{DefFn} = "HMCCUCHN_Define"; $hash->{DefFn} = 'HMCCUCHN_Define';
$hash->{UndefFn} = "HMCCUCHN_Undef"; $hash->{UndefFn} = 'HMCCUCHN_Undef';
$hash->{RenameFn} = "HMCCUCHN_Rename"; $hash->{RenameFn} = 'HMCCUCHN_Rename';
$hash->{SetFn} = "HMCCUCHN_Set"; $hash->{SetFn} = 'HMCCUCHN_Set';
$hash->{GetFn} = "HMCCUCHN_Get"; $hash->{GetFn} = 'HMCCUCHN_Get';
$hash->{AttrFn} = "HMCCUCHN_Attr"; $hash->{AttrFn} = 'HMCCUCHN_Attr';
$hash->{parseParams} = 1; $hash->{parseParams} = 1;
$hash->{AttrList} = "IODev ccucalculate ". $hash->{AttrList} = 'IODev ccucalculate '.
"ccuflags:multiple-strict,ackState,logCommand,noReadings,trace,showMasterReadings,showLinkReadings,showDeviceReadings ". 'ccuflags:multiple-strict,ackState,logCommand,noReadings,trace,showMasterReadings,showLinkReadings,showDeviceReadings '.
"ccureadingfilter ". 'ccureadingfilter:textField-long '.
"ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ". 'ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc '.
"ccureadingname:textField-long ccuSetOnChange ccuReadingPrefix ". 'ccureadingname:textField-long ccuSetOnChange ccuReadingPrefix '.
"ccuscaleval ccuverify:0,1,2 ccuget:State,Value controldatapoint ". 'ccuscaleval ccuverify:0,1,2 ccuget:State,Value controldatapoint '.
"disable:0,1 hmstatevals:textField-long statedatapoint statevals substitute:textField-long ". 'disable:0,1 hmstatevals:textField-long statedatapoint statevals substitute:textField-long '.
"substexcl stripnumber peer:textField-long ". $readingFnAttributes; 'substexcl stripnumber peer:textField-long '. $readingFnAttributes;
} }
###################################################################### ######################################################################
@ -69,9 +69,7 @@ sub HMCCUCHN_Define ($@)
my $usage = "Usage: define $name HMCCUCHN {device} ['readonly'] ['noDefaults'|'defaults'] [iodev={iodevname}]"; my $usage = "Usage: define $name HMCCUCHN {device} ['readonly'] ['noDefaults'|'defaults'] [iodev={iodevname}]";
return $usage if (@$a < 3); return $usage if (@$a < 3);
my $devname = shift @$a; my ($devname, $devtype, $devspec) = splice (@$a, 0, 3);
my $devtype = shift @$a;
my $devspec = shift @$a;
my $ioHash; my $ioHash;
my $existDev = HMCCU_ExistsClientDevice ($devspec, $devtype); my $existDev = HMCCU_ExistsClientDevice ($devspec, $devtype);
@ -81,25 +79,25 @@ sub HMCCUCHN_Define ($@)
$hash->{hmccu}{devspec} = $devspec; $hash->{hmccu}{devspec} = $devspec;
# Defaults # Defaults
$hash->{readonly} = "no"; $hash->{readonly} = 'no';
$hash->{hmccu}{channels} = 1; $hash->{hmccu}{channels} = 1;
$hash->{hmccu}{defaults} = 0;
# Parse optional command line parameters # Parse optional command line parameters
my $n = 0; my $n = 0;
while (my $arg = shift @$a) { while (my $arg = shift @$a) {
return $usage if ($n == 3); return $usage if ($n == 3);
if ($arg eq 'readonly') { $hash->{readonly} = "yes"; } if ($arg eq 'readonly') { $hash->{readonly} = "yes"; }
elsif (lc($arg) eq 'nodefaults' && $init_done) { $hash->{hmccu}{nodefaults} = 1; } elsif (lc($arg) eq 'nodefaults' && $init_done) { $hash->{hmccu}{nodefaults} = 1; }
elsif ($arg eq 'defaults' && $init_done) { $hash->{hmccu}{nodefaults} = 0; } elsif ($arg eq 'defaults' && $init_done) { $hash->{hmccu}{nodefaults} = 0; }
else { return $usage; } else { return $usage; }
$n++; $n++;
} }
# IO device can be set by command line parameter iodev, otherwise try to detect IO device # IO device can be set by command line parameter iodev, otherwise try to detect IO device
if (exists ($h->{iodev})) { if (exists($h->{iodev})) {
return "Specified IO Device ".$h->{iodev}." does not exist" if (!exists($defs{$h->{iodev}})); return "Device $h->{iodev} does not exist" if (!exists($defs{$h->{iodev}}));
return "Specified IO Device ".$h->{iodev}." is not a HMCCU device" return "Type of device $h->{iodev} is not HMCCU" if ($defs{$h->{iodev}}->{TYPE} ne 'HMCCU');
if ($defs{$h->{iodev}}->{TYPE} ne 'HMCCU');
$ioHash = $defs{$h->{iodev}}; $ioHash = $defs{$h->{iodev}};
} }
else { else {
@ -111,18 +109,15 @@ sub HMCCUCHN_Define ($@)
# Interactive define command while CCU not ready or no IO device defined # Interactive define command while CCU not ready or no IO device defined
if (!defined($ioHash)) { if (!defined($ioHash)) {
my ($ccuactive, $ccuinactive) = HMCCU_IODeviceStates (); my ($ccuactive, $ccuinactive) = HMCCU_IODeviceStates ();
if ($ccuinactive > 0) { return $ccuinactive > 0 ?
return "CCU and/or IO device not ready. Please try again later"; 'CCU and/or IO device not ready. Please try again later' :
} 'Cannot detect IO device';
else {
return "Cannot detect IO device";
}
} }
} }
else { else {
# CCU not ready during FHEM start # CCU not ready during FHEM start
if (!defined ($ioHash) || $ioHash->{ccustate} ne 'active') { if (!defined($ioHash) || $ioHash->{ccustate} ne 'active') {
Log3 $name, 2, "HMCCUCHN: [$devname] Cannot detect IO device, maybe CCU not ready. Trying later ..."; HMCCU_Log ($hash, 2, 'Cannot detect IO device, maybe CCU not ready. Trying later ...');
$hash->{ccudevstate} = 'pending'; $hash->{ccudevstate} = 'pending';
return undef; return undef;
} }
@ -130,8 +125,8 @@ sub HMCCUCHN_Define ($@)
# Initialize FHEM device, set IO device # Initialize FHEM device, set IO device
my $rc = HMCCUCHN_InitDevice ($ioHash, $hash); my $rc = HMCCUCHN_InitDevice ($ioHash, $hash);
return "Invalid or unknown CCU channel name or address" if ($rc == 1); return 'Invalid or unknown CCU channel name or address' if ($rc == 1);
return "Can't assign I/O device ".$ioHash->{NAME} if ($rc == 2); return "Can't assign I/O device $ioHash->{NAME}" if ($rc == 2);
return undef; return undef;
} }
@ -152,22 +147,23 @@ sub HMCCUCHN_InitDevice ($$)
return 1 if (!HMCCU_IsValidChannel ($ioHash, $devspec, 7)); return 1 if (!HMCCU_IsValidChannel ($ioHash, $devspec, 7));
my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($ioHash, $devspec); my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($ioHash, $devspec);
return 1 if (!defined ($da)); return 1 if (!defined($da));
# Inform HMCCU device about client device # Inform HMCCU device about client device
return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME}, undef)); return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME}));
$devHash->{ccuif} = $di; $devHash->{ccuif} = $di;
$devHash->{ccuaddr} = $da; $devHash->{ccuaddr} = $da;
$devHash->{ccuname} = $dn; $devHash->{ccuname} = $dn;
$devHash->{ccutype} = $dt; $devHash->{ccutype} = $dt;
$devHash->{ccudevstate} = 'active'; $devHash->{ccudevstate} = 'active';
if ($init_done) { if ($init_done) {
# Interactive device definition # Interactive device definition
HMCCU_AddDevice ($ioHash, $di, $da, $devHash->{NAME}); HMCCU_AddDevice ($ioHash, $di, $da, $devHash->{NAME});
HMCCU_UpdateDevice ($ioHash, $devHash); HMCCU_UpdateDevice ($ioHash, $devHash);
HMCCU_UpdateDeviceRoles ($ioHash, $devHash); HMCCU_UpdateDeviceRoles ($ioHash, $devHash);
HMCCU_UpdateRoleCommands ($ioHash, $devHash);
if (!exists($devHash->{hmccu}{nodefaults}) || $devHash->{hmccu}{nodefaults} == 0) { if (!exists($devHash->{hmccu}{nodefaults}) || $devHash->{hmccu}{nodefaults} == 0) {
if (!HMCCU_SetDefaultAttributes ($devHash)) { if (!HMCCU_SetDefaultAttributes ($devHash)) {
HMCCU_SetDefaults ($devHash); HMCCU_SetDefaults ($devHash);
@ -217,19 +213,17 @@ sub HMCCUCHN_Attr ($@)
my ($cmd, $name, $attrname, $attrval) = @_; my ($cmd, $name, $attrname, $attrval) = @_;
my $hash = $defs{$name}; my $hash = $defs{$name};
if ($cmd eq "set") { if ($cmd eq 'set') {
return "Missing attribute value" if (!defined ($attrval)); return 'Missing attribute value' if (!defined($attrval));
if ($attrname eq 'IODev') { if ($attrname eq 'IODev') {
$hash->{IODev} = $defs{$attrval}; $hash->{IODev} = $defs{$attrval};
} }
elsif ($attrname eq 'statevals') { elsif ($attrname eq 'statevals') {
return "Device is read only" if ($hash->{readonly} eq 'yes'); return 'Device is read only' if ($hash->{readonly} eq 'yes');
} }
} }
if ($init_done) { HMCCU_RefreshReadings ($hash) if ($init_done);
HMCCU_RefreshReadings ($hash);
}
return undef; return undef;
} }
@ -242,24 +236,20 @@ sub HMCCUCHN_Set ($@)
{ {
my ($hash, $a, $h) = @_; my ($hash, $a, $h) = @_;
my $name = shift @$a; my $name = shift @$a;
my $opt = shift @$a; my $opt = shift @$a // return 'No set command specified';
return 'No set command specified' if (!defined($opt));
$opt = lc($opt); $opt = lc($opt);
# Check device state # Check device state
return undef if (!defined($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' || return "Device state doesn't allow set commands"
!defined($hash->{IODev})); if (!defined($hash->{ccudevstate}) ||
return undef if ($hash->{readonly} eq 'yes' && $opt ne '?' && $hash->{ccudevstate} eq 'pending' || !defined($hash->{IODev}) ||
$opt !~ /^(clear|config|defaults)$/); ($hash->{readonly} eq 'yes' && $opt !~ /^(\?|clear|config|defaults)$/) ||
return undef if (AttrVal ($name, 'disable', 0) == 1); AttrVal ($name, 'disable', 0) == 1);
my $ioHash = $hash->{IODev}; my $ioHash = $hash->{IODev};
my $ioName = $ioHash->{NAME}; my $ioName = $ioHash->{NAME};
if (HMCCU_IsRPCStateBlocking ($ioHash)) { return ($opt eq '?' ? undef : 'Cannot perform set commands. CCU busy')
return undef if ($opt eq '?'); if (HMCCU_IsRPCStateBlocking ($ioHash));
return 'HMCCUCHN: CCU busy';
}
my $ccutype = $hash->{ccutype}; my $ccutype = $hash->{ccutype};
my $ccuaddr = $hash->{ccuaddr}; my $ccuaddr = $hash->{ccuaddr};
@ -269,37 +259,8 @@ sub HMCCUCHN_Set ($@)
# Get state and control datapoints # Get state and control datapoints
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash); my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash);
# Get additional commands (including state commands) # Get additional commands, including state commands
my $roleCmds = HMCCU_GetSpecialCommands ($hash, $cc); my $cmdList = $hash->{hmccu}{cmdlist} // '';
my %pset = ('V' => 'VALUES', 'M' => 'MASTER', 'D' => 'MASTER');
my $cmdList = '';
my %valLookup;
foreach my $cmd (keys %$roleCmds) {
$cmdList .= " $cmd";
my @setList = split (/\s+/, $roleCmds->{$cmd});
foreach my $set (@setList) {
my ($ps, $dpt, $par) = split(/:/, $set);
my @argList = ();
if ($par =~ /^#/) {
my $adr = $ccuaddr;
$adr =~ s/:[0-9]{1,2}$//;
my $paramDef = HMCCU_GetParamDef ($ioHash, $adr, $pset{$ps}, $dpt);
if (defined($paramDef)) {
if ($paramDef->{TYPE} eq 'ENUM' && defined($paramDef->{VALUE_LIST})) {
$par = $paramDef->{VALUE_LIST};
$par =~ s/[ ]+/-/g;
@argList = split (',', $par);
while (my ($i, $e) = each(@argList)) { $valLookup{$pset{$ps}}{$dpt}{$e} = $i; }
}
}
}
elsif ($par !~ /^\?/) {
@argList = split (',', $par);
}
$cmdList .= scalar(@argList) > 1 ? ":$par" : ":noArg";
}
}
# Get state values related to control command and datapoint # Get state values related to control command and datapoint
my $stateVals = HMCCU_GetStateValues ($hash, $cd); my $stateVals = HMCCU_GetStateValues ($hash, $cd);
@ -307,6 +268,12 @@ sub HMCCUCHN_Set ($@)
my %stateCmds = @stateCmdList; my %stateCmds = @stateCmdList;
my @states = keys %stateCmds; my @states = keys %stateCmds;
# Some commands require a control datapoint
if ($opt =~ /^(control|toggle|on-for-timer|on-till)$/) {
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $cd, 2));
}
my $result = ''; my $result = '';
my $rc; my $rc;
@ -315,12 +282,8 @@ sub HMCCUCHN_Set ($@)
if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($ioName, 'logCommand')); if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($ioName, 'logCommand'));
if ($opt eq 'control') { if ($opt eq 'control') {
return HMCCU_SetError ($hash, -14) if ($cd eq ''); my $value = shift @$a // return HMCCU_SetError ($hash, "Usage: set $name control {value}");
my $value = shift @$a;
return HMCCU_SetError ($hash, "Usage: set $name control {value}") if (!defined($value));
$value =~ s/\\_/%20/g; $value =~ s/\\_/%20/g;
$rc = HMCCU_SetMultipleDatapoints ($hash, $rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr.$cd" => HMCCU_Substitute ($value, $stateVals, 1, undef, '') } { "001.$ccuif.$ccuaddr.$cd" => HMCCU_Substitute ($value, $stateVals, 1, undef, '') }
); );
@ -331,14 +294,13 @@ sub HMCCUCHN_Set ($@)
my %dpval; my %dpval;
my $i = 0; my $i = 0;
push (@$a, %${h}) if (defined($h));
while (my $objname = shift @$a) { while (my $objname = shift @$a) {
my $objvalue = shift @$a; my $objvalue = shift @$a // return HMCCU_SetError ($hash, $usage);
$i++;
return HMCCU_SetError ($hash, $usage) if (!defined ($objvalue));
return HMCCU_SetError ($hash, -8) return HMCCU_SetError ($hash, -8)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $objname, 2)); if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $objname, 2));
$i++;
my $no = sprintf ("%03d", $i); my $no = sprintf ("%03d", $i);
$objvalue =~ s/\\_/%20/g; $objvalue =~ s/\\_/%20/g;
$objvalue = HMCCU_Substitute ($objvalue, $stateVals, 1, undef, '') $objvalue = HMCCU_Substitute ($objvalue, $stateVals, 1, undef, '')
@ -346,36 +308,17 @@ sub HMCCUCHN_Set ($@)
$dpval{"$no.$ccuif.$ccuaddr.$objname"} = $objvalue; $dpval{"$no.$ccuif.$ccuaddr.$objname"} = $objvalue;
} }
if (defined($h)) { return HMCCU_SetError ($hash, $usage) if (scalar(keys %dpval) < 1);
foreach my $objname (keys %$h) {
my $objvalue = $h->{$objname};
$i++;
my $no = sprintf ("%03d", $i);
return HMCCU_SetError ($hash, -8)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $objname, 2));
$objvalue =~ s/\\_/%20/g;
$objvalue = HMCCU_Substitute ($objvalue, $stateVals, 1, undef, '')
if ($stateVals ne '' && $objname eq $cd);
$dpval{"$no.$ccuif.$ccuaddr.$objname"} = $objvalue;
}
}
return HMCCU_SetError ($hash, $usage) if (scalar (keys %dpval) < 1);
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval); $rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc)); return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
} }
elsif ($opt eq 'toggle') { elsif ($opt eq 'toggle') {
return HMCCU_SetError ($hash, -15) if ($stateVals eq '');
return HMCCU_SetError ($hash, -12) if ($cc eq '');
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, -8)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $cd, 2));
my $stc = scalar (@states); my $stc = scalar (@states);
return HMCCU_SetError ($hash, -15) if ($stc == 0);
my $curState = defined($hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL}) ? my $curState = defined($hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL}) ?
$hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL} : $states[0]; $hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL} : $states[0];
my $newState = ''; my $newState = '';
my $st = 0; my $st = 0;
while ($st < $stc) { while ($st < $stc) {
@ -383,9 +326,7 @@ sub HMCCUCHN_Set ($@)
$newState = ($st == $stc-1) ? $states[0] : $states[$st+1]; $newState = ($st == $stc-1) ? $states[0] : $states[$st+1];
last; last;
} }
else { $st++;
$st++;
}
} }
return HMCCU_SetError ($hash, "Current device state doesn't match any state value") return HMCCU_SetError ($hash, "Current device state doesn't match any state value")
@ -396,122 +337,8 @@ sub HMCCUCHN_Set ($@)
); );
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc)); return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
} }
elsif (defined($roleCmds) && exists($roleCmds->{$opt})) { elsif (exists($hash->{hmccu}{roleCmds}{$opt})) {
my $value; return HMCCU_ExecuteRoleCommand ($ioHash, $hash, $opt, $a, $h);
my %dpval;
my %cfval;
my @setList = split (/\s+/, $roleCmds->{$opt});
my $i = 0;
foreach my $set (@setList) {
my ($ps, $dpt, $par) = split(/:/, $set);
return HMCCU_SetError ($hash, "Syntax error in definition of command $opt")
if (!defined($par));
if (!HMCCU_IsValidParameter ($hash, $ccuaddr, $pset{$ps}, $dpt)) {
HMCCU_Trace ($hash, 2, "Set", "Invalid parameter $ps $dpt");
return HMCCU_SetError ($hash, -8);
}
if ($par =~ /^\?(.+)$/) {
$par = $1;
my ($parName, $parDef) = split ('=', $par);
$value = shift @$a;
if (!defined($value) && defined($parDef)) {
if ($parDef =~ /^[+-][0-9]+$/) {
return HMCCU_SetError ($hash, "Current value of $cc.$dpt not available")
if (!defined($hash->{hmccu}{dp}{"$cc.$dpt"}{$pset{$ps}}{SVAL}));
$value = $hash->{hmccu}{dp}{"$cc.$dpt"}{$pset{$ps}}{SVAL}+int($parDef);
}
else {
$value = $parDef;
}
}
return HMCCU_SetError ($hash, "Missing parameter $parName")
if (!defined($value));
}
else {
if (exists($valLookup{$ps}{$dpt})) {
return HMCCU_SetError ($hash, "Illegal value $par. Use one of ".join(',', keys %{$valLookup{$ps}{$dpt}}))
if (!exists($valLookup{$ps}{$dpt}{$par}));
$value = $valLookup{$ps}{$dpt}{$par};
}
else {
$value = $par;
}
}
if ($opt eq 'pct' || $opt eq 'level') {
my $timespec = shift @$a;
my $ramptime = shift @$a;
# Set on time
if (defined ($timespec)) {
return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type $ccutype")
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "ON_TIME", 2));
if ($timespec =~ /^[0-9]{2}:[0-9]{2}/) {
$timespec = HMCCU_GetTimeSpec ($timespec);
return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM[:SS]") if ($timespec < 0);
}
$dpval{"001.$ccuif.$ccuaddr.ON_TIME"} = $timespec if ($timespec > 0);
}
# Set ramp time
if (defined($ramptime)) {
return HMCCU_SetError ($hash, "Can't find RAMP_TIME datapoint for device type $ccutype")
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "RAMP_TIME", 2));
$dpval{"002.$ccuif.$ccuaddr.RAMP_TIME"} = $ramptime if (defined ($ramptime));
}
$dpval{"003.$ccuif.$ccuaddr.$dpt"} = $value;
last;
}
else {
if ($ps eq 'V') {
my $no = sprintf ("%03d", $i);
$dpval{"$i.$ccuif.$ccuaddr.$dpt"} = $value;
$i++;
}
else {
$cfval{$dpt} = $value;
}
}
}
if (scalar(keys %dpval) > 0) {
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
if (scalar(keys %cfval) > 0) {
($rc, $result) = HMCCU_SetMultipleParameters ($hash, $ccuaddr, $h, 'MASTER');
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
}
elsif ($opt eq 'on-for-timer' || $opt eq 'on-till') {
return HMCCU_SetError ($hash, -15) if ($stateVals eq '');
return HMCCU_SetError ($hash, "No state value for 'on' defined")
if (!exists($stateCmds{"on"}));
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, -8)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $cd, 2));
return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type")
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "ON_TIME", 2));
my $timespec = shift @$a;
return HMCCU_SetError ($hash, "Usage: set $name $opt {ontime-spec}")
if (!defined ($timespec));
if ($opt eq 'on-till') {
$timespec = HMCCU_GetTimeSpec ($timespec);
return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM[:SS]") if ($timespec < 0);
}
$rc = HMCCU_SetMultipleDatapoints ($hash, {
"001.$ccuif.$ccuaddr.ON_TIME" => $timespec,
"002.$ccuif.$ccuaddr.$cd" => $stateCmds{"on"}
});
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
} }
elsif ($opt eq 'clear') { elsif ($opt eq 'clear') {
my $rnexp = shift @$a; my $rnexp = shift @$a;
@ -569,7 +396,7 @@ sub HMCCUCHN_Set ($@)
} }
} }
elsif (!HMCCU_IsChnAddr ($receiver, 0)) { elsif (!HMCCU_IsChnAddr ($receiver, 0)) {
my ($rcvAdd, $rcvChn) = HMCCU_GetAddress ($ioHash, $receiver, '', ''); my ($rcvAdd, $rcvChn) = HMCCU_GetAddress ($ioHash, $receiver);
return HMCCU_SetError ($hash, "$receiver is not a valid CCU channel name") return HMCCU_SetError ($hash, "$receiver is not a valid CCU channel name")
if ($rcvAdd eq '' || $rcvChn eq ''); if ($rcvAdd eq '' || $rcvChn eq '');
$receiver = "$rcvAdd:$rcvChn"; $receiver = "$rcvAdd:$rcvChn";
@ -583,18 +410,18 @@ sub HMCCUCHN_Set ($@)
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc)); return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
} }
elsif ($opt eq 'defaults') { elsif ($opt eq 'defaults') {
$rc = HMCCU_SetDefaultAttributes ($hash); my $mode = shift @$a // 'update';
$rc = HMCCU_SetDefaultAttributes ($hash, { mode => $mode, role => undef, ctrlChn => $cc });
$rc = HMCCU_SetDefaults ($hash) if (!$rc); $rc = HMCCU_SetDefaults ($hash) if (!$rc);
HMCCU_RefreshReadings ($hash) if ($rc);
return HMCCU_SetError ($hash, $rc == 0 ? "No default attributes found" : "OK"); return HMCCU_SetError ($hash, $rc == 0 ? "No default attributes found" : "OK");
} }
else { else {
my $retmsg = "clear defaults:noArg"; my $retmsg = "clear defaults:reset,update";
if ($hash->{readonly} ne 'yes') { if ($hash->{readonly} ne 'yes') {
$retmsg .= " config datapoint".$cmdList; $retmsg .= ' config datapoint';
# $retmsg .= ':'.join(',', @states) if (scalar(@states) > 0); $retmsg .= " $cmdList" if ($cmdList ne '');
$retmsg .= ' toggle:noArg' if (scalar(@states) > 0); $retmsg .= ' toggle:noArg' if (scalar(@states) > 0);
$retmsg .= " on-for-timer on-till"
if ($cc ne '' && HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, "ON_TIME", 2));
} }
return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a); return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a);
} }
@ -608,9 +435,7 @@ sub HMCCUCHN_Get ($@)
{ {
my ($hash, $a, $h) = @_; my ($hash, $a, $h) = @_;
my $name = shift @$a; my $name = shift @$a;
my $opt = shift @$a; my $opt = shift @$a // return 'No get command specified';
return "No get command specified" if (!defined ($opt));
$opt = lc($opt); $opt = lc($opt);
return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' || return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
@ -621,15 +446,15 @@ sub HMCCUCHN_Get ($@)
my $ioHash = $hash->{IODev}; my $ioHash = $hash->{IODev};
my $ioName = $ioHash->{NAME}; my $ioName = $ioHash->{NAME};
if (HMCCU_IsRPCStateBlocking ($ioHash)) {
return undef if ($opt eq '?'); return $opt eq '?' ? undef : 'Cannot perform get command. CCU busy'
return "HMCCUCHN: CCU busy"; if (HMCCU_IsRPCStateBlocking ($ioHash));
}
my $ccutype = $hash->{ccutype}; my $ccutype = $hash->{ccutype};
my $ccuaddr = $hash->{ccuaddr}; my $ccuaddr = $hash->{ccuaddr};
my $ccuif = $hash->{ccuif}; my $ccuif = $hash->{ccuif};
my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash);
my $result = ''; my $result = '';
my $rc; my $rc;
@ -639,33 +464,20 @@ sub HMCCUCHN_Get ($@)
if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($ioName, 'logCommand')); if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($ioName, 'logCommand'));
if ($opt eq 'datapoint') { if ($opt eq 'datapoint') {
my $objname = shift @$a; my $objname = shift @$a // return HMCCU_SetError ($hash, "Usage: get $name datapoint {datapoint}");
return HMCCU_SetError ($hash, "Usage: get $name datapoint {datapoint}")
if (!defined ($objname));
return HMCCU_SetError ($hash, -8) return HMCCU_SetError ($hash, -8)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $objname, 1)); if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $objname, 1));
$objname = $ccuif.'.'.$ccuaddr.'.'.$objname; $objname = $ccuif.'.'.$ccuaddr.'.'.$objname;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname, 0); ($rc, $result) = HMCCU_GetDatapoint ($hash, $objname, 0);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0); return $rc < 0 ? HMCCU_SetError ($hash, $rc, $result) : $result;
return $result;
} }
# elsif ($opt eq 'update') {
# my $ccuget = shift @$a;
# $ccuget = 'Attr' if (!defined ($ccuget));
# if ($ccuget !~ /^(Attr|State|Value)$/) {
# return HMCCU_SetError ($hash, "Usage: get $name update [{'State'|'Value'}]");
# }
# $rc = HMCCU_GetUpdate ($hash, $ccuaddr, $ccuget);
# return HMCCU_SetError ($hash, $rc) if ($rc < 0);
# return undef;
# }
elsif ($opt eq 'deviceinfo') { elsif ($opt eq 'deviceinfo') {
my ($a, $c) = HMCCU_SplitChnAddr ($ccuaddr); my ($a, $c) = HMCCU_SplitChnAddr ($ccuaddr);
$result = HMCCU_GetDeviceInfo ($hash, $a); $result = HMCCU_GetDeviceInfo ($hash, $a);
return HMCCU_SetError ($hash, -2) if ($result eq ''); return HMCCU_SetError ($hash, -2) if ($result eq '');
my $devInfo = HMCCU_FormatDeviceInfo ($result); my $devInfo = HMCCU_FormatDeviceInfo ($result);
$devInfo .= "StateDatapoint = $sc.$sd\nControlDatapoint = $cc.$cd";
return $devInfo; return $devInfo;
} }
elsif ($opt =~ /^(config|values|update)$/) { elsif ($opt =~ /^(config|values|update)$/) {
@ -711,10 +523,10 @@ sub HMCCUCHN_Get ($@)
$res .= "Device $da\n"; $res .= "Device $da\n";
foreach my $dc (sort keys %{$convRes->{$da}}) { foreach my $dc (sort keys %{$convRes->{$da}}) {
foreach my $ps (sort keys %{$convRes->{$da}{$dc}}) { foreach my $ps (sort keys %{$convRes->{$da}{$dc}}) {
$res .= " Channel $dc [$ps]\n"; $res .= " Channel $dc [$ps]\n".
$res .= join ("\n", map { join ("\n", map {
" ".$_.' = '.$convRes->{$da}{$dc}{$ps}{$_} " ".$_.' = '.$convRes->{$da}{$dc}{$ps}{$_}
} sort keys %{$convRes->{$da}{$dc}{$ps}})."\n"; } sort keys %{$convRes->{$da}{$dc}{$ps}})."\n";
} }
} }
} }
@ -734,6 +546,10 @@ sub HMCCUCHN_Get ($@)
elsif ($opt eq 'defaults') { elsif ($opt eq 'defaults') {
return HMCCU_GetDefaults ($hash, 0); return HMCCU_GetDefaults ($hash, 0);
} }
elsif ($opt eq 'weekprogram') {
my $program = shift @$a;
return HMCCU_DisplayWeekProgram ($hash, $program);
}
else { else {
my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of defaults:noArg datapoint"; my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of defaults:noArg datapoint";
@ -743,6 +559,8 @@ sub HMCCUCHN_Get ($@)
$retmsg .= ":".join(",",@valuelist) if ($valuecount > 0); $retmsg .= ":".join(",",@valuelist) if ($valuecount > 0);
$retmsg .= " update:noArg deviceInfo:noArg config:noArg". $retmsg .= " update:noArg deviceInfo:noArg config:noArg".
" deviceDesc:noArg paramsetDesc:noArg values:noArg"; " deviceDesc:noArg paramsetDesc:noArg values:noArg";
$retmsg .= ' weekProgram:all,'.join(',', sort keys %{$hash->{hmccu}{tt}})
if (exists($hash->{hmccu}{tt}));
return $retmsg; return $retmsg;
} }
@ -753,7 +571,7 @@ sub HMCCUCHN_Get ($@)
=pod =pod
=item device =item device
=item summary controls HMCCU client devices for Homematic CCU2 - FHEM integration =item summary controls HMCCU client devices for Homematic CCU2/3 - FHEM integration
=begin html =begin html
<a name="HMCCUCHN"></a> <a name="HMCCUCHN"></a>
@ -816,9 +634,12 @@ sub HMCCUCHN_Get ($@)
<code>set temp_control datapoint SET_TEMPERATURE 21</code><br/> <code>set temp_control datapoint SET_TEMPERATURE 21</code><br/>
<code>set temp_control datapoint AUTO_MODE 1 SET_TEMPERATURE 21</code> <code>set temp_control datapoint AUTO_MODE 1 SET_TEMPERATURE 21</code>
</li><br/> </li><br/>
<li><b>set &lt;name&gt; defaults</b><br/> <li><b>set &lt;name&gt; defaults ['reset'|'<u>update</u>']</b><br/>
Set default attributes for CCU device type. Default attributes are only available for Set default attributes for CCU device type. Default attributes are only available for
some device types and for some channels of a device type. some device types and for some channels of a device type. If option 'reset' is specified,
the following attributes are deleted before the new attributes are set:
'ccureadingname', 'ccuscaleval', 'eventMap', 'substexcl', 'webCmd', 'widgetOverride'.
During update to version 4.4 it's recommended to use option 'reset'.
</li><br/> </li><br/>
<li><b>set &lt;name&gt; down [&lt;value&gt;]</b><br/> <li><b>set &lt;name&gt; down [&lt;value&gt;]</b><br/>
Decrement value of datapoint LEVEL. This command is only available if channel contains Decrement value of datapoint LEVEL. This command is only available if channel contains
@ -948,6 +769,9 @@ sub HMCCUCHN_Get ($@)
</li><br/> </li><br/>
<li><b>get &lt;name&gt; values</b><br/> <li><b>get &lt;name&gt; values</b><br/>
Same as 'get update' but using RPC instead of ReGa. Same as 'get update' but using RPC instead of ReGa.
</li><br/>
<li><b>get &lt;name&gt; weekProgram [&lt;program-number&gt;|<u>all</u>]</b><br/>
Display week programs. This command is only available if a device supports week programs.
</li> </li>
</ul> </ul>
<br/> <br/>

View File

@ -4,7 +4,7 @@
# #
# $Id: 88_HMCCUDEV.pm 18552 2019-02-10 11:52:28Z zap $ # $Id: 88_HMCCUDEV.pm 18552 2019-02-10 11:52:28Z zap $
# #
# Version 4.4.016 # Version 4.4.022
# #
# (c) 2020 zap (zap01 <at> t-online <dot> de) # (c) 2020 zap (zap01 <at> t-online <dot> de)
# #
@ -38,21 +38,22 @@ sub HMCCUDEV_Initialize ($)
{ {
my ($hash) = @_; my ($hash) = @_;
$hash->{DefFn} = "HMCCUDEV_Define"; $hash->{DefFn} = 'HMCCUDEV_Define';
$hash->{UndefFn} = "HMCCUCHN_Undef"; $hash->{UndefFn} = 'HMCCUCHN_Undef';
$hash->{RenameFn} = "HMCCUDEV_Rename"; $hash->{RenameFn} = 'HMCCUDEV_Rename';
$hash->{SetFn} = "HMCCUDEV_Set"; $hash->{SetFn} = 'HMCCUDEV_Set';
$hash->{GetFn} = "HMCCUDEV_Get"; $hash->{GetFn} = 'HMCCUDEV_Get';
$hash->{AttrFn} = "HMCCUDEV_Attr"; $hash->{AttrFn} = 'HMCCUDEV_Attr';
$hash->{parseParams} = 1; $hash->{parseParams} = 1;
$hash->{AttrList} = "IODev ccuaggregate:textField-long ccucalculate:textField-long ". $hash->{AttrList} = 'IODev ccuaggregate:textField-long ccucalculate:textField-long '.
"ccuflags:multiple-strict,ackState,logCommand,nochn0,noReadings,trace ccureadingfilter:textField-long ". 'ccuflags:multiple-strict,ackState,logCommand,noReadings,trace,showMasterReadings,showLinkReadings,showDeviceReadings '.
"ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ". 'ccureadingfilter:textField-long '.
"ccureadingname:textField-long ". 'ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc '.
"ccuget:State,Value ccuscaleval ccuSetOnChange ccuverify:0,1,2 disable:0,1 ". 'ccureadingname:textField-long ccuSetOnChange ccuReadingPrefix '.
"hmstatevals:textField-long statevals substexcl substitute:textField-long statechannel ". 'ccuget:State,Value ccuscaleval ccuverify:0,1,2 disable:0,1 '.
"controlchannel statedatapoint controldatapoint stripnumber peer:textField-long ". 'hmstatevals:textField-long statevals substexcl substitute:textField-long statechannel '.
'controlchannel statedatapoint controldatapoint stripnumber peer:textField-long '.
$readingFnAttributes; $readingFnAttributes;
} }
@ -68,7 +69,7 @@ sub HMCCUDEV_Define ($@)
my $usage = "Usage: define $name HMCCUDEV {device|'virtual'} [control-channel] ". my $usage = "Usage: define $name HMCCUDEV {device|'virtual'} [control-channel] ".
"['readonly'] ['noDefaults'|'defaults'] [iodev={iodev-name}] [address={virtual-device-no}]". "['readonly'] ['noDefaults'|'defaults'] [iodev={iodev-name}] [address={virtual-device-no}]".
"[{groupexp=regexp|group={device|channel}[,...]]"; "[{groupexp=regexp|group={device|channel}[,...]]";
return $usage if (scalar (@$a) < 3); return $usage if (scalar(@$a) < 3);
my @errmsg = ( my @errmsg = (
"OK", "OK",
@ -81,47 +82,37 @@ sub HMCCUDEV_Define ($@)
"Too many virtual devices" "Too many virtual devices"
); );
my $devname = shift @$a; my ($devname, $devtype, $devspec) = splice (@$a, 0, 3);
my $devtype = shift @$a;
my $devspec = shift @$a;
my $ioHash = undef; my $ioHash = undef;
# my $existDev = HMCCU_ExistsClientDevice ($devspec, $devtype);
# return "FHEM device $existDev for CCU device $devspec already exists" if (defined($existDev));
# Store some definitions for delayed initialization # Store some definitions for delayed initialization
$hash->{readonly} = 'no'; $hash->{readonly} = 'no';
$hash->{hmccu}{devspec} = $devspec; $hash->{hmccu}{devspec} = $devspec;
$hash->{hmccu}{groupexp} = $h->{groupexp} if (exists ($h->{groupexp})); $hash->{hmccu}{groupexp} = $h->{groupexp} if (exists ($h->{groupexp}));
$hash->{hmccu}{group} = $h->{group} if (exists ($h->{group})); $hash->{hmccu}{group} = $h->{group} if (exists ($h->{group}));
$hash->{hmccu}{defaults} = 0;
if (exists ($h->{address})) { if (exists($h->{address})) {
if ($init_done || $devspec ne 'virtual') { return 'Option address not allowed' if ($init_done || $devspec ne 'virtual');
return "Option address not allowed"; $hash->{hmccu}{address} = $h->{address};
}
else {
$hash->{hmccu}{address} = $h->{address};
}
} }
else { else {
return "Option address not specified" if (!$init_done && $devspec eq 'virtual'); return 'Option address not specified' if (!$init_done && $devspec eq 'virtual');
} }
# Parse optional command line parameters # Parse optional command line parameters
foreach my $arg (@$a) { foreach my $arg (@$a) {
if ($arg eq 'readonly') { $hash->{readonly} = 'yes'; } if ($arg eq 'readonly') { $hash->{readonly} = 'yes'; }
elsif (lc($arg) eq 'nodefaults' && $init_done) { $hash->{hmccu}{nodefaults} = 1; } elsif (lc($arg) eq 'nodefaults' && $init_done) { $hash->{hmccu}{nodefaults} = 1; }
elsif ($arg eq 'defaults' && $init_done) { $hash->{hmccu}{nodefaults} = 0; } elsif ($arg eq 'defaults' && $init_done) { $hash->{hmccu}{nodefaults} = 0; }
elsif ($arg =~ /^[0-9]+$/) { $attr{$name}{controlchannel} = $arg; } elsif ($arg =~ /^[0-9]+$/) { $attr{$name}{controlchannel} = $arg; }
else { return $usage; } else { return $usage; }
} }
# IO device can be set by command line parameter iodev, otherwise try to detect IO device # IO device can be set by command line parameter iodev, otherwise try to detect IO device
if (exists ($h->{iodev})) { if (exists($h->{iodev})) {
return "Specified IO Device ".$h->{iodev}." does not exist" if (!exists ($defs{$h->{iodev}})); return "IO device $h->{iodev} does not exist" if (!exists($defs{$h->{iodev}}));
return "Specified IO Device ".$h->{iodev}." is not a HMCCU device" return "Type of device $h->{iodev} is not HMCCU" if ($defs{$h->{iodev}}->{TYPE} ne 'HMCCU');
if ($defs{$h->{iodev}}->{TYPE} ne 'HMCCU');
$ioHash = $defs{$h->{iodev}}; $ioHash = $defs{$h->{iodev}};
} }
else { else {
@ -133,18 +124,14 @@ sub HMCCUDEV_Define ($@)
# Interactive define command while CCU not ready # Interactive define command while CCU not ready
if (!defined($ioHash)) { if (!defined($ioHash)) {
my ($ccuactive, $ccuinactive) = HMCCU_IODeviceStates (); my ($ccuactive, $ccuinactive) = HMCCU_IODeviceStates ();
if ($ccuinactive > 0) { return $ccuinactive > 0 ? 'CCU and/or IO device not ready. Please try again later' :
return "CCU and/or IO device not ready. Please try again later"; 'Cannot detect IO device';
}
else {
return "Cannot detect IO device";
}
} }
} }
else { else {
# CCU not ready during FHEM start # CCU not ready during FHEM start
if (!defined($ioHash) || $ioHash->{ccustate} ne 'active') { if (!defined($ioHash) || $ioHash->{ccustate} ne 'active') {
Log3 $name, 2, "HMCCUDEV: [$devname] Cannot detect IO device, maybe CCU not ready. Trying later ..."; HMCCU_Log ($hash, 2, 'Cannot detect IO device, maybe CCU not ready. Trying later ...');
$hash->{ccudevstate} = 'pending'; $hash->{ccudevstate} = 'pending';
return undef; return undef;
} }
@ -152,7 +139,7 @@ sub HMCCUDEV_Define ($@)
# Initialize FHEM device, set IO device # Initialize FHEM device, set IO device
my $rc = HMCCUDEV_InitDevice ($ioHash, $hash); my $rc = HMCCUDEV_InitDevice ($ioHash, $hash);
return $errmsg[$rc] if ($rc > 0); return $errmsg[$rc] if ($rc > 0 && $rc < scalar(@errmsg));
return undef; return undef;
} }
@ -180,7 +167,7 @@ sub HMCCUDEV_InitDevice ($$)
if ($devspec eq 'virtual') { if ($devspec eq 'virtual') {
my $no = 0; my $no = 0;
if (exists ($devHash->{hmccu}{address})) { if (exists($devHash->{hmccu}{address})) {
# Only true during FHEM start # Only true during FHEM start
$no = $devHash->{hmccu}{address}; $no = $devHash->{hmccu}{address};
} }
@ -198,11 +185,11 @@ sub HMCCUDEV_InitDevice ($$)
} }
# Inform HMCCU device about client device # Inform HMCCU device about client device
return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME}, undef)); return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME}));
$devHash->{ccuif} = 'fhem'; $devHash->{ccuif} = 'fhem';
$devHash->{ccuaddr} = sprintf ("VIR%07d", $no); $devHash->{ccuaddr} = sprintf ("VIR%07d", $no);
$devHash->{ccuname} = $name; $devHash->{ccuname} = $name;
$devHash->{ccudevstate} = 'active'; $devHash->{ccudevstate} = 'active';
} }
else { else {
@ -213,13 +200,13 @@ sub HMCCUDEV_InitDevice ($$)
$gdname = $dn; $gdname = $dn;
# Inform HMCCU device about client device # Inform HMCCU device about client device
return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME}, undef)); return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME}));
$devHash->{ccuif} = $di; $devHash->{ccuif} = $di;
$devHash->{ccuaddr} = $da; $devHash->{ccuaddr} = $da;
$devHash->{ccuname} = $dn; $devHash->{ccuname} = $dn;
$devHash->{ccutype} = $dt; $devHash->{ccutype} = $dt;
$devHash->{ccudevstate} = 'active'; $devHash->{ccudevstate} = 'active';
$devHash->{hmccu}{channels} = $dc; $devHash->{hmccu}{channels} = $dc;
if ($init_done) { if ($init_done) {
@ -227,6 +214,7 @@ sub HMCCUDEV_InitDevice ($$)
HMCCU_AddDevice ($ioHash, $di, $da, $devHash->{NAME}); HMCCU_AddDevice ($ioHash, $di, $da, $devHash->{NAME});
HMCCU_UpdateDevice ($ioHash, $devHash); HMCCU_UpdateDevice ($ioHash, $devHash);
HMCCU_UpdateDeviceRoles ($ioHash, $devHash); HMCCU_UpdateDeviceRoles ($ioHash, $devHash);
HMCCU_UpdateRoleCommands ($ioHash, $devHash, $attr{$devHash->{NAME}}{controlchannel});
if (!exists($devHash->{hmccu}{nodefaults}) || $devHash->{hmccu}{nodefaults} == 0) { if (!exists($devHash->{hmccu}{nodefaults}) || $devHash->{hmccu}{nodefaults} == 0) {
if (!HMCCU_SetDefaultAttributes ($devHash)) { if (!HMCCU_SetDefaultAttributes ($devHash)) {
HMCCU_SetDefaults ($devHash); HMCCU_SetDefaults ($devHash);
@ -246,17 +234,12 @@ sub HMCCUDEV_InitDevice ($$)
} }
elsif (exists ($devHash->{hmccu}{group})) { elsif (exists ($devHash->{hmccu}{group})) {
# Group devices specified by comma separated name list # Group devices specified by comma separated name list
my @gdevlist = split (",", $devHash->{hmccu}{group}); my @gdevlist = split (',', $devHash->{hmccu}{group});
$devHash->{ccugroup} = '' if (@gdevlist > 0); $devHash->{ccugroup} = '' if (scalar(@gdevlist) > 0);
foreach my $gd (@gdevlist) { foreach my $gd (@gdevlist) {
my ($gda, $gdc, $gdo) = ('', '', '', '');
return 1 if (!HMCCU_IsValidDevice ($ioHash, $gd, 7)); return 1 if (!HMCCU_IsValidDevice ($ioHash, $gd, 7));
my ($gda, $gdc) = HMCCU_GetAddress ($ioHash, $gd);
($gda, $gdc) = HMCCU_GetAddress ($ioHash, $gd, '', ''); push @devlist, $gdc eq '' ? "$gda:$gdc" : $gda;
$gdo = $gda;
$gdo .= ':'.$gdc if ($gdc ne '');
push @devlist, $gdo;
$gdcount++; $gdcount++;
} }
} }
@ -310,9 +293,7 @@ sub HMCCUDEV_Undef ($$)
if ($hash->{IODev}) { if ($hash->{IODev}) {
HMCCU_RemoveDevice ($hash->{IODev}, $hash->{ccuif}, $hash->{ccuaddr}, $hash->{NAME}); HMCCU_RemoveDevice ($hash->{IODev}, $hash->{ccuif}, $hash->{ccuaddr}, $hash->{NAME});
if ($hash->{ccuif} eq 'fhem') { HMCCU_DeleteDevice ($hash->{IODev}) if ($hash->{ccuif} eq 'fhem');
HMCCU_DeleteDevice ($hash->{IODev});
}
} }
return undef; return undef;
@ -351,9 +332,7 @@ sub HMCCUDEV_Attr ($@)
} }
} }
if ($init_done) { HMCCU_RefreshReadings ($hash) if ($init_done);
HMCCU_RefreshReadings ($hash);
}
return; return;
} }
@ -366,24 +345,19 @@ sub HMCCUDEV_Set ($@)
{ {
my ($hash, $a, $h) = @_; my ($hash, $a, $h) = @_;
my $name = shift @$a; my $name = shift @$a;
my $opt = shift @$a; my $opt = shift @$a // return 'No set command specified';
$opt = lc($opt);
return 'No set command specified' if (!defined($opt));
# Check device state # Check device state
return undef if (!defined($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' || return "Device state doesn't allow set commands"
!defined($hash->{IODev})); if (!defined($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' || !defined($hash->{IODev}) ||
return undef if ($hash->{readonly} eq 'yes' && $opt ne '?' && $opt !~ /^(clear|config|defaults)$/); ($hash->{readonly} eq 'yes' && $opt !~ /^(\?|clear|config|defaults)$/) ||
return undef if (AttrVal ($name, 'disable', 0) == 1); AttrVal ($name, 'disable', 0) == 1);
my $ioHash = $hash->{IODev}; my $ioHash = $hash->{IODev};
my $hmccu_name = $ioHash->{NAME}; my $ioName = $ioHash->{NAME};
return ($opt eq '?' ? undef : 'Cannot perform set commands. CCU busy')
# Check if CCU is busy if (HMCCU_IsRPCStateBlocking ($ioHash));
if (HMCCU_IsRPCStateBlocking ($ioHash)) {
return undef if ($opt eq '?');
return 'HMCCUDEV: CCU busy';
}
# Get parameters of current device # Get parameters of current device
my $ccutype = $hash->{ccutype}; my $ccutype = $hash->{ccutype};
@ -394,35 +368,8 @@ sub HMCCUDEV_Set ($@)
# Get state and control datapoints # Get state and control datapoints
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash); my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash);
# Get additional commands (including state commands) # Get additional commands
my $roleCmds = HMCCU_GetSpecialCommands ($hash, $cc); my $cmdList = $hash->{hmccu}{cmdlist} // '';
my %pset = ('V' => 'VALUES', 'M' => 'MASTER', 'D' => 'MASTER');
my $cmdList = '';
my %valLookup;
foreach my $cmd (keys %$roleCmds) {
$cmdList .= " $cmd";
my @setList = split (/\s+/, $roleCmds->{$cmd});
foreach my $set (@setList) {
my ($ps, $dpt, $par) = split(/:/, $set);
my @argList = ();
if ($par =~ /^#/) {
my $paramDef = HMCCU_GetParamDef ($ioHash, $ccuaddr, $pset{$ps}, $dpt);
if (defined($paramDef)) {
if ($paramDef->{TYPE} eq 'ENUM' && defined($paramDef->{VALUE_LIST})) {
$par = $paramDef->{VALUE_LIST};
$par =~ s/[ ]+/-/g;
@argList = split (',', $par);
while (my ($i, $e) = each(@argList)) { $valLookup{$pset{$ps}}{$dpt}{$e} = $i; }
}
}
}
elsif ($par !~ /^\?/) {
@argList = split (',', $par);
}
$cmdList .= scalar(@argList) > 1 ? ":$par" : ":noArg";
}
}
# Get state values related to control command and datapoint # Get state values related to control command and datapoint
my $stateVals = HMCCU_GetStateValues ($hash, $cd, $cc); my $stateVals = HMCCU_GetStateValues ($hash, $cd, $cc);
@ -430,23 +377,24 @@ sub HMCCUDEV_Set ($@)
my %stateCmds = @stateCmdList; my %stateCmds = @stateCmdList;
my @states = keys %stateCmds; my @states = keys %stateCmds;
# Some commands require a control channel and datapoint
if ($opt =~ /^(control|toggle|on-for-timer|on-till)$/) {
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, -12) if ($cc eq '');
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, $cd, 2));
return HMCCU_SetError ($hash, -7) if ($cc >= $hash->{hmccu}{channels});
}
my $result = ''; my $result = '';
my $rc; my $rc;
# Log commands # Log commands
HMCCU_Log ($hash, 3, "set $name $opt ".join (' ', @$a)) HMCCU_Log ($hash, 3, "set $name $opt ".join (' ', @$a))
if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($hmccu_name, 'logCommand')); if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($ioName, 'logCommand'));
if ($opt eq 'control') { if ($opt eq 'control') {
return HMCCU_SetError ($hash, -12) if ($cc eq ''); my $value = shift @$a // return HMCCU_SetError ($hash, "Usage: set $name control {value}");
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, -7) if ($cc >= $hash->{hmccu}{channels});
my $value = shift @$a;
return HMCCU_SetError ($hash, "Usage: set $name control {value}") if (!defined($value));
$value =~ s/\\_/%20/g; $value =~ s/\\_/%20/g;
$rc = HMCCU_SetMultipleDatapoints ($hash, $rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr:$cc.$cd" => HMCCU_Substitute ($value, $stateVals, 1, undef, '') } { "001.$ccuif.$ccuaddr:$cc.$cd" => HMCCU_Substitute ($value, $stateVals, 1, undef, '') }
); );
@ -457,6 +405,7 @@ sub HMCCUDEV_Set ($@)
my %dpval; my %dpval;
my $i = 0; my $i = 0;
push (@$a, %${h}) if (defined($h));
while (my $objname = shift @$a) { while (my $objname = shift @$a) {
my $value = shift @$a; my $value = shift @$a;
$i += 1; $i += 1;
@ -464,24 +413,17 @@ sub HMCCUDEV_Set ($@)
if ($ccutype eq 'HM-Dis-EP-WM55' && !defined($value)) { if ($ccutype eq 'HM-Dis-EP-WM55' && !defined($value)) {
$value = ''; $value = '';
foreach my $t (keys %{$h}) { foreach my $t (keys %{$h}) {
if ($value eq '') { $value .= $value eq '' ? $t.'='.$h->{$t} : ','.$t.'='.$h->{$t};
$value = $t.'='.$h->{$t};
}
else {
$value .= ','.$t.'='.$h->{$t};
}
} }
} }
return HMCCU_SetError ($hash, $usage) if (!defined ($value) || $value eq ''); return HMCCU_SetError ($hash, $usage) if (!defined($value) || $value eq '');
if ($objname =~ /^([0-9]+)\..+$/) { if ($objname =~ /^([0-9]+)\..+$/) {
my $chn = $1; return HMCCU_SetError ($hash, -7) if ($1 >= $hash->{hmccu}{channels});
return HMCCU_SetError ($hash, -7) if ($chn >= $hash->{hmccu}{channels});
} }
else { else {
return HMCCU_SetError ($hash, -11) if ($cc eq ''); $objname = "$cc.$objname";
$objname = $cc.'.'.$objname;
} }
my $no = sprintf ("%03d", $i); my $no = sprintf ("%03d", $i);
@ -489,19 +431,15 @@ sub HMCCUDEV_Set ($@)
$dpval{"$no.$ccuif.$ccuaddr:$objname"} = HMCCU_Substitute ($value, $stateVals, 1, undef, ''); $dpval{"$no.$ccuif.$ccuaddr:$objname"} = HMCCU_Substitute ($value, $stateVals, 1, undef, '');
} }
return HMCCU_SetError ($hash, $usage) if (scalar (keys %dpval) < 1); return HMCCU_SetError ($hash, $usage) if (scalar(keys %dpval) < 1);
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval); $rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc)); return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
} }
elsif ($opt eq 'toggle') { elsif ($opt eq 'toggle') {
return HMCCU_SetError ($hash, -12) if ($cc eq ''); my $stc = scalar(@states);
return HMCCU_SetError ($hash, -14) if ($cd eq ''); return HMCCU_SetError ($hash, -15) if ($stc == 0);
return HMCCU_SetError ($hash, -15) if ($stateVals eq '');
return HMCCU_SetError ($hash, -8)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, $cd, 2));
my $stc = scalar (@states);
my $curState = defined($hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL}) ? my $curState = defined($hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL}) ?
$hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL} : $states[0]; $hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL} : $states[0];
@ -512,9 +450,7 @@ sub HMCCUDEV_Set ($@)
$newState = ($st == $stc-1) ? $states[0] : $states[$st+1]; $newState = ($st == $stc-1) ? $states[0] : $states[$st+1];
last; last;
} }
else { $st++;
$st++;
}
} }
return HMCCU_SetError ($hash, "Current device state doesn't match any state value") return HMCCU_SetError ($hash, "Current device state doesn't match any state value")
@ -525,126 +461,8 @@ sub HMCCUDEV_Set ($@)
); );
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc)); return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
} }
elsif (defined($roleCmds) && exists($roleCmds->{$opt})) { elsif (exists($hash->{hmccu}{roleCmds}{$opt})) {
return HMCCU_SetError ($hash, -12) if ($cc eq ''); return HMCCU_ExecuteRoleCommand ($ioHash, $hash, $opt, $a, $h);
return HMCCU_SetError ($hash, -14) if ($cd eq '');
my $value;
my %dpval;
my %cfval;
my @setList = split (/\s+/, $roleCmds->{$opt});
my $i = 0;
foreach my $set (@setList) {
my ($ps, $dpt, $par) = split(/:/, $set);
return HMCCU_SetError ($hash, "Syntax error in definition of command $opt")
if (!defined($par));
if (!HMCCU_IsValidParameter ($hash, $ccuaddr, $pset{$ps}, $dpt)) {
HMCCU_Trace ($hash, 2, "Set", "Invalid parameter $ps $dpt");
return HMCCU_SetError ($hash, -8);
}
# Check if parameter is required
if ($par =~ /^\?(.+)$/) {
$par = $1;
# Consider default value for parameter
my ($parName, $parDef) = split ('=', $par);
$value = shift @$a;
if (!defined($value) && defined($parDef)) {
if ($parDef =~ /^[+-][0-9]+$/) {
return HMCCU_SetError ($hash, "Current value of $cc.$dpt not available")
if (!defined($hash->{hmccu}{dp}{"$cc.$dpt"}{$pset{$ps}}{SVAL}));
$value = $hash->{hmccu}{dp}{"$cc.$dpt"}{$pset{$ps}}{SVAL}+int($parDef);
}
else {
$value = $parDef;
}
}
return HMCCU_SetError ($hash, "Missing parameter $parName")
if (!defined($value));
}
else {
if (exists($valLookup{$ps}{$dpt})) {
return HMCCU_SetError ($hash, "Illegal value $par. Use one of ".join(',', keys %{$valLookup{$ps}{$dpt}}))
if (!exists($valLookup{$ps}{$dpt}{$par}));
$value = $valLookup{$ps}{$dpt}{$par};
}
else {
$value = $par;
}
}
if ($opt eq 'pct' || $opt eq 'level') {
my $timespec = shift @$a;
my $ramptime = shift @$a;
# Set on time
if (defined ($timespec)) {
return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type $ccutype")
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "ON_TIME", 2));
if ($timespec =~ /^[0-9]{2}:[0-9]{2}/) {
$timespec = HMCCU_GetTimeSpec ($timespec);
return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM[:SS]") if ($timespec < 0);
}
$dpval{"001.$ccuif.$ccuaddr.$cc.ON_TIME"} = $timespec if ($timespec > 0);
}
# Set ramp time
if (defined($ramptime)) {
return HMCCU_SetError ($hash, "Can't find RAMP_TIME datapoint for device type $ccutype")
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "RAMP_TIME", 2));
$dpval{"002.$ccuif.$ccuaddr.$cc.RAMP_TIME"} = $ramptime if (defined ($ramptime));
}
$dpval{"003.$ccuif.$ccuaddr.$cc.$dpt"} = $value;
last;
}
else {
if ($ps eq 'V') {
my $no = sprintf ("%03d", $i);
$dpval{"$i.$ccuif.$ccuaddr.$cc.$dpt"} = $value;
$i++;
}
else {
$cfval{$dpt} = $value;
}
}
}
if (scalar(keys %dpval) > 0) {
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
if (scalar(keys %cfval) > 0) {
($rc, $result) = HMCCU_SetMultipleParameters ($hash, $ccuaddr, $h, 'MASTER');
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
}
elsif ($opt eq 'on-for-timer' || $opt eq 'on-till') {
return HMCCU_SetError ($hash, -15) if ($stateVals eq '' || !exists($hash->{hmccu}{statevals}));
return HMCCU_SetError ($hash, "No state value for 'on' defined")
if ("on" !~ /($hash->{hmccu}{statevals})/);
return HMCCU_SetError ($hash, -12) if ($cc eq '');
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type")
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, 'ON_TIME', 2));
my $timespec = shift @$a;
return HMCCU_SetError ($hash, "Usage: set $name $opt {ontime-spec}")
if (!defined ($timespec));
if ($opt eq 'on-till') {
$timespec = HMCCU_GetTimeSpec ($timespec);
return HMCCU_SetError ($hash, 'Wrong time format. Use HH:MM[:SS]') if ($timespec < 0);
}
$rc = HMCCU_SetMultipleDatapoints ($hash, {
"001.$ccuif.$ccuaddr:$cc.ON_TIME" => $timespec,
"002.$ccuif.$ccuaddr:$cc.$cd" => HMCCU_Substitute ('on', $stateVals, 1, undef, '')
});
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
} }
elsif ($opt eq 'clear') { elsif ($opt eq 'clear') {
my $rnexp = shift @$a; my $rnexp = shift @$a;
@ -673,13 +491,12 @@ sub HMCCUDEV_Set ($@)
} }
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $ccuobj, $ccuif); my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $ccuobj, $ccuif);
return HMCCU_SetError ($hash, "Can't get device description") return HMCCU_SetError ($hash, "Can't get device description") if (!defined($devDesc));
if (!defined($devDesc));
return HMCCU_SetError ($hash, "Paramset $paramset not supported by device or channel") return HMCCU_SetError ($hash, "Paramset $paramset not supported by device or channel")
if ($devDesc->{PARAMSETS} !~ /$paramset/); if ($devDesc->{PARAMSETS} !~ /$paramset/);
if (!HMCCU_IsValidParameter ($ioHash, $devDesc, $paramset, $h)) { if (!HMCCU_IsValidParameter ($ioHash, $devDesc, $paramset, $h)) {
my @parList = HMCCU_GetParamDef ($ioHash, $devDesc, $paramset); my @parList = HMCCU_GetParamDef ($ioHash, $devDesc, $paramset);
return HMCCU_SetError ($hash, "Invalid parameter specified. Valid parameters are ". return HMCCU_SetError ($hash, 'Invalid parameter specified. Valid parameters are '.
join(',', @parList)); join(',', @parList));
} }
@ -691,7 +508,7 @@ sub HMCCUDEV_Set ($@)
my $clHash = $defs{$receiver}; my $clHash = $defs{$receiver};
if ($clHash->{TYPE} eq 'HMCCUDEV') { if ($clHash->{TYPE} eq 'HMCCUDEV') {
my $chnNo = shift @$a; my $chnNo = shift @$a;
return HMCCU_SetError ($hash, "Channel number required for link receiver") return HMCCU_SetError ($hash, 'Channel number required for link receiver')
if (!defined($chnNo) || $chnNo !~ /^[0-9]{1,2}$/); if (!defined($chnNo) || $chnNo !~ /^[0-9]{1,2}$/);
$receiver = $clHash->{ccuaddr}.":$chnNo"; $receiver = $clHash->{ccuaddr}.":$chnNo";
} }
@ -703,7 +520,7 @@ sub HMCCUDEV_Set ($@)
} }
} }
elsif (!HMCCU_IsChnAddr ($receiver, 0)) { elsif (!HMCCU_IsChnAddr ($receiver, 0)) {
my ($rcvAdd, $rcvChn) = HMCCU_GetAddress ($ioHash, $receiver, '', ''); my ($rcvAdd, $rcvChn) = HMCCU_GetAddress ($ioHash, $receiver);
return HMCCU_SetError ($hash, "$receiver is not a valid CCU channel name") return HMCCU_SetError ($hash, "$receiver is not a valid CCU channel name")
if ($rcvAdd eq '' || $rcvChn eq ''); if ($rcvAdd eq '' || $rcvChn eq '');
$receiver = "$rcvAdd:$rcvChn"; $receiver = "$rcvAdd:$rcvChn";
@ -711,27 +528,25 @@ sub HMCCUDEV_Set ($@)
return HMCCU_SetError ($hash, "$receiver is not a link receiver of $name") return HMCCU_SetError ($hash, "$receiver is not a link receiver of $name")
if (!HMCCU_IsValidReceiver ($ioHash, $ccuaddr, $ccuif, $receiver)); if (!HMCCU_IsValidReceiver ($ioHash, $ccuaddr, $ccuif, $receiver));
($rc, $result) = HMCCU_RPCRequest ($hash, "putParamset", $ccuaddr, $receiver, $h); ($rc, $result) = HMCCU_RPCRequest ($hash, 'putParamset', $ccuaddr, $receiver, $h);
} }
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc)); return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
} }
elsif ($opt eq 'defaults') { elsif ($opt eq 'defaults') {
$rc = HMCCU_SetDefaultAttributes ($hash, $cc); my $mode = shift @$a // 'update';
$rc = HMCCU_SetDefaultAttributes ($hash, { mode => $mode, role => undef, ctrlChn => $cc });
$rc = HMCCU_SetDefaults ($hash) if (!$rc); $rc = HMCCU_SetDefaults ($hash) if (!$rc);
return HMCCU_SetError ($hash, $rc == 0 ? "No default attributes found" : "OK"); HMCCU_RefreshReadings ($hash) if ($rc);
return HMCCU_SetError ($hash, $rc == 0 ? 'No default attributes found' : 'OK');
} }
else { else {
my $retmsg = "clear defaults:noArg"; my $retmsg = 'clear defaults:reset,update';
if ($hash->{readonly} ne 'yes') { if ($hash->{readonly} ne 'yes') {
$retmsg .= " datapoint rpcparameter"; $retmsg .= ' config datapoint';
if ($sc ne '') { $retmsg .= " $cmdList" if ($cmdList ne '');
$retmsg .= " config datapoint".$cmdList; $retmsg .= ' toggle:noArg' if (scalar(@states) > 0);
$retmsg .= " toggle:noArg" if (scalar(@states) > 0);
$retmsg .= " on-for-timer on-till"
if ($cc ne '' && HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $cc, "ON_TIME", 2));
}
} }
return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a); return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a);
} }
@ -745,26 +560,19 @@ sub HMCCUDEV_Get ($@)
{ {
my ($hash, $a, $h) = @_; my ($hash, $a, $h) = @_;
my $name = shift @$a; my $name = shift @$a;
my $opt = shift @$a; my $opt = shift @$a // return 'No get command specified';
return "No get command specified" if (!defined ($opt));
$opt = lc($opt); $opt = lc($opt);
# Get I/O device # Get I/O device
return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' || return "Device state doesn't allow set commands"
!defined ($hash->{IODev})); if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
!defined ($hash->{IODev}) || AttrVal ($name, "disable", 0) == 1);
my $ioHash = $hash->{IODev}; my $ioHash = $hash->{IODev};
my $hmccu_name = $ioHash->{NAME}; my $ioName = $ioHash->{NAME};
# Handle disabled devices
my $disable = AttrVal ($name, "disable", 0);
return undef if ($disable == 1);
# Check if CCU is busy # Check if CCU is busy
if (HMCCU_IsRPCStateBlocking ($ioHash)) { return $opt eq '?' ? undef : 'Cannot perform get commands. CCU busy'
return undef if ($opt eq '?'); if (HMCCU_IsRPCStateBlocking ($ioHash));
return "HMCCUDEV: CCU busy";
}
# Get parameters of current device # Get parameters of current device
my $ccutype = $hash->{ccutype}; my $ccutype = $hash->{ccutype};
@ -773,22 +581,19 @@ sub HMCCUDEV_Get ($@)
my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash); my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash);
# Virtual devices only support command get update
return "HMCCUDEV: Unknown argument $opt, choose one of update:noArg"
if ($ccuif eq 'fhem' && $opt ne 'update');
my $result = ''; my $result = '';
my $rc; my $rc;
# Virtual devices only support command get update
if ($ccuif eq 'fhem' && $opt ne 'update') {
return "HMCCUDEV: Unknown argument $opt, choose one of update:noArg";
}
# Log commands # Log commands
HMCCU_Log ($hash, 3, "get $name $opt ".join (' ', @$a)) HMCCU_Log ($hash, 3, "get $name $opt ".join (' ', @$a))
if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($hmccu_name, 'logCommand')); if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($ioName, 'logCommand'));
if ($opt eq 'datapoint') { if ($opt eq 'datapoint') {
my $objname = shift @$a; my $objname = shift @$a // return HMCCU_SetError ($hash, "Usage: get $name datapoint [{channel-number}.]{datapoint}");
return HMCCU_SetError ($hash, "Usage: get $name datapoint [{channel-number}.]{datapoint}")
if (!defined ($objname));
if ($objname =~ /^([0-9]+)\..+$/) { if ($objname =~ /^([0-9]+)\..+$/) {
my $chn = $1; my $chn = $1;
@ -809,35 +614,8 @@ sub HMCCUDEV_Get ($@)
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error"); HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $result; return $result;
} }
# elsif ($opt eq 'update') {
# my $ccuget = shift @$a;
# $ccuget = 'Attr' if (!defined ($ccuget));
# if ($ccuget !~ /^(Attr|State|Value)$/) {
# return HMCCU_SetError ($hash, "Usage: get $name update [{'State'|'Value'}]");
# }
#
# if ($hash->{ccuif} ne 'fhem') {
# $rc = HMCCU_GetUpdate ($hash, $ccuaddr, $ccuget);
# return HMCCU_SetError ($hash, $rc) if ($rc < 0);
# }
# else {
# # Update all devices belonging to group
# my @vdevs = split (",", $hash->{ccugroup});
# foreach my $vd (@vdevs) {
# $rc = HMCCU_GetUpdate ($hash, $vd, $ccuget);
# return HMCCU_SetError ($hash, $rc) if ($rc < 0);
# }
# }
#
# return undef;
# }
elsif ($opt eq 'deviceinfo') { elsif ($opt eq 'deviceinfo') {
my $ccuget = shift @$a; $result = HMCCU_GetDeviceInfo ($hash, $ccuaddr);
$ccuget = 'Attr' if (!defined ($ccuget));
if ($ccuget !~ /^(Attr|State|Value)$/) {
return HMCCU_SetError ($hash, "Usage: get $name deviceinfo [{'State'|'Value'}]");
}
$result = HMCCU_GetDeviceInfo ($hash, $ccuaddr, $ccuget);
return HMCCU_SetError ($hash, -2) if ($result eq ''); return HMCCU_SetError ($hash, -2) if ($result eq '');
my $devInfo = HMCCU_FormatDeviceInfo ($result); my $devInfo = HMCCU_FormatDeviceInfo ($result);
$devInfo .= "StateDatapoint = $sc.$sd\nControlDatapoint = $cc.$cd"; $devInfo .= "StateDatapoint = $sc.$sd\nControlDatapoint = $cc.$cd";
@ -874,9 +652,12 @@ sub HMCCUDEV_Get ($@)
} }
} }
else { else {
# The following request could fail if device description or parameter set
# description is not correct.
($rc, $result) = HMCCU_RPCRequest ($hash, 'getRawParamset', $a, $ps, undef); ($rc, $result) = HMCCU_RPCRequest ($hash, 'getRawParamset', $a, $ps, undef);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0); if ($rc >= 0) {
foreach my $p (keys %$result) { $objects{$da}{$dc}{$ps}{$p} = $result->{$p}; } foreach my $p (keys %$result) { $objects{$da}{$dc}{$ps}{$p} = $result->{$p}; }
}
} }
} }
} }
@ -889,10 +670,10 @@ sub HMCCUDEV_Get ($@)
$res .= "Device $da\n"; $res .= "Device $da\n";
foreach my $dc (sort keys %{$convRes->{$da}}) { foreach my $dc (sort keys %{$convRes->{$da}}) {
foreach my $ps (sort keys %{$convRes->{$da}{$dc}}) { foreach my $ps (sort keys %{$convRes->{$da}{$dc}}) {
$res .= " Channel $dc [$ps]\n"; $res .= " Channel $dc [$ps]\n".
$res .= join ("\n", map { join ("\n", map {
" ".$_.' = '.$convRes->{$da}{$dc}{$ps}{$_} " ".$_.' = '.$convRes->{$da}{$dc}{$ps}{$_}
} sort keys %{$convRes->{$da}{$dc}{$ps}})."\n"; } sort keys %{$convRes->{$da}{$dc}{$ps}})."\n";
} }
} }
} }
@ -913,6 +694,10 @@ sub HMCCUDEV_Get ($@)
$result = HMCCU_GetDefaults ($hash, 0); $result = HMCCU_GetDefaults ($hash, 0);
return $result; return $result;
} }
elsif ($opt eq 'weekprogram') {
my $program = shift @$a;
return HMCCU_DisplayWeekProgram ($hash, $program);
}
else { else {
my $retmsg = "HMCCUDEV: Unknown argument $opt, choose one of datapoint"; my $retmsg = "HMCCUDEV: Unknown argument $opt, choose one of datapoint";
@ -921,12 +706,13 @@ sub HMCCUDEV_Get ($@)
$retmsg .= ':'.join(",", @valuelist) if ($valuecount > 0); $retmsg .= ':'.join(",", @valuelist) if ($valuecount > 0);
$retmsg .= ' defaults:noArg update:noArg config'. $retmsg .= ' defaults:noArg update:noArg config'.
' paramsetDesc:noArg deviceDesc:noArg deviceInfo:noArg values:noArg'; ' paramsetDesc:noArg deviceDesc:noArg deviceInfo:noArg values:noArg';
$retmsg .= ' weekProgram:all,'.join(',', sort keys %{$hash->{hmccu}{tt}})
if (exists($hash->{hmccu}{tt}));
return $retmsg; return $retmsg;
} }
} }
1; 1;
=pod =pod
@ -1002,9 +788,12 @@ sub HMCCUDEV_Get ($@)
<code>set temp_control datapoint 2.SET_TEMPERATURE 21</code><br/> <code>set temp_control datapoint 2.SET_TEMPERATURE 21</code><br/>
<code>set temp_control datapoint 2.AUTO_MODE 1 2.SET_TEMPERATURE 21</code> <code>set temp_control datapoint 2.AUTO_MODE 1 2.SET_TEMPERATURE 21</code>
</li><br/> </li><br/>
<li><b>set &lt;name&gt; defaults</b><br/> <li><b>set &lt;name&gt; defaults ['reset'|'<u>update</u>']</b><br/>
Set default attributes for CCU device type. Default attributes are only available for Set default attributes for CCU device type. Default attributes are only available for
some device types. some device types and for some channels of a device type. If option 'reset' is specified,
the following attributes are deleted before the new attributes are set:
'ccureadingname', 'ccuscaleval', 'eventMap', 'substexcl', 'webCmd', 'widgetOverride'.
During update to version 4.4 it's recommended to use option 'reset'.
</li><br/> </li><br/>
<li><b>set &lt;name&gt; down [&lt;value&gt;]</b><br/> <li><b>set &lt;name&gt; down [&lt;value&gt;]</b><br/>
<a href="#HMCCUCHNset">see HMCCUCHN</a> <a href="#HMCCUCHNset">see HMCCUCHN</a>
@ -1018,13 +807,6 @@ sub HMCCUDEV_Get ($@)
<li><b>set &lt;name&gt; pct &lt;value;&gt; [&lt;ontime&gt; [&lt;ramptime&gt;]]</b><br/> <li><b>set &lt;name&gt; pct &lt;value;&gt; [&lt;ontime&gt; [&lt;ramptime&gt;]]</b><br/>
<a href="#HMCCUCHNset">see HMCCUCHN</a> <a href="#HMCCUCHNset">see HMCCUCHN</a>
</li><br/> </li><br/>
<li><b>set &lt;name&gt; rpcparameter [&lt;channel&gt;] { VALUES | MASTER | LINK } &lt;parameter&gt;=&lt;value&gt; [...]</b><br/>
Set multiple datapoints or config parameters by using RPC interface instead of ReGa.
Supports attribute 'ccuscaleval' for datapoints. Methods VALUES (setting datapoints)
and LINK require a channel number. For method MASTER (setting parameters) a channel number
is optional (setting device parameters). Parameter <i>parameter</i> must be a valid
datapoint or config parameter name.
</li><br/>
<li><b>set &lt;name&gt; &lt;statevalue&gt;</b><br/> <li><b>set &lt;name&gt; &lt;statevalue&gt;</b><br/>
State datapoint of a CCU device channel is set to 'statevalue'. State channel and state State datapoint of a CCU device channel is set to 'statevalue'. State channel and state
datapoint must be defined as attribute 'statedatapoint'. Values for <i>statevalue</i> datapoint must be defined as attribute 'statedatapoint'. Values for <i>statevalue</i>
@ -1105,6 +887,9 @@ sub HMCCUDEV_Get ($@)
<li><b>get &lt;name&gt; update [{State | <u>Value</u>}]</b><br/> <li><b>get &lt;name&gt; update [{State | <u>Value</u>}]</b><br/>
<a href="#HMCCUCHNget">see HMCCUCHN</a> <a href="#HMCCUCHNget">see HMCCUCHN</a>
</li><br/> </li><br/>
<li><b>get &lt;name&gt; weekProgram [&lt;program-number&gt;|<u>all</u>]</b><br/>
Display week programs. This command is only available if a device supports week programs.
</li>
</ul> </ul>
<br/> <br/>

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
# #
# $Id: HMCCUConf.pm 18552 2019-02-10 11:52:28Z zap $ # $Id: HMCCUConf.pm 18552 2019-02-10 11:52:28Z zap $
# #
# Version 4.8 # Version 4.8.002
# #
# Configuration parameters for HomeMatic devices. # Configuration parameters for HomeMatic devices.
# #
@ -100,7 +100,7 @@ use vars qw(%HMCCU_SCRIPTS);
# Command-Defintion: # Command-Defintion:
# Command => 'Datapoint-Definition [...]' # Command => 'Datapoint-Definition [...]'
# Datapoint-Definition: # Datapoint-Definition:
# Paramset:Datapoint:FixedValue[,FixedValue] # Paramset:Datapoint:[Parameter=]FixedValue[,FixedValue]
# Paramset:Datapoint:?Parameter # Paramset:Datapoint:?Parameter
# Paramset:Datapoint:?Parameter=Default-Value # Paramset:Datapoint:?Parameter=Default-Value
# Paramset:Datapoint:#Parameter # Paramset:Datapoint:#Parameter
@ -115,21 +115,21 @@ use vars qw(%HMCCU_SCRIPTS);
%HMCCU_ROLECMDS = ( %HMCCU_ROLECMDS = (
'MOTIONDETECTOR_TRANSCEIVER' => { 'MOTIONDETECTOR_TRANSCEIVER' => {
'on' => 'V:MOTION_DETECTION_ACTIVE:true', 'on' => 'V:MOTION_DETECTION_ACTIVE:active=true',
'off' => 'V:MOTION_DETECTION_ACTIVE:false' 'off' => 'V:MOTION_DETECTION_ACTIVE:active=false'
}, },
'SMOKE_DETECTOR' => { 'SMOKE_DETECTOR' => {
'command' => 'V:SMOKE_DETECTOR_COMMAND:#command' 'command' => 'V:SMOKE_DETECTOR_COMMAND:#command'
}, },
'KEY' => { 'KEY' => {
'on' => 'V:PRESS_SHORT:true', 'on' => 'V:PRESS_SHORT:1',
'off' => 'V:PRESS_SHORT:true', 'off' => 'V:PRESS_SHORT:1',
'press' => 'V:PRESS_SHORT:true' 'press' => 'V:PRESS_SHORT:1'
}, },
'KEY_TRANSCEIVER' => { 'KEY_TRANSCEIVER' => {
'on' => 'V:PRESS_SHORT:true', 'on' => 'V:PRESS_SHORT:1',
'off' => 'V:PRESS_SHORT:true', 'off' => 'V:PRESS_SHORT:1',
'press' => 'V:PRESS_SHORT:true' 'press' => 'V:PRESS_SHORT:1'
}, },
'BLIND' => { 'BLIND' => {
'pct' => 'V:LEVEL:?level', 'pct' => 'V:LEVEL:?level',
@ -137,7 +137,7 @@ use vars qw(%HMCCU_SCRIPTS);
'close' => 'V:LEVEL:0', 'close' => 'V:LEVEL:0',
'up' => 'V:LEVEL:?delta=+10', 'up' => 'V:LEVEL:?delta=+10',
'down' => 'V:LEVEL:?delta=-10', 'down' => 'V:LEVEL:?delta=-10',
'stop' => 'V:STOP:true' 'stop' => 'V:STOP:1'
}, },
'BLIND_VIRTUAL_RECEIVER' => { 'BLIND_VIRTUAL_RECEIVER' => {
'pct' => 'V:LEVEL:?level', 'pct' => 'V:LEVEL:?level',
@ -145,7 +145,7 @@ use vars qw(%HMCCU_SCRIPTS);
'close' => 'V:LEVEL:0', 'close' => 'V:LEVEL:0',
'up' => 'V:LEVEL:?delta=+10', 'up' => 'V:LEVEL:?delta=+10',
'down' => 'V:LEVEL:?delta=-10', 'down' => 'V:LEVEL:?delta=-10',
'stop' => 'V:STOP:true' 'stop' => 'V:STOP:1'
}, },
'SHUTTER_VIRTUAL_RECEIVER' => { 'SHUTTER_VIRTUAL_RECEIVER' => {
'pct' => 'V:LEVEL:?level', 'pct' => 'V:LEVEL:?level',
@ -153,30 +153,34 @@ use vars qw(%HMCCU_SCRIPTS);
'close' => 'V:LEVEL:0', 'close' => 'V:LEVEL:0',
'up' => 'V:LEVEL:?delta=+10', 'up' => 'V:LEVEL:?delta=+10',
'down' => 'V:LEVEL:?delta=-10', 'down' => 'V:LEVEL:?delta=-10',
'stop' => 'V:STOP:true' 'stop' => 'V:STOP:1'
}, },
'SWITCH' => { 'SWITCH' => {
'on' => 'V:STATE:true', 'on' => 'V:STATE:1',
'off' => 'V:STATE:false' 'off' => 'V:STATE:0',
'on-for-timer' => 'V:ON_TIME:?duration V:STATE:1',
'on-till' => 'V:ON_TIME:?duration V:STATE:1'
}, },
'SWITCH_VIRTUAL_RECEIVER' => { 'SWITCH_VIRTUAL_RECEIVER' => {
'on' => 'V:STATE:true', 'on' => 'V:STATE:1',
'off' => 'V:STATE:false' 'off' => 'V:STATE:0',
'on-for-timer' => 'V:ON_TIME:?duration V:STATE:1',
'on-till' => 'V:ON_TIME:?duration V:STATE:1'
}, },
'DIMMER' => { 'DIMMER' => {
'pct' => 'V:LEVEL:?level', 'pct' => 'V:LEVEL:?level V:ON_TIME:?time=0.0 V:RAMP_TIME:?ramp=0.5',
'on' => 'V:LEVEL:100', 'on' => 'V:LEVEL:100',
'off' => 'V:LEVEL:0', 'off' => 'V:LEVEL:0',
'stop' => 'V:RAMP_STOP:true' 'stop' => 'V:RAMP_STOP:1'
}, },
'DIMMER_VIRTUAL_RECEIVER' => { 'DIMMER_VIRTUAL_RECEIVER' => {
'pct' => 'V:LEVEL:?level', 'pct' => 'V:LEVEL:?level V:ON_TIME:?time V:RAMP_TIME:?ramp',
'on' => 'V:LEVEL:100', 'on' => 'V:LEVEL:100',
'off' => 'V:LEVEL:0' 'off' => 'V:LEVEL:0'
}, },
'THERMALCONTROL_TRANSMIT' => { 'THERMALCONTROL_TRANSMIT' => {
'desired-temp' => 'V:SET_TEMPERATURE:?temperature', 'desired-temp' => 'V:SET_TEMPERATURE:?temperature',
'manu' => 'V:MANU_MODE:?temperature', 'manu' => 'V:MANU_MODE:?temperature=20',
'on' => 'V:MANU_MODE:30.5', 'on' => 'V:MANU_MODE:30.5',
'off' => 'V:MANU_MODE:4.5', 'off' => 'V:MANU_MODE:4.5',
'auto' => 'V:AUTO_MODE:1', 'auto' => 'V:AUTO_MODE:1',
@ -185,7 +189,7 @@ use vars qw(%HMCCU_SCRIPTS);
}, },
'CLIMATECONTROL_RT_TRANSCEIVER' => { 'CLIMATECONTROL_RT_TRANSCEIVER' => {
'desired-temp' => 'V:SET_TEMPERATURE:?temperature', 'desired-temp' => 'V:SET_TEMPERATURE:?temperature',
'manu' => 'V:MANU_MODE:?temperature', 'manu' => 'V:MANU_MODE:?temperature=20',
'on' => 'V:MANU_MODE:30.5', 'on' => 'V:MANU_MODE:30.5',
'off' => 'V:MANU_MODE:4.5', 'off' => 'V:MANU_MODE:4.5',
'auto' => 'V:AUTO_MODE:1', 'auto' => 'V:AUTO_MODE:1',
@ -196,7 +200,7 @@ use vars qw(%HMCCU_SCRIPTS);
'auto' => 'V:CONTROL_MODE:0', 'auto' => 'V:CONTROL_MODE:0',
'manu' => 'V:CONTROL_MODE:1', 'manu' => 'V:CONTROL_MODE:1',
'holiday' => 'V:CONTROL_MODE:2', 'holiday' => 'V:CONTROL_MODE:2',
'boost' => 'V:BOOST_MODE:true', 'boost' => 'V:BOOST_MODE:1',
'on' => 'V:CONTROL_MODE:1 V:SET_POINT_TEMPERATURE:30.5', 'on' => 'V:CONTROL_MODE:1 V:SET_POINT_TEMPERATURE:30.5',
'off' => 'V:CONTROL_MODE:1 V:SET_POINT_TEMPERATURE:4.5' 'off' => 'V:CONTROL_MODE:1 V:SET_POINT_TEMPERATURE:4.5'
} }
@ -243,12 +247,12 @@ use vars qw(%HMCCU_SCRIPTS);
}, },
'CLIMATECONTROL_RT_TRANSCEIVER' => { 'CLIMATECONTROL_RT_TRANSCEIVER' => {
'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus', 'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus',
'webCmd' => 'desired-temp', 'webCmd' => 'desired-temp:auto:manu:boost:on:off',
'widgetOverride' => 'desired-temp:slider,4.5,0.5,30.5,1' 'widgetOverride' => 'desired-temp:slider,4.5,0.5,30.5,1'
}, },
'HEATING_CLIMATECONTROL_TRANSCEIVER' => { 'HEATING_CLIMATECONTROL_TRANSCEIVER' => {
'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus', 'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus',
'webCmd' => 'desired-temp:auto:manu:boost', 'webCmd' => 'desired-temp:auto:manu:boost:on:off',
'widgetOverride' => 'desired-temp:slider,4.5,0.5,30.5,1' 'widgetOverride' => 'desired-temp:slider,4.5,0.5,30.5,1'
} }
); );