10_KOPP_FC.pm 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. # $Id: 10_KOPP_FC.pm 12860 2016-12-21 21:09:41Z RaspII $
  2. ##########################################################################################################################################################################################
  3. #
  4. # Kopp Free Control protocol module for FHEM
  5. # (c) Claus M.
  6. #
  7. # This modul is currenly under construction and will only work if you flashed your CCD device with hexfile from:
  8. # svn+ssh://raspii@svn.code.sf.net/p/culfw/code/branches/raspii/culfw/Devices/CCD/CCD.hex
  9. # which includes support for "K" command
  10. #
  11. # Published under GNU GPL License, v2
  12. #
  13. # Date Who Comment
  14. # ---------- ------------- -------------------------------------------------------------------------------------------------------------------------------
  15. # 2016-12-19 RaspII Test if new repository is working
  16. # 2016-03-20 RaspII Added some information to Commandref, now attrib contains correct information
  17. # 2016-01-30 RaspII Now also Blinds and Switches are implemented (all actuators I have).
  18. # 2016-01-12 RaspII Implemented Dimmer Commands for 1&3 key remote, removed toggle
  19. # 2015-06-02 RaspII Now can also Handle multiple devices with same code, next step: implement all commands (on, off, toggle... for KOPP_FC_Parse)
  20. # Missing is also 2 key commands (e.g. key1=on Key2=off for Dimmmers, key1=up key2=down for blinds)
  21. # 2015-05-21 RaspII Beim FS20 Modul sind die möglichen Set Commands abhängig vom "model" Attribute !! hier weitersuchen
  22. # Seit die Return SerExtensions eingebaut ist, lässt sich bei Taste2Rad4 dass Commando Off nicht mehr absetzen (hat was mit dem Modul SerExtensions zu tun)
  23. # 2015-05-02 RaspII Try now to receive Kopp Messages, also
  24. # 2015-04-13 RaspII Modified some typos (help section)
  25. # 2015-02-01 RaspII use small "k" to start Kopp FW, "K" was already used for raw data
  26. # 2014-12-21 RaspII V6 (fits to my FHEM.cfg V6) Removed timeout from define command, will add later to set command (best guess yet).
  27. # 2014-12-13 RaspII first version with command set: "on, off, toggle, dim, stop". Added new Parameter ("N" for do not print)
  28. # 2014-12-08 RaspII direct usage of set command @ FHEM.cfg works fine, but buttoms on/off do not appear, seems to be a setup/initialize issue in this routine
  29. # 2014-09-01 RaspII first Version
  30. #
  31. ##########################################################################################################################################################################################
  32. package main;
  33. use strict;
  34. use warnings;
  35. use SetExtensions; # 2015-05-21 Wird vermutlich benötig um später die möglichen "Set" Commandos zu definieren
  36. sub KOPP_FC_Initialize($); ##### Claus evt. nicht nötig
  37. sub KOPP_FC_Parse($$); ##### Claus evt. nicht nötig
  38. my %codes = ( # This Sheet contains all allowed codes, indevpendtly from Model type
  39. "01" => "on",
  40. "02" => "off",
  41. "03" => "toggle",
  42. "04" => "dimm",
  43. "05" => "stop",
  44. "06" => "up",
  45. "07" => "down",
  46. "08" => "top",
  47. "09" => "bottom",
  48. );
  49. my %sets = ( # Do not know whether this list is needed (guess: no)
  50. "on" => "",
  51. "off" => "",
  52. "stop" => "",
  53. "toggle" => "",
  54. "dimm" => "",
  55. "up" => "",
  56. "down" => "",
  57. "top" => "",
  58. "bottom" => ""
  59. );
  60. my %models = (
  61. Switch_8080_01 => 'Switch',
  62. Switch_8080_01_2Key => 'Switch_2KeyMode',
  63. Blind_8080_02 => 'Blind',
  64. Timer_8080_04 => 'TimerSwitch',
  65. Dimm_8011_00 => 'Dimmer',
  66. Dimm_8011_00_3Key => 'Dimmer_3KeyMode',
  67. );
  68. my %kopp_fc_c2b; # DEVICE_TYPE->hash (reverse of device_codes), ##Claus what does that mean?
  69. #############################
  70. sub KOPP_FC_Initialize($)
  71. {
  72. my ($hash) = @_;
  73. foreach my $k (keys %codes) { ## Claus needed if we wanna have the codes via commands
  74. $kopp_fc_c2b{$codes{$k}} = $k; # both lines not needed yet
  75. }
  76. # $hash->{Match} = "^kr.................."; # evt. später nehmen, damit nur genau 19 Zeichen akzeptiert werden
  77. $hash->{Match} = "^kr.*";
  78. $hash->{SetFn} = "KOPP_FC_Set";
  79. $hash->{DefFn} = "KOPP_FC_Define";
  80. $hash->{UndefFn} = "KOPP_FC_Undef";
  81. $hash->{ParseFn} = "KOPP_FC_Parse";
  82. $hash->{AttrFn} = "KOPP_FC_Attr"; # aus SOMFY Beispiel abgeleitet
  83. $hash->{AttrList} = "IODev ".
  84. "model:".join(",", sort keys %models);
  85. # . " symbol-length"
  86. # . " enc-key"
  87. # . " rolling-code"
  88. # . " repetition"
  89. # . " switch_rfmode:1,0"
  90. # . " do_not_notify:1,0"
  91. # . " ignore:0,1"
  92. # . " dummy:1,0"
  93. # . " model:somfyblinds"
  94. # . " loglevel:0,1,2,3,4,5,6";
  95. }
  96. #############################
  97. sub KOPP_FC_Define($$)
  98. {
  99. my ( $hash, $def ) = @_;
  100. my @a = split( "[ \t][ \t]*", $def );
  101. my $name = $hash->{NAME};## neu 14.5.
  102. my $u = "wrong syntax: define <name> KOPP_FC keycode(Byte) transmittercode1(2Byte) transmittercode2(Byte)";
  103. my $keycode2 = "";
  104. my $keycode3 = "";
  105. # fail early and display syntax help
  106. if ( int(@a) < 4 ) {
  107. return $u;
  108. }
  109. # check keycode format (2 hex digits)
  110. if ( ( $a[2] !~ m/^[a-fA-F0-9]{2}$/i ) ) {
  111. return "Define $a[0]: wrong keycode format: specify a 2 digit hex value "
  112. }
  113. my $keycode = $a[2];
  114. $hash->{KEYCODE} = uc($keycode);
  115. # check transmittercode1 format (4 hex digits)
  116. if ( ( $a[3] !~ m/^[a-fA-F0-9]{4}$/i ) ) {
  117. return "Define $a[0]: wrong transmittercode1 format: specify a 4 digit hex value "
  118. }
  119. my $transmittercode1 = $a[3];
  120. $hash->{TRANSMITTERCODE1} = uc($transmittercode1);
  121. # check transmittercode2 format (2 hex digits)
  122. if ( ( $a[4] !~ m/^[a-fA-F0-9]{2}$/i ) ) {
  123. return "Define $a[0]: wrong transmittercode2 format: specify a 2 digit hex value "
  124. }
  125. my $transmittercode2 = $a[4];
  126. $hash->{TRANSMITTERCODE2} = uc($transmittercode2);
  127. # check keycode2 (optional) format (2 hex digits)
  128. if (defined $a[5]){
  129. if ( ( $a[5] !~ m/^[a-fA-F0-9]{2}$/i ) ) { #Default: Keycode2 is empty
  130. }
  131. else {
  132. $keycode2 = $a[5];
  133. $hash->{KEYCODE2} = uc($keycode2);
  134. }
  135. }
  136. # check keycode3 (optional) format (2 hex digits)
  137. if (defined $a[6]){
  138. if ( ( $a[5] !~ m/^[a-fA-F0-9]{2}$/i ) ) { #Default: Keycode3 is empty
  139. }
  140. else {
  141. $keycode3 = $a[6];
  142. $hash->{KEYCODE3} = uc($keycode3);
  143. }
  144. }
  145. #Remove check for timeout
  146. # check timeout (5 dec digits)
  147. # if ( ( $a[5] !~ m/^[0-9]{5}$/i ) ) {
  148. # return "Define $a[0]: wrong timeout format: specify a 5 digits decimal value"
  149. # }
  150. # removed next lines, may be will move timeout to set command (on-for-timer) or something like that
  151. # my $timeout = $a[5];
  152. # $hash->{TIMEOUT} = uc($timeout);
  153. $hash->{TIMEOUT} = "00000"; #Default timeout = 0
  154. # group devices by their address
  155. my $code = uc("$transmittercode1 $keycode");
  156. my $ncode = 1;
  157. # my $name = $a[0]; # see above, already defined
  158. $hash->{CODE}{ $ncode++ } = $code; ## 6.1.2016: Code jetzt mit Referenz verlinken
  159. # $hash->{CODE} = $code; ## dafür diese Zeile raus
  160. $modules{KOPP_FC}{defptr}{$code}{$name} = $hash; ## neu 30.5. mit name vermutlich wird hierüber das Device eindeutig identifiziert
  161. # Noch die 2te Taste definieren, falls vorhanden
  162. if ( $keycode2 ne "") {
  163. my $code = uc("$transmittercode1 $keycode2");
  164. $hash->{CODE}{ $ncode++ } = $code;
  165. $modules{KOPP_FC}{defptr}{$code}{$name} = $hash; ## neu 30.5. mit name vermutlich wird hierüber das Device eindeutig identifiziert
  166. }
  167. # Noch die 3te Taste definieren, falls vorhanden
  168. if ( $keycode3 ne "") {
  169. my $code = uc("$transmittercode1 $keycode3");
  170. $hash->{CODE}{ $ncode++ } = $code;
  171. $modules{KOPP_FC}{defptr}{$code}{$name} = $hash; ## neu 30.5. mit name vermutlich wird hierüber das Device eindeutig identifiziert
  172. }
  173. # Noch so, der "Stop Code" = "F7" nach langem Tastendruck bekommt auch noch einen Eintrag
  174. $code = uc("$transmittercode1 F7");
  175. $hash->{CODE}{"stop"} = $code;
  176. $modules{KOPP_FC}{defptr}{$code}{$name} = $hash; ## neu 30.5. mit name vermutlich wird hierüber das Device eindeutig identifiziert
  177. Log3 $name, 2, "KOPP_FC_Define: Modules: $modules{KOPP_FC}{defptr}{$code}{$name} Name: $name a[0]: $a[0] Transmittercode1: $transmittercode1 Keycode: $keycode Keycode2: $keycode2 $keycode Keycode3: $keycode3 Hash: $hash"; # kann wieder Raus !!!! ### Claus
  178. # $hash->{move} = 'on';
  179. # ohne die folgende Zeile gibts beim Speichern von FHEM.cfg die Fehlermeldung Dimmer2 (wenn Dimmer2 als Name festgelegt werden soll)
  180. AssignIoPort($hash);
  181. }
  182. #############################
  183. sub KOPP_FC_Undef($$)
  184. {
  185. my ($hash, $name) = @_;
  186. foreach my $c (keys %{ $hash->{CODE} } )
  187. {
  188. $c = $hash->{CODE}{$c};
  189. # As after a rename the $name my be different from the $defptr{$c}{$n}
  190. # we look for the hash.
  191. foreach my $dname (keys %{ $modules{KOPP_FC}{defptr}{$c} })
  192. {
  193. delete($modules{KOPP_FC}{defptr}{$c}{$dname}) if($modules{KOPP_FC}{defptr}{$c}{$dname} == $hash);
  194. # No entry to log file (only for test)
  195. # if($modules{KOPP_FC}{defptr}{$c}{$dname} == $hash)
  196. # {
  197. # my $m=$modules{KOPP_FC}{defptr}{$c}{$dname};
  198. # Log3 $name, 3, "KOPP_FC_Undef: Name: $name, Code: $c, $m deleted";
  199. # }
  200. }
  201. }
  202. return undef;
  203. }
  204. ##############################
  205. sub KOPP_FC_Attr(@) {
  206. # write new Attributes to global $attr variable if attribute name is model
  207. my ($cmd,$name,$aName,$aVal) = @_;
  208. my $hash = $defs{$name};
  209. return "\"KOPP_FC Attr: \" $name does not exist" if (!defined($hash));
  210. # $cmd can be "del" or "set"
  211. # $name is device name
  212. # aName and aVal are Attribute name and value
  213. if ($cmd eq "set") {
  214. if ($aName eq 'model') {
  215. $attr{$name}{$aName} = $aVal;
  216. }
  217. }
  218. return undef;
  219. }
  220. #####################################
  221. sub KOPP_FC_SendCommand($@)
  222. {
  223. my ($hash, @args) = @_;
  224. my $ret = undef;
  225. my $keycodehex = $args[0];
  226. my $cmd = $args[1];
  227. my $message;
  228. my $name = $hash->{NAME};
  229. my $numberOfArgs = int(@args);
  230. my $io = $hash->{IODev};
  231. # return $keycodehex
  232. $message = "s"
  233. . $keycodehex
  234. . $hash->{TRANSMITTERCODE1}
  235. . $hash->{TRANSMITTERCODE2}
  236. . $hash->{TIMEOUT}
  237. . "N"; # N for do not print messages (FHEM will write error messages to log files if CCD/CUL sends status info
  238. ## Send Message to IODev using IOWrite
  239. IOWrite( $hash, "k", $message );
  240. return $ret;
  241. }
  242. # end sub KOPP_FC_SendCommand
  243. #############################
  244. #############################
  245. sub KOPP_FC_Set($@)
  246. {
  247. my ( $hash, $name, @args ) = @_; # Aufbau hash: Name, Command
  248. my $numberOfArgs = int(@args);
  249. my $keycodedez;
  250. my $keycodehex;
  251. my $lh;
  252. my $modl;
  253. # my $message;
  254. if ( $numberOfArgs < 1 )
  255. {
  256. return "no set value specified" ;
  257. }
  258. my $cmd = lc($args[0]);
  259. my $c = $kopp_fc_c2b{$args[0]};
  260. if(!defined($c)) # if set command was not yet defined in %codes provide command list
  261. # $c contains the first argument of %codes, "01" for "on", "02" for "off" ..
  262. {
  263. my $list;
  264. if(defined($attr{$name}) && defined($attr{$name}{"model"}))
  265. {
  266. my $mt = $models{$attr{$name}{"model"}}; # Model specific set arguments will be defined here (maybe move later to variable above)
  267. $list = "dimm stop on off" if($mt && $mt eq "Dimmer"); # --------------------------------------------------------------------------------------
  268. $list = "dimm stop on off" if($mt && $mt eq "Dimmer_3KeyMode"); # "$mt &&...", damit wird Inhalt von $mt nur geprüft wenn $mt initialisiert ist
  269. $list = "on off short" if($mt && $mt eq "TimerSwitch"); # on means long key presure
  270. $list = "top bottom up down stop" if($mt && $mt eq "Blind"); # up/down means long key presure
  271. $list = "on off" if($mt && $mt eq "Switch"); # (no difference between long/short preasure)
  272. $list = "on off" if($mt && $mt eq "Switch_2KeyMode"); # (no difference between long/short preasure)
  273. }
  274. $list = (join(" ", sort keys %kopp_fc_c2b) . " Claus") if(!defined($list)); # if list not defined model specific, allow whole default list
  275. return "[Kopp_FC_Set] unknown command <$cmd>, choose one of " . join(" ", $list); # no more text after "choose one of " allowed
  276. }
  277. if(defined($attr{$name}) && defined($attr{$name}{"model"})) # Falls Model spezifiziert ist, Model ermitteln -> $mt
  278. { # ----------------------------------------------------
  279. $modl = $models{$attr{$name}{"model"}};
  280. # Log3 $name, 2, "KOPP_FC_Set: Device Name: $name Index auf codes: $c Model: $modl"; # kann wieder Raus !!!! ### Claus
  281. }
  282. # readingsSingleUpdate($hash, "state","$cmd", 1); # update also Readings
  283. # $hash->{STATE} = $cmd; # update device state
  284. # Look for all devices with the same code, and update readings (state), (timestamp, not yet)
  285. # ------------------------------------------------------------------------------------------------------
  286. # some hints: if same code is used within config file for differen models update of state makes no sense
  287. # and may fail because command is not available for a different model. So we only update devices which are
  288. # of the same model as the original one.
  289. #
  290. # my $tn = TimeNow();
  291. # my $defptr = $modules{KOPP_FC}{defptr}{transmittercode1}{keycode};
  292. # foreach my $n (keys %{ $defptr })
  293. # {
  294. # readingsSingleUpdate($defptr->{$n}, "state","$cmd", 1);
  295. # }
  296. my $code = $hash->{CODE}{1}; # Load Devices code1 (typically key code short preasure)
  297. my $rhash = $modules{KOPP_FC}{defptr}{$code}; # Load Hash of Devices with same code
  298. # my @list; # Do (Why) I need this @lists (incl. return @list)?
  299. foreach my $n (keys %{ $rhash })
  300. {
  301. $lh = $rhash->{$n};
  302. $n = $lh->{NAME}; # It may be renamed, n now contains name of defined device, e.g. Dimmer....
  303. # return "" if(IsIgnored($n)); # Little strange.
  304. if(defined ($modl) && defined($attr{$n}) && defined($attr{$n}{"model"}))
  305. {
  306. my $m=$models{$attr{$n}{"model"}};
  307. Log3 $name, 3, "KOPP_FC_Set: Device Name: $n, command: $cmd, Model: $m, Transm.-/KeyCode: $code";
  308. # Falls auch dieses Model spezifiziert ist und Modell identisch dem Model aus Originalaufruf,
  309. if($m eq $modl) # ------------------------------------------------------------------------------------------
  310. { # dann den Status dieses Devices ebenfalls updaten
  311. # Log3 $name, 2, "KOPP_FC_Set: Orig Model: $modl, Status Update also for Model: $m"; # kann wieder Raus !!!! ### Claus
  312. $lh->{STATE} = $cmd; # update device state
  313. readingsSingleUpdate($lh, "state", $cmd, 1); # update also Readings
  314. }
  315. else
  316. {
  317. # Log3 $name, 2, "KOPP_FC_Set: Orig Model: $modl, wrong model: $m no Status Update done"; # kann wieder Raus !!!! ### Claus
  318. # Log3 $name, 2, " dont define same remote key for different actuators models"; # kann wieder Raus !!!! ### Claus
  319. }
  320. }
  321. # push(@list, $n);
  322. }
  323. # return @list;
  324. # return"";
  325. if($cmd eq 'stop') # command = stop
  326. { # --------------
  327. $keycodehex = "F7"; # Stop means F7 will be sent several times
  328. } # (e.g. to end "dimm" end or "up" / "down" )
  329. elsif($cmd eq 'dimm') # independent of Dimmer Type
  330. { # ---------------------------
  331. $keycodehex = $hash->{KEYCODE}; # use Keycode+0x80 for long key pressure = dimmer up/down
  332. $keycodedez = hex $keycodehex ; # without moving to $keycodehex and addition in second line it does not work !?
  333. $keycodedez = $keycodedez + 128; #
  334. $keycodehex = uc sprintf "%x", $keycodedez; #
  335. }
  336. elsif($modl && $modl eq "Dimmer") # if model defined and equal Dimmer
  337. { # ---------------------------------
  338. if($cmd eq 'on'||$cmd eq 'off') #
  339. { #
  340. $keycodehex = $hash->{KEYCODE}; # -> use Keycode to send "on" or "off" command (=toggle)
  341. }
  342. }
  343. elsif($modl && $modl eq "Dimmer_3KeyMode") # if model defined and equal 3-key Dimmer
  344. { # ---------------------------------------
  345. if($cmd eq 'on' && $hash->{KEYCODE2} ne "") # Command = on
  346. { #
  347. $keycodehex = $hash->{KEYCODE2}; # -> use Keycode 2 to send "on" command
  348. } #
  349. if($cmd eq 'off' && $hash->{KEYCODE3} ne "") # Command = off
  350. { #
  351. $keycodehex = $hash->{KEYCODE3}; # -> use Keycode 3 to send "on" command
  352. }
  353. }
  354. elsif($modl && $modl eq "Switch") # if model defined and equal Switch
  355. { # ---------------------------------
  356. if($cmd eq 'on' || $cmd eq 'off') #
  357. { #
  358. $keycodehex = $hash->{KEYCODE}; # -> use Keycode to send "on" or "off" command (=toggle)
  359. } #
  360. }
  361. elsif($modl && $modl eq "Switch_2KeyMode") # if model defined and equal Switch controlled by 2 Keys
  362. { # ------------------------------------------------------
  363. if($cmd eq 'on') #
  364. { #
  365. $keycodehex = $hash->{KEYCODE}; # -> use Keycode to send "on" or "off" command (=toggle)
  366. } #
  367. elsif($cmd eq 'off' && $hash->{KEYCODE2} ne "") #
  368. { #
  369. $keycodehex = $hash->{KEYCODE2}; # -> use Keycode to send "on" or "off" command (=toggle)
  370. }
  371. }
  372. elsif($modl && $modl eq "Blind") # if model defined and equal Blind: #
  373. { # ----------------------------------------
  374. if($cmd eq 'top') #
  375. { # -> use Keycode to send "top" command
  376. $keycodehex = $hash->{KEYCODE}; #
  377. } #
  378. elsif($cmd eq 'bottom' && $hash->{KEYCODE2} ne "") #
  379. { # -> use Keycode2 to send "bottom" command
  380. $keycodehex = $hash->{KEYCODE2}; #
  381. } #
  382. elsif($cmd eq 'up') #
  383. { #
  384. $keycodehex = $hash->{KEYCODE}; #
  385. $keycodedez = hex $keycodehex ; # -> use Keycode+0x80 to send "up" command
  386. $keycodedez = $keycodedez + 128; #
  387. $keycodehex = uc sprintf "%x", $keycodedez; #
  388. #
  389. } #
  390. elsif($cmd eq 'down' && $hash->{KEYCODE2} ne "") #
  391. { # -> use Keycode2+0x80 to send "dowm" command
  392. $keycodehex = $hash->{KEYCODE2}; #
  393. $keycodedez = hex $keycodehex ; #
  394. $keycodedez = $keycodedez + 128; #
  395. $keycodehex = uc sprintf "%x", $keycodedez; #
  396. }
  397. }
  398. elsif($cmd eq 'on'|| 'off' || 'toggle') # If model not known just allow on, off, toggle
  399. { # ---------------------------------------------
  400. $keycodehex = $hash->{KEYCODE}; # -> use Keycode
  401. }
  402. else # should never happen :-)
  403. { # -----------------------
  404. return "unknown command" ;
  405. }
  406. KOPP_FC_SendCommand($hash, $keycodehex, @args);
  407. # KOPP_FC_SendCommand($hash, @args);
  408. # $hash->{STATE} = 'off';
  409. #return SetExtensions($hash,'toggle', @a);
  410. return undef;
  411. }
  412. # end sub Kopp_FC_setFN
  413. ###############################
  414. #############################
  415. #
  416. sub KOPP_FC_Parse($$) { # wird von fhem.pl dispatch getriggert
  417. # Example receive Message: kr07FA5E7114CC0F02AD
  418. # 07: block length; FA5E: Transmitter Code 1; 71: Key counter(next key pressed); 14: Key Code;
  419. # CC0F: unknown, but always the same;
  420. # 02: Transmiter Code 2; (content depends on transmitter, changed value seems not to change anything; AD: Checksum)
  421. my ($hash, $msg) = @_;
  422. my $name = $hash->{NAME}; # Here: Device Hash (e.g. to CUL), e.g. $name = "CUL_0"
  423. my $state; # means receive command = new state
  424. my $keycodedez;
  425. my $specialkey = "short"; # Default: short key
  426. my $code;
  427. my $devicefound;
  428. if( $msg =~ m/^kr/ ) { # if first two char's are "kr" then we are right here (KOPP Message received)
  429. # Msg format:
  430. # kr.. rest to be defined later
  431. # if (substr($msg, 0, 16) eq "krS-ReceiveStart" || substr($msg, 0, 14) eq "krE-ReceiveEnd")
  432. if (substr($msg, 0, 2) eq "kr")
  433. {
  434. # get Transtmitter Code 1
  435. my $transmittercode1 = uc(substr($msg, 4, 4)); # Example above: FA5E
  436. # get Transtmitter Code 2
  437. my $transmittercode2 = uc(substr($msg, 16, 2)); # Example above: 02
  438. # get Key Code
  439. my $keycode = uc(substr($msg, 10, 2)); # Example above: 14
  440. $keycodedez = hex $keycode ; # If Keycode > 128 and not equal "long key end" (F7) then Long Key pressure
  441. if ($keycode eq "F7") # If end of long keypressure (stop) we need special handling
  442. { # ----------------------------------------------------------
  443. $code = uc("$transmittercode1 F7");
  444. $specialkey = "stop";
  445. }
  446. else
  447. {
  448. if ($keycodedez >= 128 && $keycode ne "F7")
  449. { # If long key pressure:
  450. $keycodedez = ($keycodedez - 128); # ---------------------
  451. $specialkey = "long";
  452. $keycode = uc sprintf "%02x", $keycodedez; # %02 damit auch eine "0"... zweistellig wird
  453. }
  454. $code = uc("$transmittercode1 $keycode");
  455. }
  456. my $rhash = $modules{KOPP_FC}{defptr}{$code}; # neu 30.5. rhash war nicht eindeutig
  457. # my $rname = $rhash->{NAME}; # $rhash is hash to corresponding device as calculated from receive data
  458. Log3 $name, 2, "KOPP_FC_Parse: name: $name code: $code Specialkey:$specialkey"; # kann wieder Raus !!!! ### Claus rname wird müll, da Hash mehrere Namen verlinkt?
  459. # rname funktioniert nur wenn $name in Zeile 149/150 nicht angehängt ist
  460. # my $tn = TimeNow();
  461. # Look for all devices with the same code, and set state, (timestamp, not yet)
  462. # ----------------------------------------------------------------------------
  463. if($rhash)
  464. {
  465. my @list;
  466. foreach my $n (keys %{ $rhash })
  467. {
  468. my $lh = $rhash->{$n};
  469. $n = $lh->{NAME}; # It may be renamed, n now contains name of defined device, e.g. Dimmer....
  470. return "" if(IsIgnored($n)); # Little strange.
  471. my $oldstate = ReadingsVal($n, "state",""); #
  472. # Je nach Model die Aktion triggern.
  473. # 3 Key Dimmer:
  474. #==============
  475. $devicefound=1; # Default: wir kennen das Device
  476. if ($attr{$n}{model} && ($attr{$n}{model} eq 'Dimm_8011_00_3Key')) # Wenn Device = 3 Key Dimmer
  477. { # ==========================
  478. if ($specialkey eq 'short' && $keycode eq $lh->{KEYCODE}) # Taste 1 kurz gedrückt: dann toggeln
  479. { # -----------------------------------
  480. if($oldstate eq 'off') {$state = "on";} # off -> on
  481. elsif($oldstate eq 'on') {$state = "off";} # on -> off
  482. elsif($oldstate eq 'stop') {$state = "off";} # stop -> off
  483. else {$state = "on";} # Weder noch? dann Neuer Zustand = on (wird dann wohl aus gewesen sein)
  484. }
  485. elsif ($specialkey eq "long" && $keycode eq $lh->{KEYCODE}) # Taste 1 lang gedrückt: dann dimmen
  486. { # ----------------------------------
  487. $state = "dimm";
  488. }
  489. elsif ($specialkey eq "stop") # Ende der lang gedrückten Taste dann dimmen stoppen
  490. { # --------------------------------------------------
  491. $state = "stop" if($oldstate eq 'dimm' || $oldstate eq 'stop'); # falls dimmen aktiv war oder bereits gestoppt wurde
  492. }
  493. elsif ($keycode eq $lh->{KEYCODE2}) {$state = "on";} # Taste 2: (kurz oder lang) -> On
  494. elsif ($keycode eq $lh->{KEYCODE3}) {$state = "off";} # Taste 3: (kurz oder lang) -> Off
  495. else {}
  496. }
  497. # 1 Key Dimmer:
  498. #==============
  499. elsif ($attr{$n}{model} && ($attr{$n}{model} eq 'Dimm_8011_00')) # Wenn Device = 1 Key Dimmer
  500. { # ==========================
  501. if ($specialkey eq 'short' && $keycode eq $lh->{KEYCODE}) # Taste 1 kurz gedrückt: dann toggeln
  502. { # -----------------------------------
  503. if($oldstate eq 'off') {$state = "on";} # off -> on
  504. elsif($oldstate eq 'on') {$state = "off";} # on -> off
  505. elsif($oldstate eq 'stop') {$state = "off";} # stop -> off
  506. else {$state = "on";} # Weder noch? dann Neuer Zustand = on (wird dann wohl aus gewesen sein)
  507. }
  508. elsif ($specialkey eq "long" && $keycode eq $lh->{KEYCODE}) # Taste 1 lang gedrückt: dann dimmen
  509. { # ----------------------------------
  510. $state = "dimm";
  511. }
  512. elsif ($specialkey eq "stop") # Ende der lang gedrückten Taste dann dimmen stoppen
  513. { # --------------------------------------------------
  514. $state = "stop" if($oldstate eq 'dimm' || $oldstate eq 'stop'); # falls dimmen aktiv war oder bereits gestoppt wurde
  515. }
  516. }
  517. # Blind:
  518. #=======
  519. elsif ($attr{$n}{model} && ($attr{$n}{model} eq 'Blind_8080_02')) # Wenn Device = Blind/Rolladen
  520. { # ============================
  521. if ($specialkey eq 'short' && $keycode eq $lh->{KEYCODE}) # Taste 1 kurz gedrückt: dann Endzustand top/oben anfahren
  522. { # --------------------------------------------------------
  523. $state = "top"; #
  524. }
  525. elsif ($specialkey eq "long" && $keycode eq $lh->{KEYCODE}) # Taste 1 lang gedrückt: dann nach oben fahren (bis zu stop)
  526. { # ----------------------------------------------------------
  527. $state = "up";
  528. }
  529. if ($specialkey eq 'short' && $keycode eq $lh->{KEYCODE2}) # Taste 2 kurz gedrückt: dann Endzustand bottom/unten anfahren
  530. { # ------------------------------------------------------------
  531. $state = "bottom"; #
  532. }
  533. elsif ($specialkey eq "long" && $keycode eq $lh->{KEYCODE2}) # Taste 2 lang gedrückt: dann nach runter fahren (bis zu stop)
  534. { # -----------------------------------------------------------
  535. $state = "down";
  536. }
  537. elsif ($specialkey eq "stop") # Ende der lang gedrückten Taste dann Fahrt stoppen
  538. { # --------------------------------------------------
  539. $state = "stop" if($oldstate eq 'up' || $oldstate eq 'down' || $oldstate eq 'stop'); # falls fahrt aktiv war oder bereits gestoppt wurde
  540. }
  541. else {}
  542. }
  543. # 2 Key Switch:
  544. #==============
  545. elsif ($attr{$n}{model} && ($attr{$n}{model} eq 'Switch_8080_01_2Key')) # Wenn Device = 2 Key Switch
  546. { # ==============================
  547. if ($keycode eq $lh->{KEYCODE}) # Taste 1 gedrückt (no matter if short or long) -> State = on
  548. { # -----------------------------------------------------------
  549. $state = "on"; #
  550. }
  551. elsif ($keycode eq $lh->{KEYCODE2}) # Taste 2 gedrückt (no matter if short or long) -> State = off
  552. { # ------------------------------------------------------------
  553. $state = "off"; #
  554. }
  555. else {}
  556. }
  557. # Für 1 Key Switch und alle anderen Modelle gilt: egal ob kurz oder langer Tastendruck: toggeln zwischen on und off !
  558. # ===================================================================================================================
  559. elsif ($specialkey ne 'stop') # Bei Ende der lang gedrückten Taste: nothing to do in this case
  560. {
  561. if($oldstate eq 'off') {$state = "on";} # off -> on
  562. elsif($oldstate eq 'on') {$state = "off";} # on -> off
  563. else {$state = "on";} # Weder noch? dann Neuer Zustand = on (wird dann wohl aus gewesen sein)
  564. }
  565. else # Bei unbekanntem Device/Aktion keine weitere Aktion
  566. {
  567. $devicefound=0; # das Device ist nicht bekannt
  568. }
  569. if ($devicefound == 1) # Update Readings if Device/Action found
  570. {
  571. # Log3 $name, 2, "KOPP_FC_Parse: Model $attr{$n}{model} gefunden "; # kann wieder Raus !!!! ### Claus
  572. # Log3 $name, 2, "KOPP_FC_Parse: Code1: $lh->{CODE}{1} "; # kann wieder Raus !!!! ### Claus
  573. # Log3 $name, 2, "KOPP_FC_Parse: Code2: $lh->{CODE}{2} "; # kann wieder Raus !!!! ### Claus
  574. # Log3 $name, 2, "KOPP_FC_Parse: Code3: $lh->{CODE}{3} "; # kann wieder Raus !!!! ### Claus
  575. # Log3 $name, 2, "KOPP_FC_Parse: KeyCode1: $lh->{KEYCODE} "; # kann wieder Raus !!!! ### Claus
  576. # Log3 $name, 2, "KOPP_FC_Parse: KeyCode2: $lh->{KEYCODE2} "; # kann wieder Raus !!!! ### Claus
  577. # Log3 $name, 2, "KOPP_FC_Parse: KeyCode3: $lh->{KEYCODE3} "; # kann wieder Raus !!!! ### Claus
  578. readingsSingleUpdate($lh, "state", $state, 1); # $state mit "" oder ohne?
  579. # Log3 $name, 2, "KOPP_FC_Parse lh: $lh n: $n oldstate: $oldstate state: $state"; # kann wieder Raus !!!! ### Claus
  580. push(@list, $n);
  581. }
  582. }
  583. return @list;
  584. }
  585. else
  586. {
  587. Log3 $name, 2, "KOPP_FC_Parse: Device not defined for message $msg";
  588. }
  589. }
  590. else
  591. {
  592. Log3 $name, 2, "$name: KOPP_FC_Parse: nicht gefunden 01 $msg"; # kann wieder Raus !!!! ### Claus
  593. return "KOPP_Parse: Command not known";
  594. }
  595. } else {
  596. DoTrigger($name, "UNKNOWNCODE $msg");
  597. Log3 $name, 2, "$name: KOPP_FC.PM Kopp nicht gefunden 02 $msg"; # kann wieder Raus !!!! ### Claus
  598. Log3 $name, 3, "$name: Unknown code $msg, help me [KOPP_FC]!";
  599. return undef;
  600. }
  601. }
  602. # end sub Kopp_FC_Parse
  603. ###############################
  604. 1;
  605. =pod
  606. =item device
  607. =item summary controls "Kopp Free Control" Devices via 868 Mhz CUL, CCD...
  608. =item summary_DE steuert "Kopp Free Control" Devices via 868 Mhz CULs, CCD...
  609. =begin html
  610. <a name="KOPP_FC"></a>
  611. <h3>Kopp Free Control protocol</h3>
  612. <ul>
  613. <b>Please take into account: this protocol is under construction. Commands may change </b>
  614. <br><br>
  615. The Kopp Free Control protocol is used by Kopp receivers/actuators and senders.
  616. This module is able to send commands to Kopp actuators and receive commands from Kopp transmitters. Currently supports devices: dimmers, switches and blinds.
  617. The communication is done via a <a href="#CUL">CUL</a> or compatible device (e.g. CCD...).
  618. This devices must be defined before using this protocol.
  619. <br><br>
  620. <b>Assign the Kopp Free Control protocol to a CUL or compatible device</b>
  621. <ul>
  622. <code>define CUL_0 CUL /dev/ttyAMA0@38400 1234</code><br>
  623. <code>attr CUL_0 rfmode KOPP_FC</code>
  624. <br>
  625. This attribute ("rfmode KOPP_FC") assigns the Kopp protocol to device CUL_0<br>
  626. You may <b>not</b> assign/use a second protocol on this device
  627. <br>
  628. </ul>
  629. <br>
  630. <a name="KOPP_FCdefine"></a>
  631. <b>Define</b>
  632. <ul>
  633. <code>define &lt;name&gt; KOPP_FC &lt;Keycode&gt; &lt;Transmittercode1&gt; &lt;Transmittercode2&gt; [&lt;Keycode2&gt] [&lt;Keycode3&gt]</code>
  634. <br>
  635. <br><li><code>&lt;name&gt;</code></li>
  636. name is the identifier (name) you plan to assign to your specific device (actuator) as done for any other FHEM device
  637. <br><br><li><code>&lt;Keycode&gt;</code></li>
  638. Keycode is a 2 digit hex code (1Byte) which reflects the transmitters key
  639. <br><br><li><code>&lt;Transmittercode1&gt;</code></li>
  640. Transmittercode1 is a 4 digit hex code. This code is specific for the transmitter itself.
  641. <br><br><li><code>&lt;Transmittercode2&gt;</code></li>
  642. Transmittercode2 is a 2 digit hex code and also specific for the transmitter, but I didn't see any difference while modifying this code.
  643. (seems this code don't matter the receiver).
  644. <br>Both codes (Transmittercode1/2) are also used to pair the transmitter with the receivers (remote switch, dimmer, blind..)
  645. <br><br><li><code>[&lt;Keycode2&gt;]</code></li>
  646. Keycode2 is an opional 2 digit hex code (1Byte) which reflects a second transmitters key
  647. <br><br><li><code>[&lt;Keycode3&gt;]</code></li>
  648. Keycode3 is an opional 2 digit hex code (1Byte) which reflects a third transmitters key
  649. <br>
  650. Some receivers like dimmers can be paired with two addional keys, which allow to switch the dimmer directly on or off.
  651. That means FHEM will always know the current state, which is not the case in one key mode (toggling between on and off)
  652. <br><br>
  653. Pairing is done by setting the receiver in programming mode by pressing the program button at the receiver<br>
  654. (small buttom, typically inside a hole).<br>
  655. Once the receiver is in programming mode send a command (or two, see dimmer above) from within FHEM to complete the pairing.
  656. For more details take a look to the data sheet of the corresponding receiver type.
  657. <br>
  658. You are now able to control the receiver from FHEM, the receiver handles FHEM just linke another remote control.
  659. </ul>
  660. <br>
  661. <a name="KOPP_FCset"></a>
  662. <b>Set</b>
  663. <ul>
  664. <code>set &lt;name&gt; &lt;value&gt</code>
  665. <br>
  666. <br><li><code>&lt;value&gt;</code></li>
  667. value is one of:
  668. <ul>
  669. <code>on</code><br>
  670. <code>off</code><br>
  671. <code>dimm</code><br>
  672. <code>stop</code><br>
  673. </ul>
  674. <pre>Examples:
  675. <code>set Dimmer on</code> # will toggle dimmer device on/off for 1Key remote control,
  676. <code> </code> will switch on for 3 key remote control
  677. <code>set Dimmer off</code> # will switch dimmer device off (3 key remote control)
  678. <code>set Dimmer dimm</code> # will start dimming process
  679. <code>set Dimmer stop</code> # will stop dimming process
  680. </pre>
  681. </ul>
  682. <a name="KOPP_FCattrib"></a>
  683. <b>Attributes</b>
  684. <ul>
  685. <code>attr &lt;name&gt; model &lt;value&gt</code>
  686. <br>
  687. <br><li><code>&lt;value&gt;</code></li>
  688. value is one of:
  689. <ul>
  690. <code>Switch_8080_01</code><br>
  691. <code>Switch_8080_01_2Key</code><br>
  692. <code>Blind_8080_02</code><br>
  693. <code>Timer_8080_04</code><br>
  694. <code>Dimm_8011_00</code><br>
  695. <code>Dimm_8011_00_3Key</code><br>
  696. </ul>
  697. </ul>
  698. <br>
  699. <b>Examples</b>
  700. <ul>
  701. <br>FHEM Config for Dimmer via 1 Key remote control:
  702. <ul>
  703. <code>define Dimmer KOPP_FC 65 FA5E 02</code><br>
  704. <code>attr Dimmer IODev CUL_0</code><br>
  705. <code>attr Dimmer devStateIcon OnOff:toggle:dimm dimm:dim50%:stop stop:on:dimm off:toggle:dimm</code><br>
  706. <code>attr Dimmer eventMap on:OnOff dimm:dimm stop:stop</code><br>
  707. <code>attr Dimmer group TestGroup</code><br>
  708. <code>attr Dimmer model Dimm_8011_00</code><br>
  709. <code>attr Dimmer room TestRoom</code><br>
  710. <code>attr Dimmer webCmd OnOff:dimm:stop</code><br>
  711. </ul>
  712. <br>FHEM Config for Dimmer via 3 Key remote control:
  713. <ul>
  714. <code>define SDimmer KOPP_FC 65 FA5E 02 55 75</code><br>
  715. <code>attr SDimmer IODev CUL_0</code><br>
  716. <code>attr SDimmer devStateIcon dimm:dim50%:stop stop:on:off on:on:off off:off:on</code><br>
  717. <code>attr SDimmer group TestGroup</code><br>
  718. <code>attr SDimmer icon light_pendant_light</code><br>
  719. <code>attr SDimmer model Dimm_8011_00_3Key</code><br>
  720. <code>attr SDimmer room TestRoom</code><br>
  721. <code>attr SDimmer webCmd on:dimm:stop:off</code><br>
  722. </ul>
  723. </ul>
  724. <br><br>
  725. <b>Additional Information you can find in corresponding FHEM Wiki</b>
  726. <ul><li><a href="http://www.fhemwiki.de/w/index.php?title=Kopp_Allgemein&redirect=no">Kopp Allgemein</a></li></ul>
  727. <br><br>
  728. </ul>
  729. =end html
  730. =cut