2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-12 16:46:35 +00:00

HMCCU: Deleted old modules from contrib

git-svn-id: https://svn.fhem.de/fhem/trunk@20879 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2020-01-04 15:18:38 +00:00
parent 0025a416b1
commit d32d7fb9d1
10 changed files with 0 additions and 6818 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,571 +0,0 @@
################################################################
#
# 88_HMCCUCHN.pm
#
# $Id:$
#
# Version 3.3
#
# (c) 2016 zap (zap01 <at> t-online <dot> de)
#
################################################################
#
# define <name> HMCCUCHN <ccudev> [readonly]
#
# set <name> control <value>
# set <name> datapoint <datapoint> <value>
# set <name> devstate <value>
# set <name> <stateval_cmds>
# set <name> toggle
# set <name> config <parameter>=<value> [...]
#
# get <name> devstate
# get <name> datapoint <datapoint>
# get <name> channel <datapoint-expr>
# get <name> config
# get <name> configdesc
# get <name> update
#
# attr <name> ccureadings { 0 | 1 }
# attr <name> ccureadingfilter <datapoint-expr>
# attr <name> ccureadingformat { name | address | datapoint }
# attr <name> ccuverify { 0 | 1 | 2 }
# attr <name> controldatapoint <datapoint>
# attr <name> disable { 0 | 1 }
# attr <name> statedatapoint <datapoint>
# attr <name> statevals <text1>:<subtext1>[,...]
# attr <name> substitute <subst-rule>[;...]
#
################################################################
# Requires module 88_HMCCU.pm
################################################################
package main;
use strict;
use warnings;
use SetExtensions;
use Time::HiRes qw( gettimeofday usleep );
sub HMCCUCHN_Define ($@);
sub HMCCUCHN_Set ($@);
sub HMCCUCHN_Get ($@);
sub HMCCUCHN_Attr ($@);
sub HMCCUCHN_SetError ($$);
#####################################
# Initialize module
#####################################
sub HMCCUCHN_Initialize ($)
{
my ($hash) = @_;
$hash->{DefFn} = "HMCCUCHN_Define";
$hash->{SetFn} = "HMCCUCHN_Set";
$hash->{GetFn} = "HMCCUCHN_Get";
$hash->{AttrFn} = "HMCCUCHN_Attr";
$hash->{AttrList} = "IODev ccureadingfilter ccureadingformat:name,address,datapoint ccureadings:0,1 ccuscaleval ccuverify:0,1,2 ccuget:State,Value controldatapoint disable:0,1 statedatapoint statevals substitute stripnumber:0,1,2 ". $readingFnAttributes;
}
#####################################
# Define device
#####################################
sub HMCCUCHN_Define ($@)
{
my ($hash, $def) = @_;
my $name = $hash->{NAME};
my @a = split("[ \t][ \t]*", $def);
return "Specifiy the CCU device name or address as parameters" if (@a < 3);
my $devname = shift @a;
my $devtype = shift @a;
my $devspec = shift @a;
return "Invalid or unknown CCU channel name or address" if (! HMCCU_IsValidDevice ($devspec));
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 (HMCCU_IsChnAddr ($devspec, 0)) {
# CCU Channel address
$hash->{ccuaddr} = $devspec;
$hash->{ccuif} = HMCCU_GetDeviceInterface ($hash->{ccuaddr}, 'BidCos-RF');
$hash->{ccuname} = HMCCU_GetChannelName ($devspec, '');
return "CCU device name not found for channel address $devspec" if ($hash->{ccuname} eq '');
}
else {
# 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 '');
$hash->{ccuaddr} = $add.':'.$chn;
$hash->{ccuif} = HMCCU_GetDeviceInterface ($hash->{ccuaddr}, 'BidCos-RF');
}
$hash->{ccutype} = HMCCU_GetDeviceType ($hash->{ccuaddr}, '');
$hash->{channels} = 1;
$hash->{statevals} = 'devstate';
my $arg = shift @a;
if (defined ($arg) && $arg eq 'readonly') {
$hash->{statevals} = $arg;
}
# Inform HMCCU device about client device
AssignIoPort ($hash);
readingsSingleUpdate ($hash, "state", "Initialized", 1);
$hash->{ccudevstate} = 'Active';
return undef;
}
#####################################
# Set attribute
#####################################
sub HMCCUCHN_Attr ($@)
{
my ($cmd, $name, $attrname, $attrval) = @_;
my $hash = $defs{$name};
if ($cmd eq "set") {
return "Missing attribute value" if (!defined ($attrval));
if ($attrname eq 'IODev') {
$hash->{IODev} = $defs{$attrval};
}
elsif ($attrname eq 'statevals') {
return "Device is read only" if ($hash->{statevals} eq 'readonly');
$hash->{statevals} = "devstate";
my @states = split /,/,$attrval;
foreach my $st (@states) {
my @statesubs = split /:/,$st;
return "value := text:substext[,...]" if (@statesubs != 2);
$hash->{statevals} .= '|'.$statesubs[0];
}
}
}
elsif ($cmd eq "del") {
if ($attrname eq 'statevals') {
$hash->{statevals} = "devstate";
}
}
return undef;
}
#####################################
# Set commands
#####################################
sub HMCCUCHN_Set ($@)
{
my ($hash, @a) = @_;
my $name = shift @a;
my $opt = shift @a;
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";
}
my $statevals = AttrVal ($name, "statevals", '');
# my $statedatapoint = AttrVal ($name, "statedatapoint", 'STATE');
# my $controldatapoint = AttrVal ($name, "controldatapoint", '');
my ($sc, $statedatapoint, $cc, $controldatapoint) = HMCCU_GetSpecialDatapoints (
$hash, '', 'STATE', '', '');
my $result = '';
my $rc;
if ($opt eq 'datapoint') {
my $objname = shift @a;
# my $objvalue = join ('%20', @a);
my $objvalue = shift @a;
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 HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'control') {
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 HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt =~ /^($hash->{statevals})$/) {
my $cmd = $1;
my $objvalue = ($cmd ne 'devstate') ? $cmd : shift @a;
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 HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'toggle') {
return HMCCU_SetError ($hash, "Attribute statevals not set")
if ($statevals eq '' || !exists($hash->{statevals}));
my $tstates = $hash->{statevals};
$tstates =~ s/devstate\|//;
my @states = split /\|/, $tstates;
my $sc = scalar (@states);
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.'.'.$statedatapoint;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
my $objvalue = '';
my $st = 0;
while ($st < $sc) {
if ($states[$st] eq $result) {
$objvalue = ($st == $sc-1) ? $states[0] : $states[$st+1];
last;
}
else {
$st++;
}
}
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 HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'config') {
return HMCCU_SetError ($hash, "Usage: set $name config {parameter}={value} [...]") if (@a < 1);;
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";
return undef if ($hash->{statevals} eq 'readonly');
if ($hash->{statevals} ne '') {
my @cmdlist = split /\|/,$hash->{statevals};
shift @cmdlist;
$retmsg .= ':'.join(',',@cmdlist) if (@cmdlist > 0);
foreach my $sv (@cmdlist) {
$retmsg .= ' '.$sv.':noArg';
}
$retmsg .= " toggle:noArg";
}
return $retmsg;
}
}
#####################################
# Get commands
#####################################
sub HMCCUCHN_Get ($@)
{
my ($hash, @a) = @_;
my $name = shift @a;
my $opt = shift @a;
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";
}
# my $statedatapoint = AttrVal ($name, "statedatapoint", 'STATE');
my ($sc, $statedatapoint, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', '');
my $ccureadings = AttrVal ($name, "ccureadings", 1);
my $result = '';
my $rc;
if ($opt eq 'devstate') {
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.'.'.$statedatapoint;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return $ccureadings ? undef : $result;
}
elsif ($opt eq 'datapoint') {
my $objname = shift @a;
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 HMCCU_SetError ($hash, $rc) if ($rc < 0);
return $ccureadings ? undef : $result;
}
elsif ($opt eq 'channel') {
my $dptexpr = shift @a;
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr};
$objname .= '.'.$dptexpr if (defined ($dptexpr));
my @chnlist = ($objname);
($rc, $result) = HMCCU_GetChannel ($hash, \@chnlist);
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 HMCCU_SetError ($hash, "Usage: get $name update [{'State'|'Value'}]");
}
$rc = HMCCU_GetUpdate ($hash, $hash->{ccuaddr}, $ccuget);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return undef;
}
elsif ($opt eq 'config') {
my $ccuobj = $hash->{ccuaddr};
my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset");
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return $ccureadings ? undef : $res;
}
elsif ($opt eq 'configdesc') {
my $ccuobj = $hash->{ccuaddr};
my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription");
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return $res;
}
else {
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;
}
}
#####################################
# Set error status
#####################################
sub HMCCUCHN_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'
);
if (exists ($errlist{$text})) {
$msg = $errlist{$text};
}
else {
$msg = $text;
}
$msg = "HMCCUCHN: ".$name." ". $msg;
readingsSingleUpdate ($hash, "state", "Error", 1);
Log3 $name, 1, $msg;
return $msg;
}
1;
=pod
=begin html
<a name="HMCCUCHN"></a>
<h3>HMCCUCHN</h3>
<ul>
The module implements client devices for HMCCU. A HMCCU device must exist
before a client device can be defined.
</br></br>
<a name="HMCCUCHNdefine"></a>
<b>Define</b>
<ul>
<br/>
<code>define &lt;name&gt; HMCCUCHN {&lt;channel-name&gt;|&lt;channel-address&gt;} [readonly]</code>
<br/><br/>
If <i>readonly</i> parameter is specified no set command will be available.
<br/><br/>
Examples:<br/>
<code>define window_living HMCCUCHN WIN-LIV-1 readonly</code><br/>
<code>define temp_control HMCCUCHN BidCos-RF.LEQ1234567:1</code>
<br/>
</ul>
<br/>
<a name="HMCCUCHNset"></a>
<b>Set</b><br/>
<ul>
<br/>
<li>set &lt;name&gt; devstate &lt;value&gt; [...]<br/>
Set state of a CCU device channel. Channel datapoint must be defined
by setting attribute 'statedatapoint'.
<br/><br/>
Example:<br/>
<code>set light_entrance devstate on</code>
</li><br/>
<li>set &lt;name&gt; &lt;statevalue&gt;<br/>
State of a CCU device channel is set to <i>StateValue</i>. State datapoint
must be defined as attribute statedatapoint. State values can be replaced
by setting attribute statevals.
<br/><br/>
Example:<br/>
<code>
attr myswitch statedatapoint TEST<br/>
attr myswitch statevals on:true,off:false<br/>
set myswitch on
</code>
</li><br/>
<li>set &lt;name&gt; toggle<br/>
Toggles between values defined by attribute 'statevals'.
</li><br/>
<li>set &lt;name&gt; datapoint &lt;datapoint&gt; &lt;value&gt;<br/>
Set value of a datapoint of a CCU device channel.
<br/><br/>
Example:<br/>
<code>set temp_control datapoint SET_TEMPERATURE 21</code>
</li><br/>
<li>set &lt;name&gt; config [&lt;rpcport&gt;] &lt;parameter&gt;=&lt;value&gt;] [...] <br/>
Set config parameters of CCU channel.
</li>
</ul>
<br/>
<a name="HMCCUCHNget"></a>
<b>Get</b><br/>
<ul>
<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/>
Get value of a CCU device datapoint.
</li><br/>
<li>get &lt;name&gt; config<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<br/>
Get description of configuration parameters of CCU channel.
</li><br/>
<li>get &lt;name&gt; update [{'State'|'Value'}]<br/>
Update all datapoints / readings of channel.
</li>
</ul>
<br/>
<a name="HMCCUCHNattr"></a>
<b>Attributes</b><br/>
<br/>
<ul>
<li>ccuget &lt;State | Value&gt;<br/>
Set read access method for CCU channel datapoints. Method 'State' is slower than 'Value' because
each request is sent to the device. With method 'Value' only CCU is queried. Default is 'Value'.
</li><br/>
<li>ccureadings &lt;0 | 1&gt;<br/>
If set to 1 values read from CCU will be stored as readings. Default is 1.
</li><br/>
<li>ccureadingfilter &lt;filter-rule[,...]&gt;<br/>
Only datapoints matching specified expression are stored as readings.<br/>
Syntax for filter rule is: [channel-no:]RegExp<br/>
If channel-no is specified the following rule applies only to this channel.
</li><br/>
<li>ccuscaleval &lt;datapoint&gt;:&lt;factor&gt;[,...] <br/>
Scale datapoint values before executing set datapoint commands or after executing get
datapoint commands. During get the value read from CCU is devided by factor. During set
the value is multiplied by factor.
</li><br/>
<li>ccuverify &lt;0 | 1 | 2&gt;<br/>
If set to 1 a datapoint is read for verification after set operation. If set to 2 the
corresponding reading will be set to the new value directly after setting a datapoint
in CCU.
</li><br/>
<li>controldatapoint &lt;datapoint&gt;<br/>
Set datapoint for device control. Can be use to realize user defined control elements for
setting control datapoint. For example if datapoint of thermostat control is
SET_TEMPERATURE one can define a slider for setting the destination temperature with
following attributes:<br/><br/>
attr mydev controldatapoint SET_TEMPERATURE
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/>
<li>statevals &lt;text&gt;:&lt;text&gt;[,...]<br/>
Define substitution for set commands values. The parameters &lt;text&gt;
are available as set commands. Example:<br/>
<code>attr my_switch statevals on:true,off:false</code><br/>
<code>set my_switch on</code>
</li><br/>
<li>substitude &lt;subst-rule&gt;[;...]<br/>
Define substitions for reading values. Substitutions for parfile values must
be specified in parfiles. Syntax of subst-rule is<br/><br/>
[datapoint!]&lt;regexp1&gt;:&lt;text1&gt;[,...]
</li>
</ul>
</ul>
=end html
=cut

View File

@ -1,830 +0,0 @@
#####################################################################
#
# 88_HMCCUDEV.pm
#
# $Id:$
#
# Version 3.3
#
# (c) 2016 zap (zap01 <at> t-online <dot> de)
#
#####################################################################
#
# define <name> HMCCUDEV {<ccudev>|virtual} [statechannel] [readonly]
# [{group={<device>|<channel>}[,...]|groupexp=<regexp>}]
#
# set <name> config [<channel>] <parameter>=<value> [...]
# set <name> control <value>
# set <name> datapoint <channel>.<datapoint> <value>
# set <name> defaults
# set <name> devstate <value>
# set <name> on-for-timer <seconds>
# set <name> <stateval_cmds>
# set <name> toggle
#
# get <name> devstate
# get <name> datapoint <channel>.<datapoint>
# get <name> defaults
# get <name> channel <channel>[.<datapoint-expr>]
# get <name> config [<channel>]
# get <name> configdesc [<channel>]
# get <name> update
#
# attr <name> ccuget { State | Value }
# attr <name> ccureadings { 0 | 1 }
# attr <name> ccureadingformat { address | name }
# attr <name> ccureadingfilter <filter-rule>[,...]
# attr <name> ccuscaleval <datapoint>:<factor>[,...]
# attr <name> ccuverify { 0 | 1 | 2}
# attr <name> controldatapoint <channel-number>.<datapoint>
# attr <name> disable { 0 | 1 }
# attr <name> mapdatapoints <channel>.<datapoint>=<channel>.<datapoint>[,...]
# attr <name> statechannel <channel>
# attr <name> statedatapoint [<channel-number>.]<datapoint>
# attr <name> statevals <text1>:<subtext1>[,...]
# attr <name> substitute <regexp1>:<subtext1>[,...]
#
#####################################################################
# Requires module 88_HMCCU
#####################################################################
package main;
use strict;
use warnings;
use SetExtensions;
# use Data::Dumper;
use Time::HiRes qw( gettimeofday usleep );
sub HMCCUDEV_Define ($@);
sub HMCCUDEV_Set ($@);
sub HMCCUDEV_Get ($@);
sub HMCCUDEV_Attr ($@);
sub HMCCUDEV_SetError ($$);
#####################################
# Initialize module
#####################################
sub HMCCUDEV_Initialize ($)
{
my ($hash) = @_;
$hash->{DefFn} = "HMCCUDEV_Define";
$hash->{SetFn} = "HMCCUDEV_Set";
$hash->{GetFn} = "HMCCUDEV_Get";
$hash->{AttrFn} = "HMCCUDEV_Attr";
$hash->{AttrList} = "IODev ccureadingfilter:textField-long ccureadingformat:name,address ccureadings:0,1 ccuget:State,Value ccuscaleval ccuverify:0,1,2 disable:0,1 mapdatapoints:textField-long statevals substitute statechannel statedatapoint controldatapoint stripnumber:0,1,2 ". $readingFnAttributes;
}
#####################################
# Define device
#####################################
sub HMCCUDEV_Define ($@)
{
my ($hash, $def) = @_;
my $name = $hash->{NAME};
my @a = split("[ \t][ \t]*", $def);
my $usage = "Usage: define $name HMCCUDEV {device|'virtual'} [state-channel] ['readonly'] [{groupexp=regexp|group={device|channel}[,...]]";
return $usage if (@a < 3);
my $devname = shift @a;
my $devtype = shift @a;
my $devspec = shift @a;
my $hmccu_hash = undef;
if ($devspec ne 'virtual') {
return "Invalid or unknown CCU device name or address" if (!HMCCU_IsValidDevice ($devspec));
}
if ($devspec eq 'virtual') {
# Virtual device FHEM only
my $no = 0;
foreach my $d (sort keys %defs) {
my $ch = $defs{$d};
$hmccu_hash = $ch if ($ch->{TYPE} eq 'HMCCU' && !defined ($hmccu_hash));
next if ($ch->{TYPE} ne 'HMCCUDEV');
next if ($d eq $name);
next if ($ch->{ccuif} ne 'VirtualDevices' || $ch->{ccuname} ne 'none');
$no++;
}
return "No IO device found" if (!defined ($hmccu_hash));
$hash->{ccuif} = "VirtualDevices";
$hash->{ccuaddr} = sprintf ("VIR%07d", $no+1);
$hash->{ccuname} = "none";
}
elsif (HMCCU_IsDevAddr ($devspec, 1)) {
# CCU Device address with interface
$hash->{ccuif} = $1;
$hash->{ccuaddr} = $2;
$hash->{ccuname} = HMCCU_GetDeviceName ($hash->{ccuaddr}, '');
}
elsif (HMCCU_IsDevAddr ($devspec, 0)) {
# CCU Device address without interface
$hash->{ccuaddr} = $devspec;
$hash->{ccuname} = HMCCU_GetDeviceName ($devspec, '');
$hash->{ccuif} = HMCCU_GetDeviceInterface ($hash->{ccuaddr}, 'BidCos-RF');
}
else {
# CCU Device name
$hash->{ccuname} = $devspec;
my ($add, $chn) = HMCCU_GetAddress ($devspec, '', '');
return "Name is a channel name" if ($chn ne '');
$hash->{ccuaddr} = $add;
$hash->{ccuif} = HMCCU_GetDeviceInterface ($hash->{ccuaddr}, 'BidCos-RF');
}
return "CCU device address not found for $devspec" if ($hash->{ccuaddr} eq '');
return "CCU device name not found for $devspec" if ($hash->{ccuname} eq '');
$hash->{ccutype} = HMCCU_GetDeviceType ($hash->{ccuaddr}, '');
$hash->{channels} = HMCCU_GetDeviceChannels ($hash->{ccuaddr});
if ($hash->{ccuif} eq "VirtualDevices" && $hash->{ccuname} eq 'none') {
$hash->{statevals} = 'readonly';
}
else {
$hash->{statevals} = 'devstate';
}
my $n = 0;
my $arg = shift @a;
while (defined ($arg)) {
return $usage if ($n == 3);
if ($arg eq 'readonly') {
$hash->{statevals} = $arg;
$n++;
}
elsif ($arg =~ /^groupexp=/ && $hash->{ccuif} eq "VirtualDevices") {
my ($g, $gdev) = split ("=", $arg);
return $usage if (!defined ($gdev));
my @devlist;
my $cnt = HMCCU_GetMatchingDevices ($hmccu_hash, $gdev, 'dev', \@devlist);
return "No matching CCU devices found" if ($cnt == 0);
$hash->{ccugroup} = shift @devlist;
foreach my $gd (@devlist) {
$hash->{ccugroup} .= ",".$gd;
}
}
elsif ($arg =~ /^group=/ && $hash->{ccuif} eq "VirtualDevices") {
my ($g, $gdev) = split ("=", $arg);
return $usage if (!defined ($gdev));
my @gdevlist = split (",", $gdev);
$hash->{ccugroup} = '' if (@gdevlist > 0);
foreach my $gd (@gdevlist) {
my ($gda, $gdc, $gdo) = ('', '', '', '');
return "Invalid device or channel $gd"
if (!HMCCU_IsValidDevice ($gd));
if (HMCCU_IsDevAddr ($gd, 0) || HMCCU_IsChnAddr ($gd, 1)) {
$gdo = $gd;
}
else {
($gda, $gdc) = HMCCU_GetAddress ($gd, '', '');
$gdo = $gda;
$gdo .= ':'.$gdc if ($gdc ne '');
}
if (exists ($hash->{ccugroup}) && $hash->{ccugroup} ne '') {
$hash->{ccugroup} .= ",".$gdo;
}
else {
$hash->{ccugroup} = $gdo;
}
}
}
elsif ($arg =~ /^[0-9]+$/) {
$attr{$name}{statechannel} = $arg;
$n++;
}
else {
return $usage;
}
$arg = shift @a;
}
return "No devices in group" if ($hash->{ccuif} eq "VirtualDevices" && (
!exists ($hash->{ccugroup}) || $hash->{ccugroup} eq ''));
# Inform HMCCU device about client device
AssignIoPort ($hash);
readingsSingleUpdate ($hash, "state", "Initialized", 1);
$hash->{ccudevstate} = 'Active';
return undef;
}
#####################################
# Set attribute
#####################################
sub HMCCUDEV_Attr ($@)
{
my ($cmd, $name, $attrname, $attrval) = @_;
my $hash = $defs{$name};
if ($cmd eq "set") {
return "Missing attribute value" if (!defined ($attrval));
if ($attrname eq 'IODev') {
$hash->{IODev} = $defs{$attrval};
}
elsif ($attrname eq "statevals") {
return "Device is read only" if ($hash->{statevals} eq 'readonly');
$hash->{statevals} = 'devstate';
my @states = split /,/,$attrval;
foreach my $st (@states) {
my @statesubs = split /:/,$st;
return "value := text:substext[,...]" if (@statesubs != 2);
$hash->{statevals} .= '|'.$statesubs[0];
}
}
elsif ($attrname eq "mapdatapoints") {
return "Not a virtual device" if ($hash->{ccuif} ne "VirtualDevices");
}
}
elsif ($cmd eq "del") {
if ($attrname eq "statevals") {
$hash->{statevals} = "devstate";
}
}
return undef;
}
#####################################
# Set commands
#####################################
sub HMCCUDEV_Set ($@)
{
my ($hash, @a) = @_;
my $name = shift @a;
my $opt = shift @a;
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";
}
# my $statechannel = AttrVal ($name, "statechannel", '');
# my $statedatapoint = AttrVal ($name, "statedatapoint", 'STATE');
my $statevals = AttrVal ($name, "statevals", '');
# my $controldatapoint = AttrVal ($name, "controldatapoint", '');
my ($statechannel, $statedatapoint, $controlchannel, $controldatapoint) =
HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', '');
my $result = '';
my $rc;
if ($opt eq 'datapoint') {
my $objname = shift @a;
# my $objvalue = join ('%20', @a);
my $objvalue = shift @a;
if (!defined ($objname) || $objname !~ /^[0-9]+\..+$/ || !defined ($objvalue)) {
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 HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'control') {
return HMCCU_SetError ($hash, "Attribute controldatapoint not set") if ($controldatapoint eq '');
my $objvalue = shift @a;
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$controlchannel.'.'.$controldatapoint;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt =~ /^($hash->{statevals})$/) {
my $cmd = $1;
my $objvalue = ($cmd ne 'devstate') ? $cmd : shift @a;
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, '');
# Build datapoint address
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$statechannel.'.'.$statedatapoint;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'toggle') {
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\|//;
my @states = split /\|/, $tstates;
my $sc = scalar (@states);
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$statechannel.'.'.$statedatapoint;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
my $objvalue = '';
my $st = 0;
while ($st < $sc) {
if ($states[$st] eq $result) {
$objvalue = ($st == $sc-1) ? $states[0] : $states[$st+1];
last;
}
else {
$st++;
}
}
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 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})/);
my $timespec = shift @a;
return HMCCU_SetError ($hash, "Usage: set $name on-for-timer {on-time} [{ramp-time}]")
if (!defined ($timespec));
my $swrtdpt = '';
my $ramptime = shift @a;
if (defined ($ramptime)) {
$swrtdpt = HMCCU_GetSwitchDatapoint ($hash, $hash->{ccutype}, 'ramptime');
return HMCCU_SetError ($hash, "Can't find ramp-time datapoint for device type")
if ($swrtdpt eq '');
}
my $swotdpt = HMCCU_GetSwitchDatapoint ($hash, $hash->{ccutype}, 'ontime');
return HMCCU_SetError ($hash, "Can't find on-time datapoint for device type")
if ($swotdpt eq '');
# Set on time
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$swotdpt;
$rc = HMCCU_SetDatapoint ($hash, $objname, $timespec);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
# Set ramp time
if ($swrtdpt ne '') {
my $objname = $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$swrtdpt;
$rc = HMCCU_SetDatapoint ($hash, $objname, $ramptime);
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, $objvalue);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'config') {
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 HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK");
return undef;
}
elsif ($opt eq 'defaults') {
HMCCU_SetDefaults ($hash);
HMCCU_SetState ($hash, "OK");
return undef;
}
else {
my $retmsg = "HMCCUDEV: Unknown argument $opt, choose one of config control datapoint defaults:noArg";
return undef if ($hash->{statevals} eq 'readonly');
if ($statechannel ne '') {
$retmsg .= " devstate";
if ($hash->{statevals} ne '') {
my @cmdlist = split /\|/,$hash->{statevals};
shift @cmdlist;
$retmsg .= ':'.join(',',@cmdlist) if (@cmdlist > 0);
foreach my $sv (@cmdlist) {
$retmsg .= ' '.$sv.':noArg';
}
$retmsg .= " toggle:noArg";
$retmsg .= " on-for-timer" if ($statechannel ne '' &&
HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $statechannel, "ON_TIME", 2));
}
}
return $retmsg;
}
}
#####################################
# Get commands
#####################################
sub HMCCUDEV_Get ($@)
{
my ($hash, @a) = @_;
my $name = shift @a;
my $opt = shift @a;
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";
}
# my $statechannel = AttrVal ($name, 'statechannel', '');
# my $statedatapoint = AttrVal ($name, 'statedatapoint', 'STATE');
my $ccureadings = AttrVal ($name, 'ccureadings', 1);
my ($statechannel, $statedatapoint, $cc, $cd) = HMCCU_GetSpecialDatapoints (
$hash, '', 'STATE', '', '');
my $result = '';
my $rc;
if ($hash->{ccuif} eq "VirtualDevices" && $hash->{ccuname} eq "none" && $opt ne 'update') {
return "HMCCUDEV: Unknown argument $opt, choose one of update:noArg";
}
if ($opt eq 'devstate') {
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 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 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 HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $ccureadings ? undef : $result;
}
elsif ($opt eq 'channel') {
my @chnlist;
foreach my $objname (@a) {
last if (!defined ($objname));
if ($objname =~ /^([0-9]+)/ && exists ($hash->{channels})) {
return HMCCU_SetError ($hash, -7) if ($1 >= $hash->{channels});
}
else {
return HMCCU_SetError ($hash, -7);
}
if ($objname =~ /^[0-9]{1,2}.*=/) {
$objname =~ s/=/ /;
}
push (@chnlist, $hash->{ccuif}.'.'.$hash->{ccuaddr}.':'.$objname);
}
if (@chnlist == 0) {
return HMCCU_SetError ($hash, "Usage: get $name channel {channel-number}[.{datapoint-expr}] [...]");
}
($rc, $result) = HMCCU_GetChannel ($hash, \@chnlist);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $ccureadings ? undef : $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->{ccuname} ne 'none') {
$rc = HMCCU_GetUpdate ($hash, $hash->{ccuaddr}, $ccuget);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
}
# Update other devices belonging to group
if ($hash->{ccuif} eq "VirtualDevices" && exists ($hash->{ccugroup})) {
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') {
my $ccuget = shift @a;
$ccuget = 'Attr' if (!defined ($ccuget));
if ($ccuget !~ /^(Attr|State|Value)$/) {
return HMCCU_SetError ($hash, "Usage: get $name deviceinfo [{'State'|'Value'}]");
}
$result = HMCCU_GetDeviceInfo ($hash, $hash->{ccuaddr}, $ccuget);
return HMCCU_SetError ($hash, -2) if ($result eq '');
return HMCCU_FormatDeviceInfo ($result);
}
elsif ($opt eq 'config') {
my $channel = undef;
my $par = shift @a;
if (defined ($par)) {
$channel = $par if ($par =~ /^[0-9]{1,2}$/);
}
my $ccuobj = $hash->{ccuaddr};
$ccuobj .= ':'.$channel if (defined ($channel));
my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset");
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $ccureadings ? undef : $res;
}
elsif ($opt eq 'configdesc') {
my $channel = undef;
my $par = shift @a;
if (defined ($par)) {
$channel = $par if ($par =~ /^[0-9]{1,2}$/);
}
my $ccuobj = $hash->{ccuaddr};
$ccuobj .= ':'.$channel if (defined ($channel));
my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription");
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $res;
}
elsif ($opt eq 'defaults') {
$result = HMCCU_GetDefaults ($hash);
return $result;
}
else {
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 .= " defaults:noArg channel update:noArg config configdesc deviceinfo:noArg";
if ($statechannel ne '') {
$retmsg .= ' devstate:noArg';
}
return $retmsg;
}
}
#####################################
# Set error status
#####################################
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'
);
if (exists ($errlist{$text})) {
$msg = $errlist{$text};
}
else {
$msg = $text;
}
$msg = "HMCCUDEV: ".$name." ". $msg;
readingsSingleUpdate ($hash, "state", "Error", 1);
Log3 $name, 1, $msg;
return $msg;
}
1;
=pod
=begin html
<a name="HMCCUDEV"></a>
<h3>HMCCUDEV</h3>
<ul>
The module implements client devices for HMCCU. A HMCCU device must exist
before a client device can be defined.
</br></br>
<a name="HMCCUDEVdefine"></a>
<b>Define</b>
<ul>
<br/>
<code>define &lt;name&gt; HMCCUDEV {&lt;device-name&gt;|&lt;device-address&gt;} [&lt;statechannel&gt;] [readonly] [{group={device|channel}[,...]|groupexp=regexp]</code>
<br/><br/>
If <i>readonly</i> parameter is specified no set command will be available.
<br/><br/>
Examples:<br/>
<code>define window_living HMCCUDEV WIN-LIV-1 readonly</code><br/>
<code>define temp_control HMCCUDEV BidCos-RF.LEQ1234567 1</code>
<br/>
</ul>
<br/>
<a name="HMCCUDEVset"></a>
<b>Set</b><br/>
<ul>
<br/>
<li>set &lt;name&gt; devstate &lt;value&gt; [...]<br/>
Set state of a CCU device channel. Channel must be defined as attribute
'statechannel'. Default datapoint can be modfied by setting attribute
'statedatapoint'.
<br/><br/>
Example:<br/>
<code>set light_entrance devstate on</code>
</li><br/>
<li>set &lt;name&gt; defaults<br/>
Set default attributes for CCU device type.
</li><br/>
<li>set &lt;name&gt; on-for-timer &lt;seconds&gt; &lt;seconds&gt;<br/>
Switch device on for specified time. Requires that device contains a datapoint
ON_TIME and optionally RAMP_TIME. Attribute '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
modified by setting attribute 'statedatapoint'. Values for <i>statevalue</i>
are defined by setting attribute 'statevals'.
<br/><br/>
Example:<br/>
<code>
attr myswitch statechannel 1<br/>
attr myswitch statevals on:true,off:false<br/>
set myswitch on
</code>
</li><br/>
<li>set &lt;name&gt; toggle<br/>
Toggles between values defined by attribute 'statevals'.
</li><br/>
<li>set &lt;name&gt; datapoint &lt;channel-number&gt;.&lt;datapoint&gt; &lt;value&gt; [...]<br/>
Set value of a datapoint of a CCU device channel.
<br/><br/>
Example:<br/>
<code>set temp_control datapoint 1.SET_TEMPERATURE 21</code>
</li><br/>
<li>set &lt;name&gt; config [&lt;channel-number&gt;] &lt;parameter&gt;=&lt;value&gt; [...]<br/>
Set configuration parameter of CCU device or channel.
</li>
</ul>
<br/>
<a name="HMCCUDEVget"></a>
<b>Get</b><br/>
<ul>
<br/>
<li>get &lt;name&gt; devstate<br/>
Get state of CCU device. Attribute 'statechannel' must be set.
</li><br/>
<li>get &lt;name&gt; datapoint &lt;channel-number&gt;.&lt;datapoint&gt;<br/>
Get value of a CCU device datapoint.
</li><br/>
<li>get &lt;name&gt; config [&lt;channel-number&gt;]<br/>
Get configuration parameters of CCU device. If attribute ccureadings is set to 0
parameters are displayed in browser window (no readings set).
</li><br/>
<li>get &lt;name&gt; configdesc [&lt;channel-number&gt;] [&lt;rpcport&gt;]<br/>
Get description of configuration parameters for CCU device.
</li><br/>
<li>get &lt;name&gt; defaults<br/>
Display default attributes for CCU device type.
</li><br/>
<li>get &lt;name&gt; update [{'State'|'Value'}]<br/>
Update datapoints / readings of device.
</li><br/>
<li>get &lt;name&gt; deviceinfo [{'State'|'Value'}]<br/>
Display all channels and datapoints of device.
</li>
</ul>
<br/>
<a name="HMCCUDEVattr"></a>
<b>Attributes</b><br/>
<br/>
<ul>
<li>ccuget &lt;State | <u>Value</u>&gt;<br/>
Set read access method for CCU channel datapoints. Method 'State' is slower than 'Value' because
each request is sent to the device. With method 'Value' only CCU is queried. Default is 'Value'.
</li><br/>
<li>ccureadings &lt;0 | <u>1</u>&gt;<br/>
If set to 1 values read from CCU will be stored as readings. Default is 1.
</li><br/>
<li>ccureadingfilter &lt;filter-rule[,...]&gt;<br/>
Only datapoints matching specified expression are stored as readings.
Syntax for filter rule is: [channel-no:]RegExp<br/>
If channel-no is specified the following rule applies only to this channel.
</li><br/>
<li>ccureadingformat &lt;address | name&gt; <br/>
Set format of readings. Default is 'name'.
</li><br/>
<li>ccuscaleval &lt;datapoint&gt;:&lt;factor&gt;[,...] <br/>
Scale datapoint values before executing set datapoint commands or after executing get
datapoint commands. During get the value read from CCU is devided by factor. During set
the value is multiplied by factor.
</li><br/>
<li>ccuverify &lt;0 | 1 | 2&gt;<br/>
If set to 1 a datapoint is read for verification after set operation. If set to 2 the
corresponding reading will be set to the new value directly after setting a datapoint
in CCU.
</li><br/>
<li>controldatapoint &lt;channel-number.datapoint&gt;<br/>
Set datapoint for device control. Can be use to realize user defined control elements for
setting control datapoint. For example if datapoint of thermostat control is
2.SET_TEMPERATURE one can define a slider for setting the destination temperature with
following attributes:<br/><br/>
attr mydev controldatapoint 2.SET_TEMPERATURE
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/>
<li>statechannel &lt;channel-number&gt;<br/>
Channel for setting device state by devstate command.
</li><br/>
<li>statedatapoint &lt;datapoint&gt;<br/>
Datapoint for setting device state by devstate command.
</li><br/>
<li>statevals &lt;text&gt;:&lt;text&gt;[,...]<br/>
Define substitution for set commands values. The parameters &lt;text&gt;
are available as set commands. Example:<br/>
<code>attr my_switch statevals on:true,off:false</code><br/>
<code>set my_switch on</code>
</li><br/>
<li>substitute &lt;subst-rule&gt;[;...]<br/>
Define substitutions for reading values. Substitutions for parfile values must
be specified in parfiles. Syntax of subst-rule is<br/><br/>
[datapoint!]&lt;regexp&gt;:&lt;text&gt;[,...]
</li><br/>
</ul>
</ul>
=end html
=cut

View File

@ -1,122 +0,0 @@
#########################################################################
#
# HMCCUConf.pm
#
# $Id:$
#
# Version 3.2
#
# Configuration parameters for Homematic devices.
#
# (c) 2016 zap (zap01 <at> t-online <dot> de)
#
#########################################################################
package HMCCUConf;
use strict;
use warnings;
use vars qw(%HMCCU_DEV_DEFAULTS);
# Default attributes for Homematic devices of type HMCCUDEV
%HMCCU_DEV_DEFAULTS = (
"HM-Sec-SCo" => { # Tuer/Fensterkontakt optisch
ccureadingfilter => "(ERROR|UNREACH|LOWBAT|STATE)",
statechannel => 1,
substitute => "STATE!(0|false):closed,(1|true):open;LOWBAT!(0|false):no,(1|true):yes"
},
"HM-Sec-SC" => { # Tuer/Fensterkontakt magnetisch
ccureadingfilter => "(ERROR|UNREACH|LOWBAT|STATE)",
statechannel => 1,
substitute => "STATE!(0|false):closed,(1|true):open;LOWBAT!(0|false):no,(1|true):yes"
},
"HM-LC-Sw1-Pl-2" => { # Steckdose
ccureadingfilter => "(STATE|UNREACH)",
controldatapoint => "1.STATE",
statechannel => 1,
statevals => "on:true,off:false",
substitute => "STATE!(1|true):on,(0|false):off",
webCmd => "control",
widgetOverride => "control:uzsuToggle,off,on"
},
"HMIP-PS" => { # Steckdose (IP)
ccureadingfilter => "(STATE|UNREACH)",
statechannel => 3,
statevals => "on:1,off:0",
substitute => "STATE!(1|true):on,(0|false):off"
},
"HM-ES-PMSw1-Pl" => { # Steckdose mit Energiemessung
ccureadingfilter => "(STATE|UNREACH|CURRENT|ENERGY_COUNTER|POWER)",
statechannel => 1,
statevals => "on:1,off:0",
stripnumber => 1,
substitute => "STATE!(1|true):on,(0|false):off"
},
"HMIP-PSM" => { # Steckdose mit Energiemessung (IP)
ccureadingfilter => "(STATE|UNREACH|CURRENT|ENERGY_COUNTER|POWER)",
statechannel => 3,
statevals => "on:true,off:false",
stripnumber => 1,
substitute => "STATE!(1|true):on,(0|false):off"
},
"HM-LC-Bl1PBU-FM" => { # Rolladenaktor
cmdIcon => "up:fts_shutter_up stop:fts_shutter_manual down:fts_shutter_down",
controldatapoint => "1.LEVEL",
eventMap => "/datapoint 1.STOP 1:stop/datapoint 1.LEVEL 1:down/datapoint 1.LEVEL 0:up/",
statechannel => 1,
statevals => "up:0.0,down:1.0",
stripnumber => 1,
webCmd => "control:up:stop:down",
widgetOverride => "control:slider,0,0.05,1,1"
},
"HM-TC-IT-WM-W-EU" => { # Wandthermostat
ccureadingfilter => "(UNREACH|^HUMIDITY|^TEMPERATURE|^SET_TEMPERATURE|^LOWBAT$|^WINDOW_OPEN)",
cmdIcon => "Auto:sani_heating_automatic Manu:sani_heating_manual Boost:sani_heating_boost on:general_an off:general_aus",
controldatapoint => "2.SET_TEMPERATURE",
eventMap => "/datapoint 2.MANU_MODE 20.0:Manu/datapoint 2.AUTO_MODE 1:Auto/datapoint 2.BOOST_MODE 1:Boost/datapoint 2.MANU_MODE 4.5:off/datapoint 2.MANU_MODE 30.5:on/",
statechannel => 2,
statedatapoint => "SET_TEMPERATURE",
stripnumber => 1,
substitute => "LOWBAT!(0|false):no,(1|true):yes;CONTROL_MODE!0:AUTO,1:MANU,2:PARTY,3:BOOST;WINDOW_OPEN_REPORTING!(true|1):open,(false|0):closed",
webCmd => "control:Auto:Manu:Boost:on:off",
widgetOverride => "control:slider,10,1,25"
},
"HM-CC-RT-DN" => { # Heizkörperthermostat
ccureadingfilter => "(UNREACH|LOWBAT|TEMPERATURE|VALVE_STATE|CONTROL)",
cmdIcon => "Auto:sani_heating_automatic Manu:sani_heating_manual Boost:sani_heating_boost on:general_an off:general_aus",
controldatapoint => "4.SET_TEMPERATURE",
eventMap => "/datapoint 4.MANU_MODE 20.0:Manu/datapoint 4.AUTO_MODE 1:Auto/datapoint 4.BOOST_MODE 1:Boost/datapoint 4.MANU_MODE 4.5:off/datapoint 4.MANU_MODE 30.5:on/",
statechannel => 4,
statedatapoint => "SET_TEMPERATURE",
stripnumber => 1,
substitute => "LOWBAT!(0|false):no,(1|true):yes;CONTROL_MODE!0:AUTO,1:MANU,2:PARTY,3:BOOST",
webCmd => "control:Auto:Manu:Boost:on:off",
widgetOverride => "control:slider,10,1,25"
},
"HM-WDS40-TH-I" => { # Temperatur/Luftfeuchte Sensor
ccureadingfilter => "(UNREACH|^HUMIDITY|^TEMPERATURE|^LOWBAT$)",
statechannel => 1,
statedatapoint => "TEMPERATURE",
stripnumber => 1,
substitute => "LOWBAT!(0|false):no,(1|true):yes"
},
"HM-ES-TX-WM" => { # Stromzähler Sensor
ccureadingfilter => "(UNREACH|LOWBAT|^ENERGY_COUNTER|^POWER)",
substitute => "LOWBAT!(true|1):yes,(false|0):no"
},
"HM-CC-VG-1" => { # Heizungsgruppe
ccureadingfilter => "(^SET_TEMPERATURE|^TEMPERATURE|^HUMIDITY|LOWBAT$|^VALVE|^CONTROL|^WINDOW_OPEN)",
cmdIcon => "Auto:sani_heating_automatic Manu:sani_heating_manual Boost:sani_heating_boost on:general_an off:general_aus",
controldatapoint => "1.SET_TEMPERATURE",
eventMap => "/datapoint 1.MANU_MODE 20.0:Manu/datapoint 1.AUTO_MODE 1:Auto/datapoint 1.BOOST_MODE 1:Boost/datapoint 1.MANU_MODE 4.5:off/datapoint 1.MANU_MODE 30.5:on/",
statechannel => 1,
statedatapoint => "SET_TEMPERATURE",
stripnumber => 1,
substitute => "LOWBAT!(0|false):no,(1|true):yes;CONTROL_MODE!0:AUTO,1:MANU,2:PARTY,3:BOOST;WINDOW_OPEN_REPORTING!(true|1):open,(false|0):closed",
webCmd => "control:Auto:Manu:Boost:on:off",
widgetOverride => "control:slider,10,1,25"
}
);
1;

View File

@ -1,186 +0,0 @@
package RPCQueue;
use strict;
use IO::File;
use Fcntl 'SEEK_END', 'SEEK_SET', 'O_CREAT', 'O_RDWR';
use Carp qw(carp croak);
our $VERSION = '1.01';
sub new
{
my $class = shift;
my $mi = $class . '->new()';
croak "$mi requires an even number of parameters" if (@_ & 1);
my %params = @_;
# convert to lower case
my @keylist = keys %params;
foreach my $key (@keylist) {
my $val = $params{$key};
delete $params{$key};
$params{ lc($key) } = $val;
}
croak "$mi needs an File parameter" unless exists $params{file};
my $queue_file = delete $params{file};
my $idx_file = $queue_file . '.idx';
$queue_file .= '.dat';
my $self;
my $mode = delete $params{mode} || '0600';
$self->{block_size} = delete $params{blocksize} || 64;
$self->{seperator} = delete $params{seperator} || "\n";
$self->{sep_length} = length $self->{seperator};
croak "Seperator length cannot be greater than BlockSize" if ($self->{sep_length} > $self->{block_size});
$self->{queue_file} = $queue_file;
$self->{idx_file} = $idx_file;
$self->{queue} = new IO::File $queue_file, O_CREAT | O_RDWR, $mode or croak $!;
$self->{idx} = new IO::File $idx_file, O_CREAT | O_RDWR, $mode or croak $!;
### Default ptr to 0, replace it with value in idx file if one exists
$self->{idx}->sysseek(0, SEEK_SET);
$self->{idx}->sysread($self->{ptr}, 1024);
$self->{ptr} = '0' unless $self->{ptr};
if($self->{ptr} > -s $queue_file)
{
carp "Ptr is greater than queue file size, resetting ptr to '0'";
$self->{idx}->truncate(0) or croak "Could not truncate idx: $!";
$self->{idx}->sysseek(0, SEEK_SET);
$self->{idx}->syswrite('0') or croak "Could not syswrite to idx: $!";
}
bless $self, $class;
return $self;
}
sub enq
{
my ($self, $element) = @_;
$self->{queue}->sysseek(0, SEEK_END);
if(ref $element)
{
croak 'Cannot handle references';
}
if($element =~ s/$self->{seperator}//g)
{
carp "Removed illegal seperator(s) from $element";
}
$self->{queue}->syswrite("$element$self->{seperator}") or croak "Could not syswrite to queue: $!";
}
sub deq
{
my $self = shift;
my $element;
$self->{queue}->sysseek($self->{ptr}, SEEK_SET);
my $i;
while($self->{queue}->sysread($_, $self->{block_size}))
{
$i = index($_, $self->{seperator});
if($i != -1)
{
$element .= substr($_, 0, $i);
$self->{ptr} += $i + $self->{sep_length};
$self->{queue}->sysseek($self->{ptr}, SEEK_SET);
last;
}
else
{
## If seperator isn't found, go back 'sep_length' spaces to ensure we don't miss it between reads
$element .= substr($_, 0, -$self->{sep_length}, '');
$self->{ptr} += $self->{block_size} - $self->{sep_length};
$self->{queue}->sysseek($self->{ptr}, SEEK_SET);
}
}
## If queue seek pointer is at the EOF, truncate the queue file
if($self->{queue}->sysread($_, 1) == 0)
{
$self->{queue}->truncate(0) or croak "Could not truncate queue: $!";
$self->{queue}->sysseek($self->{ptr} = 0, SEEK_SET);
}
## Set idx file contents to point to the current seek position in queue file
$self->{idx}->truncate(0) or croak "Could not truncate idx: $!";
$self->{idx}->sysseek(0, SEEK_SET);
$self->{idx}->syswrite($self->{ptr}) or croak "Could not syswrite to idx: $!";
return $element;
}
sub peek
{
my ($self, $count) = @_;
croak "Invalid argument to peek ($count)" unless $count > 0;
my $elements;
$self->{queue}->sysseek($self->{ptr}, SEEK_SET);
my (@items, $remainder);
GATHER:
while($self->{queue}->sysread($_, $self->{block_size}))
{
if(defined $remainder)
{
$_ = $remainder . $_;
}
@items = split /$self->{seperator}/, $_, -1;
$remainder = pop @items;
foreach (@items)
{
push @$elements, $_;
last GATHER if $count == @$elements;
}
}
return $elements;
}
sub reset
{
my $self = shift;
$self->{idx}->truncate(0) or croak "Could not truncate idx: $!";
$self->{idx}->sysseek(0, SEEK_SET);
$self->{idx}->syswrite('0') or croak "Could not syswrite to idx: $!";
$self->{queue}->sysseek($self->{ptr} = 0, SEEK_SET);
}
sub close
{
my $self = shift;
$self->{idx}->close();
$self->{queue}->close();
}
sub delete
{
my $self = shift;
$self->close();
unlink $self->{queue_file};
unlink $self->{idx_file};
}
1;

View File

@ -1,443 +0,0 @@
#!/usr/bin/perl
#########################################################
# ccurpcd.pl
#
# $Id:
#
# Version 2.1
#
# FHEM RPC server for Homematic CCU.
#
# (C) 2016 by zap
#--------------------------------------------------------
# Usage:
#
# ccurpcd.pl Hostname Port QueueFile LogFile
# ccurpcd.pl shutdown Hostname Port PID
#--------------------------------------------------------
# Queue file entries:
#
# Code|Data[|...]
#
# Server Loop: SL|pid|Server
# Initialized: IN|INIT|1|Server
# 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|Server
#########################################################
use strict;
use warnings;
# use File::Queue;
use RPC::XML::Server;
use RPC::XML::Client;
use IO::Socket::INET;
use FindBin qw($Bin);
use lib "$Bin";
use RPCQueue;
# Global variables
my $client;
my $server;
my $queue;
my $logfile;
my $shutdown = 0;
my $eventcount = 0;
my $totalcount = 0;
my $loglevel = 0;
my %ev = ('total', 0, 'EV', 0, 'ND', 0, 'DD', 0, 'UD', 0, 'RD', 0, 'RA', 0, 'SL', 0, 'IN', 0, 'EX', 0);
# Functions
sub CheckProcess ($$);
sub Log ($);
sub WriteQueue ($);
sub CCURPC_Shutdown ($$$);
sub CCURPC_Initialize ($$);
#####################################
# Get PID of running RPC server or 0
#####################################
sub CheckProcess ($$)
{
my ($prcname, $port) = @_;
my $filename = $prcname;
my $pdump = `ps ax | grep $prcname | grep -v grep`;
my @plist = split "\n", $pdump;
foreach my $proc (@plist) {
# Remove leading blanks, fix for MacOS. Thanks to mcdeck
$proc =~ s/^\s+//;
my @procattr = split /\s+/, $proc;
if ($procattr[0] != $$ && $procattr[4] =~ /perl$/ &&
($procattr[5] eq $prcname || $procattr[5] =~ /\/ccurpcd\.pl$/) &&
$procattr[7] eq "$port") {
Log "Process $proc is running connected to CCU port $port";
return $procattr[0];
}
}
return 0;
}
#####################################
# Write logfile entry
#####################################
sub Log ($)
{
my @messages = @_;
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime ();
if (open (LOGFILE, '>>', $logfile)) {
printf LOGFILE "%02d.%02d.%04d %02d:%02d:%02d ",
$mday,$mon+1,$year+1900,$hour,$min,$sec;
foreach my $token (@messages) {
print LOGFILE $token;
}
print LOGFILE "\n";
close LOGFILE;
}
}
#####################################
# Write queue entry
#####################################
sub WriteQueue ($)
{
my ($message) = @_;
$queue->enq ($message);
return 1;
}
#####################################
# Shutdown RPC connection
#####################################
sub CCURPC_Shutdown ($$$)
{
my ($serveraddr, $serverport, $pid) = @_;
# Detect local IP
my $socket = IO::Socket::INET->new (PeerAddr => $serveraddr, PeerPort => $serverport);
if (!$socket) {
print "Can't connect to CCU port $serverport";
return undef;
}
my $localaddr = $socket->sockhost ();
close ($socket);
my $ccurpcport = 5400+$serverport;
my $callbackurl = "http://".$localaddr.":".$ccurpcport."/fh".$serverport;
$client = RPC::XML::Client->new ("http://$serveraddr:$serverport/");
print "Trying to deregister RPC server $callbackurl\n";
$client->send_request("init", $callbackurl);
sleep (3);
print "Sending SIGINT to PID $pid\n";
kill ('INT', $pid);
return undef;
}
#####################################
# Initialize RPC connection
#####################################
sub CCURPC_Initialize ($$)
{
my ($serveraddr, $serverport) = @_;
my $callbackport = 5400+$serverport;
# Create RPC server
$server = RPC::XML::Server->new (port=>$callbackport);
if (!ref($server))
{
Log "Can't create RPC callback server on port $callbackport. Port in use?";
return undef;
}
else {
Log "Callback server created listening on port $callbackport";
}
# Callback for events
Log "Adding callback for events";
$server->add_method (
{ name=>"event",
signature=> ["string string string string int","string string string string double","string string string string boolean","string string string string i4"],
code=>\&CCURPC_EventCB
}
);
# Callback for new devices
Log "Adding callback for new devices";
$server->add_method (
{ name=>"newDevices",
signature=>["string string array"],
code=>\&CCURPC_NewDevicesCB
}
);
# Callback for deleted devices
Log "Adding callback for deleted devices";
$server->add_method (
{ name=>"deleteDevices",
signature=>["string string array"],
code=>\&CCURPC_DeleteDevicesCB
}
);
# Callback for modified devices
Log "Adding callback for modified devices";
$server->add_method (
{ name=>"updateDevice",
signature=>["string string string int"],
code=>\&CCURPC_UpdateDeviceCB
}
);
# 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",
signature=>["array string"],
code=>\&CCURPC_ListDevicesCB
}
);
return "OK";
}
#####################################
# Callback for new devices
#####################################
sub CCURPC_NewDevicesCB ($$$)
{
my ($server, $cb, $a) = @_;
Log "NewDevice: received ".scalar(@$a)." device specifications";
for my $dev (@$a) {
$ev{total}++;
$ev{ND}++;
WriteQueue ("ND|".$dev->{ADDRESS}."|".$dev->{TYPE});
}
# return RPC::XML::array->new();
return;
}
#####################################
# Callback for deleted devices
#####################################
sub CCURPC_DeleteDevicesCB ($$$)
{
my ($server, $cb, $a) = @_;
Log "DeleteDevice: received ".scalar(@$a)." device addresses";
for my $dev (@$a) {
$ev{total}++;
$ev{DD}++;
WriteQueue ("DD|".$dev);
}
return;
}
#####################################
# Callback for modified devices
#####################################
sub CCURPC_UpdateDeviceCB ($$$$)
{
my ($server, $cb, $devid, $hint) = @_;
$ev{total}++;
$ev{UD}++;
WriteQueue ("UD|".$devid."|".$hint);
return;
}
#####################################
# Callback for replaced devices
#####################################
sub CCURPC_ReplaceDeviceCB ($$$$)
{
my ($server, $cb, $devid1, $devid2) = @_;
$ev{total}++;
$ev{RD}++;
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) {
$ev{total}++;
$ev{RA}++;
WriteQueue ("RA|".$dev);
}
return;
}
#####################################
# Callback for handling CCU events
#####################################
sub CCURPC_EventCB ($$$$$)
{
my ($server,$cb,$devid,$attr,$val) = @_;
$ev{total}++;
$ev{EV}++;
WriteQueue ("EV|".$devid."|".$attr."|".$val);
$eventcount++;
if (($eventcount % 500) == 0 && $loglevel == 2) {
Log "Received $eventcount events from CCU since last check";
my @stkeys = ('total', 'EV', 'ND', 'DD', 'RD', 'RA', 'UD', 'IN', 'SL', 'EX');
my $msg = "ST";
foreach my $stkey (@stkeys) {
$msg .= "|".$ev{$stkey};
}
WriteQueue ($msg);
}
# Never remove this statement!
return;
}
#####################################
# Callback for list devices
#####################################
sub CCURPC_ListDevicesCB ()
{
my ($server, $cb) = @_;
$ev{total}++;
$ev{IN}++;
$cb = "unknown" if (!defined ($cb));
Log "ListDevices $cb. Sending init to HMCCU";
WriteQueue ("IN|INIT|1|$cb");
return RPC::XML::array->new();
}
#####################################
# MAIN
#####################################
my $name = $0;
# Process command line arguments
if ($#ARGV+1 < 4) {
print "Usage: $name CCU-Host Port QueueFile LogFile LogLevel\n";
print " $name shutdown CCU-Host Port PID\n";
exit 1;
}
#
# Manually shutdown RPC server
#
if ($ARGV[0] eq 'shutdown') {
CCURPC_Shutdown ($ARGV[1], $ARGV[2], $ARGV[3]);
exit 0;
}
#
# Start RPC server
#
my $ccuhost = $ARGV[0];
my $ccuport = $ARGV[1];
my $queuefile = $ARGV[2];
$logfile = $ARGV[3];
$loglevel = $ARGV[4] if ($#ARGV+1 == 5);
my $pid = CheckProcess ($name, $ccuport);
if ($pid > 0) {
Log "Error: ccurpcd.pl is already running (PID=$pid) for CCU port $ccuport";
die "Error: ccurpcd.pl is already running (PID=$pid) for CCU port $ccuport\n";
}
# Create or open queue
Log "Creating file queue";
$queue = new RPCQueue (File => $queuefile, Mode => 0666);
if (!defined ($queue)) {
Log "Error: Can't create queue";
die "Error: Can't create queue\n";
}
else {
$queue->reset ();
while ($queue->deq ()) { }
}
# Initialize RPC server
Log "Initializing RPC server";
my $callbackurl = CCURPC_Initialize ($ccuhost, $ccuport);
if (!defined ($callbackurl)) {
Log "Error: Can't initialize RPC server";
die "Error: Can't initialize RPC server\n";
}
# Server loop is interruptable bei signal SIGINT
Log "Entering server loop. Use kill -SIGINT $$ to terminate program";
WriteQueue ("SL|$$|CB".$ccuport);
$server->server_loop;
$totalcount++;
WriteQueue ("EX|SHUTDOWN|$$|CB".$ccuport);
$ev{total}++;
$ev{EX}++;
Log "RPC server terminated";
if ($loglevel == 2) {
foreach my $cnt (sort keys %ev) {
Log "Events $cnt = ".$ev{$cnt};
}
}

View File

@ -1,5 +0,0 @@
UPD 2016-03-13_18:13:51 85357 FHEM/88_HMCCU.pm
UPD 2016-03-11_18:56:09 17459 FHEM/88_HMCCUCHN.pm
UPD 2016-03-11_18:56:09 24314 FHEM/88_HMCCUDEV.pm
UPD 2016-03-11_18:56:21 7857 FHEM/ccurpcd.pl
UPD 2016-03-02_17:28:28 4377 FHEM/RPCQueue.pm

View File

@ -1,42 +0,0 @@
#
# Example configuration for modules HMCCU and HMCCUDEV
#
# Define device (hostname of CCU is "homematic")
define d_ccu HMCCU homematic
# Generate readings for values read from CCU
attr d_ccu ccureadings 1
# Parameterfile with channel/datapoints to be read from CCU
# by command get parfile
attr d_ccu parfile /opt/fhem/scripts/hmvalues.txt
# If CCU systemvariable name ends with a ":" this character
# will be removed. Applies to command set devstate only.
# Helpful if CCU variable should be set as a reaction on an
# event.
attr d_ccu stripchar :
# Substitute values read from CCU before storing them in a
# reading.
attr d_ccu substitute false:closed,true:open
# Subsitute values before setting them
attr d_ccu statevals on:true,off:false
# Define client device for door/window sensor
define d_hm_dw_window HMCCUDEV TF-WZ-Window readonly
attr d_hm_dw_window ccureadings 1
attr d_hm_dw_window substitute false:closed,true:open
# Define client device for subwoofer with state channel 1
define d_hm_st_sub HMCCUDEV ST-WZ-Sub 1
attr d_hm_st_sub ccureadings 1
attr d_hm_st_sub statevals on:true,off:false
attr d_hm_st_sub substitute true:on,false:off
# Update CCU readings and client devices every 10 minutes
define at_ccu at +*00:10:00 get d_ccu parfile
attr at_ccu alignTime 00:05

View File

@ -1,35 +0,0 @@
#
# Beispiel fuer eine HMCCU Parameterdatei
# Setzen mit attr <name> parfile <Datei>
# oder Angabe bei get <name> parfile <Datei>
#
# Tueren und Fenster
# Zustaende der CCU Geräte werden in den FHEM
# Readings ersetzt (false=closed,true=open).
#
TF-AZ-Fenster1:1.STATE false:closed,true:open
TF-AZ-Fenster2:1.STATE false:closed,true:open
TF-BE-Fenster:1.STATE false:closed,true:open
TF-BO-Fenster:1.STATE false:closed,true:open
TF-FL-Haustuer:1.STATE false:closed,true:open
TF-GA-Fenster:1.STATE false:closed,true:open
TF-GZ-Fenster1:1.STATE false:closed,true:open
TF-SZ-Fenster1:1.STATE false:closed,true:open
TF-SZ-Fenster2:1.STATE false:closed,true:open
TF-WZ-Balkon:1.STATE false:closed,true:open
TF-WZ-Terrasse:1.STATE false:closed,true:open
#
# Schalter
#
ST-HR-Pumpe:1.STATE false:off,true:on
ST-WZ-Bass:1.STATE false:off,true:on
#
# Temperatur und Luftfeuchte Sensoren
# Angabe Datenpunkt fehlt => Es werden alle Datenpunkte
# abgeholt (TEMPERATURE, HUMIDITY)
#
KL-SZ-THX:1
KL-AZ-THX:1
KL-GA-THX:1
KL-BO-THX:1
KL-WZ-THX-1:1

View File

@ -1,35 +0,0 @@
#
# Beispiel fuer eine HMCCU Parameterdatei
# Setzen mit attr <name> parfile <Datei>
# oder Angabe bei get <name> parfile <Datei>
#
# Tueren und Fenster
# Zustaende der CCU Geräte werden in den FHEM
# Readings ersetzt (false=closed,true=open).
#
TF-AZ-Fenster1:1.STATE false:closed,true:open
TF-AZ-Fenster2:1.STATE false:closed,true:open
TF-BE-Fenster:1.STATE false:closed,true:open
TF-BO-Fenster:1.STATE false:closed,true:open
TF-FL-Haustuer:1.STATE false:closed,true:open
TF-GA-Fenster:1.STATE false:closed,true:open
TF-GZ-Fenster1:1.STATE false:closed,true:open
TF-SZ-Fenster1:1.STATE false:closed,true:open
TF-SZ-Fenster2:1.STATE false:closed,true:open
TF-WZ-Balkon:1.STATE false:closed,true:open
TF-WZ-Terrasse:1.STATE false:closed,true:open
#
# Schalter
#
ST-HR-Pumpe:1.STATE false:off,true:on
ST-WZ-Bass:1.STATE false:off,true:on
#
# Temperatur und Luftfeuchte Sensoren
# Angabe Datenpunkt fehlt => Es werden alle Datenpunkte
# abgeholt (TEMPERATURE, HUMIDITY)
#
KL-SZ-THX:1
KL-AZ-THX:1
KL-GA-THX:1
KL-BO-THX:1
KL-WZ-THX-1:1