46_TRX_LIGHT.pm 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  1. # $Id: 46_TRX_LIGHT.pm 16516 2018-03-29 22:10:21Z KernSani $
  2. ##############################################################################
  3. #
  4. # 46_TRX_LIGHT.pm
  5. # FHEM module for lighting protocols:
  6. # X10 lighting, ARC, ELRO AB400D, Waveman, Chacon EMW200,
  7. # IMPULS, AC (KlikAanKlikUit, NEXA, CHACON, HomeEasy UK),
  8. # HomeEasy EU, ANSLUT, Ikea Koppla
  9. #
  10. # Copyright (C) 2012-2016 by Willi Herzig (Willi.Herzig@gmail.com)
  11. # Maintenance since 2018 by KernSani
  12. #
  13. # This file is part of fhem.
  14. #
  15. # Fhem is free software: you can redistribute it and/or modify
  16. # it under the terms of the GNU General Public License as published by
  17. # the Free Software Foundation, either version 2 of the License, or
  18. # (at your option) any later version.
  19. #
  20. # Fhem is distributed in the hope that it will be useful,
  21. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. # GNU General Public License for more details.
  24. #
  25. # You should have received a copy of the GNU General Public License
  26. # along with fhem. If not, see <http://www.gnu.org/licenses/>.
  27. #
  28. ##############################################################################
  29. #
  30. # values for "set global verbose"
  31. # 4: log unknown protocols
  32. # 5: log decoding hexlines for debugging
  33. #
  34. ##############################################################################
  35. #
  36. # CHANGELOG
  37. #
  38. # 25.03.2018 Summary for Commandref
  39. # Use SetExtensions
  40. # Fix to trigger events (userreadings) - topic #65899
  41. ##############################################################################
  42. package main;
  43. use strict;
  44. use warnings;
  45. use SetExtensions;
  46. my $time_old = 0;
  47. my $TRX_LIGHT_type_default = "ds10a";
  48. my $TRX_LIGHT_X10_type_default = "x10";
  49. my $DOT = q{_};
  50. my %light_device_codes = ( # HEXSTRING => "NAME", "name of reading",
  51. # 0x10: Lighting1
  52. 0x1000 => [ "X10", "light" ],
  53. 0x1001 => [ "ARC", "light" ],
  54. 0x1002 => [ "AB400D", "light" ],
  55. 0x1003 => [ "WAVEMAN", "light" ],
  56. 0x1004 => [ "EMW200", "light" ],
  57. 0x1005 => [ "IMPULS", "light" ],
  58. 0x1006 => [ "RISINGSUN", "light" ],
  59. 0x1007 => [ "PHILIPS_SBC", "light" ],
  60. 0x1008 => [ "ENER010", "light" ], # Energenie ENER010: untested
  61. 0x1009 => [ "ENER5", "light" ], # Energenie 5-gang: untested
  62. 0x100A => [ "COCO_GDR2", "light" ], # COCO GDR2-2000R: untestedCOCO
  63. # 0x11: Lighting2
  64. 0x1100 => [ "AC", "light" ],
  65. 0x1101 => [ "HOMEEASY", "light" ],
  66. 0x1102 => [ "ANSLUT", "light" ],
  67. # 0x12: Lighting3
  68. 0x1200 => [ "KOPPLA", "light" ], # IKEA Koppla
  69. # 0x13: Lighting4
  70. 0x1300 => [ "PT2262", "light" ], # PT2262 raw messages
  71. # 0x14: Lighting5
  72. 0x1400 => [ "LIGHTWAVERF", "light" ], # LightwaveRF
  73. 0x1401 => [ "EMW100", "light" ], # EMW100
  74. 0x1402 => [ "BBSB", "light" ], # BBSB
  75. 0x1403 => [ "MDREMOTE", "light" ], # MDREMOTE LED dimmer
  76. 0x1404 => [ "RSL2", "light" ], # Conrad RSL2
  77. 0x1405 => [ "LIVOLO", "light" ], # Livolo
  78. 0x1406 => [ "TRC02", "light" ], # RGB TRC02
  79. # 0x15: Lighting6
  80. 0x1500 => [ "BLYSS", "light" ], # Blyss
  81. # 0x16: Chime
  82. 0x1600 => [ "BYRONSX", "light" ], # Byron SX
  83. 0x1601 => [ "BYRONMP", "chime" ], # Byron MP001
  84. 0x1602 => [ "SELECTPLUS", "chime" ], # SelectPlus
  85. 0x1603 => [ "RFU", "chime" ], # RFU
  86. 0x1604 => [ "ENVIVO", "chime" ], # Envivo
  87. # 0x17: Fan
  88. 0x1700 => [ "SIEMENS_SF01", "light" ], # Siemens SF01
  89. # 0x18: Curtain1
  90. 0x1800 => [ "HARRISON", "light" ], # Harrison Curtain
  91. # 0x19: Blinds1
  92. 0x1900 => [ "ROLLER_TROL", "light" ], # Roller Trol
  93. 0x1901 => [ "HASTA_OLD", "light" ], # Hasta old
  94. 0x1902 => [ "AOK_RF01", "light" ], # A-OK RF01
  95. 0x1903 => [ "AOK_AC114", "light" ], # A-OK AC114
  96. 0x1904 => [ "RAEX_YR1326", "light" ], # Raex YR1326
  97. 0x1905 => [ "MEDIA_MOUNT", "light" ], # Media Mount
  98. 0x1906 => [ "DC106", "light" ], # DC/RMF/Yooda
  99. 0x1907 => [ "FOREST", "light" ], # Forest
  100. 0x1A00 => [ "RFY", "light" ], # RTS RFY
  101. 0x1A01 => [ "RFY_ext", "light" ], # RTS RFY ext
  102. );
  103. my %light_device_commands = ( # HEXSTRING => commands
  104. # 0x10: Lighting1
  105. 0x1000 => [ "off", "on", "dim", "bright", "", "all_off", "all_on" ], # X10
  106. 0x1001 => [ "off", "on", "", "", "", "all_off", "all_on", "chime" ], # ARC
  107. 0x1002 => [ "off", "on" ], # AB400D
  108. 0x1003 => [ "off", "on" ], # WAVEMAN
  109. 0x1004 => [ "off", "on" ], # EMW200
  110. 0x1005 => [ "off", "on" ], # IMPULS
  111. 0x1006 => [ "off", "on" ], # RisingSun
  112. 0x1007 => [ "off", "on", "", "", "", "all_off", "all_on" ], # Philips SBC
  113. 0x1008 => [ "off", "on", "", "", "", "all_off", "all_on" ], # Energenie ENER010
  114. 0x1009 => [ "off", "on" ], # Energenie 5-gang
  115. 0x100A => [ "off", "on" ], # COCO GDR2-2000R
  116. # 0x11: Lighting2
  117. 0x1100 => [ "off", "on", "level", "all_off", "all_on", "all_level" ], # AC
  118. 0x1101 => [ "off", "on", "level", "all_off", "all_on", "all_level" ], # HOMEEASY
  119. 0x1102 => [ "off", "on", "level", "all_off", "all_on", "all_level" ], # ANSLUT
  120. # 0x12: Lighting3
  121. 0x1200 => [
  122. "bright", "", "", "", "", "", "", "", "dim", "", "", "", "", "", "", "",
  123. "on", "level1", "level2", "level3", "level4", "level5", "level6", "level7", "level8", "level9", "off", "",
  124. "program", "", "", "", "",
  125. ], # Koppla
  126. # 0x13: Lighting4
  127. 0x1300 => ["Lighting4"], # Lighting4: PT2262
  128. # 0x14: Lighting5
  129. 0x1400 => [
  130. "off", "on", "all_off", "mood1", "mood2", "mood3",
  131. "mood4", "mood5", "reserved1", "reserved2", "unlock", "lock",
  132. "all_lock", "close", "stop", "open", "level"
  133. ], # LightwaveRF, Siemens
  134. 0x1401 => [ "off", "on", "learn" ], # EMW100 GAO/Everflourish
  135. 0x1402 => [ "off", "on", "all_off", "all_on" ], # BBSB new types
  136. 0x1403 => [ "power", "light", "bright", "dim", "100", "50", "25", "mode+", "speed-", "speed+", "mode-" ], # MDREMOTE
  137. 0x1404 => [ "off", "on", "all_off", "all_on" ], # Conrad RSL
  138. 0x1405 => [ "all_off", "on_off", "dim+", "dim-" ], # Livolo
  139. 0x1406 => [ "off", "on", "bright", "dim", "vivid", "pale", "color" ], # TRC02
  140. # 0x15: Lighting6
  141. 0x1500 => [ "on", "off", "all_on", "all_off" ], # Blyss
  142. # 0x16: Chime
  143. 0x1600 => [
  144. "", "tubular3_1", "solo1", "bigben1", "", "tubular2_1",
  145. "tubular2_2", "", "dingdong", "solo2", " ", "",
  146. "", "tubular3_2"
  147. ], # Byron SX
  148. 0x1601 => ["ring"], # Byron MP001
  149. 0x1602 => ["ring"], # SelectPlus
  150. 0x1603 => ["ring"], # RFU
  151. 0x1604 => ["ring"], # Envivo
  152. # 0x17: Fan
  153. 0x1700 => [ "", "timer", "-", "learn", "+", "confirm", "light", "on", "off" ], # Siemens SF01
  154. # 0x18: Curtain1
  155. 0x1800 => [ "open", "close", "stop", "program" ], # Harrison Curtain
  156. # 0x19: Blinds1
  157. 0x1900 => [ "open", "close", "stop", "confirm_pair", "set_limit" ], # Roller Trol
  158. 0x1901 => [ "open", "close", "stop", "confirm_pair", "set_limit" ], # Hasta old
  159. 0x1902 => [ "open", "close", "stop", "confirm_pair" ], # A-OK RF01
  160. 0x1903 => [ "open", "close", "stop", "confirm_pair" ], # A-OK AC114
  161. 0x1904 => [
  162. "open", "close", "stop", "confirm_pair",
  163. "set_upper_limit", "set_lower_limit", "delete_limits", "change_dir",
  164. "left", "right"
  165. ], # Raex YR1326
  166. 0x1905 => [ "down", "up", "stop" ], # Media Mount
  167. 0x1906 => [ "open", "close", "stop", "confirm" ], # DC/RMF/Yooda
  168. 0x1907 => [ "open", "close", "stop", "confirm_pair" ], # Forest
  169. 0x1A00 => [ "stop", "up", "", "down", "", "", "", "program" ], # RTS RFY
  170. 0x1A01 => [ "stop", "up", "", "down", "", "", "", "program" ], # RTS RFY ext
  171. );
  172. my %light_device_c2b; # DEVICE_TYPE->hash (reverse of light_device_codes)
  173. sub TRX_LIGHT_Initialize($) {
  174. my ($hash) = @_;
  175. foreach my $k ( keys %light_device_codes ) {
  176. $light_device_c2b{ $light_device_codes{$k}->[0] } = $k;
  177. }
  178. $hash->{Match} = "^..(10|11|12|13|14|15|16|17|18|19|1A).*";
  179. $hash->{SetFn} = "TRX_LIGHT_Set";
  180. $hash->{DefFn} = "TRX_LIGHT_Define";
  181. $hash->{UndefFn} = "TRX_LIGHT_Undef";
  182. $hash->{ParseFn} = "TRX_LIGHT_Parse";
  183. $hash->{AttrList} = "IODev ignore:1,0 do_not_notify:1,0 repeat " . $readingFnAttributes;
  184. }
  185. #####################################
  186. sub TRX_LIGHT_SetState($$$$) {
  187. my ( $hash, $tim, $vt, $val ) = @_;
  188. $val = $1 if ( $val =~ m/^(.*) \d+$/ );
  189. # to be done. Just accept everything right now.
  190. #return "Undefined value $val" if(!defined($fs20_c2b{$val}));
  191. return undef;
  192. }
  193. ###################################
  194. sub TRX_LIGHT_Set($@) {
  195. my ( $hash, $name, @a ) = @_;
  196. my $ret = undef;
  197. my $na = int(@a);
  198. return "no set value specified" if ( $na < 1 || $na > 2 );
  199. # look for device_type
  200. my $command = $a[0];
  201. my $command_state = $a[0];
  202. my $level = 0;
  203. my $color = 0;
  204. my $arg3 = "";
  205. # special for SetExtensions
  206. #old TRX_LIGHT used a special on-for-timer notation
  207. if ($command eq "on-for-timer") {
  208. my ($err,$h,$m,$s,$fb) = GetTimeSpec($a[1]);
  209. if (!defined($err)) {
  210. $a[1] = $h*3600+$m*60+$s;
  211. Log3 $name, 1, "TRX_LIGHT is now using SetExtensions. Consider changing [Set $name $command] to a numeric value (seconds) instead of a TimeSpec";
  212. }
  213. }
  214. if ( $na == 2 ) {
  215. $arg3 = $a[1];
  216. if ( $na == 2 && $command eq "level" ) {
  217. $level = $a[1];
  218. }
  219. elsif ( $na == 2 && $command eq "color" ) {
  220. $color = $a[1];
  221. }
  222. }
  223. my $device_type = $hash->{TRX_LIGHT_type};
  224. my $deviceid = $hash->{TRX_LIGHT_deviceid};
  225. if ( $device_type eq "MS14A" ) {
  226. return "No set implemented for $device_type";
  227. }
  228. if ( lc( $hash->{TRX_LIGHT_devicelog} ) eq "window"
  229. || lc( $hash->{TRX_LIGHT_devicelog} ) eq "door"
  230. || lc( $hash->{TRX_LIGHT_devicelog} ) eq "motion"
  231. || lc( $hash->{TRX_LIGHT_devicelog} ) eq "ring"
  232. || lc( $hash->{TRX_LIGHT_devicelog} ) eq "lightsensor"
  233. || lc( $hash->{TRX_LIGHT_devicelog} ) eq "photosensor"
  234. || lc( $hash->{TRX_LIGHT_devicelog} ) eq "lock" )
  235. {
  236. return "No set implemented for $device_type";
  237. }
  238. my $device_type_num = $light_device_c2b{$device_type};
  239. if ( !defined($device_type_num) ) {
  240. return "Unknown device_type, choose one of " . join( " ", sort keys %light_device_c2b );
  241. }
  242. my $protocol_type = $device_type_num >> 8; # high bytes
  243. # Now check if the command is valid and retrieve the command id:
  244. my $rec = $light_device_commands{$device_type_num};
  245. my $i;
  246. for ( $i = 0 ; $i <= $#$rec && ( $rec->[$i] ne $command ) ; $i++ ) { ; }
  247. if ( $rec->[0] eq "Lighting4" ) { # for Lighting4
  248. my $command_codes = $hash->{TRX_LIGHT_commandcodes} . ",";
  249. my $l = $command_codes;
  250. $l =~ s/([0-9]*):([a-z]*),/$2 /g;
  251. Log3 $name, 5, "TRX_LIGHT_Set() PT2262: l=$l";
  252. if ( !( $command =~ /^[0-2]*$/ ) ) { # if it is base4 just accept it
  253. if ( $command ne "?" && $command_codes =~ /([0-9]*):$command,/ ) {
  254. Log3 $name, 5, "TRX_LIGHT_Set() PT2262: arg=$command found=$1";
  255. $command = $1;
  256. }
  257. else {
  258. Log3 $name, 5, "TRX_LIGHT_Set() PT2262: else arg=$command l='$l'";
  259. my $error = "Unknown command $command, choose one of $l ";
  260. Log3 $name, 1, "TRX_LIGHT_Set() PT2262" . $error if ( $command ne "?" );
  261. return $error;
  262. }
  263. }
  264. }
  265. elsif ( $i > $#$rec ) {
  266. my $l = join( " ", sort @$rec );
  267. if ( $device_type eq "AC" || $device_type eq "HOMEEASY" || $device_type eq "ANSLUT" ) {
  268. $l =~ s/ level / level:slider,0,1,15 /;
  269. }
  270. elsif ( $device_type eq "TRC02" ) {
  271. $l =~ s/ color / color:slider,14,2,128 /;
  272. }
  273. #my $error = "Unknown command $command, choose one of $l";
  274. #my $error = "Unknown command $command, choose one of $l";
  275. return SetExtensions( $hash, $l, $name, @a );
  276. #Log3 $name, 1, "TRX_LIGHT_Set()" . $error if ( $command ne "?" );
  277. #return $error;
  278. }
  279. my $seqnr = 0;
  280. my $cmnd = $i;
  281. my $hex_prefix;
  282. my $hex_command;
  283. if ( $protocol_type == 0x10 ) {
  284. my $house;
  285. my $unit;
  286. if ( $deviceid =~ /(.)(.*)/ ) {
  287. $house = ord("$1");
  288. $unit = $2;
  289. }
  290. else {
  291. Log3 $name, 1,
  292. "TRX_LIGHT_Set() lighting1 wrong deviceid: name=$name device_type=$device_type, deviceid=$deviceid";
  293. return "error set name=$name deviceid=$deviceid";
  294. }
  295. # lighting1
  296. $hex_prefix = sprintf "0710";
  297. $hex_command = sprintf "%02x%02x%02x%02x%02x00", $device_type_num & 0xff, $seqnr, $house, $unit, $cmnd;
  298. Log3 $name, 5,
  299. "TRX_LIGHT_Set() name=$name device_type=$device_type, deviceid=$deviceid house=$house, unit=$unit command=$command";
  300. Log3 $name, 5, "TRX_LIGHT_Set hexline=$hex_prefix$hex_command";
  301. }
  302. elsif ( $protocol_type == 0x11 ) {
  303. # lighting2
  304. if ( uc($deviceid) =~ /^[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]$/ ) {
  305. ;
  306. }
  307. else {
  308. Log3 $name, 1,
  309. "TRX_LIGHT_Set() lighting2 wrong deviceid: name=$name device_type=$device_type, deviceid=$deviceid";
  310. return "error set name=$name deviceid=$deviceid";
  311. }
  312. $hex_prefix = sprintf "0B11";
  313. $hex_command = sprintf "%02x%02x%s%02x%02x00", $device_type_num & 0xff, $seqnr, $deviceid, $cmnd, $level;
  314. if ( $command eq "level" ) {
  315. $command .= sprintf " %d", $level;
  316. $command_state = $command;
  317. }
  318. Log3 $name, 5,
  319. "TRX_LIGHT_Set() lighting2 name=$name device_type=$device_type, deviceid=$deviceid command=$command";
  320. Log3 $name, 5, "TRX_LIGHT_Set() lighting2 hexline=$hex_prefix$hex_command";
  321. }
  322. elsif ( $protocol_type == 0x12 ) {
  323. # lighting3
  324. my $koppla_id = "";
  325. if ( uc($deviceid) =~ /^([0-1][0-9])([0-9A-F])([0-9A-F][0-9A-F])$/ ) {
  326. # $1 = system, $2 = high bits channel, $3 = low bits channel
  327. my $koppla_system = $1 - 1;
  328. if ( $koppla_system > 15 ) {
  329. return "error set name=$name deviceid=$deviceid. system must be in range 01-16";
  330. }
  331. $koppla_id = sprintf( "%02X", $koppla_system ) . $3 . "0" . $2;
  332. Log3 $name, 5, "TRX_LIGHT_Set() lighting3: deviceid=$deviceid kopplaid=$koppla_id";
  333. }
  334. else {
  335. Log3 $name, 1,
  336. "TRX_LIGHT_Set() lighting3 wrong deviceid: name=$name device_type=$device_type, deviceid=$deviceid. Wrong deviceid must be 3 digits with range 0000 - f3FF";
  337. return
  338. "error set name=$name deviceid=$deviceid. Wrong deviceid must be 5 digits consisting of 2 digit decimal value for system (01-16) and a 3 hex digit channel (000 - 3ff)";
  339. }
  340. $hex_prefix = sprintf "0812";
  341. $hex_command = sprintf "%02x%02x%s%02x00", $device_type_num & 0xff, $seqnr, $koppla_id, $cmnd;
  342. if ( $command eq "level" ) {
  343. $command .= sprintf " %d", $level;
  344. $command_state = $command;
  345. }
  346. Log3 $name, 5,
  347. "TRX_LIGHT_Set() lighting3 name=$name device_type=$device_type, deviceid=$deviceid command=$command";
  348. Log3 $name, 5, "TRX_LIGHT_Set() lighting3 hexline=$hex_prefix$hex_command";
  349. }
  350. elsif ( $protocol_type == 0x13 ) {
  351. # lighting4 (PT2262)
  352. my $pt2262_cmd;
  353. my $base_4;
  354. my $bindata;
  355. my $hexdata;
  356. if ( $command =~ /^[0-3]*$/ ) { # if it is base4 just append it
  357. $pt2262_cmd = $deviceid . $command;
  358. }
  359. else {
  360. return "TRX_LIGHT_Set() PT2262: cmd=$command name=$name not found";
  361. }
  362. if ( uc($pt2262_cmd) =~ /^[0-3][0-3][0-3][0-3][0-3][0-3][0-3][0-3][0-3][0-3][0-3][0-3]$/ ) {
  363. $base_4 = $pt2262_cmd;
  364. # convert base4 to binary:
  365. my %b42b = ( 0 => "00", 1 => "01", 2 => "10", 3 => "11" );
  366. ( $bindata = $base_4 ) =~ s/(.)/$b42b{lc $1}/g;
  367. $hexdata = unpack( "H*", pack( "B*", $bindata ) );
  368. Log3 $name, 5, "TRX_LIGHT_Set() PT2262: base4='$base_4', binary='$bindata' hex='$hexdata'";
  369. }
  370. else {
  371. Log3 $name, 5,
  372. "TRX_LIGHT_Set() lighting4:PT2262 cmd='$pt2262_cmd' needs to be base4 and has 12 digits (name=$name device_type=$device_type, deviceid=$deviceid)";
  373. return "error set name=$name deviceid=$pt2262_cmd (needs to be base4 and has 12 digits)";
  374. }
  375. $hex_prefix = sprintf "0913";
  376. $hex_command = sprintf "00%02x%s015E00", $seqnr, $hexdata;
  377. Log3 $name, 5,
  378. "TRX_LIGHT_Set() lighting4:PT2262 name=$name cmd=$command cmd_state=$command_state hexdata=$hexdata";
  379. Log3 $name, 5, "TRX_LIGHT_Set() lighting4:PT2262 hexline=$hex_prefix$hex_command";
  380. }
  381. elsif ( $protocol_type == 0x14 ) {
  382. # lighting5
  383. if ( uc($deviceid) =~ /^[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]$/ ) {
  384. ;
  385. }
  386. else {
  387. Log3 $name, 1,
  388. "TRX_LIGHT_Set() lighting5 wrong deviceid: name=$name device_type=$device_type, deviceid=$deviceid";
  389. return "error set name=$name deviceid=$deviceid";
  390. }
  391. if ( $command eq "color" ) {
  392. $cmnd = $color;
  393. $command .= sprintf " %d", $color;
  394. $command_state = $command;
  395. }
  396. $hex_prefix = sprintf "0A14";
  397. $hex_command = sprintf "%02x%02x%s%02x%02x00", $device_type_num & 0xff, $seqnr, $deviceid, $cmnd, $level;
  398. if ( $command eq "level" ) {
  399. $command .= sprintf " %d", $level;
  400. $command_state = $command;
  401. }
  402. Log3 $name, 5,
  403. "TRX_LIGHT_Set() lighting5 name=$name device_type=$device_type, deviceid=$deviceid command=$command";
  404. Log3 $name, 5, "TRX_LIGHT_Set() lighting5 hexline=$hex_prefix$hex_command";
  405. }
  406. elsif ( $protocol_type == 0x16 ) {
  407. # Chime
  408. if ( uc($deviceid) =~ /^[0-9A-F][0-9A-F]$/ ) {
  409. $hex_command = sprintf "%02x%02x00%s%02x00", $device_type_num & 0xff, $seqnr, $deviceid, $cmnd;
  410. }
  411. elsif ( uc($deviceid) =~ /^[0-9A-F][0-9A-F][0-9A-F][0-9A-F]$/ ) {
  412. $hex_command = sprintf "%02x%02x00%s00", $device_type_num & 0xff, $seqnr, $deviceid, $cmnd;
  413. }
  414. elsif ( uc($deviceid) =~ /^[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]$/ ) {
  415. $hex_command = sprintf "%02x%02x%s00", $device_type_num & 0xff, $seqnr, $deviceid, $cmnd;
  416. }
  417. else {
  418. Log3 $name, 1,
  419. "TRX_LIGHT_Set() chime wrong deviceid: name=$name device_type=$device_type, deviceid=$deviceid";
  420. return "error set name=$name deviceid=$deviceid";
  421. }
  422. $hex_prefix = sprintf "0716";
  423. Log3 $name, 5, "TRX_LIGHT_Set() chime name=$name device_type=$device_type, deviceid=$deviceid command=$command";
  424. Log3 $name, 5, "TRX_LIGHT_Set() chime hexline=$hex_prefix$hex_command";
  425. }
  426. elsif ( $protocol_type == 0x17 ) {
  427. # fan
  428. if ( uc($deviceid) =~ /^[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]$/ ) {
  429. ;
  430. }
  431. else {
  432. Log3 $name, 1,
  433. "TRX_LIGHT_Set() fan wrong deviceid: name=$name device_type=$device_type, deviceid=$deviceid";
  434. return "error set name=$name deviceid=$deviceid";
  435. }
  436. $hex_prefix = sprintf "0717";
  437. $hex_command = sprintf "%02x%02x%s%02xx00", $device_type_num & 0xff, $seqnr, $deviceid, $cmnd;
  438. Log3 $name, 5, "TRX_LIGHT_Set() fan name=$name device_type=$device_type, deviceid=$deviceid command=$command";
  439. Log3 $name, 5, "TRX_LIGHT_Set() fan hexline=$hex_prefix$hex_command";
  440. }
  441. elsif ( $protocol_type == 0x18 ) {
  442. # curtain1
  443. my $house;
  444. my $unit;
  445. if ( $deviceid =~ /(.)(.*)/ ) {
  446. $house = ord("$1");
  447. $unit = $2;
  448. }
  449. else {
  450. Log3 $name, 1,
  451. "TRX_LIGHT_Set() curtain1 wrong deviceid: name=$name device_type=$device_type, deviceid=$deviceid";
  452. return "error set name=$name deviceid=$deviceid";
  453. }
  454. $hex_prefix = sprintf "0718";
  455. $hex_command = sprintf "%02x%02x%02x%02x%02x00", $device_type_num & 0xff, $seqnr, $house, $unit, $cmnd;
  456. Log3 $name, 5,
  457. "TRX_LIGHT_Set() curtain1 name=$name device_type=$device_type, deviceid=$deviceid house=$house, unit=$unit command=$command";
  458. Log3 $name, 5, "TRX_LIGHT_Set curtain1 hexline=$hex_prefix$hex_command";
  459. }
  460. elsif ( $protocol_type == 0x19 ) {
  461. # Blinds1
  462. if ( uc($deviceid) =~ /^[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]$/ ) {
  463. ;
  464. }
  465. else {
  466. Log3 $name, 1,
  467. "TRX_LIGHT_Set() Blinds1 wrong deviceid: name=$name device_type=$device_type, deviceid=$deviceid";
  468. return "error set name=$name deviceid=$deviceid";
  469. }
  470. $hex_prefix = sprintf "0919";
  471. $hex_command = sprintf "%02x%02x%s%02x00", $device_type_num & 0xff, $seqnr, $deviceid, $cmnd;
  472. Log3 $name, 5,
  473. "TRX_LIGHT_Set() Blinds1 name=$name device_type=$device_type, deviceid=$deviceid command=$command";
  474. Log3 $name, 5, "TRX_LIGHT_Set() Blinds1 hexline=$hex_prefix$hex_command";
  475. }
  476. elsif ( $protocol_type == 0x1A ) {
  477. my $unitid;
  478. my $unitcode;
  479. if ( uc($deviceid) =~ /^([0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F])(0[0-9A-F])$/ ) {
  480. $unitid = $1;
  481. $unitcode = $2;
  482. if ( ( $device_type_num == 0x1A00 ) && !( $unitcode =~ /^0[0-4]$/ ) ) {
  483. Log3 $name, 1,
  484. "TRX_LIGHT_Set() RFY wrong unitcode: name=$name device_type=$device_type, unitid=$unitid unitcode=$unitcode";
  485. return "error set name=$name deviceid=$deviceid";
  486. }
  487. }
  488. else {
  489. Log3 $name, 1,
  490. "TRX_LIGHT_Set() RFY wrong deviceid: name=$name device_type=$device_type, deviceid=$deviceid";
  491. return "error set name=$name deviceid=$deviceid";
  492. }
  493. $hex_prefix = sprintf "0C1A";
  494. $hex_command = sprintf "%02x%02x%s%s%02x0000000000", $device_type_num & 0xff, $seqnr, $unitid, $unitcode, $cmnd;
  495. Log3 $name, 5,
  496. "TRX_LIGHT_Set() RFY name=$name device_type=$device_type, unitid=$unitid unitcode=$unitcode command=$command";
  497. Log3 $name, 5, "TRX_LIGHT_Set() RFY hexline=$hex_prefix$hex_command";
  498. }
  499. else {
  500. return "No set implemented for $device_type . Unknown protocol type";
  501. }
  502. for ( my $repeat = $attr{$name}{repeat} || 1 ; $repeat >= 1 ; $repeat = $repeat - 1 ) {
  503. IOWrite( $hash, $hex_prefix, $hex_command );
  504. }
  505. my $tn = TimeNow();
  506. $hash->{CHANGED}[0] = $command_state;
  507. $hash->{STATE} = $command_state;
  508. $hash->{READINGS}{state}{TIME} = $tn;
  509. $hash->{READINGS}{state}{VAL} = $command_state;
  510. # Add readingsupdate to trigger event / KernSani
  511. readingsBeginUpdate($hash);
  512. readingsBulkUpdate( $hash, "state", $command_state );
  513. readingsEndUpdate( $hash, 1 );
  514. return $ret;
  515. }
  516. #####################################
  517. sub TRX_LIGHT_Define($$) {
  518. my ( $hash, $def ) = @_;
  519. my @a = split( "[ \t][ \t]*", $def );
  520. my $a = int(@a);
  521. my $type = "";
  522. my $deviceid = "";
  523. my $devicelog = "";
  524. my $commandcodes = "";
  525. if ( int(@a) > 2 && uc( $a[2] ) eq "PT2262" ) {
  526. if ( int(@a) != 3 && int(@a) != 6 ) {
  527. Log3 $hash, 1,
  528. "TRX_LIGHT_Define() wrong syntax '@a'. \nCorrect syntax is 'define <name> TRX_LIGHT PT2262 [<deviceid> <devicelog> <commandcodes>]'";
  529. return "wrong syntax: define <name> TRX_LIGHT PT2262 [<deviceid> <devicelog> [<commandcodes>]]";
  530. }
  531. }
  532. elsif ( int(@a) != 5 && int(@a) != 7 ) {
  533. Log3 $hash, 1,
  534. "TRX_LIGHT_Define() wrong syntax '@a'. \nCorrect syntax is 'define <name> TRX_LIGHT <type> <deviceid> <devicelog> [<deviceid2> <devicelog2>]'";
  535. return "wrong syntax: define <name> TRX_LIGHT <type> <deviceid> <devicelog> [<deviceid2> <devicelog2>]";
  536. }
  537. my $name = $a[0];
  538. $type = uc( $a[2] ) if ( int(@a) > 2 );
  539. $deviceid = $a[3] if ( int(@a) > 3 );
  540. $devicelog = $a[4] if ( int(@a) > 4 );
  541. $commandcodes = $a[5] if ( $type eq "PT2262" && int(@a) > 5 );
  542. if ( $type ne "X10"
  543. && $type ne "ARC"
  544. && $type ne "MS14A"
  545. && $type ne "AB400D"
  546. && $type ne "WAVEMAN"
  547. && $type ne "EMW200"
  548. && $type ne "IMPULS"
  549. && $type ne "RISINGSUN"
  550. && $type ne "PHILIPS_SBC"
  551. && $type ne "AC"
  552. && $type ne "HOMEEASY"
  553. && $type ne "ANSLUT"
  554. && $type ne "KOPPLA"
  555. && $type ne "LIGHTWAVERF"
  556. && $type ne "EMW100"
  557. && $type ne "BBSB"
  558. && $type ne "TRC02"
  559. && $type ne "PT2262"
  560. && $type ne "ENER010"
  561. && $type ne "ENER5"
  562. && $type ne "COCO_GDR2"
  563. && $type ne "MDREMOTE"
  564. && $type ne "RSL2"
  565. && $type ne "LIVOLO"
  566. && $type ne "BLYSS"
  567. && $type ne "BYRONSX"
  568. && $type ne "SIEMENS_SF01"
  569. && $type ne "HARRISON"
  570. && $type ne "ROLLER_TROL"
  571. && $type ne "HASTA_OLD"
  572. && $type ne "AOK_RF01"
  573. && $type ne "AOK_AC114"
  574. && $type ne "RAEX_YR1326"
  575. && $type ne "MEDIA_MOUNT"
  576. && $type ne "DC106"
  577. && $type ne "FOREST"
  578. && $type ne "RFY"
  579. && $type ne "RFY_ext"
  580. && $type ne "SELECTPLUS" )
  581. {
  582. Log3 $name, 1, "TRX_LIGHT_Define() wrong type: $type";
  583. return "TRX_LIGHT: wrong type: $type";
  584. }
  585. my $my_type;
  586. if ( $type eq "MS14A" ) {
  587. $my_type = "X10"; # device will be received as X10
  588. }
  589. else {
  590. $my_type = $type;
  591. }
  592. my $device_name = "TRX" . $DOT . $my_type;
  593. if ( $deviceid ne "" ) { $device_name .= $DOT . $deviceid }
  594. $hash->{TRX_LIGHT_deviceid} = $deviceid;
  595. $hash->{TRX_LIGHT_devicelog} = $devicelog;
  596. $hash->{TRX_LIGHT_commandcodes} = $commandcodes if ( $type eq "PT2262" );
  597. $hash->{TRX_LIGHT_type} = $type;
  598. #$hash->{TRX_LIGHT_CODE} = $deviceid;
  599. $modules{TRX_LIGHT}{defptr}{$device_name} = $hash;
  600. if ( int(@a) == 7 ) {
  601. # there is a second deviceid:
  602. #
  603. my $deviceid2 = $a[5];
  604. my $devicelog2 = $a[6];
  605. my $device_name2 = "TRX" . $DOT . $my_type . $DOT . $deviceid2;
  606. $hash->{TRX_LIGHT_deviceid2} = $deviceid2;
  607. $hash->{TRX_LIGHT_devicelog2} = $devicelog2;
  608. #$hash->{TRX_LIGHT_CODE2} = $deviceid2;
  609. $modules{TRX_LIGHT}{defptr2}{$device_name2} = $hash;
  610. }
  611. AssignIoPort($hash);
  612. return undef;
  613. }
  614. #####################################
  615. sub TRX_LIGHT_Undef($$) {
  616. my ( $hash, $name ) = @_;
  617. delete( $modules{TRX_LIGHT}{defptr}{$name} );
  618. return undef;
  619. }
  620. ############################################
  621. # T R X _ L I G H T _ p a r s e _ X 1 0 ( )
  622. #-------------------------------------------
  623. sub TRX_LIGHT_parse_X10 ($$) {
  624. my ( $hash, $bytes ) = @_;
  625. my $error = "";
  626. #my $device;
  627. my $type = $bytes->[0];
  628. my $subtype = $bytes->[1];
  629. my $dev_type;
  630. my $dev_reading;
  631. my $rest;
  632. my $type_subtype = ( $type << 8 ) + $subtype;
  633. if ( exists $light_device_codes{$type_subtype} ) {
  634. my $rec = $light_device_codes{$type_subtype};
  635. ( $dev_type, $dev_reading ) = @$rec;
  636. }
  637. else {
  638. $error = sprintf "TRX_LIGHT: error undefined type=%02x, subtype=%02x", $type, $subtype;
  639. Log3 $hash, 1, "TRX_LIGHT_parse_X10() " . $error;
  640. return $error;
  641. }
  642. if ( $dev_type eq "BBSB" ) { return " "; } # ignore BBSB messages temporarily because of receiving problems
  643. my $device;
  644. my $data;
  645. if ( $type == 0x10 || $type == 0x18 ) {
  646. my $dev_first = "?";
  647. my %x10_housecode = (
  648. 0x41 => "A",
  649. 0x42 => "B",
  650. 0x43 => "C",
  651. 0x44 => "D",
  652. 0x45 => "E",
  653. 0x46 => "F",
  654. 0x47 => "G",
  655. 0x48 => "H",
  656. 0x49 => "I",
  657. 0x4A => "J",
  658. 0x4B => "K",
  659. 0x4C => "L",
  660. 0x4D => "M",
  661. 0x4E => "N",
  662. 0x4F => "O",
  663. 0x50 => "P",
  664. );
  665. my $devnr = $bytes->[3]; # housecode
  666. if ( exists $x10_housecode{$devnr} ) {
  667. $dev_first = $x10_housecode{$devnr};
  668. }
  669. else {
  670. $error = sprintf "TRX_LIGHT: x10_housecode wrong housecode=%02x", $devnr;
  671. Log3 $hash, 1, "TRX_LIGHT_parse_X10() " . $error;
  672. return $error;
  673. }
  674. my $unit = $bytes->[4]; # unitcode
  675. $device = sprintf '%s%0d', $dev_first, $unit;
  676. $data = $bytes->[5];
  677. }
  678. elsif ( $type == 0x11 ) {
  679. $device = sprintf '%02x%02x%02x%02x%02x', $bytes->[3], $bytes->[4], $bytes->[5], $bytes->[6], $bytes->[7];
  680. $data = $bytes->[8];
  681. }
  682. elsif ( $type == 0x14 ) {
  683. $device = sprintf '%02x%02x%02x%02x', $bytes->[3], $bytes->[4], $bytes->[5], $bytes->[6];
  684. $data = $bytes->[7];
  685. }
  686. elsif ( $type == 0x15 ) {
  687. $device = sprintf '%02x%02x%c%d', $bytes->[3], $bytes->[4], $bytes->[5], $bytes->[6];
  688. $data = $bytes->[7];
  689. }
  690. elsif ( $type == 0x16 ) { #Chime
  691. if ( $subtype == 0x00 ) {
  692. $device = sprintf '%02x', $bytes->[4];
  693. $data = $bytes->[5];
  694. }
  695. else {
  696. $device = sprintf '%02x', $bytes->[3], $bytes->[4];
  697. $data = 0;
  698. }
  699. }
  700. elsif ( $type == 0x17 ) { # Fan
  701. $device = sprintf '%02x%02x%02x', $bytes->[3], $bytes->[4], $bytes->[5];
  702. $data = $bytes->[6];
  703. }
  704. elsif ( $type == 0x19 ) { # Blinds1
  705. $device = sprintf '%02x%02x%02x%02x', $bytes->[3], $bytes->[4], $bytes->[5], $bytes->[6];
  706. $data = $bytes->[7];
  707. }
  708. elsif ( $type == 0x1A ) { # RFY
  709. $device = printf '%02x%02x%02x%02x', $bytes->[3], $bytes->[4], $bytes->[5], $bytes->[6];
  710. $data = $bytes->[7];
  711. }
  712. else {
  713. $error = sprintf "TRX_LIGHT: wrong type=%02x", $type;
  714. Log3 $hash, 1, "TRX_LIGHT_parse_X10() " . $error;
  715. return $error;
  716. }
  717. my $hexdata = sprintf '%02x', $data;
  718. my $command = "";
  719. if ( exists $light_device_commands{$type_subtype} ) {
  720. my $code = $light_device_commands{$type_subtype};
  721. if ( exists $code->[$data] ) {
  722. $command = $code->[$data];
  723. }
  724. else {
  725. $error = sprintf "TRX_LIGHT: unknown cmd type_subtype=%02x cmd=%02x", $type_subtype, $data;
  726. Log3 $hash, 1, "TRX_LIGHT_parse_X10() " . $error;
  727. return $error;
  728. }
  729. }
  730. else {
  731. $error = sprintf "TRX_LIGHT: unknown type_subtype %02x data=%02x", $type_subtype, $data;
  732. Log3 $hash, 1, "TRX_LIGHT_parse_X10() " . $error;
  733. return $error;
  734. }
  735. #my @res;
  736. my $current = "";
  737. #--------------
  738. my $device_name = "TRX" . $DOT . $dev_type . $DOT . $device;
  739. Log3 $hash, 5, "TRX_LIGHT: device_name=$device_name data=$hexdata";
  740. my $firstdevice = 1;
  741. my $def = $modules{TRX_LIGHT}{defptr}{$device_name};
  742. if ( !$def ) {
  743. $firstdevice = 0;
  744. $def = $modules{TRX_LIGHT}{defptr2}{$device_name};
  745. if ( !$def ) {
  746. Log3 $hash, 5, "TRX_LIGHT_parse_X10() UNDEFINED $device_name TRX_LIGHT $dev_type $device $dev_reading";
  747. Log3 $hash, 3, "TRX_LIGHT_parse_X10() Unknown device $device_name, please define it";
  748. return "UNDEFINED $device_name TRX_LIGHT $dev_type $device $dev_reading";
  749. }
  750. }
  751. # Use $def->{NAME}, because the device may be renamed:
  752. my $name = $def->{NAME};
  753. return "" if ( IsIgnored($name) );
  754. Log3 $name, 5, "TRX_LIGHT_parse_X10() $name devn=$device_name first=$firstdevice command=$command, cmd=$hexdata";
  755. my $n = 0;
  756. my $tm = TimeNow();
  757. my $val = "";
  758. my $device_type = $def->{TRX_LIGHT_type};
  759. my $sensor = "";
  760. if ( $device_type eq "MS14A" ) {
  761. # for ms14a behave like x10
  762. $device_type = "X10";
  763. }
  764. if ( lc( $def->{TRX_LIGHT_devicelog} ) eq "window" || lc( $def->{TRX_LIGHT_devicelog} ) eq "door" ) {
  765. $command = ( $command eq "on" ) ? "Open" : "Closed";
  766. }
  767. elsif ( lc( $def->{TRX_LIGHT_devicelog} ) eq "motion" ) {
  768. $command = ( $command eq "on" ) ? "alert" : "normal";
  769. }
  770. elsif ( lc( $def->{TRX_LIGHT_devicelog} ) eq "lightsensor" || lc( $def->{TRX_LIGHT_devicelog} ) eq "photosensor" ) {
  771. $command = ( $command eq "on" ) ? "dark" : "bright";
  772. }
  773. elsif ( lc( $def->{TRX_LIGHT_devicelog} ) eq "lock" ) {
  774. $command = ( $command eq "on" ) ? "Closed" : "Open";
  775. }
  776. elsif ( lc( $def->{TRX_LIGHT_devicelog} ) eq "ring" ) {
  777. $command = ( $command eq "on" ) ? "normal" : "alert";
  778. }
  779. readingsBeginUpdate($def);
  780. if ( $type == 0x10 || $type == 0x11 || $type == 0x14 || $type == 0x16 ) {
  781. # try to use it for all types:
  782. $current = $command;
  783. if ( $type == 0x11 && $command eq "level" ) {
  784. # append level number
  785. my $level = $bytes->[9];
  786. $current .= sprintf " %d", $level;
  787. }
  788. elsif ( $type == 0x14 && $command eq "level" ) {
  789. # append level number
  790. my $level = $bytes->[8];
  791. $current .= sprintf " %d", $level;
  792. }
  793. $sensor = $firstdevice == 1 ? $def->{TRX_LIGHT_devicelog} : $def->{TRX_LIGHT_devicelog2};
  794. $val .= $current;
  795. if ( $sensor ne "none" ) { readingsBulkUpdate( $def, $sensor, $current ); }
  796. }
  797. else {
  798. $error = sprintf "TRX_LIGHT: error unknown sensor type=%x device_type=%s devn=%s first=%d command=%s", $type,
  799. $device_type, $device_name, $firstdevice, $command;
  800. Log3 $name, 1, "TRX_LIGHT_parse_X10() " . $error;
  801. return $error;
  802. }
  803. if ( ( $firstdevice == 1 ) && $val ) {
  804. #$def->{STATE} = $val;
  805. readingsBulkUpdate( $def, "state", $val );
  806. }
  807. readingsEndUpdate( $def, 1 );
  808. return $name;
  809. }
  810. ########################################################
  811. # T R X _ L I G H T _ p a r s e _ P T 2 2 6 2 ( )
  812. #-------------------------------------------------------
  813. sub TRX_LIGHT_parse_PT2262 ($$) {
  814. my ( $hash, $bytes ) = @_;
  815. my $error = "";
  816. #my $device;
  817. my $type = $bytes->[0];
  818. my $subtype = $bytes->[1];
  819. my $dev_type;
  820. my $dev_reading;
  821. my $rest;
  822. my $type_subtype = ( $type << 8 ) + $subtype;
  823. if ( exists $light_device_codes{$type_subtype} ) {
  824. my $rec = $light_device_codes{$type_subtype};
  825. ( $dev_type, $dev_reading ) = @$rec;
  826. }
  827. else {
  828. $error = sprintf "TRX_LIGHT: PT2262 error undefined type=%02x, subtype=%02x", $type, $subtype;
  829. Log3 $hash, 1, "TRX_LIGHT_parse_PT2262() " . $error;
  830. return $error;
  831. }
  832. my $device;
  833. $device = "";
  834. my $command = "error";
  835. my $current = "";
  836. my $hexdata = sprintf '%02x%02x%02x', $bytes->[3], $bytes->[4], $bytes->[5];
  837. my $hex_length = length($hexdata);
  838. my $bin_length = $hex_length * 4;
  839. my $bindata = unpack( "B$bin_length", pack( "H$hex_length", $hexdata ) );
  840. #my @a = ($bindata =~ /[0-1]{2}/g);
  841. my $base_4 = $bindata;
  842. $base_4 =~ s/(.)(.)/$1*2+$2/eg;
  843. my $codes = $base_4;
  844. #$codes =~ tr/0123/UMED/; # Up,Middle,Error,Down
  845. $codes =~ s/0/up /g; #
  846. $codes =~ s/1/middle /g; #
  847. $codes =~ s/2/err /g; #
  848. $codes =~ s/3/down /g; #
  849. my $device_name = "TRX" . $DOT . $dev_type;
  850. my $command_codes = "";
  851. my $command_rest = "";
  852. my $def;
  853. # look for defined device with longest ID matching first:
  854. for ( my $i = 11 ; $i > 0 ; $i-- ) {
  855. if ( $modules{TRX_LIGHT}{defptr}{ $device_name . $DOT . substr( $base_4, 0, $i ) } ) {
  856. $device = substr( $base_4, 0, $i );
  857. $def = $modules{TRX_LIGHT}{defptr}{ $device_name . $DOT . substr( $base_4, 0, $i ) };
  858. $command_codes = $def->{TRX_LIGHT_commandcodes};
  859. $command_rest = substr( $base_4, $i );
  860. Log3 $hash, 5,
  861. "TRX_LIGHT_parse_PT2262() found device_name=$device_name i=$i code=$base_4 commandcodes='$command_codes' command_rest='$command_rest' ";
  862. }
  863. }
  864. #--------------
  865. if ( $device ne "" ) {
  866. # found a device
  867. Log3 $hash, 5, "TRX_LIGHT: PT2262 found device_name=$device_name data=$hexdata";
  868. $device_name .= $DOT . $device;
  869. }
  870. else {
  871. # no specific device found. Using generic one:
  872. Log3 $hash, 5, "TRX_LIGHT: PT2262 device_name=$device_name data=$hexdata";
  873. $def = $modules{TRX_LIGHT}{defptr}{$device_name};
  874. if ( !$def ) {
  875. $dev_reading = "";
  876. Log3 $hash, 5, "TRX_LIGHT_parse_PT2262() UNDEFINED $device_name TRX_LIGHT $dev_type $device $dev_reading";
  877. Log3 $hash, 3, "TRX_LIGHT_parse_PT2262() Unknown device $device_name, please define it";
  878. return "UNDEFINED $device_name TRX_LIGHT $dev_type $device $dev_reading";
  879. }
  880. }
  881. # Use $def->{NAME}, because the device may be renamed:
  882. my $name = $def->{NAME};
  883. return "" if ( IsIgnored($name) );
  884. Log3 $name, 5, "TRX_LIGHT_parse_PT2262() $name devn=$device_name command=$command, cmd=$hexdata";
  885. my $n = 0;
  886. my $val = "";
  887. my $device_type = $def->{TRX_LIGHT_type};
  888. my $sensor = $def->{TRX_LIGHT_devicelog};
  889. readingsBeginUpdate($def);
  890. $current = $command;
  891. if ( $device eq "" ) {
  892. #readingsBulkUpdate($def, "hex", $hexdata);
  893. #readingsBulkUpdate($def, "bin", $bindata);
  894. #readingsBulkUpdate($def, "base_4", $base_4);
  895. #readingsBulkUpdate($def, "codes", $codes);
  896. $val = $base_4;
  897. }
  898. else {
  899. # look for command code:
  900. $command_codes .= ",";
  901. #if ($command_codes =~ /$command_rest:(.*),/o ) {
  902. if ( $command_codes =~ /$command_rest:([a-z|A-Z]*),/ ) {
  903. Log3 $name, 5, "PT2262: found=$1";
  904. $command = $1;
  905. }
  906. Log3 $name, 5, "TRX_LIGHT_parse_PT2262() readingsBulkUpdate($def, $sensor, $command)";
  907. $val = $command;
  908. if ( $sensor ne "none" ) { readingsBulkUpdate( $def, $sensor, $val ); }
  909. }
  910. readingsBulkUpdate( $def, "state", $val );
  911. readingsEndUpdate( $def, 1 );
  912. return $name;
  913. }
  914. ####################################
  915. # T R X _ L I G H T _ P a r s e ( )
  916. #-----------------------------------
  917. sub TRX_LIGHT_Parse($$) {
  918. my ( $iohash, $hexline ) = @_;
  919. my $time = time();
  920. # convert to binary
  921. my $msg = pack( 'H*', $hexline );
  922. if ( $time_old == 0 ) {
  923. Log3 $iohash, 5, "TRX_LIGHT_Parse() decoding delay=0 hex=$hexline";
  924. }
  925. else {
  926. my $time_diff = $time - $time_old;
  927. Log3 $iohash, 5, "TRX_LIGHT_Parse() decoding delay=$time_diff hex=$hexline";
  928. }
  929. $time_old = $time;
  930. # convert string to array of bytes. Skip length byte
  931. my @rfxcom_data_array = ();
  932. foreach ( split( //, substr( $msg, 1 ) ) ) {
  933. push( @rfxcom_data_array, ord($_) );
  934. }
  935. my $num_bytes = ord($msg);
  936. if ( $num_bytes < 3 ) {
  937. return "";
  938. }
  939. my $type = $rfxcom_data_array[0];
  940. #Log3 $iohash, 5, "TRX_LIGHT: num_bytes=$num_bytes hex=$hexline type=$type";
  941. my $res = "";
  942. if ( $type == 0x10
  943. || $type == 0x11
  944. || $type == 0x12
  945. || $type == 0x14
  946. || $type == 0x15
  947. || $type == 0x16
  948. || $type == 0x17
  949. || $type == 0x18
  950. || $type == 0x19 )
  951. {
  952. Log3 $iohash, 5, "TRX_LIGHT_Parse() X10 num_bytes=$num_bytes hex=$hexline";
  953. $res = TRX_LIGHT_parse_X10( $iohash, \@rfxcom_data_array );
  954. Log3 $iohash, 1, "TRX_LIGHT_Parse() unsupported hex=$hexline" if ( $res eq "" );
  955. return $res;
  956. }
  957. elsif ( $type == 0x13 ) {
  958. Log3 $iohash, 5, "TRX_LIGHT_Parse()Lighting4/PT2262 num_bytes=$num_bytes hex=$hexline";
  959. $res = TRX_LIGHT_parse_PT2262( $iohash, \@rfxcom_data_array );
  960. Log3 $iohash, 1, "TRX_LIGHT_Parse() unsupported hex=$hexline" if ( $res eq "" );
  961. return $res;
  962. }
  963. else {
  964. Log3 $iohash, 1, "TRX_LIGHT_Parse() not implemented num_bytes=$num_bytes hex=$hexline";
  965. }
  966. return "";
  967. }
  968. 1;
  969. =pod
  970. =item device
  971. =item summary Sends and receive messages of lighting devices via TRX (RFXCOM)
  972. =item summary_DE Sendet und empfängt Nachrichten von Schaltaktoren via TRX (RFXCOM)
  973. =begin html
  974. <a name="TRX_LIGHT"></a>
  975. <h3>TRX_LIGHT</h3>
  976. <ul>
  977. The TRX_LIGHT module receives and sends X10, ARC, ELRO AB400D, Waveman, Chacon EMW200, IMPULS, RisingSun, AC, HomeEasy EU and ANSLUT lighting devices (switches and remote control). Allows to send Philips SBC (receive not possible). ARC is a protocol used by devices from HomeEasy, KlikAanKlikUit, ByeByeStandBy, Intertechno, ELRO, AB600, Duewi, DomiaLite and COCO with address code wheels. AC is the protocol used by different brands with units having a learning mode button:
  978. KlikAanKlikUit, NEXA, CHACON, HomeEasy UK. <br> You need to define an RFXtrx433 transceiver receiver first.
  979. See <a href="#TRX">TRX</a>.
  980. <br><br>
  981. <a name="TRX_LIGHTdefine"></a>
  982. <b>Define</b>
  983. <ul>
  984. <code>define &lt;name&gt; TRX_LIGHT &lt;type&gt; &lt;deviceid&gt; &lt;devicelog&gt; [&lt;deviceid2&gt; &lt;devicelog2&gt;] </code> <br>
  985. <code>define &lt;name&gt; TRX_LIGHT PT2262 &lt;deviceid&gt; &lt;devicelog&gt; &lt;commandcodes&gt;</code> <br>
  986. <br>
  987. <code>&lt;type&gt;</code>
  988. <ul>
  989. specifies the type of the device: <br>
  990. Lighting devices:
  991. <ul>
  992. <li> <code>MS14A</code> (X10 motion sensor. Reports [normal|alert] on the first deviceid (motion sensor) and [on|off] for the second deviceid (light sensor)) </li>
  993. <li> <code>X10</code> (All other x10 devices. Report [off|on|dim|bright|all_off|all_on] on both deviceids.)</li>
  994. <li> <code>ARC</code> (ARC devices. ARC is a protocol used by devices from HomeEasy, KlikAanKlikUit, ByeByeStandBy, Intertechno, ELRO, AB600, Duewi, DomiaLite and COCO with address code wheels. Report [off|on|all_off|all_on|chime].)</li>
  995. <li> <code>AB400D</code> (ELRO AB400D devices. Report [off|on].)</li>
  996. <li> <code>WAVEMAN</code> (Waveman devices. Report [off|on].)</li>
  997. <li> <code>EMW200</code> (Chacon EMW200 devices. Report [off|on|all_off|all_on].)</li>
  998. <li> <code>IMPULS</code> (IMPULS devices. Report [off|on].)</li>
  999. <li> <code>RISINGSUN</code> (RisingSun devices. Report [off|on].)</li>
  1000. <li> <code>PHILIPS_SBC</code> (Philips SBC devices. Send [off|on|all_off|all_on].)</li>
  1001. <li> <code>ENER010</code> (Energenie ENER010 devices. deviceid: [A-P][1-4]. Send [off|on|all_off|all_on].)</li>
  1002. <li> <code>ENER5</code> (Energenie 5-gang devices. deviceid: [A-P][1-10]. Send [off|on].)</li>
  1003. <li> <code>COCO_GDR2</code> (ECOCO GDR2-2000R devices. deviceid: [A-D][1-4]. Send [off|on].)</li>
  1004. <li> <code>AC</code> (AC devices. AC is the protocol used by different brands with units having a learning mode button: KlikAanKlikUit, NEXA, CHACON, HomeEasy UK. Report [off|on|level &lt;NUM&gt;|all_off|all_on|all_level &lt;NUM&gt;].)</li>
  1005. <li> <code>HOMEEASY</code> (HomeEasy EU devices. Report [off|on|level|all_off|all_on|all_level].)</li>
  1006. <li> <code>ANSLUT</code> (Anslut devices. Report [off|on|level|all_off|all_on|all_level].)</li>
  1007. <li> <code>PT2262</code> (Devices using PT2262/PT2272 (coder/decoder) chip. To use this enable Lighting4 in RFXmngr. Please note that this disables ARC. For more information see <a href="http://www.fhemwiki.de/wiki/RFXtrx#PT2262_empfangen_und_senden_mit_TRX_LIGHT.pm">FHEM-Wiki</a>)</li>
  1008. <li> <code>LIGHTWAVERF</code> (LightwaveRF devices. Commands ["off", "on", "all_off", "mood1", "mood2", "mood3", "mood4", "mood5", "reserved1", "reserved2", "unlock", "lock", "all_lock", "close", "stop", "open", "level"].)</li>
  1009. <li> <code>EMW100</code> (EMW100 devices. Commands ["off", "on", "learn"].)</li>
  1010. <li> <code>BBSB</code> (BBSB devices. Commands ["off", "on", "all_off", "all_on"].)</li>
  1011. <li> <code>MDREMOTE</code> (MDREMOTE LED dimmer devices. Commands ["power", "light", "bright", "dim", "100", "50", "25", "mode+", "speed-", "speed+", "mode-"].)</li>
  1012. <li> <code>RSL2</code> (Conrad RSL2 devices. Commands ["off", "on", "all_off", "all_on"].)</li>
  1013. <li> <code>LIVOLO</code> (Livolo devices. Commands ["all_off", "on_off", "dim+", "dim-"].)</li>
  1014. <li> <code>TRC02</code> (RGB TRC02 devices. Commands ["off", "on", "bright", "dim", "vivid", "pale", "color"].)</li>
  1015. <li> <code>BLYSS</code> (Blyss devices. deviceid: [A-P][1-5]. Commands ["off", "on", "all_off", "all_on"].)</li>
  1016. <li> <code>BYRONSX</code> (Byron SX chime devices. deviceid: 00-FF. Commands [ "tubular3_1", "solo1", "bigben1", "tubular2_1", "tubular2_2", "solo2", "tubular3_2"].)</li>
  1017. <li> <code>SELECTPLUS</code> (SELECTPLUS] chime devices. deviceid: 0000-FFFF. Commands [ "ring"].)</li>
  1018. <li> <code>SIEMENS_SF01</code> (Siemens SF01 devices. deviceid: 000000-007FFF. Commands [ "timer", "-", "learn", "+", "confirm", "light", "on", "off" ].)</li>
  1019. <li> <code>HARRISON</code> (Harrison curtain devices. deviceid: 00-FF. Commands [ "open", "close", "stop", "program" ].)</li>
  1020. <li> <code>ROLLER_TROL</code> (Roller Trol blind devices. deviceid: 00000100-00FFFF0F. Commands [ "open", "close", "stop", "confirm_pair", "set_limit" ].)</li>
  1021. <li> <code>HASTA_OLD</code> (Hasta old blind devices. deviceid: 00000100-00FFFF0F. Commands [ "open", "close", "stop", "confirm_pair", "set_limit" ].)</li>
  1022. <li> <code>AOK_RF01</code> (A-OK RF01 blind devices. deviceid: 00000100-FFFFFF0F. Commands [ "open", "close", "stop", "confirm_pair" ].)</li>
  1023. <li> <code>AOK_AC114</code> (A-OK AC114 blind devices. deviceid: 00000100-FFFFFF0F. Commands [ "open", "close", "stop", "confirm_pair" ].)</li>
  1024. <li> <code>RAEX_YR1326</code> (Raex YR1326 blind devices. deviceid: 00000100-FFFFFF0F. Commands [ "open", "close", "stop", "confirm_pair", "set_upper_limit", "set_lower_limit", "delete_limits", "change_dir", "left", "right"].)</li>
  1025. <li> <code>MEDIA_MOUNT</code> (Media Mount blind devices. deviceid: 00000100-FFFFFF0F. Commands [ "down", "up", "stop" ].)</li>
  1026. <li> <code>DC106</code> (DC/RMF/Yooda blind devices. deviceid: 00000100-FFFFFFF0. Commands [ "open", "close", "stop", "confirm" ].)</li>
  1027. <li> <code>FOREST</code> (Forest blind devices. deviceid: 00000100-FFFFFFF0. Commands [ "open", "close", "stop", "confirm_pair" ].)</li>
  1028. <li> <code>RFY</code> (Somfy RTS devices. deviceid: 000001-0FFFFF, unicode: 01-04 (00 = allunits). Commands [ "up", "down", "stop", "program" ].)</li>
  1029. <li> <code>RFY_ext</code> (Somfy RTS devices. deviceid: 000001-0FFFFF, unicode: 00-0F. Commands [ "up", "down", "stop", "program" ].)</li>
  1030. </ul>
  1031. </ul>
  1032. <br>
  1033. <code>&lt;deviceid&gt;</code>
  1034. <ul>
  1035. specifies the first device id of the device. <br>
  1036. A lighting device normally has a house code A..P followed by a unitcode 1..16 (example "B1").<br>
  1037. For AC, HomeEasy EU and ANSLUT it is a 10 Character-Hex-String for the deviceid, consisting of <br>
  1038. - unid-id: 8-Char-Hex: 00000001 to 03FFFFFF<br>
  1039. - unit-code: 2-Char-Hex: 01 to 10 <br>
  1040. For LIGHTWAVERF, EMW100, BBSB, MDREMOTE, RSL2, LIVOLO and TRC02 it is a 8 Character-Hex-String for the deviceid, consisting of <br>
  1041. - unid-id: 8-Char-Hex: 000001 to FFFFFF<br>
  1042. - unit-code: 2-Char-Hex: 01 to 10 <br>
  1043. For RFY and RFY-ext it is a 8 Character-Hex-String for the deviceid, consisting of <br>
  1044. - unid-id: 8-Char-Hex: 000001 to FFFFFF<br>
  1045. - unit-code: 2-Char-Hex: 01 to 04 for RFY (00 for all units) and 00 to 0F for RFY_ext <br>
  1046. </ul>
  1047. <br>
  1048. <code>&lt;devicelog&gt;</code>
  1049. <ul>
  1050. is the name of the Reading used to report. Suggested: "motion" for motion sensors. If you use "none" then no additional Reading is reported. Just the state is used to report the change.
  1051. </ul>
  1052. <br>
  1053. <code>&lt;deviceid2&gt;</code>
  1054. <ul>
  1055. is optional and specifies the second device id of the device if it exists. For example ms14a motion sensors report motion status on the first deviceid and the status of the light sensor on the second deviceid.
  1056. </ul>
  1057. <br>
  1058. <code>&lt;devicelog2&gt;</code>
  1059. <ul>
  1060. is optional for the name used for the Reading of <code>&lt;deviceid2&gt;</code>.If you use "none" then no addional Reading is reported. Just the state is used to report the change.
  1061. </ul>
  1062. <br>
  1063. <code>&lt;commandcodes&gt;</code>
  1064. <ul>
  1065. is used for PT2262 and specifies the possible base4 digits for the command separated by : and a string that specifies a string that is the command. Example '<code>0:off,1:on</code>'.
  1066. </ul>
  1067. <br>
  1068. Example: <br>
  1069. <code>define motion_sensor2 TRX_LIGHT MS14A A1 motion A2 light</code>
  1070. <br>
  1071. <code>define Steckdose TRX_LIGHT ARC G2 light</code>
  1072. <br>
  1073. <code>define light TRX_LIGHT AC 0101010101 light</code>
  1074. <br>
  1075. </ul>
  1076. <br>
  1077. <a name="TRX_LIGHTset"></a>
  1078. <b>Set </b>
  1079. <ul>
  1080. <code>set &lt;name&gt; &lt;value&gt; [&lt;levelnum&gt;]</code>
  1081. <br><br>
  1082. where <code>value</code> is one of:<br>
  1083. <ul>
  1084. <li>off</li>
  1085. <li>on</li>
  1086. <li>dim # only for X10, KOPPLA</li>
  1087. <li>bright # only for X10, KOPPLA</li>
  1088. <li>all_off # only for X10, ARC, EMW200, AC, HOMEEASY, ANSLUT</li>
  1089. <li>all_on # only for X10, ARC, EMW200, AC, HOMEEASY, ANSLUT</li>
  1090. <li>chime # only for ARC</li>
  1091. <li>level &lt;levelnum&gt; # only AC, HOMEEASY, ANSLUT: set level to &lt;levelnum&gt; (range: 0=0% to 15=100%)</li>
  1092. <li>ring # Byron MP001,SelectPlus, RFU, Envivo</li>
  1093. <li><a href="#setExtensions">setExtensions</a> # see Notes</li>
  1094. </ul>
  1095. Example: <br>
  1096. <code>set Steckdose on</code>
  1097. <br>
  1098. <br>
  1099. Notes:
  1100. <ul>
  1101. <li><code>on-for-timer</code> earlier required an absolute time in the "at" format. TRX_LIGHT is now using <a href="#setExtensions">SetExtensions</a>, thus <code>on-for-timer</code> now requires a number (seconds). TimeSpecs in the format (HH:MM:SS|HH:MM) or { &lt;perl code&gt; } are automatically converted, however it is recommended that you adjust your set commands.
  1102. </li>
  1103. </ul>
  1104. </ul><br>
  1105. <a name="TRX_LIGHTget"></a>
  1106. <b>Get</b> <ul>N/A</ul><br>
  1107. <a name="TRX_LIGHTattr"></a>
  1108. <b>Attributes</b>
  1109. <ul>
  1110. <li><a href="#ignore">ignore</a></li>
  1111. <li><a href="#do_not_notify">do_not_notify</a></li>
  1112. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  1113. </ul>
  1114. </ul>
  1115. =end html
  1116. =cut