21_N4HMODULE.pm 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033
  1. #############################################################################
  2. #
  3. # 21_N4HMODULE.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: 21_N4HMODULE.pm 12460 2016-10-28 19:00:30Z okoerber $
  24. #
  25. ##############################################################################
  26. package main;
  27. use strict;
  28. use warnings;
  29. use POSIX;
  30. use SetExtensions;
  31. sub N4HMODULE_Set($@);
  32. sub N4HMODULE_Update($@);
  33. sub N4HMODULE_DbLog_splitFn($$);
  34. my $n4hmodule_Version = "1.0.1.3 - 27.10.2016";
  35. my %OT_devices = (
  36. "1" => {"name" => "leer", "OTcanSet" => "false", "OTcanReq" => "false", "fields" => [] },
  37. "2" => {"name" => "Eingang, Binär, Sx", "OTcanSet" => "false", "OTcanReq" => "true", "fields" => [] },
  38. "3" => {"name" => "Ausgang, Binär, Relais", "OTcanSet" => "true", "OTcanReq" => "true", "fields" => [
  39. { "cmd" => "350000", "ID" => "0", "text" => "UM", "Type" => "Button" , "set" => "toggle:noArg" },
  40. { "cmd" => "326400", "ID" => "1", "text" => "EIN", "Type" => "Button" , "set" => "on:noArg" },
  41. { "cmd" => "320000", "ID" => "2", "text" => "AUS", "Type" => "Button" , "set" => "off:noArg" },
  42. { "cmd" => "428100", "ID" => "3", "text" => "Zwangsgeführt EIN", "Type" => "Button" , "set" => "lockon:noArg" },
  43. { "cmd" => "428000", "ID" => "4", "text" => "Zwangsgeführt AUS", "Type" => "Button" , "set" => "lockoff:noArg" },
  44. { "cmd" => "420000", "ID" => "5", "text" => "Zwangsführung deaktiv", "Type" => "Button" , "set" => "unlock:noArg" },
  45. ]},
  46. "4" => {"name" => "Ausgang, Binär, Timer, Relais", "OTcanSet" => "true", "OTcanReq" => "true", "fields" => [
  47. { "cmd" => "350000", "ID" => "0", "text" => "EIN für Dauer: Zeit 1", "Type" => "Button" , "set" => "toggle:noArg" },
  48. { "cmd" => "320000", "ID" => "2", "text" => "AUS", "Type" => "Button" , "set" => "off:noArg" },
  49. { "cmd" => "428100", "ID" => "3", "text" => "Zwangsgeführt EIN", "Type" => "Button" , "set" => "lockon:noArg" },
  50. { "cmd" => "428000", "ID" => "4", "text" => "Zwangsgeführt AUS", "Type" => "Button" , "set" => "lockoff:noArg" },
  51. { "cmd" => "420000", "ID" => "5", "text" => "Zwangsführung deaktiv", "Type" => "Button" , "set" => "unlock:noArg" },
  52. ]},
  53. "5" => {"name" => "Ausgang, Dimmer", "OTcanSet" => "true", "OTcanReq" => "true", "fields" => [
  54. { "cmd" => "320000", "ID" => "3", "text" => "AUS", "Type" => "Button" , "set" => "off:noArg" },
  55. { "cmd" => "326500", "ID" => "4", "text" => "EIN mit letztem Wert", "Type" => "Button" , "set" => "on:noArg" },
  56. { "cmd" => "350000", "ID" => "5", "text" => "UM", "Type" => "Button" , "set" => "toggle:noArg" },
  57. { "cmd" => "330000", "ID" => "7", "text" => "Heller", "Type" => "Button" , "set" => "dimup:noArg" },
  58. { "cmd" => "340000", "ID" => "8", "text" => "Dunkler", "Type" => "Button" , "set" => "dimdown:noArg" },
  59. { "cmd" => "428100", "ID" => "9", "text" => "Zwangsgeführt EIN", "Type" => "Button" , "set" => "lockon:noArg" },
  60. { "cmd" => "428000", "ID" => "10","text" => "Zwangsgeführt AUS", "Type" => "Button" , "set" => "lockoff:noArg" },
  61. { "cmd" => "32" , "ID" => "10","text" => "Wert setzen auf", "Type" => "Button" , "set" => "pct:slider,0,1,100" },
  62. { "cmd" => "420000", "ID" => "11", "Text" => "Zwangsführung deaktiv", "Type" => "Button" , "set" => "unlock:noArg" },
  63. ]},
  64. "24" => {"name" => "Messwert,Temperatur", "OTcanSet" => "false", "OTcanReq" => "true", "fields" => [] },
  65. "25" => {"name" => "Messwert,Helligkeit", "OTcanSet" => "false", "OTcanReq" => "true", "fields" => [] },
  66. "26" => {"name" => "Messwert,Feuchte", "OTcanSet" => "false", "OTcanReq" => "true", "fields" => [] },
  67. "95" => {"name" => "Ausgang, Jal, Motor AJ3", "OTcanSet" => "true", "OTcanReq" => "true", "fields" => [
  68. { "cmd" => "320000", "ID" => "1", "text" => "STOP", "Type" => "Button" , "set" => "stop:noArg" },
  69. { "cmd" => "320300", "ID" => "2", "text" => "AUF", "Type" => "Button" , "set" => "up:noArg" },
  70. { "cmd" => "320100", "ID" => "3", "text" => "AB", "Type" => "Button" , "set" => "down:noArg" },
  71. { "cmd" => "428300", "ID" => "4", "text" => "Sperre OFFEN", "Type" => "Button" , "set" => "lockup:noArg" },
  72. { "cmd" => "428100", "ID" => "5", "text" => "Sperre GESCHLOSSEN", "Type" => "Button" , "set" => "lockdown:noArg" },
  73. { "cmd" => "420000", "ID" => "6", "text" => "Sperre freigeben", "Type" => "Button" , "set" => "unlock:noArg" },
  74. ]},
  75. "210" => {"name" => "UP-RF Absender", "OTcanSet" => "false", "OTcanReq" => "true", "fields" => [] },
  76. "240" => {"name" => "Messwert,Wind", "OTcanSet" => "false", "OTcanReq" => "true", "fields" => [] },
  77. "242" => {"name" => "Messwert,Luftdruck", "OTcanSet" => "false", "OTcanReq" => "true", "fields" => [] },
  78. "245" => {"name" => "Messwert,Regenmenge", "OTcanSet" => "false", "OTcanReq" => "true", "fields" => [] },
  79. "310" => {"name" => "Stromzähler", "OTcanSet" => "false", "OTcanReq" => "true", "fields" => [
  80. { "cmd" => "330000", "ID" => "0", "Text" => "Inc", "Type" => "Button" , "set" => "inc" },
  81. ]},
  82. "348" => {"name" => "Zähler", "OTcanSet" => "false", "OTcanReq" => "true", "fields" => [
  83. { "cmd" => "330000", "ID" => "0", "Text" => "+1", "Type" => "Button" , "set" => "inc"},
  84. { "cmd" => "340000", "ID" => "1", "Text" => "-1", "Type" => "Button" , "set" => "dec" },
  85. { "cmd" => "320000", "ID" => "3", "Text" => "Zählerwert reset", "Type" => "Button" , "set" => "reset" },
  86. { "cmd" => "360000", "ID" => "4", "Text" => "Zählerwert lesen (nur LCD)", "Type" => "Button" },
  87. ] },
  88. "999" => {"name" => "Messwert,N56", "OTcanSet" => "false", "OTcanReq" => "true", "fields" => [] },
  89. );
  90. ##################################################################################
  91. sub N4HMODULE_Initialize($) {
  92. ##################################################################################
  93. my ($hash) = @_;
  94. my @otlist;
  95. foreach my $model (keys %OT_devices){
  96. push @otlist,$OT_devices{$model}->{name};
  97. }
  98. $hash->{DefFn} = "N4HMODULE_Define";
  99. $hash->{UndefFn} = "N4HMODULE_Undefine";
  100. $hash->{ParseFn} = "N4HMODULE_Parse";
  101. $hash->{SetFn} = "N4HMODULE_Set";
  102. $hash->{AttrFn} = "N4HMODULE_Attr";
  103. $hash->{AttrList} = "IoDev dummy:1,0 Interval sendack:on,off setList ".
  104. "$readingFnAttributes ";
  105. # "OT:" .join(",", sort @otlist);
  106. $hash->{DbLog_splitFn} = "N4HMODULE_DbLog_splitFn";
  107. }
  108. ##################################################################################
  109. sub N4HMODULE_Define($$) {
  110. ##################################################################################
  111. my ($hash, $def) = @_;
  112. my @args = split("[ \t]+", $def);
  113. my ($name, $type, $n4hbus, $ot, $objadr) = @args;
  114. my ($readings) = "";
  115. if(@args < 4) {
  116. my $msg = "Usage: define <name> N4HMODULE <N4HBUS> <OBJECTTYPE> <OBJADDR>";
  117. Log3 $hash, 2, $msg;
  118. return $msg;
  119. }
  120. $hash->{VERSION} = $n4hmodule_Version;
  121. $hash->{STATE} = "Initializing";
  122. $hash->{NOTIFYDEV} = "global";
  123. $hash->{IODev} = $n4hbus;
  124. $hash->{OBJADR} = $objadr;
  125. $hash->{OT} = $ot;
  126. $hash->{DESC} = $OT_devices{$ot}{name};
  127. $hash->{OTcanSet} = $OT_devices{$ot}{OTcanSet};
  128. $hash->{OTcanReq} = $OT_devices{$ot}{OTcanReq};
  129. $modules{N4HMODULE}{defptr}{$objadr} = $hash;
  130. AssignIoPort($hash, $n4hbus);
  131. Log3 $hash, 3, "N4HMODULE_Define -> $name ($ot) at device $n4hbus with objectadr $objadr";
  132. $hash->{helper}{from} = '';
  133. $hash->{helper}{value} = '';
  134. $hash->{helper}{cmd} = '';
  135. $hash->{helper}{ddata} = '';
  136. if ($hash->{OTcanSet}eq"true") {
  137. $hash->{helper}{state} = 'undefined';
  138. }
  139. $attr{$name}{room} = "net4home" if( !defined($attr{$name}{room}) );
  140. # Timer zum regelmäßigem aktualisieren auf dem Bus starten
  141. if (($ot == 24) or #Temperatur
  142. ($ot == 25) or #Licht
  143. ($ot == 26) or #Luftfeuchte
  144. ($ot == 240) or #Wind
  145. ($ot == 241) or #Sonne
  146. ($ot == 242) or #Luftdruck
  147. ($ot == 246) or #Luftdruck-Tendenz
  148. ($ot == 245)) { #Regenmenge l/h
  149. my $state_format;
  150. if( $ot == 24 ) { #Temperatur
  151. $state_format .= " " if( $state_format );
  152. $state_format .= "T: temperature";
  153. } elsif( $ot == 25 ) {
  154. $state_format .= " " if( $state_format );
  155. $state_format .= "L: brightness";
  156. } elsif( $ot == 26 ) {
  157. $state_format .= " " if( $state_format );
  158. $state_format .= "H: humidity";
  159. } elsif( $ot == 240 ) {
  160. $state_format .= " " if( $state_format );
  161. $state_format .= "W: wind";
  162. } elsif( $ot == 241 ) {
  163. $state_format .= " " if( $state_format );
  164. $state_format .= "L: brightness";
  165. } elsif( $ot == 242 ) {
  166. $state_format .= " " if( $state_format );
  167. $state_format .= "P: pressure";
  168. } elsif( $ot == 245 ) {
  169. $state_format .= " " if( $state_format );
  170. $state_format .= "R: rain";
  171. }
  172. $attr{$name}{stateFormat} = $state_format if( !defined($attr{$name}{stateFormat}) && defined($state_format) );
  173. RemoveInternalTimer($hash);
  174. $hash->{Interval} = 30;
  175. # Timer Zeitversetzt starten, damit nicht alles auf den Bus gleichzeit kommt 30 Sekunden + x
  176. Log3 $hash, 3, "N4HMODULE_Define (set timer) -> $name ($ot)";
  177. InternalTimer( gettimeofday() + 30 + int(rand(15)) , "N4HMODULE_Start", $hash, 0 );
  178. }
  179. return undef;
  180. }
  181. ##################################################################################
  182. sub N4HMODULE_Start($)
  183. ##################################################################################
  184. {
  185. my ($hash) = @_;
  186. my $name = $hash->{NAME};
  187. my $interval = $hash->{Interval};
  188. $interval = $attr{$name}{Interval} if( defined($attr{$name}{Interval}) );
  189. Log3 $hash, 5, "N4HMODULE (start): ($name)-> ".$interval." Sekunden";
  190. if (($interval >= 30) and ($interval <= 86400)) {
  191. # reset timer if interval is defined
  192. Log3 $hash, 5, "N4HMODULE (restart timer): ($name)-> ".$interval." Sekunden";
  193. RemoveInternalTimer( $hash );
  194. InternalTimer(gettimeofday() + $interval, "N4HMODULE_Start", $hash, 1 );
  195. N4HMODULE_Update( $hash );
  196. }
  197. }
  198. ##################################################################################
  199. sub N4HMODULE_Undefine($$) {
  200. ##################################################################################
  201. my ($hash,$arg) = @_;
  202. my $name = $hash->{NAME};
  203. Log3 $hash, 3, "N4HMODULE_Undefine -> $name";
  204. RemoveInternalTimer( $hash );
  205. delete($modules{N4HMODULE}{defptr}{$hash->{OBJADR}});
  206. return undef;
  207. }
  208. ##################################################################################
  209. sub N4HMODULE_DbLog_splitFn($$) {
  210. ##################################################################################
  211. my ($event, $device) = @_;
  212. my ($reading, $value, $unit) = "";
  213. my $hash = $defs{$device};
  214. my @parts = split(/ /,$event);
  215. $value = $parts[1];
  216. if ($event =~ m/temperature/) {
  217. $reading = 'temperature';
  218. $unit = '°C';
  219. } elsif ($event =~ m/humidity/) {
  220. $reading = 'humidity';
  221. $unit = '%';
  222. } elsif ($event =~ m/pressure/) {
  223. $reading = 'pressure';
  224. $unit = 'hPas';
  225. } elsif ($event =~ m/co2/) {
  226. $reading = 'co2';
  227. $unit = 'ppm';
  228. } elsif ($event =~ m/rain/) {
  229. $reading = 'rain';
  230. $unit = 'l/h';
  231. } elsif ($event =~ m/brightness/) {
  232. $reading = 'brightness';
  233. $unit = '';
  234. }
  235. return ($reading, $value, $unit);
  236. }
  237. ##################################################################################
  238. sub N4HMODULE_Parse($$) {
  239. ##################################################################################
  240. my ($iodev, $msg, $local) = @_;
  241. my $ioName = $iodev->{NAME};
  242. my $object = "";
  243. # Modul suchen
  244. my $type8 = hex(substr($msg,0,2));
  245. my $ipsrc = substr($msg,4,2).substr($msg,2,2);
  246. my $ipdst = hex(substr($msg,8,2).substr($msg,6,2));
  247. my $objsrc = hex(substr($msg,12,2).substr($msg,10,2));
  248. my $datalen = int(hex(substr($msg,14,2)));
  249. my $ddata = substr($msg,16, ($datalen*2));
  250. my $pos = $datalen*2+16;
  251. # Log3 "xx", 1, "(DECOMP2): T8($type8) - MI$ipsrc DST-> $ipdst SRC<-$objsrc";
  252. if ( length($msg) <= $pos ) {
  253. return undef;
  254. }
  255. my $csRX = substr($msg,$pos,2);
  256. my $csCalc = substr($msg,$pos+2,2);
  257. my $len = substr($msg,$pos+4,2);
  258. my $posb = substr($msg,$pos+6,2);
  259. if ($ipdst == 32767) {
  260. $object = $objsrc;
  261. } else {
  262. $object = $ipdst;
  263. }
  264. my $hash = $modules{N4HMODULE}{defptr}{$object};
  265. Log3 $hash, 5, "N4HMODULE (parse): $msg";
  266. if (!$hash) {
  267. $object = $objsrc;
  268. $hash = $modules{N4HMODULE}{defptr}{$objsrc};
  269. }
  270. if(!$hash) {
  271. my $ret = "Undefined ObjectAddress ($object)";
  272. return "";
  273. }
  274. my $devtype = $hash->{OT};
  275. N4HMODULE_ParsePayload($hash, $devtype, $ipsrc, $objsrc, $ddata);
  276. return $hash->{NAME};
  277. }
  278. ##################################################################################
  279. sub N4HMODULE_ParsePayload($@) {
  280. ##################################################################################
  281. my ($hash, $devtype, $ipsrc, $objsrc, $ddata) = @_;
  282. my $name = $hash->{NAME};
  283. my $dev_funcion = hex(substr($ddata,0,2));
  284. my $newState="";
  285. my $myval="";
  286. readingsBeginUpdate($hash);
  287. if( defined($objsrc)) {readingsBulkUpdate($hash,"from", $objsrc);}
  288. readingsBulkUpdate($hash,"ddata", $ddata);
  289. # +++++++ D0_SET
  290. if ($dev_funcion == hex("32")) {
  291. readingsBulkUpdate($hash,"cmd", "D0_SET");
  292. if (hex(substr($ddata,2,2))== hex("00")) {
  293. readingsBulkUpdate($hash,"state", "off");
  294. $hash->{STATE} = "off";
  295. } else {
  296. readingsBulkUpdate($hash,"state", "on");
  297. $hash->{STATE} = "on";
  298. }
  299. }
  300. # +++++++ D0_INC
  301. if ($dev_funcion == hex("33")) {
  302. readingsBulkUpdate($hash,"cmd", "D0_INC");
  303. }
  304. # +++++++ D0_TOGGLE
  305. if ($dev_funcion == hex("35")) {
  306. readingsBulkUpdate($hash,"cmd", "D0_TOGGLE");
  307. if (ReadingsVal($name, "state", "") eq "on") {
  308. readingsBulkUpdate($hash,"state", "off");
  309. $hash->{STATE} = "off";
  310. } elsif (ReadingsVal($name, "state", "") eq "off") {
  311. readingsBulkUpdate($hash,"state", "on");
  312. $hash->{STATE} = "on";
  313. }
  314. }
  315. # +++++++ D0_ACTOR_ACK
  316. if ($dev_funcion == hex("37")) {
  317. readingsBulkUpdate($hash,"cmd", "D0_ACTOR_ACK");
  318. }
  319. # +++++++ D0_REQ
  320. if ($dev_funcion == hex("36")) {
  321. readingsBulkUpdate($hash,"cmd", "D0_REQ");
  322. Log3 $hash, 5, "N4MODULE -> D0_REQ ($name) (".$hash->{OT}.")";
  323. N4HMODULE_Update( $hash );
  324. }
  325. # +++++++ D0_SENSOR_ACK
  326. if ($dev_funcion == hex("41")) {
  327. readingsBulkUpdate($hash,"cmd", "D0_SENSOR_ACK");
  328. Log3 $hash, 5, "N4MODULE -> D0_SENSOR_ACK ($name) (".$hash->{OT}.")";
  329. N4HMODULE_Update( $hash );
  330. }
  331. # +++++++ D0_VALUE_ACK (101)
  332. if ($dev_funcion == hex("65")) {
  333. readingsBulkUpdate($hash,"cmd", "D0_VALUE_ACK");
  334. my ($valtype, $lastval) = N4HMODULE_paramToText($hash, $ddata);
  335. if( defined($lastval)) { readingsBulkUpdate($hash, $valtype, $lastval); }
  336. }
  337. # +++++++ D0_VALUE_REQ
  338. if ($dev_funcion == hex("66")) {
  339. readingsBulkUpdate($hash,"cmd", "D0_VALUE_REQ");
  340. Log3 $hash, 5, "N4MODULE -> D0_VALUE_REQ ($name) (".$hash->{OT}.")";
  341. N4HMODULE_Update( $hash );
  342. }
  343. # +++++++ LCD-Text
  344. if ($dev_funcion == hex("3b")) {
  345. readingsBulkUpdate($hash,"cmd", "LCD-Text");
  346. }
  347. readingsEndUpdate( $hash , 1);
  348. return undef;
  349. }
  350. ##################################################################################
  351. sub N4HMODULE_paramToText($@) {
  352. ##################################################################################
  353. my ($hash, $ddata) = @_;
  354. my $name = $hash->{NAME};
  355. my $rettype = "unbekannte Formel / Parameter";
  356. my $w = hex(substr($ddata,6,2))*256+hex(substr($ddata,8,2));
  357. my $ret = $w;
  358. my $t;
  359. # +++++++++++++++++++ Licht analog - IN_HW_NR_IS_LICHT_ANALOG
  360. if (hex(substr($ddata,2,2)) == 5 ){
  361. $rettype = "brightness";
  362. }
  363. # +++++++++++++++++++ Uhrzeit - IN_HW_NR_IS_CLOCK
  364. elsif (hex(substr($ddata,2,2)) == 6 ){
  365. $rettype = "Uhrzeit";
  366. }
  367. # +++++++++++++++++++ RF-Tag Reader - IN_HW_NR_IS_RF_TAG_READER
  368. elsif (hex(substr($ddata,2,2)) == 7 ){
  369. $ret = uc substr($ddata,6,10);
  370. if ( (hex(substr($ddata,18,2)) & 6) == 0) {
  371. $ret = $ret." vorgehalten";
  372. } elsif ( (hex(substr($ddata,18,2)) & 6) == 2) {
  373. $ret = $ret." lang vorgehalten";
  374. } elsif ( (hex(substr($ddata,18,2)) & 6) == 4) {
  375. $ret = $ret." weggezogen nach kurz";
  376. }
  377. else { $ret = $ret." ".hex(substr($ddata,18,2)) }
  378. $rettype = "RF-Tag";
  379. }
  380. # +++++++++++++++++++ Temperatur - IN_HW_NR_IS_TEMP
  381. elsif (hex(substr($ddata,2,2)) == 9 ){
  382. if (hex(substr($ddata,4,2)) == 5 ){ # USE_FROMEL_TEMP_UI16
  383. if (hex(substr($ddata,6,2)) == 0xff ) {
  384. $t = (hex(substr($ddata,8,2))-0xff)/16;
  385. }
  386. else {
  387. $t = $w/16;
  388. }
  389. $ret = sprintf "%.1f °C", $t;
  390. $rettype = "temperature";
  391. }
  392. }
  393. # +++++++++++++++++++ Feuchte - IN_HW_NR_IS_HUMIDITY
  394. elsif (hex(substr($ddata,2,2)) == 11 ){
  395. $ret = $w." %";
  396. $rettype = "humidity";
  397. }
  398. # +++++++++++++++++++ Wind - IN_HW_NR_IS_KMH
  399. elsif (hex(substr($ddata,2,2)) == 41 ){
  400. if (hex(substr($ddata,4,2)) == 6 ){ # USE_FROMEL_RAW_16BIT
  401. $ret = $w." km/h";
  402. }
  403. elsif (hex(substr($ddata,4,2)) == 7 ){ # USE_FROMEL_16BIT_X8
  404. $t = $w/8;
  405. $ret = $t." km/h";
  406. }
  407. $rettype = "wind";
  408. }
  409. # +++++++++++++++++++ Luftdruck - IN_HW_NR_IS_PRESS_MBAR
  410. elsif (hex(substr($ddata,2,2)) == 48 ){
  411. $t = $w/10;
  412. $ret = $t." hPas";
  413. $rettype = "pressure";
  414. }
  415. # +++++++++++++++++++ pressure Tendenz - IN_HW_NR_IS_PRESS_TENDENZ
  416. elsif (hex(substr($ddata,2,2)) == 49 ){
  417. $rettype = "pressure (Tendenz)";
  418. }
  419. # +++++++++++++++++++ Uhrzeit - Sonnenaufgang heute
  420. elsif (hex(substr($ddata,2,2)) == 50 ){
  421. $rettype = "Sonnenaufgang";
  422. }
  423. # +++++++++++++++++++ Uhrzeit - Sonnenuntergang heute
  424. elsif (hex(substr($ddata,2,2)) == 51 ){
  425. $rettype = "Sonnenuntergang";
  426. }
  427. # +++++++++++++++++++ Regenmenge (Liter/Stunde) - VAL_IS_MENGE_LITER
  428. elsif (hex(substr($ddata,2,2)) == 53 ){
  429. if (hex(substr($ddata,4,2)) == 8 ){ # USE_FROMEL_16BIT_X10
  430. $t = $w/10;
  431. $ret = $t." l/h";
  432. }
  433. else {
  434. $ret = $w." l/h";
  435. }
  436. $rettype = "rain";
  437. }
  438. return ($rettype, $ret);
  439. }
  440. ##################################################################################
  441. sub N4HMODULE_Set($@) {
  442. ##################################################################################
  443. my ($hash, @a) = @_;
  444. return "\"set $a[0]\" needs at least two parameters" if(@a < 2);
  445. my $name = shift(@a);
  446. my $cmd = shift(@a);
  447. my $ext = shift(@a);
  448. Log3 $hash, 5, "N4MODULE (set): ($name) ($cmd)";
  449. my $ot = $hash->{OT};
  450. my $ipdst = $hash->{OBJADR};
  451. my $ddata = "";
  452. my @sets;
  453. my $fieldcmd = "";
  454. my $fieldname;
  455. my $fieldset;
  456. my $setfield;
  457. my $devtype = $OT_devices{$ot};
  458. if ($ot == 3 || $ot == 4 || $ot == 5 || $ot == 95) {
  459. for my $field (@{$devtype->{fields}}) {
  460. $setfield = $field->{set};
  461. if (defined($setfield)) {
  462. push(@sets,$field->{set});
  463. $setfield = ( split /:/, $setfield, 2 )[0];
  464. if ($setfield eq $cmd) {
  465. $fieldname = $field->{text};
  466. $fieldcmd = $field->{cmd};
  467. $fieldset = $field->{set};
  468. }
  469. }
  470. }
  471. if ($fieldcmd ne "" && $cmd ne "?") {
  472. if (defined($ext)) {
  473. if ($cmd eq "pct") {
  474. $fieldcmd = "$fieldcmd".sprintf ("%02x", ($ext))."00";
  475. $ddata = sprintf ("%02x%s", ((length($fieldcmd))/2), $fieldcmd);
  476. readingsSingleUpdate($hash, "pct", "$ext", 1);
  477. Log3 $hash, 5, "N4MODULE (set): $name to $cmd ($ext%) ($ddata)";
  478. } else {
  479. $ddata = sprintf ("%02x%s", (length($fieldcmd)/2), $fieldcmd);
  480. Log3 $hash, 5, "N4MODULE (set): $name to $cmd/$ext ($cmd-".join(" ", @sets)."-$devtype-$fieldcmd-$ot)";
  481. }
  482. } else {
  483. Log3 $hash, 5, "N4MODULE (set): $name to $cmd ($cmd-".join(" ", @sets)."-$devtype-$fieldcmd-$ot)";
  484. $ddata = sprintf ("%02x%s", (length($fieldcmd)/2), $fieldcmd);
  485. }
  486. readingsSingleUpdate($hash, "state", "$cmd", 1);
  487. IOWrite($hash, $ipdst, $ddata, 0);
  488. return undef;
  489. }
  490. else {
  491. return SetExtensions($hash, join(" ", @sets), $name, $cmd, @a);
  492. }
  493. }
  494. elsif ($ot == 24 || $ot == 25 || $ot == 26 || $ot == 240 || $ot == 242 || $ot == 245) {
  495. if ($cmd ne "?") {
  496. Log3 $hash, 5, "N4MODULE (set): $name to $cmd";
  497. N4HMODULE_Update($hash, $cmd);
  498. }
  499. return undef;
  500. }
  501. elsif ($ot == 999) {
  502. if ($cmd ne "?") {
  503. Log3 $hash, 5, "N4MODULE (set n56): $name to $cmd";
  504. N4HMODULE_Update($hash, $cmd);
  505. }
  506. return undef;
  507. }
  508. return undef;
  509. }
  510. ##################################################################################
  511. sub N4HMODULE_Update($@) {
  512. ##################################################################################
  513. my ($hash, @a) = @_;
  514. my $value = shift(@a);
  515. my $name = $hash->{NAME};
  516. return unless (defined($hash->{NAME}) and defined $value );
  517. Log3 $hash, 5, "N4MODULE (update): ($name) ($value)";
  518. my $ot = $hash->{OT};
  519. my $ipdst = $hash->{OBJADR};
  520. my $ddata = "";
  521. my $cs = "";
  522. my $cmd = "";
  523. if ($ot == 24) {
  524. # +++++++ 65 D0_VALUE_ACK (101)
  525. # +++++++ 09 Temperatur
  526. # +++++++ 05 USE_FROMEL_TEMP_UI16
  527. my $ddata1 = "650905";
  528. if (defined $value) {
  529. $cmd = $value;
  530. readingsSingleUpdate($hash, "temperature", "$cmd °C", 1);
  531. }
  532. else {
  533. ($cmd, undef) = split(/ /, ReadingsVal($name , "temperature", "")); }
  534. if (defined $cmd) {
  535. if ($cmd >= 0) {
  536. $cs = $cmd*16;
  537. $ddata1 = $ddata1.sprintf ("%02X", ($cs>>8) );
  538. }
  539. elsif ($cmd < 0) {
  540. $cs = 0xff+($cmd*16);
  541. $ddata1 = $ddata1.sprintf ("%02X", 0xff );
  542. }
  543. $ddata1 = $ddata1.sprintf ("%02X", ( ($cs>>0) & 255 ) );
  544. $ddata = sprintf ("%02x%s", (length($ddata1)/2), $ddata1);
  545. Log3 $hash, 5, "N4MODULE (set temperature): $name to $cmd - $ddata, $ddata1, $ipdst";
  546. IOWrite($hash, 32767, $ddata, $ipdst);
  547. }
  548. return undef;
  549. }
  550. elsif ($ot == 25) { # Licht
  551. # +++++++ 65 D0_VALUE_ACK
  552. # +++++++ 05 Licht
  553. # +++++++ 01 USE_FROMEL
  554. my $ddata1 = "650506";
  555. if (defined $value) {
  556. $cmd = $value;
  557. readingsSingleUpdate($hash, "brightness", "$cmd", 1);
  558. }
  559. else {
  560. ($cmd, undef) = split(/ /, ReadingsVal($name , "brightness","")); }
  561. if (defined $cmd) {
  562. my $cs = $cmd;
  563. $ddata1 = $ddata1.sprintf ("%02X", (0x00) );
  564. $ddata1 = $ddata1.sprintf ("%02X", ( ($cs) ) );
  565. $ddata = sprintf ("%02x%s", (length($ddata1)/2), $ddata1);
  566. Log3 $hash, 5, "N4MODULE (set brightness): $name to $cmd - $ddata, $ddata1, $ipdst";
  567. IOWrite($hash, 32767, $ddata, $ipdst);
  568. }
  569. return undef;
  570. }
  571. elsif ($ot == 26) { # Luftfeuchte
  572. # +++++++ 65 D0_VALUE_ACK
  573. # +++++++ 0B Luftfeuchte
  574. # +++++++ 01 USE_FROMEL
  575. my $ddata1 = "650B01";
  576. if (defined $value) {
  577. $cmd = $value;
  578. readingsSingleUpdate($hash, "humidity", "$cmd %", 1);
  579. }
  580. else {
  581. ($cmd, undef) = split(/ /, ReadingsVal($name , "humidity","")); }
  582. if (defined $cmd) {
  583. my $cs = $cmd;
  584. $ddata1 = $ddata1.sprintf ("%02X", (0x00) );
  585. $ddata1 = $ddata1.sprintf ("%02X", ( ($cs) ) );
  586. $ddata = sprintf ("%02x%s", (length($ddata1)/2), $ddata1);
  587. Log3 $hash, 5, "N4MODULE (set humidity): $name to $cmd - $ddata, $ddata1, $ipdst";
  588. IOWrite($hash, 32767, $ddata, $ipdst);
  589. }
  590. return undef;
  591. }
  592. elsif ($ot == 240) { # Wind
  593. # +++++++ 65 D0_VALUE_ACK
  594. # +++++++ 29 Windgeschwindigkeit
  595. # +++++++ 01 USE_FROMEL
  596. my $ddata1 = "652907";
  597. if (defined $value) {
  598. $cmd = $value;
  599. readingsSingleUpdate($hash, "wind", "$cmd km/h", 1);
  600. }
  601. else {
  602. ($cmd, undef) = split(/ /, ReadingsVal($name , "wind","")); }
  603. if (defined $cmd) {
  604. my $cs = $cmd*8;
  605. $ddata1 = $ddata1.sprintf ("%02X", ($cs>>8) );
  606. $ddata1 = $ddata1.sprintf ("%02X", ( $cs & 0xff ) );
  607. $ddata = sprintf ("%02x%s", (length($ddata1)/2), $ddata1);
  608. Log3 $hash, 5, "N4MODULE (set wind): $name to $cmd - $ddata, $ddata1, $ipdst";
  609. IOWrite($hash, 32767, $ddata, $ipdst);
  610. }
  611. return undef;
  612. }
  613. elsif ($ot == 242) { # Luftdruck
  614. # +++++++ 65 D0_VALUE_ACK
  615. # +++++++ 30 Luftdruck
  616. # +++++++ 01 USE_FROMEL
  617. my $ddata1 = "653001";
  618. if (defined $value) {
  619. $cmd = $value;
  620. readingsSingleUpdate($hash, "pressure", "$cmd hPas", 1);
  621. }
  622. else {
  623. ($cmd, undef) = split(/ /, ReadingsVal($name , "pressure","")); }
  624. if (defined $cmd) {
  625. my $cs = $cmd*10;
  626. $ddata1 = $ddata1.sprintf ("%02X", ($cs>>8) );
  627. $ddata1 = $ddata1.sprintf ("%02X", ( $cs & 0xff ) );
  628. $ddata = sprintf ("%02x%s", (length($ddata1)/2), $ddata1);
  629. Log3 $hash, 5, "N4MODULE (set pressure): $name to $cmd - $ddata, $ddata1, $ipdst";
  630. IOWrite($hash, 32767, $ddata, $ipdst);
  631. }
  632. return undef;
  633. }
  634. elsif ($ot == 245) { # Regenmenge
  635. # +++++++ 65 D0_VALUE_ACK
  636. # +++++++ 35 Regenmenge
  637. # +++++++ 01 USE_FROMEL
  638. my $ddata1 = "653508";
  639. if (defined $value) {
  640. $cmd = $value;
  641. readingsSingleUpdate($hash, "rain", "$cmd l/h", 1);
  642. }
  643. else {
  644. ($cmd, undef) = split(/ /, ReadingsVal($name , "rain","")); }
  645. if (defined $cmd) {
  646. my $cs = $cmd*10;
  647. $ddata1 = $ddata1.sprintf ("%02X", ($cs>>8) );
  648. $ddata1 = $ddata1.sprintf ("%02X", ( $cs & 0xff ) );
  649. $ddata = sprintf ("%02x%s", (length($ddata1)/2), $ddata1);
  650. Log3 $hash, 5, "N4MODULE (set rain): $name to $cmd - $ddata, $ddata1, $ipdst";
  651. IOWrite($hash, 32767, $ddata, $ipdst);
  652. }
  653. return undef;
  654. }
  655. elsif ($ot == 999) { # N56
  656. # +++++++ 65 D0_SENSOR_ACK (41)
  657. my $ddata1 = "41";
  658. if (defined $value) {
  659. $cmd = $value;
  660. # $cmd = N4HMODULE_ParseN56(substr($hash->{READINGS}{ddata},2,18));
  661. readingsSingleUpdate($hash, "value", "$cmd", 1);
  662. } else{
  663. return undef;
  664. }
  665. my $n56 = N4HMODULE_CreateN56($value,0,0,0,2);
  666. $ddata1 = $ddata1.$n56;
  667. $ddata = sprintf ("%02x%s", (length($ddata1)/2), $ddata1);
  668. $ipdst = 1;
  669. Log3 $hash, 5, "N4MODULE (set N56): $name to $cmd - $ddata, $ddata1, $ipdst, $n56";
  670. IOWrite($hash, 1, $ddata, $ipdst);
  671. return undef;
  672. }
  673. return undef;
  674. }
  675. ##################################################################################
  676. sub N4HMODULE_Attr(@) {
  677. ##################################################################################
  678. my ($cmd,$name,$attr_name,$attr_value) = @_;
  679. if($cmd eq "set") {
  680. if($attr_name eq "Interval") {
  681. if (($attr_value < 30) or ($attr_value > 86400)) {
  682. my $err = "Invalid time $attr_value to $attr_name. Must be > 30 and < 86400.";
  683. return $err;
  684. }
  685. }
  686. }
  687. return undef;
  688. }
  689. ##################################################################################
  690. sub N4HMODULE_CreateN56(@) {
  691. ##################################################################################
  692. my ($val32,$exp8,$expb,$findex,$decimal) = @_;
  693. my $ddata = "";
  694. my $myformel = "";
  695. # print "\n".$val32*($expb**$exp8)."\n";
  696. my $unsigned = $val32 < 0 ? 2 ** 32 + $val32 : $val32;
  697. my $myddata = sprintf("%08X", $unsigned);
  698. my $ps = $exp8 < 0 ? 2 ** 8 + $exp8 : $exp8;
  699. $myformel = sprintf("%04X",$findex);
  700. $ddata = substr($myddata,6,2).substr($myddata,4,2).substr($myddata,2,2).substr($myddata,0,2).sprintf("%02X",$ps).substr($myformel,2,2).substr($myformel,0,2).sprintf("%02X",$decimal).sprintf("%02X",$expb);
  701. return ($ddata);
  702. }
  703. ##################################################################################
  704. sub N4HMODULE_ParseN56($) {
  705. ##################################################################################
  706. my ($n56) = @_;
  707. my $exp8 = hex(substr($n56,8,2));
  708. my $val32 = hex(substr($n56,6,2).substr($n56,4,2).substr($n56,2,2).substr($n56,0,2));
  709. my $expb = hex(substr($n56,16,2));
  710. my $formel = hex(substr($n56,10,2)).hex(substr($n56,12,2));;
  711. my $deci = hex(substr($n56,14,2));
  712. $exp8 = $exp8 >> 7 ? $exp8 - 2 ** 8 : $exp8;
  713. $val32 = $val32 >> 31 ? $val32 - 2 ** 32 : $val32;
  714. if ($expb eq 0) {
  715. $expb = 10;
  716. } elsif ($expb eq 1) {
  717. $expb = 2;
  718. }
  719. my $ddata = sprintf("Wert: %.".$deci."f", ($val32*($expb**$exp8)))." (Formel: $formel)";
  720. return ($ddata);
  721. }
  722. ##################################################################################
  723. ##################################################################################
  724. 1;
  725. =pod
  726. =item device
  727. =item summary Module to emulate net4home Actors and Sensors via N4HBUS
  728. =item summary_DE Modul zum emulieren von net4home Aktoren und Sensoren ueber N4HBUS
  729. =begin html
  730. <a name="N4HMODULE"></a>
  731. <h3>N4HMODULE</h3>
  732. fhem-Module to communicate with net4home modules via IP
  733. <br /><br />
  734. <ul>
  735. <br />
  736. <a name="N4HMODULE_Define"></a>
  737. <b>Define</b>
  738. <ul>
  739. <code>define &lt;name&gt; N4HMODULE &lt;device&gt; &lt;type&gt; &lt;objectaddress&gt;</code><br />
  740. <br />
  741. Defines a net4home device connected to a <a href="#N4HBUS">N4HBUS</a> device <br /><br />
  742. Examples:
  743. <ul>
  744. <code>define n4h_28204 N4HMODULE n4h 24 28204</code><br />
  745. </ul>
  746. Currently the following values are supported:<br />
  747. <b>Measurement</b><br />
  748. <ul>
  749. <li> 24 - Measurement,Temperature</li>
  750. <li> 25 - Measurement,Brightness</li>
  751. <li> 26 - Measurement,Humidity</li>
  752. <li>240 - Measurement,Wind</li>
  753. <li>242 - Measurement,Pressure</li>
  754. <li>245 - Measurement,Rain</li>
  755. </ul>
  756. </ul><br />
  757. <a name="N4HMODULE_Readings"></a>
  758. <b>Readings</b>
  759. <ul>
  760. <li>The readings are dependent of the object of the net4home bus module.<br /></li>
  761. </ul><br />
  762. <a name="N4HMODULE_Attr"></a>
  763. <b>Attributes</b>
  764. <ul>
  765. <li>interval<br>
  766. the interval in seconds used to send values to bus.</li>
  767. </ul>
  768. </ul>
  769. =end html
  770. =begin html_DE
  771. <a name="N4HMODULE"></a>
  772. <h3>N4HMODULE</h3>
  773. fhem-Modul zur Kommunikation mit dem net4home Bus über IP
  774. <br /><br />
  775. <ul>
  776. <br />
  777. <a name="N4HMODULE_Define"></a>
  778. <b>Define</b>
  779. <ul>
  780. <code>define &lt;name&gt; N4HMODULE &lt;device&gt; &lt;type&gt; &lt;objectaddress&gt;</code><br />
  781. <br />
  782. Erstellt ein net4home Modul-Device welches mit dem <a href="#N4HBUS">N4HBUS</a> Device kommuniziert.
  783. Beispiel:
  784. <ul>
  785. <code>define MyN4HMODULEice N4HMODULE 24 26004</code><br />
  786. </ul>
  787. Derzeit werden folgende Typen unterst&uuml;tzt:<br />
  788. <b>Messwerte</b><br />
  789. <ul>
  790. <li> 24 - Messwert,Temperatur</li>
  791. <li> 25 - Messwert,Helligkeit</li>
  792. <li> 26 - Messwert,Feuchte</li>
  793. <li>240 - Messwert,Wind</li>
  794. <li>242 - Messwert,Luftdruck</li>
  795. <li>245 - Messwert,Regenmenge</li>
  796. </ul>
  797. </ul><br />
  798. <a name="N4HMODULE_Readings"></a>
  799. <b>Readings</b>
  800. <ul>
  801. <li>Die Readings werden Abhängig vom Modultyp angegeben.<br /></li>
  802. </ul><br />
  803. <a name="N4HMODULE_Attr"></a>
  804. <b>Attributes</b>
  805. <ul>
  806. <li>Interval<br>
  807. Das Interval bestimmt bei Messwerten die Zeit zwischen dem Senden der Daten auf den Bus. Ist kein Attribut definiert, so wird der Standardwert genutzt.</li>
  808. </ul>
  809. </ul>
  810. =end html_DE
  811. =cut