10_KOPP_FC.pm 34 KB

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