20_N4HBUS.pm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. #############################################################################
  2. #
  3. # 20_N4HBUS.pm
  4. #
  5. # net4home Busconnector Device
  6. #
  7. # (c) 2014-2016 Oliver Koerber <koerber@net4home.de>
  8. #
  9. #
  10. # Fhem is free software: you can redistribute it and/or modify
  11. # it under the terms of the GNU General Public License as published by
  12. # the Free Software Foundation, either version 2 of the License, or
  13. # (at your option) any later version.
  14. #
  15. # Fhem is distributed in the hope that it will be useful,
  16. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. # GNU General Public License for more details.
  19. #
  20. # You should have received a copy of the GNU General Public License
  21. # along with fhem. If not, see <http://www.gnu.org/licenses/>.
  22. #
  23. # $Id: 20_N4HBUS.pm 12459 2016-10-28 19:00:08Z okoerber $
  24. #
  25. ##############################################################################
  26. package main;
  27. use strict;
  28. use warnings;
  29. use POSIX;
  30. use Data::Dumper;
  31. my $n4hbus_Version = "1.0.1.2 - 27.10.2016";
  32. sub N4HBUS_Read($@);
  33. sub N4HBUS_Write($$$$);
  34. sub N4HBUS_Ready($);
  35. sub N4HBUS_getDevList($$);
  36. sub N4HBUS_decompSection($$$);
  37. sub N4HBUS_CompressSection($$);
  38. sub N4HBUS_Initialize($)
  39. {
  40. my ($hash) = @_;
  41. require "$attr{global}{modpath}/FHEM/DevIo.pm";
  42. # Provider
  43. $hash->{ReadFn} = "N4HBUS_Read";
  44. $hash->{WriteFn} = "N4HBUS_Write";
  45. $hash->{ReadyFn} = "N4HBUS_Ready";
  46. # Normal devices
  47. $hash->{UndefFn} = "N4HBUS_Undef";
  48. $hash->{DefFn} = "N4HBUS_Define";
  49. $hash->{AttrList} = "dummy:1,0 ".
  50. "OBJADR ".
  51. "MI ";
  52. }
  53. #################################################################################
  54. sub N4HBUS_Define($$) {
  55. #################################################################################
  56. my ($hash, $def) = @_;
  57. my @a = split("[ \t]+", $def);
  58. if(@a != 3) {
  59. my $msg = "wrong syntax: define <name> N4HBUS hostname:port";
  60. Log3 $hash, 2, $msg;
  61. return $msg;
  62. }
  63. DevIo_CloseDev($hash);
  64. my $name = $a[0];
  65. my $dev = $a[2];
  66. $hash->{VERSION} = $n4hbus_Version;
  67. $hash->{DeviceName} = $dev;
  68. $hash->{Clients} = ":N4HMODULE:";
  69. my %matchList = ( "1:N4HMODULE" => ".*" );
  70. $hash->{MatchList} = \%matchList;
  71. Log3 $hash, 3, "N4HBUS_Define -> $name at $dev";
  72. if($dev eq "none") {
  73. Log3 $hash, 1, "N4HBUS device is none, commands will be echoed only";
  74. $attr{$name}{dummy} = 1;
  75. return undef;
  76. }
  77. my $ret = DevIo_OpenDev($hash, 0, "N4HBUS_DoInit");
  78. return $ret;
  79. }
  80. #################################################################################
  81. sub N4HBUS_DoInit($) {
  82. #################################################################################
  83. my $hash = shift;
  84. my $name = $hash->{NAME};
  85. delete $hash->{HANDLE};
  86. # set OBJ and MI if not defined as attributes
  87. if (!defined($hash->{OBJADR}) ) {
  88. $attr{$name}{OBJADR} = 32700;
  89. }
  90. if (!defined($hash->{MI}) ) {
  91. $attr{$name}{MI} = 65281;
  92. }
  93. my $sendmsg = "190000000002ac0f400a000002bc02404600000487000000c000000200";
  94. DevIo_SimpleWrite($hash, $sendmsg, 1);
  95. return undef;
  96. }
  97. #################################################################################
  98. sub N4HBUS_Undef($@) {
  99. #################################################################################
  100. my ( $hash, $arg ) = @_;
  101. my $name = $hash->{NAME};
  102. Log3 $hash, 2, "close port for $name";
  103. DevIo_CloseDev($hash);
  104. return undef;
  105. }
  106. ##################################################################################
  107. sub decode_d2b (@) {
  108. ##################################################################################
  109. my $w = sprintf("%04x\n", @_);
  110. my $ret = substr($w,2,2).substr($w,0,2);
  111. return $ret;
  112. }
  113. #################################################################################
  114. sub N4HBUS_CompressSection($$) {
  115. #################################################################################
  116. my ($hash, $pUnCompressed) = @_;
  117. my ($cs, $x) = 0;
  118. my $pCompressed = "";
  119. my $sizeRaw = length($pUnCompressed)/2;
  120. for(my $i=0;$i < (length($pUnCompressed)/2); $i++) {
  121. $cs = $cs + hex(substr($pUnCompressed,$i*2,2));
  122. }
  123. my $len = length($pUnCompressed)/2;
  124. my $hi = $len >> 8;
  125. my $lo = $len & 0b0000000011111111;
  126. $pCompressed = sprintf ("%02X%02X", $hi,$lo);
  127. my $p = 0;
  128. while ($len>0){
  129. $pCompressed = $pCompressed.(substr($pUnCompressed,$p*2,2));
  130. $len--;
  131. $p++;
  132. }
  133. $pCompressed = $pCompressed."C0";
  134. $pCompressed = $pCompressed.sprintf ("%02X", ($cs>>24) );
  135. $pCompressed = $pCompressed.sprintf ("%02X", ($cs>>16) );
  136. $pCompressed = $pCompressed.sprintf ("%02X", ($cs>>8) );
  137. $pCompressed = $pCompressed.sprintf ("%02X", ( ($cs>>0) & 0xff ) );
  138. $pCompressed = sprintf ("%02X", (length($pCompressed)/2))."000000".$pCompressed;
  139. return $pCompressed;
  140. }
  141. #################################################################################
  142. sub N4HBUS_decompSection($$$) {
  143. #################################################################################
  144. my ($hash, $p2, $fs) = @_;
  145. my $ret = 0;
  146. my $inBlock;
  147. my $gPoutPos = 0;
  148. my $zaehler = 0;
  149. my $err = 0;
  150. my $ende = 0;
  151. my $gPout = "";
  152. my $bb = 0;
  153. my $bc = 0;
  154. my $csCalc = 0;
  155. my $csRx;
  156. my $maxoutlen = 372;
  157. my @ar2k;
  158. my $decompressor_err = -4;
  159. my $decompressor_errAdr = 0;
  160. while (($zaehler<$fs) && ($gPoutPos < $maxoutlen) && ($ende != 1) && ($err != 1)) {
  161. $bb = substr($p2,$zaehler*2,2);
  162. my $bbout = hex($bb) & 192;
  163. if ( (hex($bb) & 192) == 192) {
  164. # Ende ist gefunden
  165. $ende = 1;
  166. } elsif ((hex($bb) & 192) == 0) {
  167. $bc = substr($p2,(($zaehler+1)*2),2);
  168. $inBlock = (hex(substr($p2,$zaehler*2,2))*256) + hex($bc);
  169. $zaehler = $zaehler+2;
  170. while ($inBlock > 0) {
  171. $inBlock--;
  172. $gPout = $gPout.substr($p2,$zaehler*2,2);
  173. $zaehler++;
  174. }
  175. } elsif ((hex($bb) & 192) == 64) {
  176. $bc = substr($p2,(($zaehler+1)*2),2);
  177. $inBlock = ((hex(substr($p2,$zaehler*2,2))*256) + hex($bc)) & 16383;
  178. $bb = substr($p2,($zaehler+2)*2,2);
  179. $zaehler = $zaehler+3;
  180. while ($inBlock > 0) {
  181. $inBlock--;
  182. $gPout = $gPout.$bb;
  183. }
  184. } elsif ($bb & 0xC0 == 0x80) {
  185. $err = 1;
  186. $decompressor_err = -2;
  187. $zaehler++;
  188. }
  189. $decompressor_errAdr = $zaehler;
  190. }
  191. if (($err != 1) and ($ende == 1)) {
  192. $ret = $gPout;
  193. }
  194. return $ret;
  195. }
  196. ##################################################################################
  197. sub N4HBUS_bin2text ($) {
  198. ##################################################################################
  199. # Umwandlung der empfangenen oder zu sendenden Daten in lesbares Format
  200. my ( $data ) = @_;
  201. my $ret = "";
  202. my $sub;
  203. if (length($data)>60) {
  204. # Kenne ich noch nicht
  205. $ret = "(".substr($data,0,12).")\t";
  206. # ptype
  207. $sub = hex(substr($data,14,2).substr($data,12,2));
  208. $ret = $ret."ptype=$sub\t";
  209. # payloadlen
  210. $sub = hex(substr($data,18,2).substr($data,16,2));
  211. $ret = $ret."payloadlen=$sub\t";
  212. # MMS oder BIN
  213. $sub = hex(substr($data,22,2).substr($data,20,2));
  214. $ret = $ret."IP=$sub\t";
  215. # Kenne ich noch nicht
  216. $sub = substr($data,24, 6);
  217. $ret = $ret."($sub)\t";
  218. # type8
  219. $sub = hex(substr($data,30,2));
  220. $ret = $ret."type8=$sub\t";
  221. # ipsrc
  222. $sub = (substr($data,34,2).substr($data,32,2));
  223. $ret = $ret."MI=$sub\t";
  224. # ipdst
  225. $ret = $ret."ipdst=".hex(substr($data,38,2).substr($data,36,2))."\t";
  226. # objsrc
  227. $ret = $ret."objsrc=".hex(substr($data,42,2).substr($data,40,2))."\t";
  228. # datalen
  229. my $datalen = hex((substr($data,44,2)));
  230. $ret = $ret."datalen=".$datalen."\t";
  231. # ddata
  232. $ret = $ret."ddata=".substr($data,46, ($datalen*2))."\t";
  233. my $pos = $datalen*2+46;
  234. my $csRX = hex(substr($data,$pos,2));
  235. my $csCalc = hex(substr($data,$pos+2,2));
  236. my $len = hex(substr($data,$pos+4,2));
  237. my $posb = hex(substr($data,$pos+6,2));
  238. $ret = $ret."($csRX/$csCalc/$len/$posb)"
  239. }
  240. return $ret;
  241. }
  242. ##################################################################################
  243. sub N4HBUS_Write($$$$) {
  244. ##################################################################################
  245. my ($hash,$ipdst,$ddata,$objsource) = @_;
  246. my $name = $hash->{NAME};
  247. return if(!$hash || AttrVal($hash->{NAME}, "dummy", 0) != 0);
  248. my $sendmsg = "";
  249. my $sendbus = "";
  250. my $msg = "";
  251. my $objsrc = AttrVal($name, "OBJADR", 32700);
  252. my $ipsrc = AttrVal($name, "MI", 65281);
  253. # A10F 0000 4E00 0000 00 - 00 5902 0D62 2D65 03 32 00 64 03D416070102201500003120736563742000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004A4A030000
  254. # payload type
  255. $sendbus = "A10F0000";
  256. # payload len0
  257. $sendbus = $sendbus."4E000000";
  258. #??
  259. $sendbus = $sendbus."00";
  260. # typ8
  261. $sendbus = $sendbus."00";
  262. $sendbus = $sendbus.decode_d2b($ipsrc);
  263. $sendbus = $sendbus.decode_d2b($ipdst);
  264. if ($objsource !=0 ) {
  265. $objsrc = $objsource;
  266. }
  267. $sendbus = $sendbus.decode_d2b($objsrc);
  268. # ddata
  269. while (length($ddata)<128) {
  270. $ddata = $ddata."00";
  271. }
  272. $sendbus = $sendbus.$ddata;
  273. # csRx, csCalc, len, posb
  274. $sendbus = $sendbus."00000000";
  275. $sendmsg = N4HBUS_CompressSection($hash, $sendbus);
  276. Log3 $hash, 5, "N4HBUS (+++): $sendmsg";
  277. if(defined($hash)) {
  278. DevIo_SimpleWrite($hash, $sendmsg, 1);
  279. }
  280. }
  281. ##################################################################################
  282. sub N4HBUS_Read($@) {
  283. #################################################################################
  284. my ($hash, $local, $regexp) = @_;
  285. my $buf = DevIo_SimpleRead($hash);
  286. return "" if(!defined($buf));
  287. my $name = $hash->{NAME};
  288. my $recdata = unpack('H*', $buf);
  289. my $data;
  290. my $len = 0;
  291. $len = substr($recdata,6,2);
  292. $len = $len.substr($recdata,4,2);
  293. $len = $len.substr($recdata,2,2);
  294. $len = $len.substr($recdata,0,2);
  295. $len =~ s/^0+//;
  296. my $test = "";
  297. $recdata = substr($recdata,8,hex($len)*2);
  298. while (length($recdata) >= ( hex($len) *2)) {
  299. $data = substr($recdata,0, hex($len)*2);
  300. Log3 $hash, 5, "N4HBUS (DECOMP): Länge (".hex($len)." bytes)-$data";
  301. # Log3 $hash, 1, "(DECOMP1): Länge (".hex($len)." bytes)-$data";
  302. # 0005 a10f 0000 04 40 05 0000 1c 7302 ff7f a86a 05 65 09 05 01 c2 4d617263656c20476f6572747a6b6175403000c000000b24
  303. # 0005 a10f 0000 04 40 06 0000 1b 01 bc7f 1127 04 41 00 01 04 624d617263656c20476f6572747a6b6175403000c000000904
  304. # 1b 01 ffff 1127 03 ff ff ff 64b44d617263656c20476f6572747a6b6175403000c000000d33
  305. # 0005 a10f 0000 04 40 05 0000 1f 2600 ffff 2c0a 03 ff ff ff 017f2127100320160100271003201601006f00a19c400aff402300c000001333
  306. my $idx;
  307. $idx = index($data,"a10f");
  308. if ($idx>=0) {
  309. $data = substr($data,$idx); # Cut off beginning - Der Anfang interessiert erst mal nicht...
  310. my $msg = substr($data,18,length($data));
  311. my $type8 = hex(substr($msg,0,2));
  312. # Es ist ein "normales" Status-Paket
  313. if ($type8>=0) {
  314. $hash->{"${name}_MSGCNT"}++;
  315. $hash->{"${name}_TIME"} = TimeNow();
  316. $hash->{RAWMSG} = $msg;
  317. my %addvals = (RAWMSG => $data);
  318. Dispatch($hash, $msg, \%addvals) if($init_done);
  319. }
  320. } # a10f - Statuspaket
  321. $recdata = substr($recdata,( hex($len) *2));
  322. } # while
  323. return undef;
  324. }
  325. #################################################################################
  326. sub N4HBUS_Ready($) {
  327. #################################################################################
  328. my ($hash) = @_;
  329. Log3 $hash, 1, "N4HBUS_Ready";
  330. return DevIo_OpenDev($hash, 1, "N4HBUS_DoInit");
  331. }
  332. # function decompSection(p2:pbyte; offset, fs:dword; p2out:pbyte; MaxOutLen:dword; useCS:boolean):dword;
  333. #################################################################################
  334. 1;
  335. =pod
  336. =item device
  337. =item summary Connector to net4home bus via IP
  338. =item summary_DE Konnektor zum net4home Bus über IP
  339. =begin html
  340. <a name="N4HBUS"></a>
  341. <h3>N4HBUS</h3>
  342. This module connects fhem to the net4home Bus. You need to define ojects with <a href="#N4MODULE">N4MODULE</a> to set or read
  343. data of th net4home bus.
  344. <br /><br />
  345. Further technical information can be found at the <a href="http://www.net4home.de">net4home.de</a> Homepage
  346. <br /><br />
  347. <a name="N4HBUS_Define"></a>
  348. <b>Define</b>
  349. <ul>
  350. <code>define &lt;name&gt; N4HBUS &lt;device&gt;</code>
  351. <br /> <br />
  352. &lt;device&gt; is a combination of &lt;host&gt;:&lt;port&gt;, where &lt;host&gt; is the IP address of the net4home Busconnector and &lt;port&gt; (default:3478).
  353. <br /> <br />
  354. Example:
  355. <ul>
  356. <code>define net4home N4HBUS 192.168.1.69:3478</code>
  357. </ul>
  358. <br />
  359. The device can also be connected to the busconnector on the same machine. <br />
  360. Default Port for communication is 3478. In case you need to change this please change also the Port in the conf of busconnector service.
  361. </ul>
  362. <br />
  363. <a name="N4HBUS_Readings"></a>
  364. <b>Readings</b>
  365. <ul>
  366. <li>state - current state of the Bus connection</li>
  367. </ul><br />
  368. <a name="N4HBUS_Attr"></a>
  369. <b>Attributes</b>
  370. <ul>
  371. <li>MI - a unique MI in the net4home environment (default:65281)</li>
  372. <li>OBJADR - a unique OBJADR in the net4home environment (default:32700)</li>
  373. </ul>
  374. =end html
  375. =begin html_DE
  376. <a name="N4HBUS"></a>
  377. <h3>N4HBUS</h3>
  378. Dieses Modul verbindet fhem &uuml;ber IP mit dem net4home Bus. Zus&auml;tzlich m&uuml;ssen Objekte &uuml;ber den Typ
  379. <a href="#N4MODULE">N4MODULE</a> definiert werden, um Daten an den net4home-Bus zu senden oder zu lesen.
  380. <br /><br />
  381. Weitere technische Informationen gibt es auf der Homepage unter <a href="http://www.net4home.de">net4home.de</a>
  382. <br /><br />
  383. <a name="N4HBUS_Define"></a>
  384. <b>Define</b>
  385. <ul>
  386. <code>define &lt;name&gt; N4HBUS &lt;device&gt;</code>
  387. <br /> <br />
  388. &lt;device&gt; ist eine Kombination aus IP Adresse des net4home Busconnectors und dem Port (default:3478).
  389. <br /> <br />
  390. Beispiel:
  391. <ul>
  392. <code>define net4home N4HBUS 192.168.1.69:3478</code>
  393. </ul>
  394. <br />
  395. Das Device kann sich auch mit dem Busconnector auf dem selben System verbinden.
  396. Der Default-Port für die Kommunikation ist 3478. Sollte es n&ouml;tig sein den Port zu ver&auml;ndern, so muss dies ebenfalls
  397. in der Konfiguration des Services durchgef&uuml;hrt werden.<br />
  398. </ul>
  399. <br />
  400. <a name="N4HBUS_Readings"></a>
  401. <b>Readings</b>
  402. <ul>
  403. <li>state - aktueller Status der Verbindung zum net4home Busconnector</li>
  404. </ul><br />
  405. <a name="N4HBUS_Attr"></a>
  406. <b>Attributes</b>
  407. <ul>
  408. <li>MI - die eindeutige MI in der net4home Umgebung (default:65281)</li>
  409. <li>OBJADR - die eindeutige OBJADR in der net4home Umgebung (default:32700)</li>
  410. </ul>
  411. =end html_DE
  412. =cut