###################################################################### # # 88_HMCCUCHN.pm # # $Id$ # # Version 4.2.003 # # (c) 2018 zap (zap01 t-online de) # ###################################################################### # # define HMCCUCHN [readonly] [defaults] # [iodev=] # # set config [device] = [...] # set control # set datapoint [...] # set defaults # set devstate # set # set on-till # set on-for-timer # set pct [{ | 0 } []] # set toggle # # get config [device] [] # get configdesc [device] # get configlist [device] [] # get datapoint # get defaults # get deviceinfo # get devstate # get update # # attr ccucalculate :[:][...] # attr ccuflags { ackState, nochn0, trace } # attr ccuget { State | Value } # attr ccureadings { 0 | 1 } # attr ccureadingfilter [;...] # attr ccureadingformat { name[lc] | address[lc] | datapoint[lc] } # attr ccureadingname :[;...] # attr ccuverify { 0 | 1 | 2 } # attr controldatapoint # attr disable { 0 | 1 } # attr peer datapoints:condition:{hmccu:object=value|ccu:object=value|fhem:command} # attr hmstatevals [;...] # attr statedatapoint # attr statevals :[,...] # attr substexcl # attr substitute [;...] # ###################################################################### # Requires modules 88_HMCCU.pm, HMCCUConf.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 ($@); ################################################## # Initialize module ################################################## sub HMCCUCHN_Initialize ($) { my ($hash) = @_; $hash->{DefFn} = "HMCCUCHN_Define"; $hash->{SetFn} = "HMCCUCHN_Set"; $hash->{GetFn} = "HMCCUCHN_Get"; $hash->{AttrFn} = "HMCCUCHN_Attr"; $hash->{parseParams} = 1; $hash->{AttrList} = "IODev ccucalculate ". "ccuflags:multiple-strict,ackState,nochn0,trace ccureadingfilter ". "ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ". "ccureadingname:textField-long ". "ccureadings:0,1 ccuscaleval ccuverify:0,1,2 ccuget:State,Value controldatapoint ". "disable:0,1 hmstatevals:textField-long statedatapoint statevals substitute:textField-long ". "substexcl stripnumber peer:textField-long ". $readingFnAttributes; } ################################################## # Define device ################################################## sub HMCCUCHN_Define ($@) { my ($hash, $a, $h) = @_; my $name = $hash->{NAME}; my $usage = "Usage: define $name HMCCUCHN {device} ['readonly'] ['defaults'] [iodev={iodevname}]"; return $usage if (@$a < 3); my $devname = shift @$a; my $devtype = shift @$a; my $devspec = shift @$a; my $hmccu_hash = undef; # IO device can be set by command line parameter iodev if (exists ($h->{iodev})) { $hmccu_hash = $defs{$h->{iodev}} if (exists ($defs{$h->{iodev}})); } $hmccu_hash = HMCCU_FindIODevice ($devspec) if (!defined ($hmccu_hash)); return "Cannot detect IO device" if (!defined ($hmccu_hash)); return "Invalid or unknown CCU channel name or address" if (! HMCCU_IsValidChannel ($hmccu_hash, $devspec, 7)); my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($hmccu_hash, $devspec); return "Invalid or unknown CCU device name or address" if (!defined ($da)); $hash->{ccuif} = $di; $hash->{ccuaddr} = $da; $hash->{ccuname} = $dn; $hash->{ccutype} = $dt; $hash->{channels} = 1; $hash->{statevals} = 'devstate'; # Parse optional command line parameters my $n = 0; my $arg = shift @$a; while (defined ($arg)) { return $usage if ($n == 3); if ($arg eq 'readonly') { $hash->{statevals} = $arg; } elsif ($arg eq 'defaults') { HMCCU_SetDefaults ($hash); } else { return $usage; } $n++; $arg = shift @$a; } # Inform HMCCU device about client device AssignIoPort ($hash, $hmccu_hash->{NAME}); 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, $h) = @_; my $name = shift @$a; my $opt = shift @$a; my $rocmds = "clear config defaults:noArg"; return HMCCU_SetError ($hash, -3) if (!defined ($hash->{IODev})); return undef if ($hash->{statevals} eq 'readonly' && $opt ne '?' && $opt !~ /^(clear|config|defaults)$/); 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 $ccutype = $hash->{ccutype}; my $ccuaddr = $hash->{ccuaddr}; my $ccuif = $hash->{ccuif}; my $statevals = AttrVal ($name, "statevals", ''); my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', ''); my $result = ''; my $rc; if ($opt eq 'datapoint') { my $usage = "Usage: set $name datapoint {datapoint} {value} [...]"; my %dpval; while (my $objname = shift @$a) { my $objvalue = shift @$a; return HMCCU_SetError ($hash, $usage) if (!defined ($objvalue)); return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $objname, 2)); $objvalue =~ s/\\_/%20/g; $objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, ''); $objname = $ccuif.'.'.$ccuaddr.'.'.$objname; $dpval{$objname} = $objvalue; } return HMCCU_SetError ($hash, $usage) if (scalar (keys %dpval) < 1); foreach my $dpt (keys %dpval) { $rc = HMCCU_SetDatapoint ($hash, $dpt, $dpval{$dpt}); return HMCCU_SetError ($hash, $rc) if ($rc < 0); } return HMCCU_SetState ($hash, "OK"); } elsif ($opt eq 'control') { return HMCCU_SetError ($hash, -14) if ($cd eq ''); return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, $cd, 2)); my $objvalue = shift @$a; return HMCCU_SetError ($hash, "Usage: set $name control {value}") if (!defined ($objvalue)); $objvalue =~ s/\\_/%20/g; $objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, ''); my $objname = $ccuif.'.'.$ccuaddr.'.'.$cd; $rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue); return HMCCU_SetError ($hash, $rc) if ($rc < 0); return HMCCU_SetState ($hash, "OK"); } elsif ($opt =~ /^($hash->{statevals})$/) { my $cmd = $1; my $objvalue = ($cmd ne 'devstate') ? $cmd : shift @$a; return HMCCU_SetError ($hash, -13) if ($sd eq ''); return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $sd, 2)); return HMCCU_SetError ($hash, "Usage: set $name devstate {value}") if (!defined ($objvalue)); $objvalue =~ s/\\_/%20/g; $objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, ''); my $objname = $ccuif.'.'.$ccuaddr.'.'.$sd; $rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue); return HMCCU_SetError ($hash, $rc) if ($rc < 0); return HMCCU_SetState ($hash, "OK"); } elsif ($opt eq 'toggle') { return HMCCU_SetError ($hash, -15) if ($statevals eq '' || !exists($hash->{statevals})); return HMCCU_SetError ($hash, -13) if ($sd eq ''); return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $sd, 2)); my $tstates = $hash->{statevals}; $tstates =~ s/devstate\|//; my @states = split /\|/, $tstates; my $stc = scalar (@states); my $objname = $ccuif.'.'.$ccuaddr.'.'.$sd; ($rc, $result) = HMCCU_GetDatapoint ($hash, $objname); return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0); my $objvalue = ''; my $st = 0; while ($st < $stc) { if ($states[$st] eq $result) { $objvalue = ($st == $stc-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, undef, ''); $rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue); return HMCCU_SetError ($hash, $rc) if ($rc < 0); return HMCCU_SetState ($hash, "OK"); } elsif ($opt eq 'pct') { return HMCCU_SetError ($hash, "Can't find LEVEL datapoint for device type $ccutype") if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "LEVEL", 2)); my $objname = ''; my $objvalue = shift @$a; return HMCCU_SetError ($hash, "Usage: set $name pct {value} [{ontime} [{ramptime}]]") if (!defined ($objvalue)); my $timespec = shift @$a; my $ramptime = shift @$a; # Set on time if (defined ($timespec)) { return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type $ccutype") if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "ON_TIME", 2)); if ($timespec =~ /^[0-9]{2}:[0-9]{2}/) { my (undef, $h, $m, $s) = GetTimeSpec ($timespec); return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM or HH:MM:SS") if (!defined ($h)); $s += $h*3600+$m*60; my @lt = localtime; my $cs = $lt[2]*3600+$lt[1]*60+$lt[0]; $s += 86400 if ($cs > $s); $timespec = $s-$cs; } if ($timespec > 0) { $objname = $ccuif.'.'.$ccuaddr.'.ON_TIME'; $rc = HMCCU_SetDatapoint ($hash, $objname, $timespec); return HMCCU_SetError ($hash, $rc) if ($rc < 0); } } # Set ramp time if (defined ($ramptime)) { return HMCCU_SetError ($hash, "Can't find RAMP_TIME datapoint for device type $ccutype") if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "RAMP_TIME", 2)); $objname = $ccuif.'.'.$ccuaddr.'.RAMP_TIME'; $rc = HMCCU_SetDatapoint ($hash, $objname, $ramptime); return HMCCU_SetError ($hash, $rc) if ($rc < 0); } # Set level $objname = $ccuif.'.'.$ccuaddr.'.LEVEL'; $rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue); return HMCCU_SetError ($hash, $rc) if ($rc < 0); return HMCCU_SetState ($hash, "OK"); } elsif ($opt eq 'on-for-timer' || $opt eq 'on-till') { return HMCCU_SetError ($hash, -15) if ($statevals eq '' || !exists($hash->{statevals})); return HMCCU_SetError ($hash, "No state value for 'on' defined") if ("on" !~ /($hash->{statevals})/); return HMCCU_SetError ($hash, -13) if ($sd eq ''); return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $sd, 2)); return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type") if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "ON_TIME", 2)); my $timespec = shift @$a; return HMCCU_SetError ($hash, "Usage: set $name $opt {ontime-spec}") if (!defined ($timespec)); if ($opt eq 'on-till') { my (undef, $h, $m, $s) = GetTimeSpec ($timespec); return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM or HH:MM:SS") if (!defined ($h)); $s += $h*3600+$m*60; my @lt = localtime; my $cs = $lt[2]*3600+$lt[1]*60+$lt[0]; $s += 86400 if ($cs > $s); $timespec = $s-$cs; } # Set time my $objname = $ccuif.'.'.$ccuaddr.'.ON_TIME'; $rc = HMCCU_SetDatapoint ($hash, $objname, $timespec); return HMCCU_SetError ($hash, $rc) if ($rc < 0); # Set state $objname = $ccuif.'.'.$ccuaddr.'.'.$sd; my $objvalue = HMCCU_Substitute ("on", $statevals, 1, undef, ''); $rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue); return HMCCU_SetError ($hash, $rc) if ($rc < 0); return HMCCU_SetState ($hash, "OK"); } elsif ($opt eq 'clear') { my $rnexp = shift @$a; $rnexp = '.*' if (!defined ($rnexp)); my @readlist = keys %{$hash->{READINGS}}; foreach my $rd (@readlist) { delete ($hash->{READINGS}{$rd}) if ($rd ne 'state' && $rd ne 'control' && $rd =~ /$rnexp/); } } elsif ($opt eq 'config') { return HMCCU_SetError ($hash, "Usage: set $name config [device] {parameter}={value} [...]") if ((scalar keys %{$h}) < 1); my $ccuobj = $ccuaddr; my $par = shift @$a; if (defined ($par) && $par eq 'device') { ($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr); } my $rc = HMCCU_RPCSetConfig ($hash, $ccuobj, $h); return HMCCU_SetError ($hash, $rc) if ($rc < 0); return HMCCU_SetState ($hash, "OK"); } elsif ($opt eq 'defaults') { my $rc = HMCCU_SetDefaults ($hash); return HMCCU_SetError ($hash, "HMCCU: No default attributes found") if ($rc == 0); return HMCCU_SetState ($hash, "OK"); } else { return "HMCCUCHN: Unknown argument $opt, choose one of ".$rocmds if ($hash->{statevals} eq 'readonly'); my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of clear config control datapoint defaults:noArg devstate"; 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 on-till" if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $ccuaddr, "ON_TIME", 2)); $retmsg .= " pct" if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $ccuaddr, "LEVEL", 2)); } return $retmsg; } } ##################################### # Get commands ##################################### sub HMCCUCHN_Get ($@) { my ($hash, $a, $h) = @_; 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 $ccutype = $hash->{ccutype}; my $ccuaddr = $hash->{ccuaddr}; my $ccuif = $hash->{ccuif}; my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', ''); my $ccureadings = AttrVal ($name, "ccureadings", 1); my $result = ''; my $rc; if ($opt eq 'devstate') { return HMCCU_SetError ($hash, -13) if ($sd eq ''); return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $sd, 1)); my $objname = $ccuif.'.'.$ccuaddr.'.'.$sd; ($rc, $result) = HMCCU_GetDatapoint ($hash, $objname); return HMCCU_SetError ($hash, $rc, $result) 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, $ccutype, $ccuaddr, $objname, 1)); $objname = $ccuif.'.'.$ccuaddr.'.'.$objname; ($rc, $result) = HMCCU_GetDatapoint ($hash, $objname); return HMCCU_SetError ($hash, $rc, $result) 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, $ccuaddr, $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'}]"); } my ($a, $c) = split(":", $hash->{ccuaddr}); $result = HMCCU_GetDeviceInfo ($hash, $a, $ccuget); return HMCCU_SetError ($hash, -2) if ($result eq ''); return HMCCU_FormatDeviceInfo ($result); } elsif ($opt eq 'config') { my $ccuobj = $ccuaddr; my $par = shift @$a; if (defined ($par)) { if ($par eq 'device') { ($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr); $par = shift @$a; } } $par = '.*' if (!defined ($par)); my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset", $par); return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0); return $ccureadings ? undef : $res; } elsif ($opt eq 'configlist') { my $ccuobj = $ccuaddr; my $par = shift @$a; if (defined ($par)) { if ($par eq 'device') { ($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr); $par = shift @$a; } } $par = '.*' if (!defined ($par)); my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "listParamset", $par); return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0); return $res; } elsif ($opt eq 'configdesc') { my $ccuobj = $ccuaddr; my $par = shift @$a; if (defined ($par) && $par eq 'device') { ($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr); } my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription", undef); return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0); return $res; } elsif ($opt eq 'defaults') { $result = HMCCU_GetDefaults ($hash, 0); return $result; } else { my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of devstate:noArg defaults: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 .= " update:noArg deviceinfo config configlist configdesc:noArg"; return $retmsg; } } 1; =pod =item device =item summary controls HMCCU client devices for Homematic CCU2 - FHEM integration =begin html

HMCCUCHN

    The module implements Homematic CCU channels as client devices for HMCCU. A HMCCU I/O device must exist before a client device can be defined. If a CCU channel is not found execute command 'get devicelist' in I/O device.

    Define

      define <name> HMCCUCHN {<channel-name> | <channel-address>} [readonly] [defaults] [iodev=<iodev-name>]

      If option 'readonly' is specified no set command will be available. With option 'defaults' some default attributes depending on CCU device type will be set. Default attributes are only available for some device types.
      The define command accepts a CCU2 channel name or channel address as parameter.

      Examples:
      define window_living HMCCUCHN WIN-LIV-1 readonly
      define temp_control HMCCUCHN BidCos-RF.LEQ1234567:1

      The interface part of a channel address must not be specified. The default is 'BidCos-RF'. Channel addresses can be found with command 'get deviceinfo <devicename>' executed in I/O device.

    Set

    • set <name> clear [<reading-exp>]
      Delete readings matching specified reading name expression. Default expression is '.*'. Readings 'state' and 'control' are not deleted.

    • set <name> config [device] [<rpcport>] <parameter>=<value>] [...]
      Set config parameters of CCU channel. This is equal to setting device parameters in CCU. Valid parameters can be listed by using commands 'get configdesc' or 'get configlist'. With option 'device' specified parameters are set in device instead of channel.

    • set <name> datapoint <datapoint> <value> [...]
      Set datapoint values of a CCU channel. If parameter value contains special character \_ it's substituted by blank.

      Examples:
      set temp_control datapoint SET_TEMPERATURE 21
      set temp_control datapoint AUTO_MODE 1 SET_TEMPERATURE 21

    • set <name> defaults
      Set default attributes for CCU device type. Default attributes are only available for some device types and for some channels of a device type.

    • set <name> devstate <value>
      Set state of a CCU device channel. The state datapoint of a channel must be defined by setting attribute 'statedatapoint' to a valid datapoint name.

      Example:
      set light_entrance devstate true

    • set <name> <statevalue>
      Set state of a CCU device channel to StateValue. The state datapoint of a channel must be defined by setting attribute 'statedatapoint'. The available state values must be defined by setting attribute 'statevals'.

      Example: Turn switch on
      attr myswitch statedatapoint STATE
      attr myswitch statevals on:true,off:false
      set myswitch on

    • set <name> toggle
      Toggle state datapoint between values defined by attribute 'statevals'. This command is only available if attribute 'statevals' is set. Toggling supports more than two state values.

      Example: Toggle blind actor
      attr myswitch statedatapoint LEVEL
      attr myswitch statevals up:100,down:0
      set myswitch toggle

    • set <name> on-for-timer <ontime>
      Switch device on for specified number of seconds. This command is only available if channel contains a datapoint ON_TIME. The attribute 'statevals' must contain at least a value for 'on'. The attribute 'statedatapoint' must be set to a writeable datapoint.

      Example: Turn switch on for 300 seconds
      attr myswitch statedatapoint STATE
      attr myswitch statevals on:true,off:false
      set myswitch on-for-timer 300

    • set <name> on-till <timestamp>
      Switch device on until timestamp. Parameter timestamp can be a time in format HH:MM or HH:MM:SS. This command is only available if channel contains a datapoint ON_TIME. The attribute 'statevals' must contain at least a value for 'on'. The Attribute 'statedatapoint' must be set to a writeable datapoint.

    • set <name> pct <value> [<ontime> [<ramptime>]]
      Set datapoint LEVEL of a channel to the specified value. Optionally a ontime and a ramptime (both in seconds) can be specified. This command is only available if channel contains at least a datapoint LEVEL and optionally datapoints ON_TIME and RAMP_TIME. The parameter ontime can be specified in seconds or as timestamp in format HH:MM or HH:MM:SS. If ontime is 0 it's ignored. This syntax can be used to modify the ramp time only.

      Example: Turn dimmer on for 600 second. Increase light to 100% over 10 seconds
      attr myswitch statedatapoint LEVEL
      attr myswitch statevals on:100,off:0
      set myswitch pct 100 600 10


    Get

    • get <name> config [device] [<filter-expr>]
      Get configuration parameters of CCU channel. If attribute 'ccureadings' is 0 results are displayed in browser window. Parameters can be filtered by filter-expr. Parameters to be stored as readings must be part of 'ccureadingfilter'. If option 'device' is specified parameters of device are read.

    • get <name> configdesc [device]
      Get description of configuration parameters of CCU channel or device if option 'device' is specified.

    • get <name> configlist [device] [<filter-expr>]
      Get configuration parameters of CCU channel. Parameters can be filtered by filter-expr. With option 'device' device parameters are listed.

    • get <name> datapoint <datapoint>
      Get value of a CCU channel datapoint.

    • get <name> defaults
      Display default attributes for CCU device type.

    • get <name> deviceinfo [{State | Value}]
      Display all channels and datapoints of device with datapoint values and types.

    • get <name> devstate
      Get state of CCU device. Default datapoint STATE can be changed by setting attribute 'statedatapoint'. Command will fail if state datapoint does not exist in channel.

    • get <name> update [{State | Value}]
      Update all datapoints / readings of channel. With option 'State' the device is queried. This request method is more accurate but slower then 'Value'.

    Attributes

      To reduce the amount of events it's recommended to set attribute 'event-on-change-reading' to '.*'.

    • ccucalculate <value-type>:<reading>[:<dp-list>[;...]
      Calculate special values like dewpoint based on datapoints specified in dp-list. The result is stored in reading. The following values are supported:
      dewpoint = calculate dewpoint, dp-list = <temperature>,<humidity>
      abshumidity = calculate absolute humidity, dp-list = <temperature>,<humidity>
      inc = increment datapoint value considering reset of datapoint, dp-list = <counter-datapoint>
      min = calculate minimum continuously, dp-list = <datapoint>
      max = calculate maximum continuously, dp-list = <datapoint>
      sum = calculate sum continuously, dp-list = <datapoint>
      avg = calculate average continuously, dp-list = <datapoint>
      Example:
      dewpoint:taupunkt:1.TEMPERATURE,1.HUMIDITY

    • ccuflags {nochn0, trace}
      Control behaviour of device:
      ackState: Acknowledge command execution by setting STATE to error or success.
      nochn0: Prevent update of status channel 0 datapoints / readings.
      trace: Write log file information for operations related to this device.

    • ccuget {State | Value}
      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'.

    • ccureadings {0 | 1}
      If set to 1 values read from CCU will be stored as readings. Default is 1.

    • ccureadingfilter <filter-rule[;...]>
      Only datapoints matching specified expression are stored as readings.
      Syntax for filter-rule is either:
      [N:]{<channel-name>|<channel-number>}!<RegExp> or:
      [N:][<channel-number>.]<RegExp>
      If channel-name or channel-number is specified the following rule applies only to this channel. By default all datapoints will be stored as readings. Attribute ccudef-readingfilter of I/O device will be checked before this attribute.
      If a rule starts with 'N:' the filter is negated which means that a reading is stored if rule doesn't match.

    • ccureadingformat {address[lc] | name[lc] | datapoint[lc]}
      Set format of reading names. Default for virtual device groups is 'name'. The default for all other device types is 'datapoint'. If set to 'address' format of reading names is channel-address.datapoint. If set to 'name' format of reading names is channel-name.datapoint. If set to 'datapoint' format is channel-number.datapoint. With suffix 'lc' reading names are converted to lowercase.

    • ccureadingname <old-readingname-expr>:[+]<new-readingname>[;...]
      Set alternative or additional reading names or group readings. Only part of old reading name matching old-readingname-exptr is substituted by new-readingname. If new-readingname is preceded by '+' an additional reading is created. If old-readingname-expr matches more than one reading the values of these readings are stored in one reading. This makes sense only in some cases, i.e. if a device has several pressed_short datapoints and a reading should contain a value if any button is pressed.

      Examples:
      # Rename readings 0.LOWBAT and 0.LOW_BAT as battery
      attr mydev ccureadingname 0.(LOWBAT|LOW_BAT):battery
      # Add reading battery as a copy of readings LOWBAT and LOW_BAT.
      # Rename reading 4.SET_TEMPERATURE as desired-temp
      attr mydev ccureadingname 0.(LOWBAT|LOW_BAT):+battery;1.SET_TEMPERATURE:desired-temp
      # Store values of readings n.PRESS_SHORT in new reading pressed.
      # Value of pressed is 1/true if any button is pressed
      attr mydev ccureadingname [1-4].PRESSED_SHORT:+pressed

    • ccuscaleval <[channelno.]datapoint>:<factor>[,...]
      ccuscaleval <[!][channelno.]datapoint>:<min>:<max>:<minn>:<maxn>[,...]
      Scale, spread, shift and optionally reverse values before executing set datapoint commands or after executing get datapoint commands / before storing values in readings.
      If first syntax is used during get the value read from CCU is devided by factor. During set the value is multiplied by factor.
      With second syntax one must specify the interval in CCU (min,max) and the interval in FHEM (minn, maxn). The scaling factor is calculated automatically. If parameter datapoint starts with a '!' the resulting value is reversed.

      Example: Scale values of datapoint LEVEL for blind actor and reverse values
      attr myblind ccuscale !LEVEL:0:1:0:100

    • ccuverify {0 | 1 | 2}
      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 without any verification.

    • controldatapoint <datapoint>
      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:

      attr mydev controldatapoint SET_TEMPERATURE
      attr mydev webCmd control
      attr mydev widgetOverride control:slider,10,1,25

    • disable {0 | 1}
      Disable client device.

    • hmstatevals <subst-rule>[;...]
      Define building rules and substitutions for reading hmstate. Syntax of subst-rule is
      [=<reading>;]<datapoint-expr>!<{#n1-m1|regexp}>:<text>[,...]

      The syntax is almost the same as of attribute 'substitute', except there's no channel specification possible for datapoint and parameter datapoint-expr is a regular expression.
      The value of the I/O device attribute 'ccudef-hmstatevals' is appended to the value of this attribute. The default value of 'ccudef-hmstatevals' is '^UNREACH!(1|true):unreachable;LOW_?BAT!(1|true):warn_battery'. Normally one should not specify a substitution rule for the "good" value of an error datapoint (i.e. 0 for UNREACH). If none of the rules is matching, reading 'hmstate' is set to value of reading 'state'.
      Parameter text can contain variables in format ${varname}. The variable $value is substituted by the original datapoint value. All other variables must match with a valid datapoint name or a combination of channel number and datapoint name seperated by a '.'.
      Optionally the name of the HomeMatic state reading can be specified at the beginning of the attribute in format =<reading>;. The default reading name is 'hmstate'.

    • peer <datapoints>:<condition>: {ccu:<object>=<value>|hmccu:<object>=<value>| fhem:<command>}
      Logically peer datapoints of a HMCCUCHN or HMCCUDEV device with another device or any FHEM command.
      Parameter datapoints is a comma separated list of datapoints in format channelno.datapoint which can trigger the action.
      Parameter condition is a valid Perl expression which can contain channelno.datapoint names as variables. Variables must start with a '$' or a '%'. If a variable is preceded by a '$' the variable is substituted by the converted datapoint value (i.e. "on" instead of "true"). If variable is preceded by a '%' the raw value (i.e. "true") is used. If '$' or '%' is doubled the previous values will be used.
      If the result of this operation is true, the action specified after the second colon is executed. Three types of actions are supported:
      hmccu: Parameter object refers to a FHEM device/datapoint in format <device>:<channelno>.<datapoint>
      ccu: Parameter object refers to a CCU channel/datapoint in format <channel>.<datapoint>. channel can be a channel name or address.
      fhem: The specified command will be executed
      If action contains the string $value it is substituted by the current value of the datapoint which triggered the action. The attribute supports multiple peering rules separated by semicolons and optionally by newline characters.

      Examples:
      # Set FHEM device mydummy to value if formatted value of 1.STATE is 'on'
      attr mydev peer 1.STATE:'$1.STATE' eq 'on':fhem:set mydummy $value
      # Set 2.LEVEL of device myBlind to 100 if raw value of 1.STATE is 1
      attr mydev peer 1.STATE:'%1.STATE' eq '1':hmccu:myBlind:2.LEVEL=100
      # Set 1.STATE of device LEQ1234567 to true if 1.LEVEL < 100
      attr mydev peer 1.LEVEL:$1.LEVEL < 100:ccu:LEQ1234567:1.STATE=true
      # Set 1.STATE of device LEQ1234567 to true if current level is different from old level
      attr mydev peer 1.LEVEL:$1.LEVEL != $$1.LEVEL:ccu:LEQ1234567:1.STATE=true

    • statedatapoint <datapoint>
      Set state datapoint used by some commands like 'set devstate'.

    • statevals <text>:<text>[,...]
      Define substitution for values of set commands. The parameters text are available as set commands.

      Example:
      attr my_switch statevals on:true,off:false
      set my_switch on

    • stripnumber [<datapoint-expr>!]{0|1|2|-n|%fmt}[;...]
      Remove trailing digits or zeroes from floating point numbers, round or format numbers. If attribute is negative (-0 is valid) floating point values are rounded to the specified number of digits before they are stored in readings. The meaning of values 0,1,2 is:
      0 = Floating point numbers are stored as read from CCU (i.e. with trailing zeros)
      1 = Trailing zeros are stripped from floating point numbers except one digit.
      2 = All trailing zeros are stripped from floating point numbers.
      With %fmt one can specify any valid sprintf() format string.
      If datapoint-expr is specified the formatting applies only to datapoints matching the regular expression.
      Example:
      attr myDev stripnumber TEMPERATURE!%.2f degree

    • substexcl <reading-expr>
      Exclude values of readings matching reading-expr from substitution. This is helpful for reading 'control' if the reading is used for a slider widget and the corresponding datapoint is assigned to attribute statedatapoint and controldatapoint.

    • substitute <subst-rule>[;...]
      Define substitutions for datapoint/reading values. Syntax of subst-rule is

      [[<channelno>.]<datapoint>[,...]!]<{#n1-m1|regexp}>:<text>[,...]

      Parameter text can contain variables in format ${varname}. The variable ${value} is substituted by the original datapoint value. All other variables must match with a valid datapoint name or a combination of channel number and datapoint name seperated by a '.'.

      Example: Substitute the value of datapoint TEMPERATURE by the string 'T=val deg' and append current value of datapoint 1.HUMIDITY
      attr my_weather substitute TEMPERATURE!.+:T=${value} deg H=${1.HUMIDITY}%

      If rule expression starts with a hash sign a numeric datapoint value is substituted if it fits in the number range n <= value <= m.

      Example: Interpret LEVEL values 100 and 0 of dimmer as "on" and "off"
      attr my_dim substitute LEVEL!#0-0:off,#1-100:on
=end html =cut