59_LuftdatenInfo.pm 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. # Id ##########################################################################
  2. # $Id: 59_LuftdatenInfo.pm 15273 2017-10-18 03:43:26Z igami $
  3. # copyright ###################################################################
  4. #
  5. # 59_LuftdatenInfo.pm
  6. #
  7. # Copyright by igami
  8. #
  9. # This file is part of FHEM.
  10. #
  11. # FHEM is free software: you can redistribute it and/or modify
  12. # it under the terms of the GNU General Public License as published by
  13. # the Free Software Foundation, either version 2 of the License, or
  14. # (at your option) any later version.
  15. #
  16. # FHEM is distributed in the hope that it will be useful,
  17. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. # GNU General Public License for more details.
  20. #
  21. # You should have received a copy of the GNU General Public License
  22. # along with FHEM. If not, see <http://www.gnu.org/licenses/>.
  23. # packages ####################################################################
  24. package main;
  25. use Encode;
  26. use strict;
  27. use warnings;
  28. use HttpUtils;
  29. # forward declarations ########################################################
  30. sub LuftdatenInfo_Initialize($);
  31. sub LuftdatenInfo_Define($$);
  32. sub LuftdatenInfo_Undefine($$);
  33. sub LuftdatenInfo_Set($@);
  34. sub LuftdatenInfo_Get($@);
  35. sub LuftdatenInfo_Attr(@);
  36. sub LuftdatenInfo_GetHttpResponse($$);
  37. sub LuftdatenInfo_ParseHttpResponse($);
  38. sub LuftdatenInfo_statusRequest($);
  39. # initialize ##################################################################
  40. sub LuftdatenInfo_Initialize($) {
  41. my ($hash) = @_;
  42. my $TYPE = "LuftdatenInfo";
  43. $hash->{DefFn} = $TYPE."_Define";
  44. $hash->{UndefFn} = $TYPE."_Undefine";
  45. $hash->{SetFn} = $TYPE."_Set";
  46. $hash->{GetFn} = $TYPE."_Get";
  47. $hash->{AttrFn} = $TYPE."_Attr";
  48. $hash->{AttrList} = ""
  49. . "disable:1,0 "
  50. . "disabledForIntervals "
  51. . "interval "
  52. . "rawReading:0,1 "
  53. . "timeout "
  54. . $readingFnAttributes
  55. ;
  56. }
  57. # regular Fn ##################################################################
  58. sub LuftdatenInfo_Define($$) {
  59. my ($hash, $def) = @_;
  60. my ($SELF, $TYPE, $MODE, $DEF) = split(/[\s]+/, $def, 4);
  61. my $rc = eval{
  62. require JSON;
  63. JSON->import();
  64. 1;
  65. };
  66. return(
  67. "Error loading JSON. Maybe this module is not installed? "
  68. . "\nUnder debian (based) system it can be installed using "
  69. . "\"apt-get install libjson-perl\""
  70. ) unless($rc);
  71. delete($hash->{SENSORIDS});
  72. delete($hash->{ADDRESS});
  73. delete($hash->{INTERVAL});
  74. delete($hash->{TIMEOUT});
  75. delete($hash->{MASTER});
  76. delete($hash->{SENSORS});
  77. my $hadTemperature = 1 if(ReadingsVal($SELF, "temperature", undef));
  78. delete($hash->{READINGS});
  79. if($MODE eq "remote"){
  80. return("Usage: define <name> $TYPE $MODE <SENSORID1> [<SENSORID2> ...]")
  81. if($DEF !~ m/^[\s\d]+$/);
  82. $hash->{SENSORIDS} = $DEF;
  83. }
  84. elsif($MODE eq "local"){
  85. return("Usage: define <name> $TYPE $MODE <IP>")
  86. if($DEF =~ m/\s/);
  87. $hash->{ADDRESS} = $DEF;
  88. }
  89. elsif($MODE eq "slave"){
  90. return("Usage: define <name> $TYPE $MODE <master-name> <reading regexps>")
  91. if($DEF !~ m/\s/);
  92. ($hash->{MASTER}, $hash->{SENSORS}) = split(/[\s]+/, $DEF, 2);
  93. delete($defs{$hash->{MASTER}}->{READINGS})
  94. if(IsDevice($hash->{MASTER}, $TYPE));
  95. }
  96. else{
  97. if(looks_like_number($MODE)){
  98. $hash->{SENSORIDS} = $MODE;
  99. $hash->{SENSORIDS} .= " ".($MODE + 1) if($hadTemperature);
  100. $hash->{SENSORIDS} .= " $DEF" if($DEF && looks_like_number($DEF));
  101. $MODE = "remote";
  102. $hash->{DEF} = "$MODE $hash->{SENSORIDS}";
  103. }
  104. elsif(!$DEF){
  105. $hash->{ADDRESS} = $MODE;
  106. $MODE = "local";
  107. $hash->{DEF} = "$MODE $hash->{ADDRESS}";
  108. }
  109. else{
  110. return(
  111. "Usage: define <name> $TYPE remote <SENSORID1> [<SENSORID2> ...]"
  112. . " define <name> $TYPE local <IP>"
  113. . " define <name> $TYPE slave <master-name> <sensor1 sensor2 ...>"
  114. );
  115. }
  116. }
  117. $hash->{MODE} = $MODE;
  118. unless($MODE eq "slave"){
  119. my $minInterval = $hash->{MODE} eq "local" ? 30 : 300;
  120. my $interval = AttrVal($SELF, "interval", $minInterval);
  121. $interval = $minInterval unless(looks_like_number($interval));
  122. $interval = $minInterval if($interval < $minInterval);
  123. my $minTimeout = 5;
  124. my $timeout = AttrVal($SELF, "timeout", $minTimeout);
  125. $timeout = $minTimeout unless(looks_like_number($timeout));
  126. $timeout = $minTimeout if($timeout < $minTimeout);
  127. $hash->{INTERVAL} = $interval;
  128. $hash->{TIMEOUT} = $timeout;
  129. }
  130. readingsSingleUpdate($hash, "state", "active", 1);
  131. LuftdatenInfo_statusRequest($hash);
  132. return;
  133. }
  134. sub LuftdatenInfo_Undefine($$) {
  135. my ($hash, $arg) = @_;
  136. HttpUtils_Close($hash);
  137. RemoveInternalTimer($hash);
  138. return;
  139. }
  140. sub LuftdatenInfo_Set($@) {
  141. my ($hash, @a) = @_;
  142. my $TYPE = $hash->{TYPE};
  143. return "\"set $TYPE\" needs at least one argument" if(@a < 2);
  144. my $SELF = shift @a;
  145. my $argument = shift @a;
  146. my $value = join(" ", @a) if (@a);
  147. my %LuftdatenInfo_sets = (
  148. "statusRequest" => "statusRequest:noArg",
  149. );
  150. return(
  151. "Unknown argument $argument, choose one of "
  152. . join(" ", values %LuftdatenInfo_sets)
  153. ) if(!exists($LuftdatenInfo_sets{$argument}));
  154. if(!IsDisabled($SELF)){
  155. if($argument eq "statusRequest"){
  156. LuftdatenInfo_statusRequest($hash);
  157. }
  158. }
  159. return;
  160. }
  161. sub LuftdatenInfo_Get($@) {
  162. my ($hash, @a) = @_;
  163. my $TYPE = $hash->{TYPE};
  164. return "\"get $TYPE\" needs at least one argument" if(@a < 2);
  165. my $SELF = shift @a;
  166. my $argument = shift @a;
  167. my $value = join(" ", @a) if (@a);
  168. my %LuftdatenInfo_gets = (
  169. "sensors" => "sensors:noArg",
  170. );
  171. return(
  172. "Unknown argument $argument, choose one of "
  173. . join(" ", values %LuftdatenInfo_gets)
  174. ) if(!exists($LuftdatenInfo_gets{$argument}));
  175. if($argument eq "sensors"){
  176. return (join("\n", split(" ", ReadingsVal(
  177. InternalVal($SELF, "MASTER", $SELF), ".sensors", "No sensors found."
  178. ))));
  179. }
  180. return;
  181. }
  182. sub LuftdatenInfo_Attr(@) {
  183. my ($cmd, $SELF, $attribute, $value) = @_;
  184. my $hash = $defs{$SELF};
  185. my $TYPE = $hash->{TYPE};
  186. Log3($SELF, 5, "$TYPE ($SELF) - entering LuftdatenInfo_Attr");
  187. if($attribute eq "disable"){
  188. if($value && $value == 1){
  189. readingsSingleUpdate($hash, "state", "disabled", 1);
  190. }
  191. elsif($cmd eq "del" || !$value){
  192. LuftdatenInfo_statusRequest($hash);
  193. readingsSingleUpdate($hash, "state", "active", 1);
  194. }
  195. }
  196. elsif($attribute eq "interval"){
  197. my $minInterval = $hash->{CONNECTION} eq "local" ? 30 : 300;
  198. my $interval = $cmd eq "set" ? $value : $minInterval;
  199. $interval = $minInterval unless(looks_like_number($interval));
  200. $interval = $minInterval if($interval < $minInterval);
  201. $hash->{INTERVAL} = $interval;
  202. }
  203. elsif($attribute eq "timeout"){
  204. my $minTimeout = 5;
  205. my $timeout = $cmd eq "set" ? $value : $minTimeout;
  206. $timeout = $minTimeout unless(looks_like_number($timeout));
  207. $timeout = $minTimeout if($timeout < $minTimeout);
  208. $hash->{TIMEOUT} = $timeout;
  209. }
  210. return;
  211. }
  212. # HttpUtils Fn ################################################################
  213. sub LuftdatenInfo_GetHttpResponse($$) {
  214. my ($hash, $arg) = @_;
  215. my $SELF = $hash->{NAME};
  216. my $TYPE = $hash->{TYPE};
  217. my $MODE = $hash->{MODE};
  218. my $timeout = $hash->{TIMEOUT};
  219. Log3($SELF, 5, "$TYPE ($SELF) - entering LuftdatenInfo_GetHttpResponse");
  220. my $param = {
  221. timeout => $timeout,
  222. hash => $hash,
  223. method => "GET",
  224. header => "Accept: application/json",
  225. callback => \&LuftdatenInfo_ParseHttpResponse,
  226. };
  227. $param->{url} = "http://api.luftdaten.info/v1/sensor/$arg/"
  228. if($MODE eq "remote");
  229. $param->{url} = "http://$arg/data.json"
  230. if($MODE eq "local");
  231. HttpUtils_NonblockingGet($param);
  232. }
  233. sub LuftdatenInfo_ParseHttpResponse($) {
  234. my ($param, $err, $data) = @_;
  235. my $hash = $param->{hash};
  236. my $SELF = $hash->{NAME};
  237. my $TYPE = $hash->{TYPE};
  238. Log3($SELF, 5, "$TYPE ($SELF) - entering LuftdatenInfo_ParseHttpResponse");
  239. if($err ne ""){
  240. Log3($SELF, 2, "$TYPE ($SELF) - error while request: $err");
  241. readingsSingleUpdate($hash, "state", "error", 1);
  242. }
  243. elsif($data eq "[]"){
  244. Log3($SELF, 2, "$TYPE ($SELF) - error while request: no data returned");
  245. readingsSingleUpdate($hash, "state", "error", 1);
  246. }
  247. elsif($data ne ""){
  248. Log3 $SELF, 4, "$TYPE ($SELF) - returned data: $data";
  249. $data = encode('UTF-8', $data);
  250. $data = eval{decode_json($data)};
  251. if($@){
  252. Log3($SELF, 2, "$TYPE ($SELF) - error while request: $@");
  253. readingsSingleUpdate($hash, "state", "error", 1);
  254. return;
  255. }
  256. my $MODE = $hash->{MODE};
  257. my $rawReading = AttrVal($SELF, "rawReading", 0);
  258. if($param->{url} =~ m/openstreetmap/){
  259. my $address = $data->{address};
  260. readingsSingleUpdate(
  261. $hash, "location"
  262. , "$address->{postcode} "
  263. . ($address->{city} ? $address->{city} : $address->{town})
  264. , 1
  265. );
  266. }
  267. elsif($MODE eq "remote"){
  268. my $sensor = @{$data}[-1];
  269. my $sensor_type = $sensor->{sensor}{sensor_type}{name};
  270. Log3 $SELF, 5, "$TYPE ($SELF) - parsing $sensor_type data";
  271. my $latitude = $sensor->{location}{latitude};
  272. my $longitude = $sensor->{location}{longitude};
  273. if(
  274. $latitude ne ReadingsVal($SELF, "latitude", $latitude)
  275. || $longitude ne ReadingsVal($SELF, "longitude", $longitude)
  276. ){
  277. Log3(
  278. $SELF, 2
  279. , "$TYPE ($SELF) - "
  280. . "$sensor->{sensor}{sensor_type}{name} position differs from "
  281. . "other sensor position"
  282. );
  283. return;
  284. }
  285. unless(ReadingsVal($SELF, "location", undef)){
  286. my $param = {
  287. url => "http://nominatim.openstreetmap.org/reverse?".
  288. "format=json&lat=$latitude&lon=$longitude",
  289. timeout => $hash->{TIMEOUT},
  290. hash => $hash,
  291. method => "GET",
  292. header => "Accept: application/json",
  293. callback => \&LuftdatenInfo_ParseHttpResponse,
  294. };
  295. HttpUtils_NonblockingGet($param);
  296. }
  297. readingsBeginUpdate($hash);
  298. foreach (@{$sensor->{sensordatavalues}}){
  299. $_->{value} =~ m/^(\S+)(\s|$)/;
  300. $_->{value} = $1;
  301. my $knownReading = 1;
  302. if($_->{value_type} eq "P1"){
  303. $_->{value_type} = "PM10";
  304. }
  305. elsif($_->{value_type} eq "P2"){
  306. $_->{value_type} = "PM2.5";
  307. }
  308. elsif($_->{value_type} =~ /temperature$/){
  309. $_->{value_type} = "temperature";
  310. }
  311. elsif($_->{value_type} =~ /humidity$/){
  312. $_->{value_type} = "humidity";
  313. }
  314. elsif($_->{value_type} =~ /pressure$/){
  315. $_->{value} = ($_->{value} > 10000 ? $_->{value} / 100 : $_->{value});
  316. $_->{value_type} = "pressure";
  317. }
  318. else{
  319. $knownReading = 0;
  320. }
  321. readingsBulkUpdate($hash, $_->{value_type}, $_->{value})
  322. if($knownReading || $rawReading);
  323. }
  324. readingsBulkUpdateIfChanged($hash, "latitude", $latitude);
  325. readingsBulkUpdateIfChanged($hash, "longitude", $longitude);
  326. readingsBulkUpdate($hash, "state", "active");
  327. readingsEndUpdate($hash, 1);
  328. }
  329. elsif($MODE eq "local"){
  330. my @slaves = devspec2array("TYPE=$TYPE:FILTER=MASTER=$SELF");
  331. my @sensors;
  332. push(@sensors, $_->{value_type}) foreach (@{$data->{sensordatavalues}});
  333. readingsBeginUpdate($defs{$_}) foreach($SELF, @slaves);
  334. readingsBulkUpdateIfChanged(
  335. $hash, "softwareVersion", $data->{software_version}
  336. );
  337. readingsBulkUpdateIfChanged($hash, ".sensors", join(" ", sort(@sensors)));
  338. foreach (@{$data->{sensordatavalues}}){
  339. my $knownReading = 1;
  340. $_->{value} =~ m/^(\S+)(\s|$)/;
  341. $_->{value} = $1;
  342. my $device = (devspec2array(
  343. "MASTER=$SELF:FILTER=SENSORS=(.+ )?$_->{value_type}( .+)?"
  344. ))[0];
  345. $device = IsDevice($device, $TYPE) ? $defs{$device} : $hash;
  346. if($_->{value_type} =~ /P0$/){
  347. $_->{value_type} = "PM1";
  348. }
  349. elsif($_->{value_type} =~ /P1$/){
  350. $_->{value_type} = "PM10";
  351. }
  352. elsif($_->{value_type} =~ /P2$/){
  353. $_->{value_type} = "PM2.5";
  354. }
  355. elsif($_->{value_type} =~ /_height$/){
  356. $_->{value_type} = "altitude";
  357. }
  358. elsif($_->{value_type} =~ /_date$/){
  359. $_->{value_type} = "date";
  360. }
  361. elsif($_->{value_type} =~ /humidity$/){
  362. $_->{value_type} = "humidity";
  363. }
  364. elsif($_->{value_type} =~ /_Full$/){
  365. $_->{value_type} = "illuminanceFull";
  366. }
  367. elsif($_->{value_type} =~ /_UV$/){
  368. $_->{value_type} = "illuminanceUV";
  369. }
  370. elsif($_->{value_type} =~ /_IR$/){
  371. $_->{value_type} = "illuminanceIR";
  372. }
  373. elsif($_->{value_type} =~ /_Visible$/){
  374. $_->{value_type} = "illuminanceVisible";
  375. }
  376. elsif($_->{value_type} =~ /_lat$/){
  377. $_->{value_type} = "latitude";
  378. }
  379. elsif($_->{value_type} =~ /_lon$/){
  380. $_->{value_type} = "longitude";
  381. }
  382. elsif($_->{value_type} =~ /pressure$/){
  383. $_->{value} = ($_->{value} > 10000 ? $_->{value} / 100 : $_->{value});
  384. $_->{value_type} = "pressure";
  385. }
  386. elsif($_->{value_type} =~ /pressure_nn$/){
  387. $_->{value} = ($_->{value} > 10000 ? $_->{value} / 100 : $_->{value});
  388. $_->{value_type} = "pressureNN";
  389. }
  390. elsif($_->{value_type} =~ /_risk/){
  391. $_->{value_type} = "UVRisk";
  392. }
  393. elsif($_->{value_type} eq "signal"){
  394. $_->{value_type} = "signal";
  395. }
  396. elsif($_->{value_type} =~ /temperature$/){
  397. $_->{value_type} = "temperature";
  398. }
  399. elsif($_->{value_type} =~ /_watt/){
  400. $_->{value_type} = "UVIntensity";
  401. }
  402. elsif($_->{value_type} =~ /_time$/){
  403. $_->{value_type} = "time";
  404. }
  405. else{
  406. $knownReading = 0;
  407. }
  408. readingsBulkUpdate($device, $_->{value_type}, $_->{value})
  409. if($knownReading || $rawReading);
  410. }
  411. foreach($SELF, @slaves){
  412. readingsBulkUpdate($defs{$_}, "state", "active");
  413. readingsEndUpdate($defs{$_}, 1);
  414. }
  415. }
  416. }
  417. return;
  418. }
  419. # module Fn ###################################################################
  420. sub LuftdatenInfo_statusRequest($) {
  421. my ($hash) = @_;
  422. my $SELF = $hash->{NAME};
  423. my $TYPE = $hash->{TYPE};
  424. my $MODE = $hash->{MODE};
  425. my $interval = InternalVal($SELF, "INTERVAL", undef);
  426. Log3($SELF, 5, "$TYPE ($SELF) - entering LuftdatenInfo_statusRequest");
  427. if($interval){
  428. RemoveInternalTimer($hash);
  429. InternalTimer(
  430. gettimeofday() + $interval, "LuftdatenInfo_statusRequest", $hash
  431. );
  432. }
  433. return if(IsDisabled($SELF));
  434. if($MODE eq "remote"){
  435. LuftdatenInfo_GetHttpResponse($hash, $_)
  436. foreach(split(/[\s]+/, $hash->{SENSORIDS}));
  437. }
  438. elsif($MODE eq "local"){
  439. LuftdatenInfo_GetHttpResponse($hash, $hash->{ADDRESS});
  440. }
  441. elsif($MODE eq "slave"){
  442. if( IsDevice($hash->{MASTER}, $TYPE)
  443. && InternalVal($hash->{MASTER}, "MODE", "") eq "local"
  444. ){
  445. readingsSingleUpdate($hash, "state", "active", 1);
  446. LuftdatenInfo_statusRequest($defs{$hash->{MASTER}});
  447. }
  448. else{
  449. readingsSingleUpdate($hash, "state", "master not defined", 1);
  450. }
  451. }
  452. }
  453. 1;
  454. # commandref ##################################################################
  455. =pod
  456. =item summary provides data from Luftdaten.info
  457. =item summary_DE stellt Daten von Luftdaten.info bereit
  458. =begin html
  459. <a name="LuftdatenInfo"></a>
  460. <h3>LuftdatenInfo</h3>
  461. (en | <a href="commandref_DE.html#LuftdatenInfo"><u>de</u></a>)
  462. <div>
  463. <ul>
  464. LuftdatenInfo is the FHEM module to read particulate matter, temperature
  465. and humidity values ​​from the self-assembly particulate matter sensors
  466. from <a href="http://Luftdaten.info"><u>Luftdaten.info</u></a>.<br>
  467. The values ​​can be queried directly from the server or locally.<br>
  468. There is an
  469. <a href="https://forum.fhem.de/index.php/topic,73879">
  470. <u>alternative Firmware</u>
  471. </a>
  472. to support more sensors.<br>
  473. <br>
  474. <b>Prerequisites</b>
  475. <ul>
  476. The Perl module "JSON" is required.<br>
  477. Under Debian (based) system, this can be installed using
  478. <code>"apt-get install libjson-perl"</code>.
  479. </ul>
  480. <br>
  481. <a name="LuftdatenInfodefine"></a>
  482. <b>Define</b>
  483. <ul>
  484. <code>
  485. define &lt;name&gt; LuftdatenInfo remote
  486. &lt;SENSORID1&gt; [&lt;SENSORID2&gt; ..]<br>
  487. define &lt;name&gt; LuftdatenInfo local &lt;IP&gt;<br>
  488. define &lt;name&gt; LuftdatenInfo
  489. slave &lt;master-name&gt; &lt;sensor1 sensor2 ...&gt;
  490. </code><br>
  491. To query the data from the server, all affected SensorIDs must be
  492. specified. The IDs of the SDS01 stands right at
  493. <a href="http://maps.luftdaten.info/">
  494. <u>http://maps.luftdaten.info/</u>
  495. </a>
  496. . The DHT22 SensorID is usually the SDS011 SensorID + 1. While parsing
  497. the data the location values from all sensors will be compared and a
  498. message will be written into the log if they differ.<br>
  499. For a local query of the data, the IP address or hostname must be
  500. specified.<br>
  501. If several similar sensors are used, the duplicate values can be written
  502. in another device.
  503. </ul><br>
  504. <a name="LuftdatenInfoset"></a>
  505. <b>Set</b>
  506. <ul>
  507. <li>
  508. <code>statusRequest</code><br>
  509. Starts a status request.
  510. </li>
  511. </ul><br>
  512. <a name="LuftdatenInfoget"></a>
  513. <b>Get</b>
  514. <ul>
  515. <li>
  516. <code>sensors</code><br>
  517. Lists all senors.
  518. </li>
  519. </ul><br>
  520. <a name="LuftdatenInforeadings"></a>
  521. <b>Readings</b><br>
  522. <ul>
  523. <li>
  524. <code>altitude</code>
  525. </li>
  526. <li>
  527. <code>humidity</code><br>
  528. Relative humidity in %
  529. </li>
  530. <li>
  531. <code>illuminanceFull</code><br>
  532. Illuminace of the full spectrum in lux
  533. </li>
  534. <li>
  535. <code>illuminanceIR</code><br>
  536. Iilluminace of the IR spectrum in lux
  537. </li>
  538. <li>
  539. <code>illuminanceUV</code><br>
  540. Iilluminace of the UV spectrum in lux
  541. </li>
  542. <li>
  543. <code>illuminanceVisible</code><br>
  544. Iilluminace of the visible spectrum in lux
  545. </li>
  546. <li>
  547. <code>latitude</code>
  548. </li>
  549. <li>
  550. <code>location</code><br>
  551. location as "postcode city"<br>
  552. Only available with remote query.
  553. </li>
  554. <li>
  555. <code>longitude</code>
  556. </li>
  557. <li>
  558. <code>PM1</code><br>
  559. Quantity of particles with a diameter of less than 1 μm in μg/m³
  560. </li>
  561. <li>
  562. <code>PM2.5</code><br>
  563. Quantity of particles with a diameter of less than 2.5 μm in μg/m³
  564. </li>
  565. <li>
  566. <code>PM10</code><br>
  567. Quantity of particles with a diameter of less than 10 μm in μg/m³
  568. </li>
  569. <li>
  570. <code>pressure</code><br>
  571. Pressure in hPa
  572. </li>
  573. <li>
  574. <code>pressureNN</code><br>
  575. Pressure at sea level in hPa<br>
  576. Is calculated if pressure and temperature sensor are active and the
  577. sensor is not at sea level.<br>
  578. The height, can be determined by maps or SmartPhone, needs to be
  579. specified at the configuration page.
  580. </li>
  581. <li>
  582. <code>signal</code><br>
  583. WLAN signal strength in dBm<br>
  584. Only available with local query.
  585. </li>
  586. <li>
  587. <code>temperature</code><br>
  588. Temperature in °C
  589. </li>
  590. <li>
  591. <code>UVIntensity</code><br>
  592. UV intensity in W
  593. </li>
  594. <li>
  595. <code>UVRisk</code><br>
  596. UV risk from 1 to 5
  597. </li>
  598. </ul><br>
  599. <a name="LuftdatenInfoattr"></a>
  600. <b>Attribute</b>
  601. <ul>
  602. <li>
  603. <code>disable 1</code><br>
  604. No queries are started.
  605. </li>
  606. <li>
  607. <a href="#disabledForIntervals">
  608. <u><code>disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM ...</code></u>
  609. </a>
  610. </li>
  611. <li>
  612. <code>interval &lt;seconds&gt;</code><br>
  613. Interval in seconds in which queries are performed.<br>
  614. The default and minimum value is 300 seconds.
  615. </li>
  616. <li>
  617. <code>timeout &lt;seconds&gt;</code><br>
  618. Timeout in seconds for the queries.<br>
  619. The default and minimum value is 5 seconds.
  620. </li>
  621. </ul>
  622. </ul>
  623. </div>
  624. =end html
  625. =begin html_DE
  626. <a name="LuftdatenInfo"></a>
  627. <h3>LuftdatenInfo</h3>
  628. (<a href="commandref.html#LuftdatenInfo"><u>en</u></a> | de)
  629. <div>
  630. <ul>
  631. LuftdatenInfo ist das FHEM Modul um Feinstaub-, Temperatur- und
  632. Luftfeuchtichkeitswerte von den selbstbau Feinstaub Sensoren von
  633. <a href="http://Luftdaten.info"><u>Luftdaten.info</u></a> auszulesen.<br>
  634. Dabei k&ouml;nnen die Werte direkt vom Server oder auch lokal abgefragt
  635. werden.<br>
  636. Bei einer lokalen Abfrage werden durch eine
  637. <a href="https://forum.fhem.de/index.php/topic,73879">
  638. <u>alternative Firmware</u>
  639. </a>
  640. noch weitere Sensoren unterstützt.<br>
  641. <br>
  642. <b>Vorraussetzungen</b>
  643. <ul>
  644. Das Perl-Modul "JSON" wird ben&ouml;tigt.<br>
  645. Unter Debian (basierten) System, kann dies mittels
  646. <code>"apt-get install libjson-perl"</code> installiert werden.
  647. </ul>
  648. <br>
  649. <a name="LuftdatenInfodefine"></a>
  650. <b>Define</b>
  651. <ul>
  652. <code>
  653. define &lt;name&gt; LuftdatenInfo remote
  654. &lt;SENSORID1&gt; [&lt;SENSORID2&gt; ..]<br>
  655. define &lt;name&gt; LuftdatenInfo local &lt;IP&gt;<br>
  656. define &lt;name&gt; LuftdatenInfo
  657. slave &lt;master-name&gt; &lt;sensor1 sensor2 ...&gt;
  658. </code><br>
  659. F&uuml;r eine Abfrage der Daten vom Server müssem alle betroffenenen
  660. SensorIDs angegeben werden. Die IDs vom SDS01 stehen rechts auf der Seite
  661. <a href="http://maps.luftdaten.info/">
  662. <u>http://maps.luftdaten.info/</u>
  663. </a>
  664. . Die DHT22 SensorID entspricht normalerweise der SDS011 SensorID + 1.
  665. Bei einer Abfrage werden die die Positionsangaben verglichen und bei
  666. einer Abweichung eine Meldung ins Log geschrieben.<br>
  667. F&uuml;r eine lokale Abfrage der Daten muss die IP Addresse oder der
  668. Hostname angegeben werden.<br>
  669. Werden mehrere ähnliche Sensoren betrieben lassen sich die doppelten
  670. Werte in einem anderen Gerät geschrieben werden.
  671. </ul><br>
  672. <a name="LuftdatenInfoset"></a>
  673. <b>Set</b>
  674. <ul>
  675. <li>
  676. <code>statusRequest</code><br>
  677. Startet eine Abfrage der Daten.
  678. </li>
  679. </ul><br>
  680. <a name="LuftdatenInfoget"></a>
  681. <b>Get</b>
  682. <ul>
  683. <li>
  684. <code>sensors</code><br>
  685. Listet alle Sensoren auf.
  686. </li>
  687. </ul><br>
  688. <a name="LuftdatenInforeadings"></a>
  689. <b>Readings</b><br>
  690. <ul>
  691. <li>
  692. <code>altitude</code><br>
  693. Höhe über NN
  694. </li>
  695. <li>
  696. <code>humidity</code><br>
  697. Relative Luftfeuchtgkeit in %
  698. </li>
  699. <li>
  700. <code>illuminanceFull</code><br>
  701. Helligkeit des vollen Bereich in lux
  702. </li>
  703. <li>
  704. <code>illuminanceIR</code><br>
  705. Helligkeit des IR Bereich in lux
  706. </li>
  707. <li>
  708. <code>illuminanceUV</code><br>
  709. Helligkeit des UV Bereich in lux
  710. </li>
  711. <li>
  712. <code>illuminanceVisible</code><br>
  713. Helligkeit des sichtbaren Bereich in lux
  714. </li>
  715. <li>
  716. <code>latitude</code><br>
  717. Längengrad
  718. </li>
  719. <li>
  720. <code>location</code><br>
  721. Standort als "Postleitzahl Ort"<br>
  722. Nur bei remote Abfrage verf&uuml;gbar.
  723. </li>
  724. <li>
  725. <code>longitude</code><br>
  726. Breitengrad
  727. </li>
  728. <li>
  729. <code>PM1</code><br>
  730. Menge der Partikel mit einem Durchmesser von weniger als 1 µm in µg/m³
  731. </li>
  732. <li>
  733. <code>PM2.5</code><br>
  734. Menge der Partikel mit einem Durchmesser von weniger als 2.5 µm in µg/m³
  735. </li>
  736. <li>
  737. <code>PM10</code><br>
  738. Menge der Partikel mit einem Durchmesser von weniger als 10 µm in µg/m³
  739. </li>
  740. <li>
  741. <code>pressure</code><br>
  742. Luftdruck in hPa
  743. </li>
  744. <li>
  745. <code>pressureNN</code><br>
  746. Luftdruck für Normal Null in hPa<br>
  747. Wird bei aktivem Luftdruck- und Temperatursensor berechnet, sofern sich
  748. der Sensor nicht auf Normal Null befindet.<br>
  749. Hierzu ist die Höhe, kann über Kartendienste oder SmartPhone ermittelt
  750. werden, auf der Konfigurationsseite anzugeben.
  751. </li>
  752. <li>
  753. <code>signal</code><br>
  754. WLAN Signalst&auml;rke in dBm<br>
  755. Nur bei local Abfrage verf&uuml;gbar.
  756. </li>
  757. <li>
  758. <code>temperature</code><br>
  759. Temperatur in °C
  760. </li>
  761. <li>
  762. <code>UVIntensity</code><br>
  763. UV Intensität in W
  764. </li>
  765. <li>
  766. <code>UVRisk</code><br>
  767. UV Risiko von 1 bis 5
  768. </li>
  769. </ul><br>
  770. <a name="LuftdatenInfoattr"></a>
  771. <b>Attribute</b>
  772. <ul>
  773. <li>
  774. <code>disable 1</code><br>
  775. Es werden keine Abfragen mehr gestartet.
  776. </li>
  777. <li>
  778. <a href="#disabledForIntervals">
  779. <u><code>disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM ...</code></u>
  780. </a>
  781. </li>
  782. <li>
  783. <code>interval &lt;seconds&gt;</code><br>
  784. Intervall in Sekunden in dem Abfragen durchgef&uuml;hrt werden.<br>
  785. Der Vorgabe- und Mindestwert betr&auml;gt 300 Sekunden.
  786. </li>
  787. <li>
  788. <code>timeout &lt;seconds&gt;</code><br>
  789. Timeout in Sekunden für die Abfragen.<br>
  790. Der Vorgabe- und Mindestwert betr&auml;gt 5 Sekunden.
  791. </li>
  792. </ul>
  793. </ul>
  794. </div>
  795. =end html_DE
  796. =cut