2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-03 16:56:54 +00:00

HMCCU: Added Homematic IP Support

git-svn-id: https://svn.fhem.de/fhem/trunk@11075 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
fhemzap 2016-03-16 17:57:58 +00:00
parent a71fc29e6e
commit 7ce0e2c84f
4 changed files with 837 additions and 284 deletions

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
#
# $Id:$
#
# Version 2.7
# Version 3.0
#
# (c) 2016 zap (zap01 <at> t-online <dot> de)
#
@ -31,6 +31,7 @@
# attr <name> ccureadingformat { name | address | datapoint }
# attr <name> ccuverify { 0 | 1 }
# attr <name> controldatapoint <datapoint>
# attr <name> disable { 0 | 1 }
# attr <name> statevals <text1>:<subtext1>[,...]
# attr <name> substitute <subst-rule>[;...]
#
@ -65,7 +66,7 @@ sub HMCCUCHN_Initialize ($)
$hash->{GetFn} = "HMCCUCHN_Get";
$hash->{AttrFn} = "HMCCUCHN_Attr";
$hash->{AttrList} = "IODev ccureadingfilter ccureadingformat:name,address,datapoint ccureadings:0,1 ccuverify:0,1 ccuget:State,Value controldatapoint statedatapoint statevals substitute stripnumber:0,1,2 ". $readingFnAttributes;
$hash->{AttrList} = "IODev ccureadingfilter ccureadingformat:name,address,datapoint ccureadings:0,1 ccuverify:0,1 ccuget:State,Value controldatapoint disable:0,1 statedatapoint statevals substitute stripnumber:0,1,2 ". $readingFnAttributes;
}
#####################################
@ -86,14 +87,14 @@ sub HMCCUCHN_Define ($@)
return "Invalid or unknown CCU channel name or address" if (! HMCCU_IsValidDevice ($devspec));
if ($devspec =~ /^(.+)\.([A-Z]{3,3}[0-9]{7,7}:[0-9]+)$/) {
if (HMCCU_IsChnAddr ($devspec, 1)) {
# CCU Channel address with interface
$hash->{ccuif} = $1;
$hash->{ccuaddr} = $2;
$hash->{ccuname} = HMCCU_GetChannelName ($hash->{ccuaddr}, '');
return "CCU device name not found for channel address $devspec" if ($hash->{ccuname} eq '');
}
elsif ($devspec =~ /^[A-Z]{3,3}[0-9]{7,7}:[0-9]+$/) {
elsif (HMCCU_IsChnAddr ($devspec, 0)) {
# CCU Channel address
$hash->{ccuaddr} = $devspec;
$hash->{ccuif} = HMCCU_GetDeviceInterface ($hash->{ccuaddr}, 'BidCos-RF');
@ -101,7 +102,7 @@ sub HMCCUCHN_Define ($@)
return "CCU device name not found for channel address $devspec" if ($hash->{ccuname} eq '');
}
else {
# CCU Device name
# CCU Channel name
$hash->{ccuname} = $devspec;
my ($add, $chn) = HMCCU_GetAddress ($devspec, '', '');
return "Channel address not found for channel name $devspec" if ($add eq '' || $chn eq '');
@ -171,15 +172,13 @@ sub HMCCUCHN_Set ($@)
my $name = shift @a;
my $opt = shift @a;
if (!defined ($hash->{IODev})) {
return HMCCUCHN_SetError ($hash, "No IO device defined");
}
if ($hash->{statevals} eq 'readonly' && $opt ne 'config') {
return undef;
}
return HMCCU_SetError ($hash, -3) if (!defined ($hash->{IODev}));
return undef if ($hash->{statevals} eq 'readonly' && $opt ne 'config');
my $disable = AttrVal ($name, "disable", 0);
return undef if ($disable == 1);
my $hmccu_hash = $hash->{IODev};
if (HMCCU_IsRPCStateBlocking ($hmccu_hash)) {
return undef if ($opt eq '?');
return "HMCCUCHN: CCU busy";
@ -197,32 +196,33 @@ sub HMCCUCHN_Set ($@)
my $objname = shift @a;
my $objvalue = join ('%20', @a);
if (!defined ($objname) || !defined ($objvalue)) {
return HMCCUCHN_SetError ($hash, "Usage: set <name> datapoint <datapoint> <value> [...]");
}
return HMCCU_SetError ($hash, "Usage: set $name datapoint {datapoint} {value} [...]")
if (!defined ($objname) || !defined ($objvalue));
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $hash->{ccutype},
$hash->{ccuaddr}, $objname, 2));
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, '');
# Build datapoint address
$objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.'.'.$objname;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
if ($ccuverify) {
usleep (100000);
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
}
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'control') {
return HMCCUCHN_SetError ($hash, "Attribute control datapoint not set") if ($controldatapoint eq '');
return HMCCU_SetError ($hash, "Attribute controldatapoint not set") if ($controldatapoint eq '');
my $objvalue = shift @a;
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$controldatapoint;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
@ -230,27 +230,26 @@ sub HMCCUCHN_Set ($@)
my $cmd = $1;
my $objvalue = ($cmd ne 'devstate') ? $cmd : join ('%20', @a);
if (!defined ($objvalue)) {
return HMCCUCHN_SetError ($hash, "Usage: set <device> devstate <value>");
}
return HMCCU_SetError ($hash, "Usage: set $name devstate {value}") if (!defined ($objvalue));
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, '');
# Build datapoint address
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.'.'.$statedatapoint;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
if ($ccuverify) {
usleep (100000);
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
}
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'toggle') {
return HMCCUCHN_SetError ($hash, "Attribute statevals not set")
elsif ($opt eq 'toggle') {
return HMCCU_SetError ($hash, "Attribute statevals not set")
if ($statevals eq '' || !exists($hash->{statevals}));
my $tstates = $hash->{statevals};
@ -260,7 +259,7 @@ sub HMCCUCHN_Set ($@)
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.'.'.$statedatapoint;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
my $objvalue = '';
my $st = 0;
@ -274,22 +273,22 @@ sub HMCCUCHN_Set ($@)
}
}
return HMCCUCHN_SetError ($hash, "Current device state doesn't match statevals")
return HMCCU_SetError ($hash, "Current device state doesn't match statevals")
if ($objvalue eq '');
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, '');
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'config') {
return HMCCUCHN_SetError ($hash, "Usage: set $name config {parameter}={value} [...]") if (@a < 1);;
return HMCCU_SetError ($hash, "Usage: set $name config {parameter}={value} [...]") if (@a < 1);;
my $rc = HMCCU_RPCSetConfig ($hash, $hash->{ccuaddr}, \@a);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return undef;
my $rc = HMCCU_RPCSetConfig ($hash, $hash->{ccuaddr}, \@a);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
else {
my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of config datapoint devstate";
@ -319,12 +318,12 @@ sub HMCCUCHN_Get ($@)
my $name = shift @a;
my $opt = shift @a;
if (!defined ($hash->{IODev})) {
return HMCCUCHN_SetError ($hash, "No IO device defined");
}
return HMCCU_SetError ($hash, -3) if (!defined ($hash->{IODev}));
my $disable = AttrVal ($name, "disable", 0);
return undef if ($disable == 1);
my $hmccu_hash = $hash->{IODev};
if (HMCCU_IsRPCStateBlocking ($hmccu_hash)) {
return undef if ($opt eq '?');
return "HMCCUCHN: CCU busy";
@ -339,16 +338,18 @@ sub HMCCUCHN_Get ($@)
if ($opt eq 'devstate') {
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.'.'.$statedatapoint;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return $ccureadings ? undef : $result;
}
elsif ($opt eq 'datapoint') {
my $objname = shift @a;
return HMCCUCHN_SetError ($hash, "Usage: get <name> datapoint <datapoint>") if (!defined ($objname));
return HMCCU_SetError ($hash, "Usage: get $name datapoint {datapoint}") if (!defined ($objname));
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $hash->{ccutype},
$hash->{ccuaddr}, $objname, 1));
$objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.'.'.$objname;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return $ccureadings ? undef : $result;
}
elsif ($opt eq 'channel') {
@ -357,17 +358,17 @@ sub HMCCUCHN_Get ($@)
$objname .= '.'.$dptexpr if (defined ($dptexpr));
my @chnlist = ($objname);
($rc, $result) = HMCCU_GetChannel ($hash, \@chnlist);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return $ccureadings ? undef : $result;
}
elsif ($opt eq 'update') {
my $ccuget = shift @a;
$ccuget = 'Attr' if (!defined ($ccuget));
if ($ccuget !~ /^(Attr|State|Value)$/) {
return HMCCUCHN_SetError ($hash, "Usage: get $name update [{'State'|'Value'}]");
return HMCCU_SetError ($hash, "Usage: get $name update [{'State'|'Value'}]");
}
$rc = HMCCU_GetUpdate ($hash, $hash->{ccuaddr}, $ccuget);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return undef;
}
elsif ($opt eq 'config') {
@ -376,7 +377,7 @@ sub HMCCUCHN_Get ($@)
$port = 2001 if (!defined ($port));
my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset", $port);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return $ccureadings ? undef : $res;
}
elsif ($opt eq 'configdesc') {
@ -385,11 +386,19 @@ sub HMCCUCHN_Get ($@)
$port = 2001 if (!defined ($port));
my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription", $port);
return HMCCUCHN_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return $res;
}
else {
return "HMCCUCHN: Unknown argument $opt, choose one of devstate:noArg datapoint channel update:noArg config:noArg configdesc:noArg";
my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of devstate:noArg datapoint";
my ($a, $c) = split(":", $hash->{ccuaddr});
my @valuelist;
my $valuecount = HMCCU_GetValidDatapoints ($hash, $hash->{ccutype}, $c, 1, \@valuelist);
$retmsg .= ":".join(",",@valuelist) if ($valuecount > 0);
$retmsg .= " channel update:noArg config:noArg configdesc:noArg";
return $retmsg;
}
}
@ -403,12 +412,12 @@ sub HMCCUCHN_SetError ($$)
my $name = $hash->{NAME};
my $msg;
my %errlist = (
-1 => 'Channel name or address invalid',
-2 => 'Execution of CCU script failed',
-3 => 'Cannot detect IO device',
-4 => 'Device deleted in CCU',
-5 => 'No response from CCU',
-6 => 'Update of readings disabled. Set attribute ccureadings first'
-1 => 'Channel name or address invalid',
-2 => 'Execution of CCU script failed',
-3 => 'Cannot detect IO device',
-4 => 'Device deleted in CCU',
-5 => 'No response from CCU',
-6 => 'Update of readings disabled. Set attribute ccureadings first'
);
if (exists ($errlist{$text})) {
@ -492,22 +501,18 @@ sub HMCCUCHN_SetError ($$)
<b>Get</b><br/>
<ul>
<br/>
<li>get &lt;name&gt; devstate
<br/>
<li>get &lt;name&gt; devstate<br/>
Get state of CCU device. Default datapoint STATE can be changed by setting
attribute 'statedatapoint'.
</li><br/>
<li>get &lt;name&gt; datapoint &lt;datapoint&gt;
<br/>
<li>get &lt;name&gt; datapoint &lt;datapoint&gt;<br/>
Get value of a CCU device datapoint.
</li><br/>
<li>get &lt;name&gt; config [&lt;rpcport&gt;]
<br/>
<li>get &lt;name&gt; config [&lt;rpcport&gt;]<br/>
Get configuration parameters of CCU channel. If attribute ccureadings is 0 results will be
displayed in browser window.
</li><br/>
<li>get &lt;name&gt; configdesc [&lt;rpcport&gt;]
<br/>
<li>get &lt;name&gt; configdesc [&lt;rpcport&gt;]<br/>
Get description of configuration parameters of CCU channel.
</li><br/>
<li>get &lt;name&gt; update [{'State'|'Value'}]<br/>
@ -544,6 +549,9 @@ sub HMCCUCHN_SetError ($$)
attr mydev webCmd control
attr mydev widgetOverride control:slider,10,1,25
</li><br/>
<li>disable &lt;0 | 1&gt;<br/>
Disable client device.
</li><br/>
<li>statedatapoint &lt;datapoint&gt;<br/>
Set datapoint for devstate commands.
</li><br/>

View File

@ -4,7 +4,7 @@
#
# $Id:$
#
# Version 2.8
# Version 3.0
#
# (c) 2016 zap (zap01 <at> t-online <dot> de)
#
@ -13,12 +13,13 @@
# define <name> HMCCUDEV {<ccudev>|virtual} [statechannel] [readonly]
# [{group={<device>|<channel>}[,...]|groupexp=<regexp>}]
#
# set <name> config [<channel>] [<port>] <parameter>=<value> [...]
# set <name> control <value>
# set <name> datapoint <channel>.<datapoint> <value>
# set <name> devstate <value>
# set <name> on-for-timer <seconds>
# set <name> <stateval_cmds>
# set <name> toggle
# set <name> config [<channel>] [<port>] <parameter>=<value> [...]
#
# get <name> devstate
# get <name> datapoint <channel>.<datapoint>
@ -33,6 +34,7 @@
# attr <name> ccureadingfilter <filter-rule>[,...]
# attr <name> ccuverify { 0 | 1 }
# attr <name> controldatapoint <channel>.<datapoint>
# attr <name> disable { 0 | 1 }
# attr <name> mapdatapoints <channel>.<datapoint>=<channel>.<datapoint>[,...]
# attr <name> statechannel <channel>
# attr <name> statedatapoint <datapoint>
@ -71,7 +73,7 @@ sub HMCCUDEV_Initialize ($)
$hash->{GetFn} = "HMCCUDEV_Get";
$hash->{AttrFn} = "HMCCUDEV_Attr";
$hash->{AttrList} = "IODev ccureadingfilter:textField-long ccureadingformat:name,address ccureadings:0,1 ccuget:State,Value ccuverify:0,1 mapdatapoints:textField-long statevals substitute statechannel statedatapoint controldatapoint stripnumber:0,1,2 ". $readingFnAttributes;
$hash->{AttrList} = "IODev ccureadingfilter:textField-long ccureadingformat:name,address ccureadings:0,1 ccuget:State,Value ccuverify:0,1 disable:0,1 mapdatapoints:textField-long statevals substitute statechannel statedatapoint controldatapoint stripnumber:0,1,2 ". $readingFnAttributes;
}
#####################################
@ -263,14 +265,14 @@ sub HMCCUDEV_Set ($@)
my $name = shift @a;
my $opt = shift @a;
if (!exists ($hash->{IODev})) {
return HMCCUDEV_SetError ($hash, "No IO device defined");
}
return HMCCU_SetError ($hash, -3) if (!exists ($hash->{IODev}));
return undef if ($hash->{statevals} eq 'readonly');
my $disable = AttrVal ($name, "disable", 0);
return undef if ($disable == 1);
my $hmccu_hash = $hash->{IODev};
my $hmccu_name = $hash->{IODev}->{NAME};
if (HMCCU_IsRPCStateBlocking ($hmccu_hash)) {
return undef if ($opt eq '?');
return "HMCCUDEV: CCU busy";
@ -290,31 +292,35 @@ sub HMCCUDEV_Set ($@)
my $objvalue = join ('%20', @a);
if (!defined ($objname) || $objname !~ /^[0-9]+\..+$/ || !defined ($objvalue)) {
return HMCCUDEV_SetError ($hash, "Usage: set <name> datapoint <channel-number>.<datapoint> <value> [...]");
return HMCCU_SetError ($hash, "Usage: set $name datapoint {channel-number}.{datapoint} {value} [...]");
}
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $hash->{ccutype},
$hash->{ccuaddr}, $objname, 2));
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, '');
# Build datapoint address
$objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$objname;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
if ($ccuverify) {
if ($ccuverify && HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $hash->{ccuaddr},
$objname, 1)) {
usleep (100000);
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
}
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'control') {
return HMCCUDEV_SetError ($hash, "Attribute control datapoint not set") if ($controldatapoint eq '');
return HMCCU_SetError ($hash, "Attribute controldatapoint not set") if ($controldatapoint eq '');
my $objvalue = shift @a;
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$controldatapoint;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
@ -323,8 +329,8 @@ sub HMCCUDEV_Set ($@)
my $cmd = $1;
my $objvalue = ($cmd ne 'devstate') ? $cmd : join ('%20', @a);
return HMCCUDEV_SetError ($hash, "No state channel specified") if ($statechannel eq '');
return HMCCUDEV_SetError ($hash, "Usage: set <name> devstate <value> [...]") if (!defined ($objvalue));
return HMCCU_SetError ($hash, "No state channel specified") if ($statechannel eq '');
return HMCCU_SetError ($hash, "Usage: set $name devstate {value} [...]") if (!defined ($objvalue));
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, '');
@ -332,20 +338,21 @@ sub HMCCUDEV_Set ($@)
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$statechannel.'.'.$statedatapoint;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
if ($ccuverify) {
usleep (100000);
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
}
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'toggle') {
return HMCCUDEV_SetError ($hash, "Attribute statevals not set")
return HMCCU_SetError ($hash, "Attribute statevals not set")
if ($statevals eq '' || !exists($hash->{statevals}));
return HMCCU_SetError ($hash, "No state channel specified") if ($statechannel eq '');
my $tstates = $hash->{statevals};
$tstates =~ s/devstate\|//;
@ -354,7 +361,7 @@ sub HMCCUDEV_Set ($@)
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$statechannel.'.'.$statedatapoint;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
my $objvalue = '';
my $st = 0;
@ -368,23 +375,50 @@ sub HMCCUDEV_Set ($@)
}
}
return HMCCUDEV_SetError ($hash, "Current device state doesn't match statevals")
return HMCCU_SetError ($hash, "Current device state doesn't match statevals")
if ($objvalue eq '');
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, '');
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'on-for-timer') {
return HMCCU_SetError ($hash, "Attribute statevals not set")
if ($statevals eq '' || !exists($hash->{statevals}));
return HMCCU_SetError ($hash, "No state channel specified") if ($statechannel eq '');
return HMCCU_SetError ($hash, "No state value for 'on' defined")
if ("on" !~ /($hash->{statevals})/);
return HMCCU_SetError ($hash, "Parameter ON_TIME not available in channel $statechannel")
if (!HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $statechannel, "ON_TIME", 2));
my $timespec = shift @a;
return HMCCU_SetError ($hash, "Usage: set $name on-timer {seconds}") if (!defined ($timespec));
# Set on time
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$statechannel.'.ON_TIME';
$rc = HMCCU_SetDatapoint ($hash, $objname, $timespec);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
# Set state
$objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$statechannel.'.'.$statedatapoint;
my $objvalue = HMCCU_Substitute ("on", $statevals, 1, '');
$rc = HMCCU_SetDatapoint ($hash, $objname, $timespec);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'config') {
return HMCCUDEV_SetError ($hash, "Usage: set $name config [{channel-number}] {parameter}={value} [...]") if (@a < 1);;
return HMCCU_SetError ($hash, "Usage: set $name config [{channel-number}] {parameter}={value} [...]")
if (@a < 1);
my $objname = $hash->{ccuaddr};
$objname .= ':'.shift @a if ($a[0] =~ /^[0-9]$/);
my $rc = HMCCU_RPCSetConfig ($hash, $objname, \@a);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
@ -403,6 +437,8 @@ sub HMCCUDEV_Set ($@)
$retmsg .= ' '.$sv.':noArg';
}
$retmsg .= " toggle:noArg";
$retmsg .= " on-for-timer" if ($statechannel ne '' &&
HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $statechannel, "ON_TIME", 2));
}
}
@ -420,12 +456,12 @@ sub HMCCUDEV_Get ($@)
my $name = shift @a;
my $opt = shift @a;
if (!defined ($hash->{IODev})) {
return HMCCUDEV_SetError ($hash, "No IO device defined");
}
return HMCCU_SetError ($hash, -3) if (!defined ($hash->{IODev}));
my $disable = AttrVal ($name, "disable", 0);
return undef if ($disable == 1);
my $hmccu_hash = $hash->{IODev};
if (HMCCU_IsRPCStateBlocking ($hmccu_hash)) {
return undef if ($opt eq '?');
return "HMCCUDEV: CCU busy";
@ -443,26 +479,26 @@ sub HMCCUDEV_Get ($@)
}
if ($opt eq 'devstate') {
if ($statechannel eq '') {
return HMCCUDEV_SetError ($hash, "No state channel specified");
}
return HMCCU_SetError ($hash, "No state channel specified") if ($statechannel eq '');
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$statechannel.'.'.$statedatapoint;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return $ccureadings ? undef : $result;
}
elsif ($opt eq 'datapoint') {
my $objname = shift @a;
if (!defined ($objname) || $objname !~ /^[0-9]+\..*$/) {
return HMCCUDEV_SetError ($hash, "Usage: get <name> datapoint <channel-number>.<datapoint>");
return HMCCU_SetError ($hash, "Usage: get $name datapoint {channel-number}.{datapoint}");
}
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $hash->{ccutype},
$hash->{ccuaddr}, $objname, 1));
$objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$objname;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $ccureadings ? undef : $result;
@ -472,10 +508,10 @@ sub HMCCUDEV_Get ($@)
foreach my $objname (@a) {
last if (!defined ($objname));
if ($objname =~ /^([0-9]+)/ && exists ($hash->{channels})) {
return HMCCUDEV_SetError ($hash, "Invalid channel number: $objname") if ($1 >= $hash->{channels});
return HMCCU_SetError ($hash, -7) if ($1 >= $hash->{channels});
}
else {
return HMCCUDEV_SetError ($hash, "Invalid channel number: $objname");
return HMCCU_SetError ($hash, -7);
}
if ($objname =~ /^[0-9]{1,2}.*=/) {
$objname =~ s/=/ /;
@ -483,11 +519,11 @@ sub HMCCUDEV_Get ($@)
push (@chnlist, $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$objname);
}
if (@chnlist == 0) {
return HMCCUDEV_SetError ($hash, "Usage: get $name channel {channel-number}[.{datapoint-expr}] [...]");
return HMCCU_SetError ($hash, "Usage: get $name channel {channel-number}[.{datapoint-expr}] [...]");
}
($rc, $result) = HMCCU_GetChannel ($hash, \@chnlist);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $ccureadings ? undef : $result;
@ -496,12 +532,12 @@ sub HMCCUDEV_Get ($@)
my $ccuget = shift @a;
$ccuget = 'Attr' if (!defined ($ccuget));
if ($ccuget !~ /^(Attr|State|Value)$/) {
return HMCCUDEV_SetError ($hash, "Usage: get $name update [{'State'|'Value'}]");
return HMCCU_SetError ($hash, "Usage: get $name update [{'State'|'Value'}]");
}
if ($hash->{ccuname} ne 'none') {
$rc = HMCCU_GetUpdate ($hash, $hash->{ccuaddr}, $ccuget);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
}
# Update other devices belonging to group
@ -509,7 +545,7 @@ sub HMCCUDEV_Get ($@)
my @vdevs = split (",", $hash->{ccugroup});
foreach my $vd (@vdevs) {
$rc = HMCCU_GetUpdate ($hash, $vd, $ccuget);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
}
}
@ -519,56 +555,67 @@ sub HMCCUDEV_Get ($@)
my $ccuget = shift @a;
$ccuget = 'Attr' if (!defined ($ccuget));
if ($ccuget !~ /^(Attr|State|Value)$/) {
return HMCCUDEV_SetError ($hash, "Usage: get $name deviceinfo [{'State'|'Value'}]");
return HMCCU_SetError ($hash, "Usage: get $name deviceinfo [{'State'|'Value'}]");
}
$result = HMCCU_GetDeviceInfo ($hash, $hash->{ccuaddr}, $ccuget);
return HMCCUDEV_SetError ($hash, -2) if ($result eq '');
return $result;
return HMCCU_SetError ($hash, -2) if ($result eq '');
return HMCCU_FormatDeviceInfo ($result);
}
elsif ($opt eq 'config') {
my $channel = undef;
my $port = undef;
my $par = shift @a;
if ($par =~ /^[0-9]$/) {
$channel = $par;
$port = shift @a;
}
else {
$port = $par;
if (defined ($par)) {
if ($par =~ /^[0-9]$/) {
$channel = $par;
$port = shift @a;
}
else {
$port = $par;
}
}
my $ccuobj = $hash->{ccuaddr};
$ccuobj .= ':'.$channel if (defined ($channel));
$port = 2001 if (!defined ($port));
my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset", $port);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset", $port);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $ccureadings ? undef : $res;
return $ccureadings ? undef : $res;
}
elsif ($opt eq 'configdesc') {
my $channel = undef;
my $port = undef;
my $par = shift @a;
if ($par =~ /^[0-9]$/) {
$channel = $par;
$port = shift @a;
}
else {
$port = $par;
if (defined ($par)) {
if ($par =~ /^[0-9]$/) {
$channel = $par;
$port = shift @a;
}
else {
$port = $par;
}
}
my $ccuobj = $hash->{ccuaddr};
$ccuobj .= ':'.$channel if (defined ($channel));
$port = 2001 if (!defined ($port));
my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription", $port);
return HMCCUDEV_SetError ($hash, $rc) if ($rc < 0);
my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription", $port);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $res;
return $res;
}
else {
my $retmsg = "HMCCUDEV: Unknown argument $opt, choose one of datapoint channel update:noArg config configdesc deviceinfo:noArg";
my $retmsg = "HMCCUDEV: Unknown argument $opt, choose one of datapoint";
my @valuelist;
my $valuecount = HMCCU_GetValidDatapoints ($hash, $hash->{ccutype}, -1, 1, \@valuelist);
$retmsg .= ":".join(",", @valuelist) if ($valuecount > 0);
$retmsg .= " channel update:noArg config configdesc deviceinfo:noArg";
if ($statechannel ne '') {
$retmsg .= ' devstate:noArg';
}
@ -584,22 +631,22 @@ sub HMCCUDEV_SetError ($$)
{
my ($hash, $text) = @_;
my $name = $hash->{NAME};
my $msg;
my %errlist = (
-1 => 'Channel name or address invalid',
-2 => 'Execution of CCU script failed',
-3 => 'Cannot detect IO device',
-4 => 'Device deleted in CCU',
-5 => 'No response from CCU',
-6 => 'Update of readings disabled. Set attribute ccureadings first'
);
my $msg;
my %errlist = (
-1 => 'Channel name or address invalid',
-2 => 'Execution of CCU script failed',
-3 => 'Cannot detect IO device',
-4 => 'Device deleted in CCU',
-5 => 'No response from CCU',
-6 => 'Update of readings disabled. Set attribute ccureadings first'
);
if (exists ($errlist{$text})) {
$msg = $errlist{$text};
}
else {
$msg = $text;
}
if (exists ($errlist{$text})) {
$msg = $errlist{$text};
}
else {
$msg = $text;
}
$msg = "HMCCUDEV: ".$name." ". $msg;
readingsSingleUpdate ($hash, "state", "Error", 1);
@ -645,6 +692,10 @@ sub HMCCUDEV_SetError ($$)
Example:<br/>
<code>set light_entrance devstate on</code>
</li><br/>
<li>set &lt;name&gt; on-for-timer &lt;seconds&gt;<br/>
Switch device on for specified time. Requires that 'statechannel' is set and
contains datapoint ON_TIME. In addition 'statevals' must contain value 'on'.
</li><br/>
<li>set &lt;name&gt; &lt;statevalue&gt; <br/>
State of a CCU device channel is set to 'statevalue'. Channel must
be defined as attribute 'statechannel'. Default datapoint STATE can be
@ -734,6 +785,9 @@ sub HMCCUDEV_SetError ($$)
attr mydev webCmd control
attr mydev widgetOverride control:slider,10,1,25
</li><br/>
<li>disable &lt;0 | 1&gt;<br/>
Disable client device.
</li><br/>
<li>mapdatapoints &lt;channel.datapoint&gt;=&lt;channel.datapoint&gt;[,...]
Map channel to other channel in virtual devices (groups). Readings will be duplicated.
</li><br/>

View File

@ -5,7 +5,7 @@
#
# $Id:
#
# Version 1.9
# Version 2.0
#
# FHEM RPC server for Homematic CCU.
#
@ -24,8 +24,10 @@
# New device: ND|Address|Type
# Updated device: UD|Address|Hint
# Deleted device: DD|Address
# Replace device: RD|Address1|Address2
# Readd device: RA|Address
# Event: EV|Address|Attribute|Value
# Shutdown: EX|SHUTDOWN|PID
# Shutdown: EX|SHUTDOWN|pid
#########################################################
use strict;
@ -162,7 +164,7 @@ sub CCURPC_Initialize ($$)
return undef;
}
else {
Log "callback server created listening on port $callbackport";
Log "Callback server created listening on port $callbackport";
}
# Callback for events
@ -201,6 +203,24 @@ sub CCURPC_Initialize ($$)
}
);
# Callback for replaced devices
Log "Adding callback for replaced devices";
$server->add_method (
{ name=>"replaceDevice",
signature=>["string string string string"],
code=>\&CCURPC_ReplaceDeviceCB
}
);
# Callback for readded devices
Log "Adding callback for readded devices";
$server->add_method (
{ name=>"replaceDevice",
signature=>["string string array"],
code=>\&CCURPC_ReaddDeviceCB
}
);
# Dummy implementation, always return an empty array
$server->add_method (
{ name=>"listDevices",
@ -260,6 +280,36 @@ sub CCURPC_UpdateDeviceCB ($$$$)
return;
}
#####################################
# Callback for replaced devices
#####################################
sub CCURPC_ReplaceDeviceCB ($$$$)
{
my ($server, $cb, $devid1, $devid2) = @_;
WriteQueue ("RD|".$devid1."|".$devid2);
return;
}
#####################################
# Callback for readded devices
#####################################
sub CCURPC_ReaddDevicesCB ($$$)
{
my ($server, $cb, $a) = @_;
Log "ReaddDevice: received ".scalar(@$a)." device addresses";
for my $dev (@$a) {
WriteQueue ("RA|".$dev);
}
return;
}
#####################################
# Callback for handling CCU events
#####################################