51_MOBILEALERTS.pm 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188
  1. ##############################################
  2. # $Id: 51_MOBILEALERTS.pm 16104 2018-02-06 19:11:13Z MarkusF $
  3. # Written by Markus Feist, 2017
  4. package main;
  5. use strict;
  6. use warnings;
  7. use constant MA_RAIN_FACTOR => 0.258;
  8. sub MOBILEALERTS_Initialize($) {
  9. my ($hash) = @_;
  10. $hash->{DefFn} = "MOBILEALERTS_Define";
  11. $hash->{UndefFn} = "MOBILEALERTS_Undef";
  12. $hash->{SetFn} = "MOBILEALERTS_Set";
  13. $hash->{AttrFn} = "MOBILEALERTS_Attr";
  14. $hash->{ParseFn} = "MOBILEALERTS_Parse";
  15. $hash->{Match} = "^.*";
  16. $hash->{AttrList} =
  17. "actCycle "
  18. . "lastMsg:0,1 "
  19. . "expert:0,1,4 "
  20. . "stateFormat "
  21. . "ignore:0,1 "
  22. . $readingFnAttributes;
  23. $hash->{AutoCreate} = {
  24. "MA_.*" => {
  25. ATTR => "event-on-change-reading:.* timestamp-on-change-reading:.*",
  26. FILTER => "%NAME"
  27. }
  28. };
  29. InternalTimer( gettimeofday() + 60, "MOBILEALERTS_ActionDetector", $hash );
  30. Log3 "MOBILEALERTS", 5, "MOBILEALERTS_Initialize finished.";
  31. }
  32. sub MOBILEALERTS_Define($$) {
  33. my ( $hash, $def ) = @_;
  34. my ( $name, $type, $deviceID ) = split( "[ \t]+", $def );
  35. Log3 $name, 3, "$name MOBILEALERTS: DeviceID $deviceID";
  36. return "Usage: define <name> MOBILEALERTS <id-12 stellig hex >"
  37. if ( $deviceID !~ m/^[0-9a-f]{12}$/ );
  38. $modules{MOBILEALERTS}{defptr}{$deviceID} = $hash;
  39. $hash->{DeviceID} = $deviceID;
  40. if ( ( exists $modules{MOBILEALERTS}{AutoCreateMessages} )
  41. && ( exists $modules{MOBILEALERTS}{AutoCreateMessages}{$deviceID} ) )
  42. {
  43. MOBILEALERTS_Parse(
  44. $modules{MOBILEALERTS}{AutoCreateMessages}{$deviceID}[0],
  45. $modules{MOBILEALERTS}{AutoCreateMessages}{$deviceID}[1]
  46. );
  47. delete $modules{MOBILEALERTS}{AutoCreateMessages}{$deviceID};
  48. }
  49. if ( substr( $deviceID, 0, 2 ) eq "08" ) {
  50. Log3 $name, 5, "$name MOBILEALERTS: is rainSensor, start Timer";
  51. InternalTimer( gettimeofday() + 60,
  52. "MOBILEALERTS_CheckRainSensorTimed", $hash );
  53. }
  54. return undef;
  55. }
  56. sub MOBILEALERTS_Undef($$) {
  57. my ( $hash, $name ) = @_;
  58. delete $modules{MOBILEALERTS}{defptr}{ $hash->{DeviceID} };
  59. RemoveInternalTimer( $hash, "MOBILEALERTS_CheckRainSensorTimed" );
  60. return undef;
  61. }
  62. sub MOBILEALERTS_Attr($$$$) {
  63. my ( $cmd, $name, $attrName, $attrValue ) = @_;
  64. if ( $cmd eq "set" ) {
  65. if ( $attrName eq "lastMsg" ) {
  66. if ( $attrValue !~ /^[01]$/ ) {
  67. Log3 $name, 3,
  68. "$name MOBILELAERTS: Invalid parameter attr $name $attrName $attrValue";
  69. return "Invalid value $attrValue allowed 0,1";
  70. }
  71. }
  72. elsif ( $attrName eq "expert" ) {
  73. if ( $attrValue !~ /^[014]$/ ) {
  74. Log3 $name, 3,
  75. "$name MOBILELAERTS: Invalid parameter attr $name $attrName $attrValue";
  76. return "Invalid value $attrValue allowed 0,1,4";
  77. }
  78. }
  79. elsif ( $attrName eq "actCycle" ) {
  80. unless ( $attrValue eq "off" ) {
  81. ( $_[3], my $sec ) = MOBILEALERTS_time2sec($attrValue);
  82. if ( $sec > 0 ) {
  83. my $hash = $modules{MOBILEALERTS};
  84. if ($init_done) {
  85. RemoveInternalTimer($hash);
  86. InternalTimer( gettimeofday() + 60,
  87. "MOBILEALERTS_ActionDetector", $hash );
  88. }
  89. }
  90. }
  91. }
  92. }
  93. return undef;
  94. }
  95. sub MOBILEALERTS_Notify($$) {
  96. my ( $hash, $dev ) = @_;
  97. my $name = $hash->{NAME};
  98. my $devName = $dev->{NAME};
  99. }
  100. sub MOBILEALERTS_Set ($$@) {
  101. my ( $hash, $name, $cmd, @args ) = @_;
  102. return "\"set $name\" needs at least one argument" unless ( defined($cmd) );
  103. if ( $cmd eq "clear" ) {
  104. if ( $args[0] eq "readings" ) {
  105. for ( keys %{ $hash->{READINGS} } ) {
  106. readingsDelete($hash, $_) if ( $_ ne 'state' );
  107. }
  108. return undef;
  109. }
  110. elsif ( $args[0] eq "counters" ) {
  111. my $test = ReadingsVal( $hash->{NAME}, "mmRain", undef );
  112. readingsSingleUpdate( $hash, "mmRain", 0, 1 ) if ( defined $test );
  113. return undef;
  114. }
  115. else {
  116. return
  117. "Unknown value $args[0] for $cmd, choose one of readings,counters";
  118. }
  119. }
  120. else {
  121. return "Unknown argument $cmd, choose one of clear:readings,counters";
  122. }
  123. }
  124. sub MOBILEALERTS_Parse ($$) {
  125. my ( $io_hash, $message ) = @_;
  126. my ( $packageHeader, $timeStamp, $packageLength, $deviceID ) =
  127. unpack( "H2NCH12", $message );
  128. my $name = $io_hash->{NAME};
  129. Log3 $name, 5, "$name MOBILELAERTS: Search for Device ID: $deviceID";
  130. if ( my $hash = $modules{MOBILEALERTS}{defptr}{$deviceID} ) {
  131. my $verbose = GetVerbose( $hash->{NAME} );
  132. Log3 $name, 5, "$name MOBILELAERTS: Found Device: " . $hash->{NAME};
  133. Log3 $hash->{NAME}, 5,
  134. "$hash->{NAME} MOBILELAERTS: Message: " . unpack( "H*", $message )
  135. if ( $verbose >= 5 );
  136. # Nachricht für $hash verarbeiten
  137. $timeStamp = FmtDateTime($timeStamp);
  138. readingsBeginUpdate($hash);
  139. $hash->{".updateTimestamp"} = $timeStamp;
  140. $hash->{".expertMode"} = AttrVal( $hash->{NAME}, "expert", 0 );
  141. my $sub =
  142. "MOBILEALERTS_Parse_"
  143. . substr( $deviceID, 0, 2 ) . "_"
  144. . $packageHeader;
  145. if ( defined &$sub ) {
  146. #no strict "refs";
  147. &{ \&$sub }( $hash, substr $message, 12, $packageLength - 12 );
  148. #use strict "refs";
  149. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "lastMsg",
  150. unpack( "H*", $message ) )
  151. if ( AttrVal( $hash->{NAME}, "lastMsg", 0 ) == 1 );
  152. }
  153. else {
  154. Log3 $name, 2,
  155. "$name MOBILELAERTS: For id "
  156. . substr( $deviceID, 0, 2 )
  157. . " and packageHeader $packageHeader is no decoding defined.";
  158. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  159. "Unknown - "
  160. . substr( $deviceID, 0, 2 ) . " "
  161. . $packageHeader );
  162. $sub = "MOBILEALERTS_Parse_" . $packageHeader;
  163. if ( defined &$sub ) {
  164. #no strict "refs";
  165. &{ \&$sub }( $hash, substr $message, 12, $packageLength - 12 );
  166. #use strict "refs";
  167. }
  168. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "lastMsg",
  169. unpack( "H*", $message ) );
  170. }
  171. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "lastRcv", $timeStamp );
  172. my $actCycle = AttrVal( $hash->{NAME}, "actCycle", undef );
  173. if ($actCycle) {
  174. ( undef, my $sec ) = MOBILEALERTS_time2sec($actCycle);
  175. if ( $sec > 0 ) {
  176. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "actStatus",
  177. "alive" );
  178. }
  179. }
  180. readingsEndUpdate( $hash, 1 );
  181. # Rückgabe des Gerätenamens, für welches die Nachricht bestimmt ist.
  182. return $hash->{NAME};
  183. }
  184. $modules{MOBILEALERTS}{AutoCreateMessages}{$deviceID} =
  185. [ $io_hash, $message ];
  186. my $res = "UNDEFINED MA_" . $deviceID . " MOBILEALERTS $deviceID";
  187. Log3 $name, 5, "$name MOBILELAERTS: Parse return: " . $res;
  188. return $res;
  189. }
  190. sub MOBILEALERTS_Parse_02_ce ($$) {
  191. my ( $hash, $message ) = @_;
  192. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  193. "MA10100/MA10101" );
  194. MOBILEALERTS_Parse_ce( $hash, $message );
  195. }
  196. sub MOBILEALERTS_Parse_ce ($$) {
  197. my ( $hash, $message ) = @_;
  198. my ( $txCounter, $temperature, $prevTemperature ) =
  199. unpack( "nnn", $message );
  200. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  201. MOBILEALERTS_decodeTxCounter($txCounter) );
  202. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "triggered",
  203. MOBILEALERTS_triggeredTxCounter($txCounter) );
  204. $temperature = MOBILEALERTS_decodeTemperature($temperature);
  205. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperature", $temperature );
  206. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureString",
  207. MOBILEALERTS_temperatureToString($temperature) );
  208. $prevTemperature = MOBILEALERTS_decodeTemperature($prevTemperature);
  209. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevTemperature",
  210. $prevTemperature );
  211. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state", "T: " . $temperature );
  212. }
  213. sub MOBILEALERTS_Parse_0f_d2 ($$) {
  214. my ( $hash, $message ) = @_;
  215. my ( $txCounter, $temperatureIn, $temperatureOut, $prevTemperatureIn,
  216. $prevTemperatureOut )
  217. = unpack( "nnnnn", $message );
  218. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  219. "MA10450" );
  220. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  221. MOBILEALERTS_decodeTxCounter($txCounter) );
  222. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "triggered",
  223. MOBILEALERTS_triggeredTxCounter($txCounter) );
  224. $temperatureIn = MOBILEALERTS_decodeTemperature($temperatureIn);
  225. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureIn",
  226. $temperatureIn );
  227. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureInString",
  228. MOBILEALERTS_temperatureToString($temperatureIn) );
  229. $temperatureOut = MOBILEALERTS_decodeTemperature($temperatureOut);
  230. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureOut",
  231. $temperatureOut );
  232. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureOutString",
  233. MOBILEALERTS_temperatureToString($temperatureOut) );
  234. $prevTemperatureIn = MOBILEALERTS_decodeTemperature($prevTemperatureIn);
  235. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevTemperatureIn",
  236. $prevTemperatureIn );
  237. $prevTemperatureOut = MOBILEALERTS_decodeTemperature($prevTemperatureOut);
  238. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevTemperatureOut",
  239. $prevTemperatureOut );
  240. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state",
  241. "In T: " . $temperatureIn . " Out T: " . $temperatureOut );
  242. }
  243. sub MOBILEALERTS_Parse_03_d2 ($$) {
  244. my ( $hash, $message ) = @_;
  245. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  246. "MA10200" );
  247. MOBILEALERTS_Parse_d2( $hash, $message );
  248. }
  249. sub MOBILEALERTS_Parse_d2 ($$) {
  250. my ( $hash, $message ) = @_;
  251. my ( $txCounter, $temperature, $humidity, $prevTemperature, $prevHumidity )
  252. = unpack( "nnnnn", $message );
  253. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  254. MOBILEALERTS_decodeTxCounter($txCounter) );
  255. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "triggered",
  256. MOBILEALERTS_triggeredTxCounter($txCounter) );
  257. $temperature = MOBILEALERTS_decodeTemperature($temperature);
  258. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperature", $temperature );
  259. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureString",
  260. MOBILEALERTS_temperatureToString($temperature) );
  261. $humidity = MOBILEALERTS_decodeHumidity($humidity);
  262. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity", $humidity );
  263. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidityString",
  264. MOBILEALERTS_humidityToString($humidity) );
  265. $prevTemperature = MOBILEALERTS_decodeTemperature($prevTemperature);
  266. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevTemperature",
  267. $prevTemperature );
  268. $prevHumidity = MOBILEALERTS_decodeHumidity($prevHumidity);
  269. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevHumidity", $prevHumidity );
  270. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state",
  271. "T: " . $temperature . " H: " . $humidity );
  272. }
  273. sub MOBILEALERTS_Parse_04_d4 ($$) {
  274. my ( $hash, $message ) = @_;
  275. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  276. "MA10350" );
  277. MOBILEALERTS_Parse_d4( $hash, $message );
  278. }
  279. sub MOBILEALERTS_Parse_d4 ($$) {
  280. my ( $hash, $message ) = @_;
  281. my ( $txCounter, $temperature, $humidity, $wetness,
  282. $prevTemperature, $prevHumidity, $prevWetness )
  283. = unpack( "nnnCnnC", $message );
  284. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  285. MOBILEALERTS_decodeTxCounter($txCounter) );
  286. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "triggered",
  287. MOBILEALERTS_triggeredTxCounter($txCounter) );
  288. $temperature = MOBILEALERTS_decodeTemperature($temperature);
  289. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperature", $temperature );
  290. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureString",
  291. MOBILEALERTS_temperatureToString($temperature) );
  292. $humidity = MOBILEALERTS_decodeHumidity($humidity);
  293. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity", $humidity );
  294. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidityString",
  295. MOBILEALERTS_humidityToString($humidity) );
  296. $wetness = MOBILEALERTS_decodeWetness($wetness);
  297. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "wetness", $wetness );
  298. $prevTemperature = MOBILEALERTS_decodeTemperature($prevTemperature);
  299. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevTemperature",
  300. $prevTemperature );
  301. $prevHumidity = MOBILEALERTS_decodeHumidity($prevHumidity);
  302. $prevWetness = MOBILEALERTS_decodeWetness($prevWetness);
  303. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevWetness", $prevWetness );
  304. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevHumidity", $prevHumidity );
  305. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state",
  306. "T: " . $temperature . " H: " . $humidity . " " . $wetness );
  307. }
  308. sub MOBILEALERTS_Parse_05_da ($$) {
  309. my ( $hash, $message ) = @_;
  310. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  311. "WL2000" );
  312. my ( $txCounter, $temperatureOut, $temperatureIn, $humidityIn, $co2,
  313. $prevTemperatureOut, $prevTemperatureIn, $prevHumidityIn )
  314. = unpack( "nnnnnnnn", $message );
  315. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  316. MOBILEALERTS_decodeTxCounter($txCounter) );
  317. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "triggered",
  318. MOBILEALERTS_triggeredTxCounter($txCounter) );
  319. $temperatureIn = MOBILEALERTS_decodeTemperature($temperatureIn);
  320. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureIn",
  321. $temperatureIn );
  322. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureStringIn",
  323. MOBILEALERTS_temperatureToString($temperatureIn) );
  324. $temperatureOut = MOBILEALERTS_decodeTemperature($temperatureOut);
  325. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureOut",
  326. $temperatureOut );
  327. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureStringOut",
  328. MOBILEALERTS_temperatureToString($temperatureOut) );
  329. $humidityIn = MOBILEALERTS_decodeHumidity($humidityIn);
  330. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity", $humidityIn );
  331. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidityString",
  332. MOBILEALERTS_humidityToString($humidityIn) );
  333. $co2 = MOBILEALERTS_decodeCO2($co2);
  334. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "co2", $co2 );
  335. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "co2String",
  336. MOBILEALERTS_cO2ToString($co2) );
  337. $prevTemperatureIn = MOBILEALERTS_decodeTemperature($prevTemperatureIn);
  338. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevTemperatureIn",
  339. $prevTemperatureIn );
  340. $prevTemperatureOut = MOBILEALERTS_decodeTemperature($prevTemperatureOut);
  341. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevTemperatureOut",
  342. $prevTemperatureOut );
  343. $prevHumidityIn = MOBILEALERTS_decodeHumidity($prevHumidityIn);
  344. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevHumidityIn",
  345. $prevHumidityIn );
  346. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state",
  347. "In T: "
  348. . $temperatureIn . " H: "
  349. . $humidityIn
  350. . " Out T: "
  351. . $temperatureOut
  352. . " CO2: "
  353. . $co2 );
  354. }
  355. sub MOBILEALERTS_Parse_07_da ($$) {
  356. my ( $hash, $message ) = @_;
  357. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  358. "MA10410" );
  359. MOBILEALERTS_Parse_da( $hash, $message );
  360. }
  361. sub MOBILEALERTS_Parse_da ($$) {
  362. my ( $hash, $message ) = @_;
  363. my (
  364. $txCounter, $temperatureIn, $humidityIn,
  365. $temperatureOut, $humidityOut, $prevTemperatureIn,
  366. $prevHumidityIn, $prevTemperatureOut, $prevHumidityOut
  367. ) = unpack( "nnnnnnnnn", $message );
  368. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  369. MOBILEALERTS_decodeTxCounter($txCounter) );
  370. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "triggered",
  371. MOBILEALERTS_triggeredTxCounter($txCounter) );
  372. $temperatureIn = MOBILEALERTS_decodeTemperature($temperatureIn);
  373. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureIn",
  374. $temperatureIn );
  375. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureInString",
  376. MOBILEALERTS_temperatureToString($temperatureIn) );
  377. $humidityIn = MOBILEALERTS_decodeHumidity($humidityIn);
  378. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidityIn", $humidityIn );
  379. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidityInString",
  380. MOBILEALERTS_humidityToString($humidityIn) );
  381. $temperatureOut = MOBILEALERTS_decodeTemperature($temperatureOut);
  382. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureOut",
  383. $temperatureOut );
  384. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureOutString",
  385. MOBILEALERTS_temperatureToString($temperatureOut) );
  386. $humidityOut = MOBILEALERTS_decodeHumidity($humidityOut);
  387. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidityOut", $humidityOut );
  388. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidityOutString",
  389. MOBILEALERTS_humidityToString($humidityOut) );
  390. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state",
  391. "In T: "
  392. . $temperatureIn . " H: "
  393. . $humidityIn
  394. . " Out T: "
  395. . $temperatureOut . " H: "
  396. . $humidityOut );
  397. }
  398. sub MOBILEALERTS_Parse_08_e1 ($$) {
  399. my ( $hash, $message ) = @_;
  400. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  401. "MA10650" );
  402. MOBILEALERTS_Parse_e1( $hash, $message );
  403. }
  404. sub MOBILEALERTS_Parse_e1 ($$) {
  405. my ( $hash, $message ) = @_;
  406. my @eventTime;
  407. ( my ( $txCounter, $temperature, $eventCounter ), @eventTime[ 0 .. 8 ] ) =
  408. unpack( "nnnnnnnnnnnn", $message );
  409. my $lastEventCounter = ReadingsVal( $hash->{NAME}, "eventCounter", undef );
  410. my $mmRain = 0;
  411. if ( !defined($lastEventCounter) ) {
  412. # First Data
  413. $mmRain = $eventCounter * MA_RAIN_FACTOR;
  414. }
  415. elsif ( $lastEventCounter > $eventCounter ) {
  416. # Overflow EventCounter or fresh Batterie
  417. $mmRain = $eventCounter * MA_RAIN_FACTOR;
  418. }
  419. elsif ( $lastEventCounter < $eventCounter ) {
  420. $mmRain = ( $eventCounter - $lastEventCounter ) * MA_RAIN_FACTOR;
  421. }
  422. else {
  423. $mmRain = 0;
  424. }
  425. MOBILEALERTS_CheckRainSensor( $hash, $mmRain );
  426. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  427. MOBILEALERTS_decodeTxCounter($txCounter) );
  428. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "triggered",
  429. MOBILEALERTS_triggeredTxCounter($txCounter) );
  430. $temperature = MOBILEALERTS_decodeTemperature($temperature);
  431. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperature", $temperature );
  432. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureString",
  433. MOBILEALERTS_temperatureToString($temperature) );
  434. for ( my $z = 0 ; $z < 9 ; $z++ ) {
  435. my $eventTimeString =
  436. MOBILEALERTS_convertEventTimeString( $eventTime[$z], 14 );
  437. $eventTime[$z] = MOBILEALERTS_convertEventTime( $eventTime[$z], 14 );
  438. if ( $z == 0 ) {
  439. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "lastEvent",
  440. $eventTime[$z] );
  441. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "lastEventString",
  442. $eventTimeString );
  443. }
  444. else {
  445. MOBILEALERTS_readingsBulkUpdate( $hash, 4, "lastEvent" . $z,
  446. $eventTime[$z] );
  447. MOBILEALERTS_readingsBulkUpdate( $hash, 4,
  448. "lastEvent" . $z . "String",
  449. $eventTimeString );
  450. }
  451. }
  452. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "eventCounter", $eventCounter );
  453. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state",
  454. "T: " . $temperature . " C: " . $eventCounter );
  455. }
  456. sub MOBILEALERTS_Parse_0b_e2 ($$) {
  457. my ( $hash, $message ) = @_;
  458. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  459. "MA10660" );
  460. MOBILEALERTS_Parse_e2( $hash, $message );
  461. }
  462. sub MOBILEALERTS_Parse_e2 ($$) {
  463. my ( $hash, $message ) = @_;
  464. my @dirTable = (
  465. "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE",
  466. "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"
  467. );
  468. my ( $txCounter, $data0, $data1, $data2, $data3 ) =
  469. unpack( "NCCCC", "\0" . $message );
  470. my $dir = $data0 >> 4;
  471. my $overFlowBits = $data0 & 3;
  472. my $windSpeed = ( ( ( $overFlowBits & 2 ) >> 1 ) << 8 ) + $data1 * 0.1;
  473. my $gustSpeed = ( ( ( $overFlowBits & 1 ) >> 1 ) << 8 ) + $data2 * 0.1;
  474. my $lastTransmit = $data3 * 2;
  475. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  476. MOBILEALERTS_decodeTxCounter($txCounter) );
  477. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "direction", $dirTable[$dir] );
  478. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "directionInt", $dir );
  479. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "windSpeed", $windSpeed );
  480. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "gustSpeed", $gustSpeed );
  481. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state",
  482. "D: " . $dirTable[$dir] . " W: " . $windSpeed . " G: " . $gustSpeed );
  483. }
  484. sub MOBILEALERTS_Parse_0e_d8 ($$) {
  485. my ( $hash, $message ) = @_;
  486. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  487. "TFA30.3312.02" );
  488. MOBILEALERTS_Parse_d8( $hash, $message );
  489. }
  490. sub MOBILEALERTS_Parse_d8 ($$) {
  491. my ( $hash, $message ) = @_;
  492. my (
  493. $txCounter, $temperature, $humidity, $prevTemperature,
  494. $prevHumidity, $prevTemperature2, $prevHumidity2
  495. ) = unpack( "nnnxnnxnn", $message );
  496. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  497. MOBILEALERTS_decodeTxCounter($txCounter) );
  498. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "triggered",
  499. MOBILEALERTS_triggeredTxCounter($txCounter) );
  500. $temperature = MOBILEALERTS_decodeTemperature($temperature);
  501. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperature", $temperature );
  502. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureString",
  503. MOBILEALERTS_temperatureToString($temperature) );
  504. $humidity = MOBILEALERTS_decodeHumidityDecimal($humidity);
  505. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity", $humidity );
  506. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidityString",
  507. MOBILEALERTS_humidityToString($humidity) );
  508. $prevTemperature = MOBILEALERTS_decodeTemperature($prevTemperature);
  509. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevTemperature",
  510. $prevTemperature );
  511. $prevHumidity = MOBILEALERTS_decodeHumidityDecimal($prevHumidity);
  512. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevHumidity", $prevHumidity );
  513. $prevTemperature2 = MOBILEALERTS_decodeTemperature($prevTemperature2);
  514. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevTemperature2",
  515. $prevTemperature2 );
  516. $prevHumidity2 = MOBILEALERTS_decodeHumidityDecimal($prevHumidity2);
  517. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevHumidity2",
  518. $prevHumidity2 );
  519. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state",
  520. "T: " . $temperature . " H: " . $humidity );
  521. }
  522. sub MOBILEALERTS_Parse_10_d3 ($$) {
  523. my ( $hash, $message ) = @_;
  524. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  525. "MA10800" );
  526. MOBILEALERTS_Parse_d3( $hash, $message );
  527. }
  528. sub MOBILEALERTS_Parse_d3 ($$) {
  529. my ( $hash, $message ) = @_;
  530. my @data;
  531. ( my ($txCounter), @data[ 0 .. 3 ] ) = unpack( "nnnnn", $message );
  532. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  533. MOBILEALERTS_decodeTxCounter($txCounter) );
  534. for ( my $z = 0 ; $z < 4 ; $z++ ) {
  535. my $eventTimeString =
  536. MOBILEALERTS_convertEventTimeString( $data[$z], 13 );
  537. my $eventTime = MOBILEALERTS_convertEventTime( $data[$z], 13 );
  538. $data[$z] = MOBILEALERTS_convertOpenState( $data[$z] );
  539. if ( $z == 0 ) {
  540. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state", $data[$z] );
  541. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "lastEvent",
  542. $eventTime );
  543. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "lastEventString",
  544. $eventTimeString );
  545. }
  546. else {
  547. MOBILEALERTS_readingsBulkUpdate( $hash, 4, "state" . $z,
  548. $data[$z] );
  549. MOBILEALERTS_readingsBulkUpdate( $hash, 4, "lastEvent" . $z,
  550. $eventTime );
  551. MOBILEALERTS_readingsBulkUpdate( $hash, 4,
  552. "lastEvent" . $z . "String",
  553. $eventTimeString );
  554. }
  555. }
  556. }
  557. sub MOBILEALERTS_Parse_12_d9 ($$) {
  558. my ( $hash, $message ) = @_;
  559. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  560. "MA10230" );
  561. MOBILEALERTS_Parse_d9( $hash, $message );
  562. }
  563. sub MOBILEALERTS_Parse_d9 ($$) {
  564. my ( $hash, $message ) = @_;
  565. my (
  566. $txCounter, $humidity3h, $humidity24h, $humidity7d,
  567. $humidity30d, $temperature, $humidity
  568. ) = unpack( "nCCCCnC", $message );
  569. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  570. MOBILEALERTS_decodeTxCounter($txCounter) );
  571. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "triggered",
  572. MOBILEALERTS_triggeredTxCounter($txCounter) );
  573. $temperature = MOBILEALERTS_decodeTemperature($temperature);
  574. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperature", $temperature );
  575. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureString",
  576. MOBILEALERTS_temperatureToString($temperature) );
  577. $humidity = MOBILEALERTS_decodeHumidity($humidity);
  578. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity", $humidity );
  579. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidityString",
  580. MOBILEALERTS_humidityToString($humidity) );
  581. $humidity3h = MOBILEALERTS_decodeHumidity($humidity3h);
  582. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity3h", $humidity3h );
  583. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity3hString",
  584. MOBILEALERTS_humidityToString($humidity3h) );
  585. $humidity24h = MOBILEALERTS_decodeHumidity($humidity24h);
  586. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity24h", $humidity3h );
  587. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity24hString",
  588. MOBILEALERTS_humidityToString($humidity24h) );
  589. $humidity7d = MOBILEALERTS_decodeHumidity($humidity7d);
  590. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity7d", $humidity7d );
  591. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity7dString",
  592. MOBILEALERTS_humidityToString($humidity7d) );
  593. $humidity30d = MOBILEALERTS_decodeHumidity($humidity30d);
  594. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity30d", $humidity30d );
  595. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity30dString",
  596. MOBILEALERTS_humidityToString($humidity30d) );
  597. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state",
  598. "T: "
  599. . $temperature . " H: "
  600. . $humidity . " "
  601. . $humidity3h . "/"
  602. . $humidity24h . "/"
  603. . $humidity7d . "/"
  604. . $humidity30d );
  605. }
  606. sub MOBILEALERTS_Parse_06_d6 ($$) {
  607. my ( $hash, $message ) = @_;
  608. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  609. "MA10300/MA10700" );
  610. MOBILEALERTS_Parse_d6( $hash, $message );
  611. }
  612. sub MOBILEALERTS_Parse_09_d6 ($$) {
  613. my ( $hash, $message ) = @_;
  614. MOBILEALERTS_readingsBulkUpdateIfChanged( $hash, 0, "deviceType",
  615. "MA10320PRO" );
  616. MOBILEALERTS_Parse_d6( $hash, $message );
  617. }
  618. sub MOBILEALERTS_Parse_d6 ($$) {
  619. my ( $hash, $message ) = @_;
  620. my ( $txCounter, $temperatureIn, $temperatureOut, $humidityIn,
  621. $prevTemperatureIn, $prevTemperatureOut, $prevHumidityIn )
  622. = unpack( "nnnnnnn", $message );
  623. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "txCounter",
  624. MOBILEALERTS_decodeTxCounter($txCounter) );
  625. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "triggered",
  626. MOBILEALERTS_triggeredTxCounter($txCounter) );
  627. $temperatureIn = MOBILEALERTS_decodeTemperature($temperatureIn);
  628. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureIn",
  629. $temperatureIn );
  630. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureStringIn",
  631. MOBILEALERTS_temperatureToString($temperatureIn) );
  632. $temperatureOut = MOBILEALERTS_decodeTemperature($temperatureOut);
  633. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureOut",
  634. $temperatureOut );
  635. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "temperatureStringOut",
  636. MOBILEALERTS_temperatureToString($temperatureOut) );
  637. $humidityIn = MOBILEALERTS_decodeHumidity($humidityIn);
  638. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidity", $humidityIn );
  639. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "humidityString",
  640. MOBILEALERTS_humidityToString($humidityIn) );
  641. $prevTemperatureIn = MOBILEALERTS_decodeTemperature($prevTemperatureIn);
  642. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevTemperatureIn",
  643. $prevTemperatureIn );
  644. $prevTemperatureOut = MOBILEALERTS_decodeTemperature($prevTemperatureOut);
  645. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevTemperatureOut",
  646. $prevTemperatureOut );
  647. $prevHumidityIn = MOBILEALERTS_decodeHumidity($prevHumidityIn);
  648. MOBILEALERTS_readingsBulkUpdate( $hash, 1, "prevHumidityIn",
  649. $prevHumidityIn );
  650. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "state",
  651. "In T: "
  652. . $temperatureIn . " H: "
  653. . $humidityIn
  654. . " Out T: "
  655. . $temperatureOut );
  656. }
  657. sub MOBILEALERTS_decodeTxCounter($) {
  658. my ($txCounter) = @_;
  659. return $txCounter & 0x3FFF;
  660. }
  661. sub MOBILEALERTS_triggeredTxCounter($) {
  662. my ($txCounter) = @_;
  663. if ( ( $txCounter & 0x4000 ) == 0x4000 ) {
  664. return 1;
  665. }
  666. return 0;
  667. }
  668. sub MOBILEALERTS_decodeTemperature($) {
  669. my ($temperature) = @_;
  670. #Overflow
  671. return 9999 if ( ( $temperature & 0x2000 ) == 0x2000 );
  672. #Illegal value
  673. return -9999 if ( ( $temperature & 0x1000 ) == 0x1000 );
  674. #Negativ Values
  675. return ( 0x800 - ( $temperature & 0x7ff ) ) * -0.1
  676. if ( ( $temperature & 0x400 ) == 0x400 );
  677. #Positiv Values
  678. return ( $temperature & 0x7ff ) * 0.1;
  679. }
  680. sub MOBILEALERTS_temperatureToString($) {
  681. my ($temperature) = @_;
  682. return "---" if ( $temperature < -1000 );
  683. return "OLF" if ( $temperature > 1000 );
  684. return $temperature . "°C";
  685. }
  686. sub MOBILEALERTS_decodeHumidity($) {
  687. my ($humidity) = @_;
  688. return 9999 if ( ( $humidity & 0x80 ) == 0x80 );
  689. return $humidity & 0x7F;
  690. }
  691. sub MOBILEALERTS_decodeHumidityDecimal($) {
  692. my ($humidity) = @_;
  693. return ( $humidity & 0x3FF ) * 0.1;
  694. }
  695. sub MOBILEALERTS_humidityToString($) {
  696. my ($humidity) = @_;
  697. return "---" if ( $humidity > 1000 );
  698. return $humidity . "%";
  699. }
  700. sub MOBILEALERTS_decodeCO2($) {
  701. my ($co2) = @_;
  702. return 9999 if ( ( $co2 & 0x80 ) == 0x80 );
  703. return ( $co2 & 0x7F ) * 50;
  704. }
  705. sub MOBILEALERTS_cO2ToString($) {
  706. my ($co2) = @_;
  707. return "---" if ( $co2 == 9999 );
  708. return $co2 . " ppm";
  709. }
  710. sub MOBILEALERTS_decodeWetness($) {
  711. my ($wetness) = @_;
  712. return "dry" if ( $wetness & 0x01 );
  713. return "wet";
  714. }
  715. sub MOBILEALERTS_convertOpenState($) {
  716. my ($value) = @_;
  717. return "open" if ( $value & 0x8000 );
  718. return "closed";
  719. }
  720. sub MOBILEALERTS_convertEventTime($$) {
  721. my ( $value, $timeScaleBitOffset ) = @_;
  722. my $timeScaleFactor = ( $value >> $timeScaleBitOffset ) & 3;
  723. $value = $value & ( ( 1 << $timeScaleBitOffset ) - 1 );
  724. if ( $timeScaleFactor == 0 ) { # days
  725. return $value * 60 * 60 * 24;
  726. }
  727. elsif ( $timeScaleFactor == 1 ) { # hours
  728. return $value * 60 * 60;
  729. }
  730. elsif ( $timeScaleFactor == 2 ) { # minutes
  731. return $value * 60;
  732. }
  733. elsif ( $timeScaleFactor == 3 ) { # seconds
  734. return $value;
  735. }
  736. }
  737. sub MOBILEALERTS_convertEventTimeString($$) {
  738. my ( $value, $timeScaleBitOffset ) = @_;
  739. my $timeScaleFactor = ( $value >> $timeScaleBitOffset ) & 3;
  740. $value = $value & ( ( 1 << $timeScaleBitOffset ) - 1 );
  741. if ( $timeScaleFactor == 0 ) { # days
  742. return $value . " d";
  743. }
  744. elsif ( $timeScaleFactor == 1 ) { # hours
  745. return $value . " h";
  746. }
  747. elsif ( $timeScaleFactor == 2 ) { # minutes
  748. return $value . " m";
  749. }
  750. elsif ( $timeScaleFactor == 3 ) { # seconds
  751. return $value . " s";
  752. }
  753. }
  754. sub MOBILEALERTS_readingsBulkUpdate($$$$@) {
  755. my ( $hash, $expert, $reading, $value, $changed ) = @_;
  756. if ( $expert > $hash->{".expertMode"} ) {
  757. readingsDelete($hash, $reading);
  758. return undef;
  759. }
  760. my $i = $#{ $hash->{CHANGED} };
  761. my $res = readingsBulkUpdate( $hash, $reading, $value, $changed );
  762. $hash->{CHANGETIME}->[ $#{ $hash->{CHANGED} } ] =
  763. $hash->{".updateTimestamp"}
  764. if ( $#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to
  765. return $res;
  766. }
  767. sub MOBILEALERTS_readingsBulkUpdateIfChanged($$$$@) {
  768. my ( $hash, $expert, $reading, $value, $changed ) = @_;
  769. if ( $expert > $hash->{".expertMode"} ) {
  770. readingsDelete($hash, $reading);
  771. return undef;
  772. }
  773. my $i = $#{ $hash->{CHANGED} };
  774. my $res = readingsBulkUpdateIfChanged( $hash, $reading, $value, $changed );
  775. $hash->{CHANGETIME}->[ $#{ $hash->{CHANGED} } ] =
  776. $hash->{".updateTimestamp"}
  777. if ( $#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to
  778. return $res;
  779. }
  780. sub MOBILEALERTS_time2sec($) {
  781. my ($timeout) = @_;
  782. return ( "off", 0 ) unless ($timeout);
  783. return ( "off", 0 ) if ( $timeout eq "off" );
  784. my ( $h, $m ) = split( ":", $timeout );
  785. no warnings 'numeric';
  786. $h = int($h);
  787. $m = int($m);
  788. use warnings 'numeric';
  789. return (
  790. ( sprintf( "%03s:%02d", $h, $m ) ),
  791. ( ( int($h) * 60 + int($m) ) * 60 )
  792. );
  793. }
  794. sub MOBILEALERTS_CheckRainSensorTimed($) {
  795. my ($hash) = @_;
  796. $hash->{".expertMode"} = AttrVal( $hash->{NAME}, "expert", 0 );
  797. readingsBeginUpdate($hash);
  798. MOBILEALERTS_CheckRainSensor( $hash, 0 );
  799. readingsEndUpdate( $hash, 1 );
  800. InternalTimer(
  801. time_str2num(
  802. substr( FmtDateTime( gettimeofday() + 3600 ), 0, 13 ) . ":00:00"
  803. ),
  804. "MOBILEALERTS_CheckRainSensorTimed",
  805. $hash
  806. );
  807. }
  808. sub MOBILEALERTS_CheckRainSensor($$) {
  809. my ( $hash, $mmRain ) = @_;
  810. #Event
  811. push @{ $hash->{CHANGED} }, "rain" if ( $mmRain > 0 );
  812. #lastHour
  813. my $actTime = $hash->{".updateTimestamp"};
  814. my $actH = ReadingsTimestamp( $hash->{NAME}, "mmRainActHour", $actTime );
  815. if ( substr( $actTime, 0, 13 ) eq substr( $actH, 0, 13 ) ) {
  816. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "mmRainActHour",
  817. $mmRain + ReadingsVal( $hash->{NAME}, "mmRainActHour", "0" ) )
  818. if ( $mmRain > 0 );
  819. }
  820. else {
  821. if (
  822. (
  823. time_str2num( substr( $actTime, 0, 13 ) . ":00:00" ) -
  824. time_str2num( substr( $actH, 0, 13 ) . ":00:00" )
  825. ) > 3600
  826. )
  827. {
  828. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "mmRainLastHour", 0 );
  829. }
  830. else {
  831. $hash->{".updateTimestamp"} = $actH;
  832. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "mmRainLastHour",
  833. ReadingsVal( $hash->{NAME}, "mmRainActHour", "0" ) );
  834. $hash->{".updateTimestamp"} = $actTime;
  835. }
  836. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "mmRainActHour", 0 );
  837. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "mmRainActHour", $mmRain )
  838. if ( $mmRain > 0 );
  839. }
  840. #Yesterday
  841. my $actD = ReadingsTimestamp( $hash->{NAME}, "mmRainActDay", $actTime );
  842. if ( substr( $actTime, 0, 10 ) eq substr( $actD, 0, 10 ) ) {
  843. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "mmRainActDay",
  844. $mmRain + ReadingsVal( $hash->{NAME}, "mmRainActDay", "0" ) )
  845. if ( $mmRain > 0 );
  846. }
  847. else {
  848. if (
  849. (
  850. time_str2num( substr( $actTime, 0, 13 ) . " 00:00:00" ) -
  851. time_str2num( substr( $actD, 0, 13 ) . " 00:00:00" )
  852. ) > 86400
  853. )
  854. {
  855. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "mmRainYesterday", 0 );
  856. }
  857. else {
  858. $hash->{".updateTimestamp"} =
  859. ReadingsTimestamp( $hash->{NAME}, "mmRainActDay", $actD );
  860. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "mmRainYesterday",
  861. ReadingsVal( $hash->{NAME}, "mmRainActDay", "0" ) );
  862. $hash->{".updateTimestamp"} = $actTime;
  863. }
  864. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "mmRainActDay", 0 );
  865. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "mmRainActDay", $mmRain )
  866. if ( $mmRain > 0 );
  867. }
  868. MOBILEALERTS_readingsBulkUpdate( $hash, 0, "mmRain",
  869. $mmRain + ReadingsVal( $hash->{NAME}, "mmRain", "0" ) )
  870. if ( $mmRain > 0 );
  871. }
  872. sub MOBILEALERTS_ActionDetector($) {
  873. my ($hash) = @_;
  874. my $name = "ActionDetector";
  875. unless ($init_done) {
  876. Log3 $name, 5,
  877. "$name MOBILELAERTS: ActionDetector run - fhem not intialized";
  878. InternalTimer( gettimeofday() + 60,
  879. "MOBILEALERTS_ActionDetector", $hash );
  880. return;
  881. }
  882. Log3 $name, 5, "$name MOBILELAERTS: ActionDetector run";
  883. my $now = gettimeofday();
  884. my $nextTimer = $now + 60 * 60; # Check at least Hourly
  885. for my $chash ( values %{ $modules{MOBILEALERTS}{defptr} } ) {
  886. Log3 $name, 5, "$name MOBILELAERTS: ActionDetector " . $chash->{NAME};
  887. my $actCycle = AttrVal( $chash->{NAME}, "actCycle", undef );
  888. ( undef, my $sec ) = MOBILEALERTS_time2sec($actCycle);
  889. if ( $sec == 0 ) {
  890. readingsBeginUpdate($chash);
  891. readingsBulkUpdateIfChanged( $chash, "actStatus", "switchedOff" );
  892. readingsEndUpdate( $chash, 1 );
  893. next;
  894. }
  895. my $lastRcv = ReadingsTimestamp( $chash->{NAME}, "lastRcv", undef );
  896. my $deadTime = undef;
  897. readingsBeginUpdate($chash);
  898. if ( defined($lastRcv) ) {
  899. Log3 $name, 5,
  900. "$name MOBILELAERTS: ActionDetector "
  901. . $chash->{NAME}
  902. . " lastRcv "
  903. . $lastRcv;
  904. $lastRcv = time_str2num($lastRcv);
  905. $deadTime = $lastRcv + $sec;
  906. if ( $deadTime < $now ) {
  907. readingsBulkUpdateIfChanged( $chash, "actStatus", "dead" );
  908. $deadTime = $now + $sec;
  909. }
  910. else {
  911. readingsBulkUpdate( $chash, "actStatus", "alive" );
  912. }
  913. }
  914. else {
  915. readingsBulkUpdateIfChanged( $chash, "actStatus", "unknown" );
  916. $deadTime = $now + $sec;
  917. }
  918. readingsEndUpdate( $chash, 1 );
  919. if ( ( defined($deadTime) ) && ( $deadTime < $nextTimer ) ) {
  920. $nextTimer = $deadTime;
  921. Log3 $name, 5,
  922. "$name MOBILELAERTS: ActionDetector "
  923. . $chash->{NAME}
  924. . " nextTime Set to "
  925. . FmtDateTime($nextTimer);
  926. }
  927. }
  928. Log3 $name, 5,
  929. "$name MOBILELAERTS: MOBILEALERTS_ActionDetector nextRun "
  930. . FmtDateTime($nextTimer);
  931. InternalTimer( $nextTimer, "MOBILEALERTS_ActionDetector", $hash );
  932. }
  933. # Eval-Rückgabewert für erfolgreiches
  934. # Laden des Moduls
  935. 1;
  936. =pod
  937. =item device
  938. =item summary virtual device for MOBILEALERTSGW
  939. =item summary_DE virtuelles device für MOBILEALERTSGW
  940. =begin html
  941. <a name="MOBILEALERTS"></a>
  942. <h3>MOBILEALERTS</h3>
  943. <ul>
  944. The MOBILEALERTS is a fhem module for the german MobileAlerts devices and TFA WEATHERHUB devices.
  945. <br><br>
  946. The fhem module represents a MobileAlerts device. The connection is provided by the <a href="#MOBILEALERTSGW">MOBILELAERTSGW</a> module.
  947. Currently supported: MA10100, MA10101, MA10200, MA10230, MA10300, MA10650, MA10320PRO, MA10350, MA10410, MA10450, MA10660, MA10700, TFA 30.3312.02, MA10800, WL2000<br>
  948. Supported but untested: ./.<br>
  949. <br>
  950. <a name="MOBILEALERTSdefine"></a>
  951. <b>Define</b>
  952. <ul>
  953. <code>define &lt;name&gt; MOBILEALERTS &lt;deviceID&gt;</code><br>
  954. <br>
  955. deviceID is the sensorcode on the sensor.
  956. </ul>
  957. <br>
  958. <a name="MOBILEALERTSreadings"></a>
  959. <b>Readings</b>
  960. <ul>
  961. <li>lastMsg<br>The last message received (always for unknown devices, for known devices only if attr lastMsg is set).</li>
  962. <li>deviceType<br>The devicetype.</li>
  963. <li>lastRcv<br>Timestamp of last message.</li>
  964. <li>actStatus<br>Shows 'unknown', 'alive', 'dead', 'switchedOff' depending on attribut actCycle</li>
  965. <li>txCounter<br>Counter of last message.</li>
  966. <li>triggered<br>1=last message was triggered by a event.</li>
  967. <li>tempertature, prevTemperature, temperatureIn, temperatureOut, prevTemperatureIn, prevTemperatureOut<br>Temperature (depending on device and attribut expert).</li>
  968. <li>tempertatureString, prevTemperatureString, temperatureInString, temperatureOutString, prevTemperatureInString, prevTemperatureOutString<br>Temperature as string (depending on device and attribut expert).</li>
  969. <li>state<br>State of device (short actual reading)</li>
  970. <li>humidity, prevHumidity, humidityIn, humidityOut, prevHumidityIn, prevHumidityOut<br>Humidity (depending on device and attribut expert).</li>
  971. <li>humidityString, prevHumidityString, humidityInString, humidityOutString, prevHumidityInString, prevHumidityOutString<br>Humidity as string (depending on device and attribut expert).</li>
  972. <li>wetness<br>Shows if sensor detects water.</li>
  973. <li>lastEvent, lastEvent&lt;X&gt; ,lastEventString, lastEvent&lt;X&gt;String<br>Time when last event (rain) happend (MA10650 only).</li>
  974. <li>mmRain, mmRainActHour, mmRainLastHour, mmRainActDay, mmRainYesterday<br>Rain since reset of counter, current hour, last hour, current day, yesterday.</li>
  975. <li>direction, directionInt<br>Direction of wind.</li>
  976. <li>windSpeed, gustSpeed<br>Windspeed.</li>
  977. </ul>
  978. <br>
  979. <a name="MOBILEALERTSset"></a>
  980. <b>Set</b>
  981. <ul>
  982. <li><code>set &lt;name&gt; clear &lt;readings|counters&gt;</code><br>
  983. Clears the readings (all) or counters (like mmRain). </li>
  984. </ul>
  985. <br>
  986. <a name="MOBILEALERTSget"></a>
  987. <b>Get</b>
  988. <ul>
  989. N/A
  990. </ul>
  991. <br>
  992. <br>
  993. <a name="MOBILEALERTSattr"></a>
  994. <b>Attributes</b>
  995. <ul>
  996. <li><a href="#ignore">ignore</a></li>
  997. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  998. <li>lastMsg<br>
  999. If value 1 is set, the last received message will be logged as reading even if device is known.
  1000. </li>
  1001. <li>actCycle &lt;[hhh:mm]|off&gt;<br>
  1002. This value triggers a 'alive' and 'not alive' detection. [hhh:mm] is the maximum silent time for the device.
  1003. The reading actStatus will show the states: 'unknown', 'alive', 'dead'.
  1004. </li>
  1005. <li>expert<br>
  1006. Defines how many readings are show (0=only current, 1=previous, 4=all).
  1007. </li>
  1008. </ul>
  1009. </ul>
  1010. =end html
  1011. =begin html_DE
  1012. <a name="MOBILEALERTS"></a>
  1013. <h3>MOBILEALERTS</h3>
  1014. <ul>
  1015. MOBILEALERTS ist ein FHEM-Modul f&uuml; die deutschen MobileAlerts Ger&auml; und TFA WEATHERHUB.
  1016. <br><br>
  1017. Dieses FHEM Modul stellt jeweils ein MobileAlerts Ger&auml;t dar. Die Verbindung wird durch das
  1018. <a href="#MOBILEALERTSGW">MOBILELAERTSGW</a> Modul bereitgestellt.<br>
  1019. Aktuell werden unterst&uuml;zt: MA10100, MA10101, MA10200, MA10230, MA10300, MA10650, MA10320PRO, MA10350, MA10410, MA10450, MA10660, MA10700, TFA 30.3312.02, MA10800, WL2000<br>
  1020. Unterst&uuml;zt aber ungetestet: ./.<br>
  1021. <br>
  1022. <a name="MOBILEALERTSdefine"></a>
  1023. <b>Define</b>
  1024. <ul>
  1025. <code>define &lt;name&gt; MOBILEALERTS &lt;deviceID&gt;</code><br>
  1026. <br>
  1027. deviceID ist der Sensorcode auf dem Sensor.
  1028. </ul>
  1029. <br>
  1030. <a name="MOBILEALERTSreadings"></a>
  1031. <b>Readings</b>
  1032. <ul>
  1033. <li>lastMsg<br>Die letzte empfangene Nachricht (immer f&uuml;r unbekannte Ger&auml;te, f&uuml;r bekannte nur wenn das Attribut lastMsg gesetzt ist).</li>
  1034. <li>deviceType<br>Der Ger&auml;tetyü.</li>
  1035. <li>lastRcv<br>Timestamp der letzten Nachricht.</li>
  1036. <li>actStatus<br>Zeigt 'unknown', 'alive', 'dead', 'switchedOff' abh&auml;ngig vom Attribut actCycle</li>
  1037. <li>txCounter<br>Counter des letzten Nachricht (wird 0 nach Batteriewechsel).</li>
  1038. <li>triggered<br>1=letzte Nachricht wurde von einem Ereignis ausgel&ouml;st.</li>
  1039. <li>tempertature, prevTemperature, temperatureIn, temperatureOut, prevTemperatureIn, prevTemperatureOut<br>Temperatur (abh&auml;nging vom Ger&auml;t und dem Attribut expert).</li>
  1040. <li>tempertatureString, prevTemperatureString, temperatureInString, temperatureOutString, prevTemperatureInString, prevTemperatureOutString<br>Temperatur als Zeichkette.</li>
  1041. <li>state<br>State of device (short actual reading)</li>
  1042. <li>humidity, prevHumidity, humidityIn, humidityOut, prevHumidityIn, prevHumidityOut<br>Luftfeuchte (abh&auml;nging vom Ger&auml;t und dem Attribut expert).</li>
  1043. <li>humidityString, prevHumidityString, humidityInString, humidityOutString, prevHumidityInString, prevHumidityOutString<br>Luftfeuchte als Zeichenkette</li>
  1044. <li>wetness<br>Zeigt ob der Sensors Wasser entdeckt.</li>
  1045. <li>lastEvent, lastEvent&lt;X&gt; ,lastEventString, lastEvent&lt;X&gt;String<br>Zeitpunkt wann das letzte Event (Regen) stattgefunden hat (nur MA10650).</li>
  1046. <li>mmRain, mmRainActHour, mmRainLastHour, mmRainActDay, mmRainYesterday<br>Regen seit dem letzten Reset des Counters, in der aktuellen Stunde, seit der letzten Stunden, am aktuellen Tagn, gestern.</li>
  1047. <li>direction, directionInt<br>Richtung des Winds.</li>
  1048. <li>windSpeed, gustSpeed<br>Windgeschwindigkeit.</li>
  1049. </ul>
  1050. <br>
  1051. <a name="MOBILEALERTSset"></a>
  1052. <b>Set</b>
  1053. <ul>
  1054. <li><code>set &lt;name&gt; clear &lt;readings|counters&gt;</code><br>
  1055. L&ouml;scht die Readings (alle) oder Counter (wie mmRain). </li>
  1056. </ul>
  1057. <br>
  1058. <a name="MOBILEALERTSget"></a>
  1059. <b>Get</b>
  1060. <ul>
  1061. N/A
  1062. </ul>
  1063. <br>
  1064. <br>
  1065. <a name="MOBILEALERTSattr"></a>
  1066. <b>Attributes</b>
  1067. <ul>
  1068. <li><a href="#ignore">ignore</a></li>
  1069. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  1070. <li>lastMsg<br>
  1071. Wenn dieser Wert auf 1 gesetzt ist, wird die letzte erhaltene Nachricht als Reading gelogt auch wenn das Ger&auml bekannt ist.
  1072. </li>
  1073. <li>actCycle &lt;[hhh:mm]|off&gt;<br>
  1074. Dieses Attribut erm&ouml;licht eine 'nicht erreichbarkeit' Erkennung.
  1075. [hhh:mm] ist die maximale Zeit, innerhalb der keine Nachrichten empfrangen wird.
  1076. Das Reading actStatus zeigt den Status 'unknown', 'alive', 'dead' an.
  1077. </li>
  1078. <li>expert<br>
  1079. Gibt an wie detailiert die Readings angezeigt werden (0=nur aktuelle, 1=mit vorhergehenden, 4=alle).
  1080. </li>
  1081. </ul>
  1082. </ul>
  1083. =end html_DE
  1084. =cut