59_LuftdatenInfo.pm 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. # Id ##########################################################################
  2. # $Id: 59_LuftdatenInfo.pm 17548 2018-10-16 19:33:15Z 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} =~ /_air_quality$/){
  356. $_->{value_type} = "airQuality";
  357. }
  358. elsif($_->{value_type} =~ /_height$/){
  359. $_->{value_type} = "altitude";
  360. }
  361. elsif($_->{value_type} =~ /_date$/){
  362. $_->{value_type} = "date";
  363. }
  364. elsif($_->{value_type} =~ /humidity$/){
  365. $_->{value_type} = "humidity";
  366. }
  367. elsif($_->{value_type} =~ /_Full$/){
  368. $_->{value_type} = "illuminanceFull";
  369. }
  370. elsif($_->{value_type} =~ /_UV$/){
  371. $_->{value_type} = "illuminanceUV";
  372. }
  373. elsif($_->{value_type} =~ /_IR$/){
  374. $_->{value_type} = "illuminanceIR";
  375. }
  376. elsif($_->{value_type} =~ /_Visible$/){
  377. $_->{value_type} = "illuminanceVisible";
  378. }
  379. elsif($_->{value_type} =~ /_lat$/){
  380. $_->{value_type} = "latitude";
  381. }
  382. elsif($_->{value_type} =~ /_lon$/){
  383. $_->{value_type} = "longitude";
  384. }
  385. elsif($_->{value_type} =~ /pressure$/){
  386. $_->{value} = ($_->{value} > 10000 ? $_->{value} / 100 : $_->{value});
  387. $_->{value_type} = "pressure";
  388. }
  389. elsif($_->{value_type} =~ /pressure_nn$/){
  390. $_->{value} = ($_->{value} > 10000 ? $_->{value} / 100 : $_->{value});
  391. $_->{value_type} = "pressureNN";
  392. }
  393. elsif($_->{value_type} =~ /_risk/){
  394. $_->{value_type} = "UVRisk";
  395. }
  396. elsif($_->{value_type} eq "signal"){
  397. $_->{value_type} = "signal";
  398. }
  399. elsif($_->{value_type} =~ /temperature$/){
  400. $_->{value_type} = "temperature";
  401. }
  402. elsif($_->{value_type} =~ /_watt/){
  403. $_->{value_type} = "UVIntensity";
  404. }
  405. elsif($_->{value_type} =~ /_time$/){
  406. $_->{value_type} = "time";
  407. }
  408. else{
  409. $knownReading = 0;
  410. }
  411. readingsBulkUpdate($device, $_->{value_type}, $_->{value})
  412. if($knownReading || $rawReading);
  413. }
  414. foreach($SELF, @slaves){
  415. readingsBulkUpdate($defs{$_}, "state", "active");
  416. readingsEndUpdate($defs{$_}, 1);
  417. }
  418. }
  419. }
  420. return;
  421. }
  422. # module Fn ###################################################################
  423. sub LuftdatenInfo_statusRequest($) {
  424. my ($hash) = @_;
  425. my $SELF = $hash->{NAME};
  426. my $TYPE = $hash->{TYPE};
  427. my $MODE = $hash->{MODE};
  428. my $interval = InternalVal($SELF, "INTERVAL", undef);
  429. Log3($SELF, 5, "$TYPE ($SELF) - entering LuftdatenInfo_statusRequest");
  430. if($interval){
  431. RemoveInternalTimer($hash);
  432. InternalTimer(
  433. gettimeofday() + $interval, "LuftdatenInfo_statusRequest", $hash
  434. );
  435. }
  436. return if(IsDisabled($SELF));
  437. if($MODE eq "remote"){
  438. LuftdatenInfo_GetHttpResponse($hash, $_)
  439. foreach(split(/[\s]+/, $hash->{SENSORIDS}));
  440. }
  441. elsif($MODE eq "local"){
  442. LuftdatenInfo_GetHttpResponse($hash, $hash->{ADDRESS});
  443. }
  444. elsif($MODE eq "slave"){
  445. if( IsDevice($hash->{MASTER}, $TYPE)
  446. && InternalVal($hash->{MASTER}, "MODE", "") eq "local"
  447. ){
  448. readingsSingleUpdate($hash, "state", "active", 1);
  449. LuftdatenInfo_statusRequest($defs{$hash->{MASTER}});
  450. }
  451. else{
  452. readingsSingleUpdate($hash, "state", "master not defined", 1);
  453. }
  454. }
  455. }
  456. 1;
  457. # commandref ##################################################################
  458. =pod
  459. =item summary provides data from Luftdaten.info
  460. =item summary_DE stellt Daten von Luftdaten.info bereit
  461. =begin html
  462. <a name="LuftdatenInfo"></a>
  463. <h3>LuftdatenInfo</h3>
  464. (en | <a href="commandref_DE.html#LuftdatenInfo"><u>de</u></a>)
  465. <div>
  466. <ul>
  467. LuftdatenInfo is the FHEM module to read particulate matter, temperature
  468. and humidity values ​​from the self-assembly particulate matter sensors
  469. from <a href="http://Luftdaten.info"><u>Luftdaten.info</u></a>.<br>
  470. The values ​​can be queried directly from the server or locally.<br>
  471. There is an
  472. <a href="https://forum.fhem.de/index.php/topic,73879">
  473. <u>alternative Firmware</u>
  474. </a>
  475. to support more sensors.<br>
  476. <br>
  477. <b>Prerequisites</b>
  478. <ul>
  479. The Perl module "JSON" is required.<br>
  480. Under Debian (based) system, this can be installed using
  481. <code>"apt-get install libjson-perl"</code>.
  482. </ul>
  483. <br>
  484. <a name="LuftdatenInfodefine"></a>
  485. <b>Define</b>
  486. <ul>
  487. <code>
  488. define &lt;name&gt; LuftdatenInfo remote
  489. &lt;SENSORID1&gt; [&lt;SENSORID2&gt; ..]<br>
  490. define &lt;name&gt; LuftdatenInfo local &lt;IP&gt;<br>
  491. define &lt;name&gt; LuftdatenInfo
  492. slave &lt;master-name&gt; &lt;sensor1 sensor2 ...&gt;
  493. </code><br>
  494. To query the data from the server, all affected SensorIDs must be
  495. specified. The IDs of the SDS01 stands right at
  496. <a href="http://maps.luftdaten.info/">
  497. <u>http://maps.luftdaten.info/</u>
  498. </a>
  499. . The DHT22 SensorID is usually the SDS011 SensorID + 1. While parsing
  500. the data the location values from all sensors will be compared and a
  501. message will be written into the log if they differ.<br>
  502. For a local query of the data, the IP address or hostname must be
  503. specified.<br>
  504. If several similar sensors are used, the duplicate values can be written
  505. in another device.
  506. </ul><br>
  507. <a name="LuftdatenInfoset"></a>
  508. <b>Set</b>
  509. <ul>
  510. <li>
  511. <code>statusRequest</code><br>
  512. Starts a status request.
  513. </li>
  514. </ul><br>
  515. <a name="LuftdatenInfoget"></a>
  516. <b>Get</b>
  517. <ul>
  518. <li>
  519. <code>sensors</code><br>
  520. Lists all senors.
  521. </li>
  522. </ul><br>
  523. <a name="LuftdatenInforeadings"></a>
  524. <b>Readings</b><br>
  525. <ul>
  526. <li>
  527. <code>airQuality</code>
  528. 1 => good<br>
  529. 2 => moderate<br>
  530. 3 => unhealthy for sensitive groups<br>
  531. 4 => unhealthy<br>
  532. 5 => very unhealthy<br>
  533. 6 => hazardous<br>
  534. </li>
  535. <li>
  536. <code>altitude</code>
  537. </li>
  538. <li>
  539. <code>humidity</code><br>
  540. Relative humidity in %
  541. </li>
  542. <li>
  543. <code>illuminanceFull</code><br>
  544. Illuminace of the full spectrum in lux
  545. </li>
  546. <li>
  547. <code>illuminanceIR</code><br>
  548. Iilluminace of the IR spectrum in lux
  549. </li>
  550. <li>
  551. <code>illuminanceUV</code><br>
  552. Iilluminace of the UV spectrum in lux
  553. </li>
  554. <li>
  555. <code>illuminanceVisible</code><br>
  556. Iilluminace of the visible spectrum in lux
  557. </li>
  558. <li>
  559. <code>latitude</code>
  560. </li>
  561. <li>
  562. <code>location</code><br>
  563. location as "postcode city"<br>
  564. Only available with remote query.
  565. </li>
  566. <li>
  567. <code>longitude</code>
  568. </li>
  569. <li>
  570. <code>PM1</code><br>
  571. Quantity of particles with a diameter of less than 1 μm in μg/m³
  572. </li>
  573. <li>
  574. <code>PM2.5</code><br>
  575. Quantity of particles with a diameter of less than 2.5 μm in μg/m³
  576. </li>
  577. <li>
  578. <code>PM10</code><br>
  579. Quantity of particles with a diameter of less than 10 μm in μg/m³
  580. </li>
  581. <li>
  582. <code>pressure</code><br>
  583. Pressure in hPa
  584. </li>
  585. <li>
  586. <code>pressureNN</code><br>
  587. Pressure at sea level in hPa<br>
  588. Is calculated if pressure and temperature sensor are active and the
  589. sensor is not at sea level.<br>
  590. The height, can be determined by maps or SmartPhone, needs to be
  591. specified at the configuration page.
  592. </li>
  593. <li>
  594. <code>signal</code><br>
  595. WLAN signal strength in dBm<br>
  596. Only available with local query.
  597. </li>
  598. <li>
  599. <code>temperature</code><br>
  600. Temperature in °C
  601. </li>
  602. <li>
  603. <code>UVIntensity</code><br>
  604. UV intensity in W
  605. </li>
  606. <li>
  607. <code>UVRisk</code><br>
  608. UV risk from 1 to 5
  609. </li>
  610. </ul><br>
  611. <a name="LuftdatenInfoattr"></a>
  612. <b>Attribute</b>
  613. <ul>
  614. <li>
  615. <code>disable 1</code><br>
  616. No queries are started.
  617. </li>
  618. <li>
  619. <a href="#disabledForIntervals">
  620. <u><code>disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM ...</code></u>
  621. </a>
  622. </li>
  623. <li>
  624. <code>interval &lt;seconds&gt;</code><br>
  625. Interval in seconds in which queries are performed.<br>
  626. The default and minimum value is 300 seconds.
  627. </li>
  628. <li>
  629. <code>timeout &lt;seconds&gt;</code><br>
  630. Timeout in seconds for the queries.<br>
  631. The default and minimum value is 5 seconds.
  632. </li>
  633. </ul>
  634. </ul>
  635. </div>
  636. =end html
  637. =begin html_DE
  638. <a name="LuftdatenInfo"></a>
  639. <h3>LuftdatenInfo</h3>
  640. (<a href="commandref.html#LuftdatenInfo"><u>en</u></a> | de)
  641. <div>
  642. <ul>
  643. LuftdatenInfo ist das FHEM Modul um Feinstaub-, Temperatur- und
  644. Luftfeuchtichkeitswerte von den selbstbau Feinstaub Sensoren von
  645. <a href="http://Luftdaten.info"><u>Luftdaten.info</u></a> auszulesen.<br>
  646. Dabei k&ouml;nnen die Werte direkt vom Server oder auch lokal abgefragt
  647. werden.<br>
  648. Bei einer lokalen Abfrage werden durch eine
  649. <a href="https://forum.fhem.de/index.php/topic,73879">
  650. <u>alternative Firmware</u>
  651. </a>
  652. noch weitere Sensoren unterstützt.<br>
  653. <br>
  654. <b>Vorraussetzungen</b>
  655. <ul>
  656. Das Perl-Modul "JSON" wird ben&ouml;tigt.<br>
  657. Unter Debian (basierten) System, kann dies mittels
  658. <code>"apt-get install libjson-perl"</code> installiert werden.
  659. </ul>
  660. <br>
  661. <a name="LuftdatenInfodefine"></a>
  662. <b>Define</b>
  663. <ul>
  664. <code>
  665. define &lt;name&gt; LuftdatenInfo remote
  666. &lt;SENSORID1&gt; [&lt;SENSORID2&gt; ..]<br>
  667. define &lt;name&gt; LuftdatenInfo local &lt;IP&gt;<br>
  668. define &lt;name&gt; LuftdatenInfo
  669. slave &lt;master-name&gt; &lt;sensor1 sensor2 ...&gt;
  670. </code><br>
  671. F&uuml;r eine Abfrage der Daten vom Server müssem alle betroffenenen
  672. SensorIDs angegeben werden. Die IDs vom SDS01 stehen rechts auf der Seite
  673. <a href="http://maps.luftdaten.info/">
  674. <u>http://maps.luftdaten.info/</u>
  675. </a>
  676. . Die DHT22 SensorID entspricht normalerweise der SDS011 SensorID + 1.
  677. Bei einer Abfrage werden die die Positionsangaben verglichen und bei
  678. einer Abweichung eine Meldung ins Log geschrieben.<br>
  679. F&uuml;r eine lokale Abfrage der Daten muss die IP Addresse oder der
  680. Hostname angegeben werden.<br>
  681. Werden mehrere ähnliche Sensoren betrieben lassen sich die doppelten
  682. Werte in einem anderen Gerät geschrieben werden.
  683. </ul><br>
  684. <a name="LuftdatenInfoset"></a>
  685. <b>Set</b>
  686. <ul>
  687. <li>
  688. <code>statusRequest</code><br>
  689. Startet eine Abfrage der Daten.
  690. </li>
  691. </ul><br>
  692. <a name="LuftdatenInfoget"></a>
  693. <b>Get</b>
  694. <ul>
  695. <li>
  696. <code>sensors</code><br>
  697. Listet alle Sensoren auf.
  698. </li>
  699. </ul><br>
  700. <a name="LuftdatenInforeadings"></a>
  701. <b>Readings</b><br>
  702. <ul>
  703. <li>
  704. <code>airQuality</code>
  705. 1 => gut<br>
  706. 2 => mittelmä&suml;ig<br>
  707. 3 => ungesund für empfindliche Menschen<br>
  708. 4 => ungesund<br>
  709. 5 => sehr ungesund<br>
  710. 6 => katastrophal<br>
  711. </li>
  712. <li>
  713. <code>altitude</code><br>
  714. Höhe über NN
  715. </li>
  716. <li>
  717. <code>humidity</code><br>
  718. Relative Luftfeuchtgkeit in %
  719. </li>
  720. <li>
  721. <code>illuminanceFull</code><br>
  722. Helligkeit des vollen Bereich in lux
  723. </li>
  724. <li>
  725. <code>illuminanceIR</code><br>
  726. Helligkeit des IR Bereich in lux
  727. </li>
  728. <li>
  729. <code>illuminanceUV</code><br>
  730. Helligkeit des UV Bereich in lux
  731. </li>
  732. <li>
  733. <code>illuminanceVisible</code><br>
  734. Helligkeit des sichtbaren Bereich in lux
  735. </li>
  736. <li>
  737. <code>latitude</code><br>
  738. Längengrad
  739. </li>
  740. <li>
  741. <code>location</code><br>
  742. Standort als "Postleitzahl Ort"<br>
  743. Nur bei remote Abfrage verf&uuml;gbar.
  744. </li>
  745. <li>
  746. <code>longitude</code><br>
  747. Breitengrad
  748. </li>
  749. <li>
  750. <code>PM1</code><br>
  751. Menge der Partikel mit einem Durchmesser von weniger als 1 µm in µg/m³
  752. </li>
  753. <li>
  754. <code>PM2.5</code><br>
  755. Menge der Partikel mit einem Durchmesser von weniger als 2.5 µm in µg/m³
  756. </li>
  757. <li>
  758. <code>PM10</code><br>
  759. Menge der Partikel mit einem Durchmesser von weniger als 10 µm in µg/m³
  760. </li>
  761. <li>
  762. <code>pressure</code><br>
  763. Luftdruck in hPa
  764. </li>
  765. <li>
  766. <code>pressureNN</code><br>
  767. Luftdruck für Normal Null in hPa<br>
  768. Wird bei aktivem Luftdruck- und Temperatursensor berechnet, sofern sich
  769. der Sensor nicht auf Normal Null befindet.<br>
  770. Hierzu ist die Höhe, kann über Kartendienste oder SmartPhone ermittelt
  771. werden, auf der Konfigurationsseite anzugeben.
  772. </li>
  773. <li>
  774. <code>signal</code><br>
  775. WLAN Signalst&auml;rke in dBm<br>
  776. Nur bei local Abfrage verf&uuml;gbar.
  777. </li>
  778. <li>
  779. <code>temperature</code><br>
  780. Temperatur in °C
  781. </li>
  782. <li>
  783. <code>UVIntensity</code><br>
  784. UV Intensität in W
  785. </li>
  786. <li>
  787. <code>UVRisk</code><br>
  788. UV Risiko von 1 bis 5
  789. </li>
  790. </ul><br>
  791. <a name="LuftdatenInfoattr"></a>
  792. <b>Attribute</b>
  793. <ul>
  794. <li>
  795. <code>disable 1</code><br>
  796. Es werden keine Abfragen mehr gestartet.
  797. </li>
  798. <li>
  799. <a href="#disabledForIntervals">
  800. <u><code>disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM ...</code></u>
  801. </a>
  802. </li>
  803. <li>
  804. <code>interval &lt;seconds&gt;</code><br>
  805. Intervall in Sekunden in dem Abfragen durchgef&uuml;hrt werden.<br>
  806. Der Vorgabe- und Mindestwert betr&auml;gt 300 Sekunden.
  807. </li>
  808. <li>
  809. <code>timeout &lt;seconds&gt;</code><br>
  810. Timeout in Sekunden für die Abfragen.<br>
  811. Der Vorgabe- und Mindestwert betr&auml;gt 5 Sekunden.
  812. </li>
  813. </ul>
  814. </ul>
  815. </div>
  816. =end html_DE
  817. =cut