88_HMCCUCHN.pm 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028
  1. ######################################################################
  2. #
  3. # 88_HMCCUCHN.pm
  4. #
  5. # $Id: 88_HMCCUCHN.pm 17355 2018-09-16 09:34:40Z zap $
  6. #
  7. # Version 4.3.002
  8. #
  9. # (c) 2018 zap (zap01 <at> t-online <dot> de)
  10. #
  11. ######################################################################
  12. #
  13. # define <name> HMCCUCHN <ccudev> [readonly] [defaults]
  14. # [iodev=<iodevname>]
  15. #
  16. # set <name> config [device] <parameter>=<value> [...]
  17. # set <name> control <value>
  18. # set <name> datapoint <datapoint> <value> [...]
  19. # set <name> defaults
  20. # set <name> devstate <value>
  21. # set <name> <stateval_cmds>
  22. # set <name> on-till <timestamp>
  23. # set <name> on-for-timer <ontime>
  24. # set <name> pct <level> [{ <ontime> | 0 } [<ramptime>]]
  25. # set <name> toggle
  26. #
  27. # get <name> config [device] [<filter-expr>]
  28. # get <name> configdesc [device]
  29. # get <name> configlist [device] [<filtet-expr>]
  30. # get <name> datapoint <datapoint>
  31. # get <name> defaults
  32. # get <name> deviceinfo
  33. # get <name> devstate
  34. # get <name> update
  35. #
  36. # attr <name> ccucalculate <value>:<reading>[:<dp-list>][...]
  37. # attr <name> ccuflags { ackState, nochn0, trace }
  38. # attr <name> ccuget { State | Value }
  39. # attr <name> ccureadings { 0 | 1 }
  40. # attr <name> ccureadingfilter <filter-rule>[;...]
  41. # attr <name> ccureadingformat { name[lc] | address[lc] | datapoint[lc] }
  42. # attr <name> ccureadingname <oldname>:<newname>[;...]
  43. # attr <name> ccuverify { 0 | 1 | 2 }
  44. # attr <name> controldatapoint <datapoint>
  45. # attr <name> disable { 0 | 1 }
  46. # attr <name> peer datapoints:condition:{hmccu:object=value|ccu:object=value|fhem:command}
  47. # attr <name> hmstatevals <subst-rule>[;...]
  48. # attr <name> statedatapoint <datapoint>
  49. # attr <name> statevals <text1>:<subtext1>[,...]
  50. # attr <name> substexcl <reading-expr>
  51. # attr <name> substitute <subst-rule>[;...]
  52. #
  53. ######################################################################
  54. # Requires modules 88_HMCCU.pm, HMCCUConf.pm
  55. ######################################################################
  56. package main;
  57. use strict;
  58. use warnings;
  59. use SetExtensions;
  60. # use Time::HiRes qw( gettimeofday usleep );
  61. sub HMCCUCHN_Initialize ($);
  62. sub HMCCUCHN_Define ($@);
  63. sub HMCCUCHN_InitDevice ($$);
  64. sub HMCCUCHN_Set ($@);
  65. sub HMCCUCHN_Get ($@);
  66. sub HMCCUCHN_Attr ($@);
  67. ######################################################################
  68. # Initialize module
  69. ######################################################################
  70. sub HMCCUCHN_Initialize ($)
  71. {
  72. my ($hash) = @_;
  73. $hash->{DefFn} = "HMCCUCHN_Define";
  74. $hash->{SetFn} = "HMCCUCHN_Set";
  75. $hash->{GetFn} = "HMCCUCHN_Get";
  76. $hash->{AttrFn} = "HMCCUCHN_Attr";
  77. $hash->{parseParams} = 1;
  78. $hash->{AttrList} = "IODev ccucalculate ".
  79. "ccuflags:multiple-strict,ackState,nochn0,trace ccureadingfilter ".
  80. "ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ".
  81. "ccureadingname:textField-long ".
  82. "ccureadings:0,1 ccuscaleval ccuverify:0,1,2 ccuget:State,Value controldatapoint ".
  83. "disable:0,1 hmstatevals:textField-long statedatapoint statevals substitute:textField-long ".
  84. "substexcl stripnumber peer:textField-long ". $readingFnAttributes;
  85. }
  86. ######################################################################
  87. # Define device
  88. ######################################################################
  89. sub HMCCUCHN_Define ($@)
  90. {
  91. my ($hash, $a, $h) = @_;
  92. my $name = $hash->{NAME};
  93. my $usage = "Usage: define $name HMCCUCHN {device} ['readonly'] ['defaults'] [iodev={iodevname}]";
  94. return $usage if (@$a < 3);
  95. my $devname = shift @$a;
  96. my $devtype = shift @$a;
  97. my $devspec = shift @$a;
  98. my $hmccu_hash = undef;
  99. # Store some definitions for delayed initialization
  100. $hash->{hmccu}{devspec} = $devspec;
  101. # Defaults
  102. $hash->{channels} = 1;
  103. $hash->{statevals} = 'devstate';
  104. # Parse optional command line parameters
  105. my $n = 0;
  106. my $arg = shift @$a;
  107. while (defined ($arg)) {
  108. return $usage if ($n == 3);
  109. if ($arg eq 'readonly') { $hash->{statevals} = $arg; }
  110. elsif ($arg eq 'defaults') {
  111. HMCCU_SetDefaults ($hash) if ($init_done);
  112. }
  113. else { return $usage; }
  114. $n++;
  115. $arg = shift @$a;
  116. }
  117. # IO device can be set by command line parameter iodev, otherwise try to detect IO device
  118. if (exists ($h->{iodev})) {
  119. return "Specified IO Device ".$h->{iodev}." does not exist" if (!exists ($defs{$h->{iodev}}));
  120. return "Specified IO Device ".$h->{iodev}." is not a HMCCU device"
  121. if ($defs{$h->{iodev}}->{TYPE} ne 'HMCCU');
  122. $hmccu_hash = $defs{$h->{iodev}};
  123. }
  124. else {
  125. # The following call will fail during FHEM start if CCU is not ready
  126. $hmccu_hash = HMCCU_FindIODevice ($devspec);
  127. }
  128. if ($init_done) {
  129. # Interactive define command while CCU not ready or no IO device defined
  130. if (!defined ($hmccu_hash)) {
  131. my ($ccuactive, $ccuinactive) = HMCCU_IODeviceStates ();
  132. if ($ccuinactive > 0) {
  133. return "CCU and/or IO device not ready. Please try again later";
  134. }
  135. else {
  136. return "Cannot detect IO device";
  137. }
  138. }
  139. }
  140. else {
  141. # CCU not ready during FHEM start
  142. if (!defined ($hmccu_hash) || $hmccu_hash->{ccustate} ne 'active') {
  143. Log3 $name, 2, "HMCCUCHN: [$devname] Cannot detect IO device, maybe CCU not ready. Trying later ...";
  144. readingsSingleUpdate ($hash, "state", "Pending", 1);
  145. $hash->{ccudevstate} = 'pending';
  146. return undef;
  147. }
  148. }
  149. # Initialize FHEM device, set IO device
  150. my $rc = HMCCUCHN_InitDevice ($hmccu_hash, $hash);
  151. return "Invalid or unknown CCU channel name or address" if ($rc == 1);
  152. return "Can't assign I/O device ".$hmccu_hash->{NAME} if ($rc == 2);
  153. return undef;
  154. }
  155. ######################################################################
  156. # Initialization of FHEM device.
  157. # Called during Define() or by HMCCU after CCU ready.
  158. # Return 0 on successful initialization or >0 on error:
  159. # 1 = Invalid channel name or address
  160. # 2 = Cannot assign IO device
  161. ######################################################################
  162. sub HMCCUCHN_InitDevice ($$) {
  163. my ($hmccu_hash, $dev_hash) = @_;
  164. my $devspec = $dev_hash->{hmccu}{devspec};
  165. return 1 if (!HMCCU_IsValidChannel ($hmccu_hash, $devspec, 7));
  166. my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($hmccu_hash, $devspec);
  167. return 1 if (!defined ($da));
  168. # Inform HMCCU device about client device
  169. return 2 if (!HMCCU_AssignIODevice ($dev_hash, $hmccu_hash->{NAME}, undef));
  170. $dev_hash->{ccuif} = $di;
  171. $dev_hash->{ccuaddr} = $da;
  172. $dev_hash->{ccuname} = $dn;
  173. $dev_hash->{ccutype} = $dt;
  174. readingsSingleUpdate ($dev_hash, "state", "Initialized", 1);
  175. $dev_hash->{ccudevstate} = 'active';
  176. return 0;
  177. }
  178. ######################################################################
  179. # Set attribute
  180. ######################################################################
  181. sub HMCCUCHN_Attr ($@)
  182. {
  183. my ($cmd, $name, $attrname, $attrval) = @_;
  184. my $hash = $defs{$name};
  185. if ($cmd eq "set") {
  186. return "Missing attribute value" if (!defined ($attrval));
  187. if ($attrname eq 'IODev') {
  188. $hash->{IODev} = $defs{$attrval};
  189. }
  190. elsif ($attrname eq 'statevals') {
  191. return "Device is read only" if ($hash->{statevals} eq 'readonly');
  192. $hash->{statevals} = "devstate";
  193. my @states = split /,/,$attrval;
  194. foreach my $st (@states) {
  195. my @statesubs = split /:/,$st;
  196. return "value := text:substext[,...]" if (@statesubs != 2);
  197. $hash->{statevals} .= '|'.$statesubs[0];
  198. }
  199. }
  200. }
  201. elsif ($cmd eq "del") {
  202. if ($attrname eq 'statevals') {
  203. $hash->{statevals} = "devstate";
  204. }
  205. }
  206. return undef;
  207. }
  208. #####################################
  209. # Set commands
  210. #####################################
  211. sub HMCCUCHN_Set ($@)
  212. {
  213. my ($hash, $a, $h) = @_;
  214. my $name = shift @$a;
  215. my $opt = shift @$a;
  216. my $rocmds = "clear config defaults:noArg";
  217. # Get I/O device, check device state
  218. return HMCCU_SetError ($hash, -19) if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending');
  219. return HMCCU_SetError ($hash, -3) if (!defined ($hash->{IODev}));
  220. return undef if ($hash->{statevals} eq 'readonly' && $opt ne '?' &&
  221. $opt !~ /^(clear|config|defaults)$/);
  222. my $disable = AttrVal ($name, "disable", 0);
  223. return undef if ($disable == 1);
  224. my $hmccu_hash = $hash->{IODev};
  225. if (HMCCU_IsRPCStateBlocking ($hmccu_hash)) {
  226. return undef if ($opt eq '?');
  227. return "HMCCUCHN: CCU busy";
  228. }
  229. my $ccutype = $hash->{ccutype};
  230. my $ccuaddr = $hash->{ccuaddr};
  231. my $ccuif = $hash->{ccuif};
  232. my $statevals = AttrVal ($name, 'statevals', '');
  233. my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', '');
  234. my $result = '';
  235. my $rc;
  236. if ($opt eq 'datapoint') {
  237. my $usage = "Usage: set $name datapoint {datapoint} {value} [...]";
  238. my %dpval;
  239. while (my $objname = shift @$a) {
  240. my $objvalue = shift @$a;
  241. return HMCCU_SetError ($hash, $usage) if (!defined ($objvalue));
  242. return HMCCU_SetError ($hash, -8)
  243. if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $objname, 2));
  244. $objvalue =~ s/\\_/%20/g;
  245. $objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
  246. $objname = $ccuif.'.'.$ccuaddr.'.'.$objname;
  247. $dpval{$objname} = $objvalue;
  248. }
  249. return HMCCU_SetError ($hash, $usage) if (scalar (keys %dpval) < 1);
  250. foreach my $dpt (keys %dpval) {
  251. $rc = HMCCU_SetDatapoint ($hash, $dpt, $dpval{$dpt});
  252. return HMCCU_SetError ($hash, $rc) if ($rc < 0);
  253. }
  254. return HMCCU_SetState ($hash, "OK");
  255. }
  256. elsif ($opt eq 'control') {
  257. return HMCCU_SetError ($hash, -14) if ($cd eq '');
  258. return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, $cd, 2));
  259. my $objvalue = shift @$a;
  260. return HMCCU_SetError ($hash, "Usage: set $name control {value}") if (!defined ($objvalue));
  261. $objvalue =~ s/\\_/%20/g;
  262. $objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
  263. my $objname = $ccuif.'.'.$ccuaddr.'.'.$cd;
  264. $rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
  265. return HMCCU_SetError ($hash, $rc) if ($rc < 0);
  266. return HMCCU_SetState ($hash, "OK");
  267. }
  268. elsif ($opt =~ /^($hash->{statevals})$/) {
  269. my $cmd = $1;
  270. my $objvalue = ($cmd ne 'devstate') ? $cmd : shift @$a;
  271. return HMCCU_SetError ($hash, -13) if ($sd eq '');
  272. return HMCCU_SetError ($hash, -8)
  273. if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $sd, 2));
  274. return HMCCU_SetError ($hash, "Usage: set $name devstate {value}") if (!defined ($objvalue));
  275. $objvalue =~ s/\\_/%20/g;
  276. $objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
  277. my $objname = $ccuif.'.'.$ccuaddr.'.'.$sd;
  278. $rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
  279. return HMCCU_SetError ($hash, $rc) if ($rc < 0);
  280. return HMCCU_SetState ($hash, "OK");
  281. }
  282. elsif ($opt eq 'toggle') {
  283. return HMCCU_SetError ($hash, -15) if ($statevals eq '' || !exists($hash->{statevals}));
  284. return HMCCU_SetError ($hash, -13) if ($sd eq '');
  285. return HMCCU_SetError ($hash, -8)
  286. if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $sd, 2));
  287. my $tstates = $hash->{statevals};
  288. $tstates =~ s/devstate\|//;
  289. my @states = split /\|/, $tstates;
  290. my $stc = scalar (@states);
  291. my $objname = $ccuif.'.'.$ccuaddr.'.'.$sd;
  292. ($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
  293. return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
  294. my $objvalue = '';
  295. my $st = 0;
  296. while ($st < $stc) {
  297. if ($states[$st] eq $result) {
  298. $objvalue = ($st == $stc-1) ? $states[0] : $states[$st+1];
  299. last;
  300. }
  301. else {
  302. $st++;
  303. }
  304. }
  305. return HMCCU_SetError ($hash, "Current device state doesn't match statevals")
  306. if ($objvalue eq '');
  307. $objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
  308. $rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
  309. return HMCCU_SetError ($hash, $rc) if ($rc < 0);
  310. return HMCCU_SetState ($hash, "OK");
  311. }
  312. elsif ($opt eq 'pct') {
  313. return HMCCU_SetError ($hash, "Can't find LEVEL datapoint for device type $ccutype")
  314. if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "LEVEL", 2));
  315. my $objname = '';
  316. my $objvalue = shift @$a;
  317. return HMCCU_SetError ($hash, "Usage: set $name pct {value} [{ontime} [{ramptime}]]")
  318. if (!defined ($objvalue));
  319. my $timespec = shift @$a;
  320. my $ramptime = shift @$a;
  321. # Set on time
  322. if (defined ($timespec)) {
  323. return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type $ccutype")
  324. if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "ON_TIME", 2));
  325. if ($timespec =~ /^[0-9]{2}:[0-9]{2}/) {
  326. my (undef, $h, $m, $s) = GetTimeSpec ($timespec);
  327. return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM or HH:MM:SS")
  328. if (!defined ($h));
  329. $s += $h*3600+$m*60;
  330. my @lt = localtime;
  331. my $cs = $lt[2]*3600+$lt[1]*60+$lt[0];
  332. $s += 86400 if ($cs > $s);
  333. $timespec = $s-$cs;
  334. }
  335. if ($timespec > 0) {
  336. $objname = $ccuif.'.'.$ccuaddr.'.ON_TIME';
  337. $rc = HMCCU_SetDatapoint ($hash, $objname, $timespec);
  338. return HMCCU_SetError ($hash, $rc) if ($rc < 0);
  339. }
  340. }
  341. # Set ramp time
  342. if (defined ($ramptime)) {
  343. return HMCCU_SetError ($hash, "Can't find RAMP_TIME datapoint for device type $ccutype")
  344. if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "RAMP_TIME", 2));
  345. $objname = $ccuif.'.'.$ccuaddr.'.RAMP_TIME';
  346. $rc = HMCCU_SetDatapoint ($hash, $objname, $ramptime);
  347. return HMCCU_SetError ($hash, $rc) if ($rc < 0);
  348. }
  349. # Set level
  350. $objname = $ccuif.'.'.$ccuaddr.'.LEVEL';
  351. $rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
  352. return HMCCU_SetError ($hash, $rc) if ($rc < 0);
  353. return HMCCU_SetState ($hash, "OK");
  354. }
  355. elsif ($opt eq 'on-for-timer' || $opt eq 'on-till') {
  356. return HMCCU_SetError ($hash, -15) if ($statevals eq '' || !exists($hash->{statevals}));
  357. return HMCCU_SetError ($hash, "No state value for 'on' defined")
  358. if ("on" !~ /($hash->{statevals})/);
  359. return HMCCU_SetError ($hash, -13) if ($sd eq '');
  360. return HMCCU_SetError ($hash, -8)
  361. if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $sd, 2));
  362. return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type")
  363. if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "ON_TIME", 2));
  364. my $timespec = shift @$a;
  365. return HMCCU_SetError ($hash, "Usage: set $name $opt {ontime-spec}")
  366. if (!defined ($timespec));
  367. if ($opt eq 'on-till') {
  368. my (undef, $h, $m, $s) = GetTimeSpec ($timespec);
  369. return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM or HH:MM:SS")
  370. if (!defined ($h));
  371. $s += $h*3600+$m*60;
  372. my @lt = localtime;
  373. my $cs = $lt[2]*3600+$lt[1]*60+$lt[0];
  374. $s += 86400 if ($cs > $s);
  375. $timespec = $s-$cs;
  376. }
  377. # Set time
  378. my $objname = $ccuif.'.'.$ccuaddr.'.ON_TIME';
  379. $rc = HMCCU_SetDatapoint ($hash, $objname, $timespec);
  380. return HMCCU_SetError ($hash, $rc) if ($rc < 0);
  381. # Set state
  382. $objname = $ccuif.'.'.$ccuaddr.'.'.$sd;
  383. my $objvalue = HMCCU_Substitute ("on", $statevals, 1, undef, '');
  384. $rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
  385. return HMCCU_SetError ($hash, $rc) if ($rc < 0);
  386. return HMCCU_SetState ($hash, "OK");
  387. }
  388. elsif ($opt eq 'clear') {
  389. my $rnexp = shift @$a;
  390. $rnexp = '.*' if (!defined ($rnexp));
  391. my @readlist = keys %{$hash->{READINGS}};
  392. foreach my $rd (@readlist) {
  393. delete ($hash->{READINGS}{$rd}) if ($rd ne 'state' && $rd ne 'control' && $rd =~ /$rnexp/);
  394. }
  395. }
  396. elsif ($opt eq 'config') {
  397. return HMCCU_SetError ($hash, "Usage: set $name config [device] {parameter}={value} [...]")
  398. if ((scalar keys %{$h}) < 1);
  399. my $ccuobj = $ccuaddr;
  400. my $par = shift @$a;
  401. if (defined ($par) && $par eq 'device') {
  402. ($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr);
  403. }
  404. my $rc = HMCCU_RPCSetConfig ($hash, $ccuobj, $h);
  405. return HMCCU_SetError ($hash, $rc) if ($rc < 0);
  406. return HMCCU_SetState ($hash, "OK");
  407. }
  408. elsif ($opt eq 'defaults') {
  409. my $rc = HMCCU_SetDefaults ($hash);
  410. return HMCCU_SetError ($hash, "HMCCU: No default attributes found") if ($rc == 0);
  411. return HMCCU_SetState ($hash, "OK");
  412. }
  413. else {
  414. return "HMCCUCHN: Unknown argument $opt, choose one of ".$rocmds
  415. if ($hash->{statevals} eq 'readonly');
  416. my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of clear config control datapoint defaults:noArg devstate";
  417. if ($hash->{statevals} ne '') {
  418. my @cmdlist = split /\|/,$hash->{statevals};
  419. shift @cmdlist;
  420. $retmsg .= ':'.join(',',@cmdlist) if (@cmdlist > 0);
  421. foreach my $sv (@cmdlist) {
  422. $retmsg .= ' '.$sv.':noArg';
  423. }
  424. $retmsg .= " toggle:noArg";
  425. $retmsg .= " on-for-timer on-till"
  426. if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $ccuaddr, "ON_TIME", 2));
  427. $retmsg .= " pct"
  428. if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $ccuaddr, "LEVEL", 2));
  429. }
  430. return $retmsg;
  431. }
  432. }
  433. #####################################
  434. # Get commands
  435. #####################################
  436. sub HMCCUCHN_Get ($@)
  437. {
  438. my ($hash, $a, $h) = @_;
  439. my $name = shift @$a;
  440. my $opt = shift @$a;
  441. return HMCCU_SetError ($hash, -3) if (!defined ($hash->{IODev}));
  442. my $disable = AttrVal ($name, "disable", 0);
  443. return undef if ($disable == 1);
  444. my $hmccu_hash = $hash->{IODev};
  445. if (HMCCU_IsRPCStateBlocking ($hmccu_hash)) {
  446. return undef if ($opt eq '?');
  447. return "HMCCUCHN: CCU busy";
  448. }
  449. my $ccutype = $hash->{ccutype};
  450. my $ccuaddr = $hash->{ccuaddr};
  451. my $ccuif = $hash->{ccuif};
  452. my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', '');
  453. my $ccureadings = AttrVal ($name, "ccureadings", 1);
  454. my $result = '';
  455. my $rc;
  456. if ($opt eq 'devstate') {
  457. return HMCCU_SetError ($hash, -13) if ($sd eq '');
  458. return HMCCU_SetError ($hash, -8)
  459. if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $sd, 1));
  460. my $objname = $ccuif.'.'.$ccuaddr.'.'.$sd;
  461. ($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
  462. return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
  463. return $ccureadings ? undef : $result;
  464. }
  465. elsif ($opt eq 'datapoint') {
  466. my $objname = shift @$a;
  467. return HMCCU_SetError ($hash, "Usage: get $name datapoint {datapoint}")
  468. if (!defined ($objname));
  469. return HMCCU_SetError ($hash, -8)
  470. if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $objname, 1));
  471. $objname = $ccuif.'.'.$ccuaddr.'.'.$objname;
  472. ($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
  473. return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
  474. return $ccureadings ? undef : $result;
  475. }
  476. elsif ($opt eq 'update') {
  477. my $ccuget = shift @$a;
  478. $ccuget = 'Attr' if (!defined ($ccuget));
  479. if ($ccuget !~ /^(Attr|State|Value)$/) {
  480. return HMCCU_SetError ($hash, "Usage: get $name update [{'State'|'Value'}]");
  481. }
  482. $rc = HMCCU_GetUpdate ($hash, $ccuaddr, $ccuget);
  483. return HMCCU_SetError ($hash, $rc) if ($rc < 0);
  484. return undef;
  485. }
  486. elsif ($opt eq 'deviceinfo') {
  487. my $ccuget = shift @$a;
  488. $ccuget = 'Attr' if (!defined ($ccuget));
  489. if ($ccuget !~ /^(Attr|State|Value)$/) {
  490. return HMCCU_SetError ($hash, "Usage: get $name deviceinfo [{'State'|'Value'}]");
  491. }
  492. my ($a, $c) = split(":", $hash->{ccuaddr});
  493. $result = HMCCU_GetDeviceInfo ($hash, $a, $ccuget);
  494. return HMCCU_SetError ($hash, -2) if ($result eq '');
  495. return HMCCU_FormatDeviceInfo ($result);
  496. }
  497. elsif ($opt eq 'config') {
  498. my $ccuobj = $ccuaddr;
  499. my $par = shift @$a;
  500. if (defined ($par)) {
  501. if ($par eq 'device') {
  502. ($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr);
  503. $par = shift @$a;
  504. }
  505. }
  506. $par = '.*' if (!defined ($par));
  507. my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset", $par);
  508. return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0);
  509. return $ccureadings ? undef : $res;
  510. }
  511. elsif ($opt eq 'configlist') {
  512. my $ccuobj = $ccuaddr;
  513. my $par = shift @$a;
  514. if (defined ($par)) {
  515. if ($par eq 'device') {
  516. ($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr);
  517. $par = shift @$a;
  518. }
  519. }
  520. $par = '.*' if (!defined ($par));
  521. my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "listParamset", $par);
  522. return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0);
  523. return $res;
  524. }
  525. elsif ($opt eq 'configdesc') {
  526. my $ccuobj = $ccuaddr;
  527. my $par = shift @$a;
  528. if (defined ($par) && $par eq 'device') {
  529. ($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr);
  530. }
  531. my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription", undef);
  532. return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0);
  533. return $res;
  534. }
  535. elsif ($opt eq 'defaults') {
  536. $result = HMCCU_GetDefaults ($hash, 0);
  537. return $result;
  538. }
  539. else {
  540. my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of devstate:noArg defaults:noArg datapoint";
  541. my ($a, $c) = split(":", $hash->{ccuaddr});
  542. my @valuelist;
  543. my $valuecount = HMCCU_GetValidDatapoints ($hash, $hash->{ccutype}, $c, 1, \@valuelist);
  544. $retmsg .= ":".join(",",@valuelist) if ($valuecount > 0);
  545. $retmsg .= " update:noArg deviceinfo config configlist configdesc:noArg";
  546. return $retmsg;
  547. }
  548. }
  549. 1;
  550. =pod
  551. =item device
  552. =item summary controls HMCCU client devices for Homematic CCU2 - FHEM integration
  553. =begin html
  554. <a name="HMCCUCHN"></a>
  555. <h3>HMCCUCHN</h3>
  556. <ul>
  557. The module implements Homematic CCU channels as client devices for HMCCU. A HMCCU I/O device must
  558. exist before a client device can be defined. If a CCU channel is not found execute command
  559. 'get devicelist' in I/O device.
  560. </br></br>
  561. <a name="HMCCUCHNdefine"></a>
  562. <b>Define</b><br/><br/>
  563. <ul>
  564. <code>define &lt;name&gt; HMCCUCHN {&lt;channel-name&gt; | &lt;channel-address&gt;}
  565. [readonly] [defaults] [iodev=&lt;iodev-name&gt;]</code>
  566. <br/><br/>
  567. If option 'readonly' is specified no set command will be available. With option 'defaults'
  568. some default attributes depending on CCU device type will be set. Default attributes are only
  569. available for some device types.<br/>
  570. The define command accepts a CCU2 channel name or channel address as parameter.
  571. <br/><br/>
  572. Examples:<br/>
  573. <code>define window_living HMCCUCHN WIN-LIV-1 readonly</code><br/>
  574. <code>define temp_control HMCCUCHN BidCos-RF.LEQ1234567:1</code>
  575. <br/><br/>
  576. The interface part of a channel address must not be specified. The default is 'BidCos-RF'.
  577. Channel addresses can be found with command 'get deviceinfo &lt;devicename&gt;' executed
  578. in I/O device.
  579. </ul>
  580. <br/>
  581. <a name="HMCCUCHNset"></a>
  582. <b>Set</b><br/><br/>
  583. <ul>
  584. <li><b>set &lt;name&gt; clear [&lt;reading-exp&gt;]</b><br/>
  585. Delete readings matching specified reading name expression. Default expression is '.*'.
  586. Readings 'state' and 'control' are not deleted.
  587. </li><br/>
  588. <li><b>set &lt;name&gt; config [device] [&lt;rpcport&gt;] &lt;parameter&gt;=&lt;value&gt;]
  589. [...]</b><br/>
  590. Set config parameters of CCU channel. This is equal to setting device parameters in CCU.
  591. Valid parameters can be listed by using commands 'get configdesc' or 'get configlist'.
  592. With option 'device' specified parameters are set in device instead of channel.
  593. </li><br/>
  594. <li><b>set &lt;name&gt; datapoint &lt;datapoint&gt; &lt;value&gt; [...]</b><br/>
  595. Set datapoint values of a CCU channel. If parameter <i>value</i> contains special
  596. character \_ it's substituted by blank.
  597. <br/><br/>
  598. Examples:<br/>
  599. <code>set temp_control datapoint SET_TEMPERATURE 21</code><br/>
  600. <code>set temp_control datapoint AUTO_MODE 1 SET_TEMPERATURE 21</code>
  601. </li><br/>
  602. <li><b>set &lt;name&gt; defaults</b><br/>
  603. Set default attributes for CCU device type. Default attributes are only available for
  604. some device types and for some channels of a device type.
  605. </li><br/>
  606. <li><b>set &lt;name&gt; devstate &lt;value&gt;</b><br/>
  607. Set state of a CCU device channel. The state datapoint of a channel must be defined
  608. by setting attribute 'statedatapoint' to a valid datapoint name.
  609. <br/><br/>
  610. Example:<br/>
  611. <code>set light_entrance devstate true</code>
  612. </li><br/>
  613. <li><b>set &lt;name&gt; &lt;statevalue&gt;</b><br/>
  614. Set state of a CCU device channel to <i>StateValue</i>. The state datapoint of a channel
  615. must be defined by setting attribute 'statedatapoint'. The available state values must
  616. be defined by setting attribute 'statevals'.
  617. <br/><br/>
  618. Example: Turn switch on<br/>
  619. <code>
  620. attr myswitch statedatapoint STATE<br/>
  621. attr myswitch statevals on:true,off:false<br/>
  622. set myswitch on
  623. </code>
  624. </li><br/>
  625. <li><b>set &lt;name&gt; toggle</b><br/>
  626. Toggle state datapoint between values defined by attribute 'statevals'. This command is
  627. only available if attribute 'statevals' is set. Toggling supports more than two state
  628. values.
  629. <br/><br/>
  630. Example: Toggle blind actor<br/>
  631. <code>
  632. attr myswitch statedatapoint LEVEL<br/>
  633. attr myswitch statevals up:100,down:0<br/>
  634. set myswitch toggle
  635. </code>
  636. </li><br/>
  637. <li><b>set &lt;name&gt; on-for-timer &lt;ontime&gt;</b><br/>
  638. Switch device on for specified number of seconds. This command is only available if
  639. channel contains a datapoint ON_TIME. The attribute 'statevals' must contain at least a
  640. value for 'on'. The attribute 'statedatapoint' must be set to a writeable datapoint.
  641. <br/><br/>
  642. Example: Turn switch on for 300 seconds<br/>
  643. <code>
  644. attr myswitch statedatapoint STATE<br/>
  645. attr myswitch statevals on:true,off:false<br/>
  646. set myswitch on-for-timer 300
  647. </code>
  648. </li><br/>
  649. <li><b>set &lt;name&gt; on-till &lt;timestamp&gt;</b><br/>
  650. Switch device on until <i>timestamp</i>. Parameter <i>timestamp</i> can be a time in
  651. format HH:MM or HH:MM:SS. This command is only available if channel contains a datapoint
  652. ON_TIME. The attribute 'statevals' must contain at least a value for 'on'. The Attribute
  653. 'statedatapoint' must be set to a writeable datapoint.
  654. </li><br/>
  655. <li><b>set &lt;name&gt; pct &lt;value&gt; [&lt;ontime&gt; [&lt;ramptime&gt;]]</b><br/>
  656. Set datapoint LEVEL of a channel to the specified <i>value</i>. Optionally a <i>ontime</i>
  657. and a <i>ramptime</i> (both in seconds) can be specified. This command is only available
  658. if channel contains at least a datapoint LEVEL and optionally datapoints ON_TIME and
  659. RAMP_TIME. The parameter <i>ontime</i> can be specified in seconds or as timestamp in
  660. format HH:MM or HH:MM:SS. If <i>ontime</i> is 0 it's ignored. This syntax can be used to
  661. modify the ramp time only.
  662. <br/><br/>
  663. Example: Turn dimmer on for 600 second. Increase light to 100% over 10 seconds<br>
  664. <code>
  665. attr myswitch statedatapoint LEVEL<br/>
  666. attr myswitch statevals on:100,off:0<br/>
  667. set myswitch pct 100 600 10
  668. </code>
  669. </li><br/>
  670. </ul>
  671. <br/>
  672. <a name="HMCCUCHNget"></a>
  673. <b>Get</b><br/><br/>
  674. <ul>
  675. <li><b>get &lt;name&gt; config [device] [&lt;filter-expr&gt;]</b><br/>
  676. Get configuration parameters of CCU channel. If attribute 'ccureadings' is 0 results
  677. are displayed in browser window. Parameters can be filtered by <i>filter-expr</i>.
  678. Parameters to be stored as readings must be part of 'ccureadingfilter'. If option
  679. 'device' is specified parameters of device are read.
  680. </li><br/>
  681. <li><b>get &lt;name&gt; configdesc [device]</b><br/>
  682. Get description of configuration parameters of CCU channel or device if option 'device'
  683. is specified.
  684. </li><br/>
  685. <li><b>get &lt;name&gt; configlist [device] [&lt;filter-expr&gt;]</b><br/>
  686. Get configuration parameters of CCU channel. Parameters can be filtered by
  687. <i>filter-expr</i>. With option 'device' device parameters are listed.
  688. </li><br/>
  689. <li><b>get &lt;name&gt; datapoint &lt;datapoint&gt;</b><br/>
  690. Get value of a CCU channel datapoint.
  691. </li><br/>
  692. <li><b>get &lt;name&gt; defaults</b><br/>
  693. Display default attributes for CCU device type.
  694. </li><br/>
  695. <li><b>get &lt;name&gt; deviceinfo [{State | <u>Value</u>}]</b><br/>
  696. Display all channels and datapoints of device with datapoint values and types.
  697. </li><br/>
  698. <li><b>get &lt;name&gt; devstate</b><br/>
  699. Get state of CCU device. Default datapoint STATE can be changed by setting
  700. attribute 'statedatapoint'. Command will fail if state datapoint does not exist in
  701. channel.
  702. </li><br/>
  703. <li><b>get &lt;name&gt; update [{State | <u>Value</u>}]</b><br/>
  704. Update all datapoints / readings of channel. With option 'State' the device is queried.
  705. This request method is more accurate but slower then 'Value'.
  706. </li>
  707. </ul>
  708. <br/>
  709. <a name="HMCCUCHNattr"></a>
  710. <b>Attributes</b><br/><br/>
  711. <ul>
  712. To reduce the amount of events it's recommended to set attribute 'event-on-change-reading'
  713. to '.*'.
  714. <br/><br/>
  715. <li><b>ccucalculate &lt;value-type&gt;:&lt;reading&gt;[:&lt;dp-list&gt;[;...]</b><br/>
  716. Calculate special values like dewpoint based on datapoints specified in
  717. <i>dp-list</i>. The result is stored in <i>reading</i>. The following <i>values</i>
  718. are supported:<br/>
  719. dewpoint = calculate dewpoint, <i>dp-list</i> = &lt;temperature&gt;,&lt;humidity&gt;<br/>
  720. abshumidity = calculate absolute humidity, <i>dp-list</i> = &lt;temperature&gt;,&lt;humidity&gt;<br/>
  721. inc = increment datapoint value considering reset of datapoint, <i>dp-list</i> = &lt;counter-datapoint&gt;<br/>
  722. min = calculate minimum continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/>
  723. max = calculate maximum continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/>
  724. sum = calculate sum continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/>
  725. avg = calculate average continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/>
  726. Example:<br/>
  727. <code>dewpoint:taupunkt:1.TEMPERATURE,1.HUMIDITY</code>
  728. </li><br/>
  729. <li><b>ccuflags {nochn0, trace}</b><br/>
  730. Control behaviour of device:<br/>
  731. ackState: Acknowledge command execution by setting STATE to error or success.<br/>
  732. nochn0: Prevent update of status channel 0 datapoints / readings.<br/>
  733. trace: Write log file information for operations related to this device.
  734. </li><br/>
  735. <li><b>ccuget {State | <u>Value</u>}</b><br/>
  736. Set read access method for CCU channel datapoints. Method 'State' is slower than 'Value'
  737. because each request is sent to the device. With method 'Value' only CCU is queried.
  738. Default is 'Value'.
  739. </li><br/>
  740. <li><b>ccureadings {0 | <u>1</u>}</b><br/>
  741. If set to 1 values read from CCU will be stored as readings. Default is 1.
  742. </li><br/>
  743. <li><b>ccureadingfilter &lt;filter-rule[;...]&gt;</b><br/>
  744. Only datapoints matching specified expression are stored as readings.<br/>
  745. Syntax for <i>filter-rule</i> is either:<br/>
  746. [N:]{&lt;channel-name&gt;|&lt;channel-number&gt;}!&lt;RegExp&gt; or:<br/>
  747. [N:][&lt;channel-number&gt;.]&lt;RegExp&gt;<br/>
  748. If <i>channel-name</i> or <i>channel-number</i> is specified the following rule
  749. applies only to this channel.
  750. By default all datapoints will be stored as readings. Attribute ccudef-readingfilter
  751. of I/O device will be checked before this attribute.<br/>
  752. If a rule starts with 'N:' the filter is negated which means that a reading is
  753. stored if rule doesn't match.
  754. </li><br/>
  755. <li><b>ccureadingformat {address[lc] | name[lc] | datapoint[lc]}</b><br/>
  756. Set format of reading names. Default for virtual device groups is 'name'. The default for all
  757. other device types is 'datapoint'. If set to 'address' format of reading names
  758. is channel-address.datapoint. If set to 'name' format of reading names is
  759. channel-name.datapoint. If set to 'datapoint' format is channel-number.datapoint. With
  760. suffix 'lc' reading names are converted to lowercase.
  761. </li><br/>
  762. <li><b>ccureadingname &lt;old-readingname-expr&gt;:[+]&lt;new-readingname&gt;[;...]</b><br/>
  763. Set alternative or additional reading names or group readings. Only part of old reading
  764. name matching <i>old-readingname-exptr</i> is substituted by <i>new-readingname</i>.
  765. If <i>new-readingname</i> is preceded by '+' an additional reading is created. If
  766. <i>old-readingname-expr</i> matches more than one reading the values of these readings
  767. are stored in one reading. This makes sense only in some cases, i.e. if a device has
  768. several pressed_short datapoints and a reading should contain a value if any button
  769. is pressed.<br/><br/>
  770. Examples:<br/>
  771. <code>
  772. # Rename readings 0.LOWBAT and 0.LOW_BAT as battery<br/>
  773. attr mydev ccureadingname 0.(LOWBAT|LOW_BAT):battery<br/>
  774. # Add reading battery as a copy of readings LOWBAT and LOW_BAT.<br/>
  775. # Rename reading 4.SET_TEMPERATURE as desired-temp<br/>
  776. attr mydev ccureadingname 0.(LOWBAT|LOW_BAT):+battery;1.SET_TEMPERATURE:desired-temp<br/>
  777. # Store values of readings n.PRESS_SHORT in new reading pressed.<br/>
  778. # Value of pressed is 1/true if any button is pressed<br/>
  779. attr mydev ccureadingname [1-4].PRESSED_SHORT:+pressed
  780. </code>
  781. </li><br/>
  782. <li><b>ccuscaleval &lt;[channelno.]datapoint&gt;:&lt;factor&gt;[,...]</b><br/>
  783. <b>ccuscaleval &lt;[!][channelno.]datapoint&gt;:&lt;min&gt;:&lt;max&gt;:&lt;minn&gt;:&lt;maxn&gt;[,...]
  784. </b><br/>
  785. Scale, spread, shift and optionally reverse values before executing set datapoint commands
  786. or after executing get datapoint commands / before storing values in readings.<br/>
  787. If first syntax is used during get the value read from CCU is devided by <i>factor</i>.
  788. During set the value is multiplied by factor.<br/>
  789. With second syntax one must specify the interval in CCU (<i>min,max</i>) and the interval
  790. in FHEM (<i>minn, maxn</i>). The scaling factor is calculated automatically. If parameter
  791. <i>datapoint</i> starts with a '!' the resulting value is reversed.
  792. <br/><br/>
  793. Example: Scale values of datapoint LEVEL for blind actor and reverse values<br/>
  794. <code>
  795. attr myblind ccuscale !LEVEL:0:1:0:100
  796. </code>
  797. </li><br/>
  798. <li><b>ccuverify {<u>0</u> | 1 | 2}</b><br/>
  799. If set to 1 a datapoint is read for verification after set operation. If set to 2 the
  800. corresponding reading will be set to the new value directly after setting a datapoint
  801. in CCU without any verification.
  802. </li><br/>
  803. <li><b>controldatapoint &lt;datapoint&gt;</b><br/>
  804. Set datapoint for device control. Can be use to realize user defined control elements for
  805. setting control datapoint. For example if datapoint of thermostat control is
  806. SET_TEMPERATURE one can define a slider for setting the destination temperature with
  807. following attributes:<br/><br/>
  808. attr mydev controldatapoint SET_TEMPERATURE<br/>
  809. attr mydev webCmd control<br/>
  810. attr mydev widgetOverride control:slider,10,1,25
  811. </li><br/>
  812. <li><b>disable {<u>0</u> | 1}</b><br/>
  813. Disable client device.
  814. </li><br/>
  815. <li><b>hmstatevals &lt;subst-rule&gt;[;...]</b><br/>
  816. Define building rules and substitutions for reading hmstate. Syntax of <i>subst-rule</i>
  817. is<br/>
  818. [=&lt;reading&gt;;]&lt;datapoint-expr&gt;!&lt;{#n1-m1|regexp}&gt;:&lt;text&gt;[,...]
  819. <br/><br/>
  820. The syntax is almost the same as of attribute 'substitute', except there's no channel
  821. specification possible for datapoint and parameter <i>datapoint-expr</i> is a regular
  822. expression.<br/>
  823. The value of the I/O device attribute 'ccudef-hmstatevals' is appended to the value of
  824. this attribute. The default value of 'ccudef-hmstatevals' is
  825. '^UNREACH!(1|true):unreachable;LOW_?BAT!(1|true):warn_battery'.
  826. Normally one should not specify a substitution rule for the "good" value of an error
  827. datapoint (i.e. 0 for UNREACH). If none of the rules is matching, reading 'hmstate' is set
  828. to value of reading 'state'.<br/>
  829. Parameter <i>text</i> can contain variables in format ${<i>varname</i>}. The variable
  830. $value is substituted by the original datapoint value. All other variables must match
  831. with a valid datapoint name or a combination of channel number and datapoint name
  832. seperated by a '.'.<br/>
  833. Optionally the name of the HomeMatic state reading can be specified at the beginning of
  834. the attribute in format =&lt;reading&gt;;. The default reading name is 'hmstate'.
  835. </li><br/>
  836. <li><b>peer &lt;datapoints&gt;:&lt;condition&gt;:
  837. {ccu:&lt;object&gt;=&lt;value&gt;|hmccu:&lt;object&gt;=&lt;value&gt;|
  838. fhem:&lt;command&gt;}</b><br/>
  839. Logically peer datapoints of a HMCCUCHN or HMCCUDEV device with another device or any
  840. FHEM command.<br/>
  841. Parameter <i>datapoints</i> is a comma separated list of datapoints in format
  842. <i>channelno.datapoint</i> which can trigger the action.<br/>
  843. Parameter <i>condition</i> is a valid Perl expression which can contain
  844. <i>channelno.datapoint</i> names as variables. Variables must start with a '$' or a '%'.
  845. If a variable is preceded by a '$' the variable is substituted by the converted datapoint
  846. value (i.e. "on" instead of "true"). If variable is preceded by a '%' the raw value
  847. (i.e. "true") is used. If '$' or '%' is doubled the previous values will be used.<br/>
  848. If the result of this operation is true, the action specified after the second colon
  849. is executed. Three types of actions are supported:<br/>
  850. <b>hmccu</b>: Parameter <i>object</i> refers to a FHEM device/datapoint in format
  851. &lt;device&gt;:&lt;channelno&gt;.&lt;datapoint&gt;<br/>
  852. <b>ccu</b>: Parameter <i>object</i> refers to a CCU channel/datapoint in format
  853. &lt;channel&gt;.&lt;datapoint&gt;. <i>channel</i> can be a channel name or address.<br/>
  854. <b>fhem</b>: The specified <i>command</i> will be executed<br/>
  855. If action contains the string $value it is substituted by the current value of the
  856. datapoint which triggered the action. The attribute supports multiple peering rules
  857. separated by semicolons and optionally by newline characters.<br/><br/>
  858. Examples:<br/>
  859. # Set FHEM device mydummy to value if formatted value of 1.STATE is 'on'<br/>
  860. <code>attr mydev peer 1.STATE:'$1.STATE' eq 'on':fhem:set mydummy $value</code><br/>
  861. # Set 2.LEVEL of device myBlind to 100 if raw value of 1.STATE is 1<br/>
  862. <code>attr mydev peer 1.STATE:'%1.STATE' eq '1':hmccu:myBlind:2.LEVEL=100</code><br/>
  863. # Set 1.STATE of device LEQ1234567 to true if 1.LEVEL < 100<br/>
  864. <code>attr mydev peer 1.LEVEL:$1.LEVEL < 100:ccu:LEQ1234567:1.STATE=true</code><br/>
  865. # Set 1.STATE of device LEQ1234567 to true if current level is different from old level<br/>
  866. <code>attr mydev peer 1.LEVEL:$1.LEVEL != $$1.LEVEL:ccu:LEQ1234567:1.STATE=true</code><br/>
  867. </li><br/>
  868. <li><b>statedatapoint &lt;datapoint&gt;</b><br/>
  869. Set state datapoint used by some commands like 'set devstate'.
  870. </li><br/>
  871. <li><b>statevals &lt;text&gt;:&lt;text&gt;[,...]</b><br/>
  872. Define substitution for values of set commands. The parameters <i>text</i> are available
  873. as set commands.
  874. <br/><br/>
  875. Example:<br/>
  876. <code>
  877. attr my_switch statevals on:true,off:false<br/>
  878. set my_switch on
  879. </code>
  880. </li><br/>
  881. <li><b>stripnumber [&lt;datapoint-expr&gt;!]{0|1|2|-n|%fmt}[;...]</b><br/>
  882. Remove trailing digits or zeroes from floating point numbers, round or format
  883. numbers. If attribute is negative (-0 is valid) floating point values are rounded
  884. to the specified number of digits before they are stored in readings. The meaning of
  885. values 0,1,2 is:<br/>
  886. 0 = Floating point numbers are stored as integer.<br/>
  887. 1 = Trailing zeros are stripped from floating point numbers except one digit.<br/>
  888. 2 = All trailing zeros are stripped from floating point numbers.<br/>
  889. With %fmt one can specify any valid sprintf() format string.<br/>
  890. If <i>datapoint-expr</i> is specified the formatting applies only to datapoints
  891. matching the regular expression.<br/>
  892. Example:<br>
  893. <code>
  894. attr myDev stripnumber TEMPERATURE!%.2f degree
  895. </code>
  896. </li><br/>
  897. <li><b>substexcl &lt;reading-expr&gt;</b><br/>
  898. Exclude values of readings matching <i>reading-expr</i> from substitution. This is helpful
  899. for reading 'control' if the reading is used for a slider widget and the corresponding
  900. datapoint is assigned to attribute statedatapoint and controldatapoint.
  901. </li><br/>
  902. <li><b>substitute &lt;subst-rule&gt;[;...]</b><br/>
  903. Define substitutions for datapoint/reading values. Syntax of <i>subst-rule</i> is<br/><br/>
  904. [[&lt;channelno&gt;.]&lt;datapoint&gt;[,...]!]&lt;{#n1-m1|regexp}&gt;:&lt;text&gt;[,...]
  905. <br/><br/>
  906. Parameter <i>text</i> can contain variables in format ${<i>varname</i>}. The variable
  907. ${value} is
  908. substituted by the original datapoint value. All other variables must match with a valid
  909. datapoint name or a combination of channel number and datapoint name seperated by a '.'.
  910. <br/><br/>
  911. Example: Substitute the value of datapoint TEMPERATURE by the string
  912. 'T=<i>val</i> deg' and append current value of datapoint 1.HUMIDITY<br/>
  913. <code>
  914. attr my_weather substitute TEMPERATURE!.+:T=${value} deg H=${1.HUMIDITY}%
  915. </code><br/><br/>
  916. If rule expression starts with a hash sign a numeric datapoint value is substituted if
  917. it fits in the number range n &lt;= value &lt;= m.
  918. <br/><br/>
  919. Example: Interpret LEVEL values 100 and 0 of dimmer as "on" and "off"<br/>
  920. <code>
  921. attr my_dim substitute LEVEL!#0-0:off,#1-100:on
  922. </code>
  923. </li>
  924. </ul>
  925. </ul>
  926. =end html
  927. =cut