mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-25 03:44:52 +00:00
922 lines
26 KiB
Perl
922 lines
26 KiB
Perl
# Id ##########################################################################
|
||
# $Id$
|
||
|
||
# copyright ###################################################################
|
||
#
|
||
# 59_LuftdatenInfo.pm
|
||
#
|
||
# Copyright by igami
|
||
#
|
||
# This file is part of FHEM.
|
||
#
|
||
# FHEM is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 2 of the License, or
|
||
# (at your option) any later version.
|
||
#
|
||
# FHEM is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
#
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with FHEM. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
# packages ####################################################################
|
||
package main;
|
||
use Encode;
|
||
use strict;
|
||
use warnings;
|
||
|
||
use HttpUtils;
|
||
|
||
# forward declarations ########################################################
|
||
sub LuftdatenInfo_Initialize($);
|
||
|
||
sub LuftdatenInfo_Define($$);
|
||
sub LuftdatenInfo_Undefine($$);
|
||
sub LuftdatenInfo_Set($@);
|
||
sub LuftdatenInfo_Get($@);
|
||
sub LuftdatenInfo_Attr(@);
|
||
|
||
sub LuftdatenInfo_GetHttpResponse($$);
|
||
sub LuftdatenInfo_ParseHttpResponse($);
|
||
|
||
sub LuftdatenInfo_statusRequest($);
|
||
|
||
# initialize ##################################################################
|
||
sub LuftdatenInfo_Initialize($) {
|
||
my ($hash) = @_;
|
||
my $TYPE = "LuftdatenInfo";
|
||
|
||
$hash->{DefFn} = $TYPE."_Define";
|
||
$hash->{UndefFn} = $TYPE."_Undefine";
|
||
$hash->{SetFn} = $TYPE."_Set";
|
||
$hash->{GetFn} = $TYPE."_Get";
|
||
$hash->{AttrFn} = $TYPE."_Attr";
|
||
|
||
$hash->{AttrList} = ""
|
||
. "disable:1,0 "
|
||
. "disabledForIntervals "
|
||
. "interval "
|
||
. "rawReading:0,1 "
|
||
. "timeout "
|
||
. $readingFnAttributes
|
||
;
|
||
}
|
||
|
||
# regular Fn ##################################################################
|
||
sub LuftdatenInfo_Define($$) {
|
||
my ($hash, $def) = @_;
|
||
my ($SELF, $TYPE, $MODE, $DEF) = split(/[\s]+/, $def, 4);
|
||
my $rc = eval{
|
||
require JSON;
|
||
JSON->import();
|
||
1;
|
||
};
|
||
|
||
return(
|
||
"Error loading JSON. Maybe this module is not installed? "
|
||
. "\nUnder debian (based) system it can be installed using "
|
||
. "\"apt-get install libjson-perl\""
|
||
) unless($rc);
|
||
|
||
delete($hash->{SENSORIDS});
|
||
delete($hash->{ADDRESS});
|
||
delete($hash->{INTERVAL});
|
||
delete($hash->{TIMEOUT});
|
||
delete($hash->{MASTER});
|
||
delete($hash->{SENSORS});
|
||
|
||
my $hadTemperature = 1 if(ReadingsVal($SELF, "temperature", undef));
|
||
|
||
delete($hash->{READINGS});
|
||
|
||
$DEF =~ s/\s+/ /g;
|
||
|
||
if($MODE eq "remote"){
|
||
return("Usage: define <name> $TYPE $MODE <SENSORID1> [<SENSORID2> ...]")
|
||
if($DEF !~ m/^[\s\d]+$/);
|
||
|
||
$hash->{SENSORIDS} = $DEF;
|
||
}
|
||
elsif($MODE eq "local"){
|
||
return("Usage: define <name> $TYPE $MODE <IP>")
|
||
if($DEF =~ m/\s/);
|
||
|
||
$hash->{ADDRESS} = $DEF;
|
||
}
|
||
elsif($MODE eq "slave"){
|
||
return("Usage: define <name> $TYPE $MODE <master-name> <reading regexps>")
|
||
if($DEF !~ m/\s/);
|
||
|
||
($hash->{MASTER}, $hash->{SENSORS}) = split(/[\s]+/, $DEF, 2);
|
||
|
||
delete($defs{$hash->{MASTER}}->{READINGS})
|
||
if(IsDevice($hash->{MASTER}, $TYPE));
|
||
}
|
||
else{
|
||
if(looks_like_number($MODE)){
|
||
$hash->{SENSORIDS} = $MODE;
|
||
$hash->{SENSORIDS} .= " ".($MODE + 1) if($hadTemperature);
|
||
$hash->{SENSORIDS} .= " $DEF" if($DEF && looks_like_number($DEF));
|
||
|
||
$MODE = "remote";
|
||
|
||
$hash->{DEF} = "$MODE $hash->{SENSORIDS}";
|
||
}
|
||
elsif(!$DEF){
|
||
$hash->{ADDRESS} = $MODE;
|
||
|
||
$MODE = "local";
|
||
|
||
$hash->{DEF} = "$MODE $hash->{ADDRESS}";
|
||
}
|
||
else{
|
||
return(
|
||
"Usage: define <name> $TYPE remote <SENSORID1> [<SENSORID2> ...]"
|
||
. " define <name> $TYPE local <IP>"
|
||
. " define <name> $TYPE slave <master-name> <sensor1 sensor2 ...>"
|
||
);
|
||
}
|
||
}
|
||
|
||
$hash->{MODE} = $MODE;
|
||
|
||
unless($MODE eq "slave"){
|
||
my $minInterval = $hash->{MODE} eq "local" ? 30 : 300;
|
||
my $interval = AttrVal($SELF, "interval", $minInterval);
|
||
$interval = $minInterval unless(looks_like_number($interval));
|
||
$interval = $minInterval if($interval < $minInterval);
|
||
my $minTimeout = 5;
|
||
my $timeout = AttrVal($SELF, "timeout", $minTimeout);
|
||
$timeout = $minTimeout unless(looks_like_number($timeout));
|
||
$timeout = $minTimeout if($timeout < $minTimeout);
|
||
|
||
$hash->{INTERVAL} = $interval;
|
||
$hash->{TIMEOUT} = $timeout;
|
||
}
|
||
|
||
readingsSingleUpdate($hash, "state", "active", 1);
|
||
|
||
LuftdatenInfo_statusRequest($hash);
|
||
|
||
return;
|
||
}
|
||
|
||
sub LuftdatenInfo_Undefine($$) {
|
||
my ($hash, $arg) = @_;
|
||
|
||
HttpUtils_Close($hash);
|
||
RemoveInternalTimer($hash);
|
||
|
||
return;
|
||
}
|
||
|
||
sub LuftdatenInfo_Set($@) {
|
||
my ($hash, @a) = @_;
|
||
my $TYPE = $hash->{TYPE};
|
||
|
||
return "\"set $TYPE\" needs at least one argument" if(@a < 2);
|
||
|
||
my $SELF = shift @a;
|
||
my $argument = shift @a;
|
||
my $value = join(" ", @a) if (@a);
|
||
|
||
my %LuftdatenInfo_sets = (
|
||
"statusRequest" => "statusRequest:noArg",
|
||
);
|
||
|
||
return(
|
||
"Unknown argument $argument, choose one of "
|
||
. join(" ", values %LuftdatenInfo_sets)
|
||
) if(!exists($LuftdatenInfo_sets{$argument}));
|
||
|
||
if(!IsDisabled($SELF)){
|
||
if($argument eq "statusRequest"){
|
||
LuftdatenInfo_statusRequest($hash);
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
sub LuftdatenInfo_Get($@) {
|
||
my ($hash, @a) = @_;
|
||
my $TYPE = $hash->{TYPE};
|
||
|
||
return "\"get $TYPE\" needs at least one argument" if(@a < 2);
|
||
|
||
my $SELF = shift @a;
|
||
my $argument = shift @a;
|
||
my $value = join(" ", @a) if (@a);
|
||
|
||
my %LuftdatenInfo_gets = (
|
||
"sensors" => "sensors:noArg",
|
||
);
|
||
|
||
return(
|
||
"Unknown argument $argument, choose one of "
|
||
. join(" ", values %LuftdatenInfo_gets)
|
||
) if(!exists($LuftdatenInfo_gets{$argument}));
|
||
|
||
if($argument eq "sensors"){
|
||
return (join("\n", split(" ", ReadingsVal(
|
||
InternalVal($SELF, "MASTER", $SELF), ".sensors", "No sensors found."
|
||
))));
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
sub LuftdatenInfo_Attr(@) {
|
||
my ($cmd, $SELF, $attribute, $value) = @_;
|
||
my $hash = $defs{$SELF};
|
||
my $TYPE = $hash->{TYPE};
|
||
|
||
Log3($SELF, 5, "$TYPE ($SELF) - entering LuftdatenInfo_Attr");
|
||
|
||
if($attribute eq "disable"){
|
||
if($value && $value == 1){
|
||
readingsSingleUpdate($hash, "state", "disabled", 1);
|
||
}
|
||
elsif($cmd eq "del" || !$value){
|
||
LuftdatenInfo_statusRequest($hash);
|
||
|
||
readingsSingleUpdate($hash, "state", "active", 1);
|
||
}
|
||
}
|
||
elsif($attribute eq "interval"){
|
||
my $minInterval = $hash->{MODE} eq "local" ? 30 : 300;
|
||
my $interval = $cmd eq "set" ? $value : $minInterval;
|
||
$interval = $minInterval unless(looks_like_number($interval));
|
||
$interval = $minInterval if($interval < $minInterval);
|
||
|
||
$hash->{INTERVAL} = $interval;
|
||
}
|
||
elsif($attribute eq "timeout"){
|
||
my $minTimeout = 5;
|
||
my $timeout = $cmd eq "set" ? $value : $minTimeout;
|
||
$timeout = $minTimeout unless(looks_like_number($timeout));
|
||
$timeout = $minTimeout if($timeout < $minTimeout);
|
||
|
||
$hash->{TIMEOUT} = $timeout;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
# HttpUtils Fn ################################################################
|
||
sub LuftdatenInfo_GetHttpResponse($$) {
|
||
my ($hash, $arg) = @_;
|
||
my $SELF = $hash->{NAME};
|
||
my $TYPE = $hash->{TYPE};
|
||
my $MODE = $hash->{MODE};
|
||
my $timeout = $hash->{TIMEOUT};
|
||
|
||
Log3($SELF, 5, "$TYPE ($SELF) - entering LuftdatenInfo_GetHttpResponse");
|
||
|
||
my $param = {
|
||
timeout => $timeout,
|
||
hash => $hash,
|
||
method => "GET",
|
||
header => "Accept: application/json",
|
||
callback => \&LuftdatenInfo_ParseHttpResponse,
|
||
};
|
||
$param->{url} = "https://data.sensor.community/airrohr/v1/sensor/$arg/"
|
||
if($MODE eq "remote");
|
||
$param->{url} = "http://$arg/data.json"
|
||
if($MODE eq "local");
|
||
|
||
HttpUtils_NonblockingGet($param);
|
||
}
|
||
|
||
sub LuftdatenInfo_ParseHttpResponse($) {
|
||
my ($param, $err, $data) = @_;
|
||
my $hash = $param->{hash};
|
||
my $SELF = $hash->{NAME};
|
||
my $TYPE = $hash->{TYPE};
|
||
|
||
Log3($SELF, 5, "$TYPE ($SELF) - entering LuftdatenInfo_ParseHttpResponse");
|
||
|
||
if($err ne ""){
|
||
Log3($SELF, 2, "$TYPE ($SELF) - error while request: $err");
|
||
|
||
readingsSingleUpdate($hash, "state", "error", 1);
|
||
}
|
||
elsif($data eq "[]"){
|
||
Log3($SELF, 2, "$TYPE ($SELF) - error while request: no data returned");
|
||
|
||
readingsSingleUpdate($hash, "state", "error", 1);
|
||
}
|
||
elsif($data ne ""){
|
||
Log3 $SELF, 4, "$TYPE ($SELF) - returned data: $data";
|
||
|
||
$data = encode('UTF-8', $data);
|
||
$data = eval{decode_json($data)};
|
||
|
||
if($@){
|
||
Log3($SELF, 2, "$TYPE ($SELF) - error while request: $@");
|
||
|
||
readingsSingleUpdate($hash, "state", "error", 1);
|
||
|
||
return;
|
||
}
|
||
|
||
my $MODE = $hash->{MODE};
|
||
my $rawReading = AttrVal($SELF, "rawReading", 0);
|
||
|
||
if($param->{url} =~ m/openstreetmap/){
|
||
my $address = $data->{address};
|
||
|
||
readingsSingleUpdate(
|
||
$hash, "location"
|
||
, "$address->{postcode} "
|
||
. ($address->{city} ? $address->{city} : $address->{town})
|
||
, 1
|
||
);
|
||
}
|
||
elsif($MODE eq "remote"){
|
||
my $sensor = @{$data}[-1];
|
||
my $sensor_type = $sensor->{sensor}{sensor_type}{name};
|
||
|
||
Log3 $SELF, 5, "$TYPE ($SELF) - parsing $sensor_type data";
|
||
|
||
my $latitude = $sensor->{location}{latitude};
|
||
my $longitude = $sensor->{location}{longitude};
|
||
|
||
if(
|
||
$latitude ne ReadingsVal($SELF, "latitude", $latitude)
|
||
|| $longitude ne ReadingsVal($SELF, "longitude", $longitude)
|
||
){
|
||
Log3(
|
||
$SELF, 2
|
||
, "$TYPE ($SELF) - "
|
||
. "$sensor->{sensor}{sensor_type}{name} position differs from "
|
||
. "other sensor position"
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
unless(ReadingsVal($SELF, "location", undef)){
|
||
my $param = {
|
||
url => "http://nominatim.openstreetmap.org/reverse?".
|
||
"format=json&lat=$latitude&lon=$longitude",
|
||
timeout => $hash->{TIMEOUT},
|
||
hash => $hash,
|
||
method => "GET",
|
||
header => "Accept: application/json",
|
||
callback => \&LuftdatenInfo_ParseHttpResponse,
|
||
};
|
||
|
||
HttpUtils_NonblockingGet($param);
|
||
}
|
||
|
||
readingsBeginUpdate($hash);
|
||
|
||
foreach (@{$sensor->{sensordatavalues}}){
|
||
$_->{value} =~ m/^(\S+)(\s|$)/;
|
||
$_->{value} = $1;
|
||
my $knownReading = 1;
|
||
|
||
if($_->{value_type} eq "P1"){
|
||
$_->{value_type} = "PM10";
|
||
}
|
||
elsif($_->{value_type} eq "P2"){
|
||
$_->{value_type} = "PM2.5";
|
||
}
|
||
elsif($_->{value_type} =~ /temperature$/){
|
||
$_->{value_type} = "temperature";
|
||
}
|
||
elsif($_->{value_type} =~ /humidity$/){
|
||
$_->{value_type} = "humidity";
|
||
}
|
||
elsif($_->{value_type} =~ /pressure$/){
|
||
$_->{value} = ($_->{value} > 10000 ? $_->{value} / 100 : $_->{value});
|
||
$_->{value_type} = "pressure";
|
||
}
|
||
else{
|
||
$knownReading = 0;
|
||
}
|
||
|
||
readingsBulkUpdate($hash, $_->{value_type}, $_->{value})
|
||
if($knownReading || $rawReading);
|
||
}
|
||
|
||
readingsBulkUpdateIfChanged($hash, "latitude", $latitude);
|
||
readingsBulkUpdateIfChanged($hash, "longitude", $longitude);
|
||
readingsBulkUpdate($hash, "state", "active");
|
||
readingsEndUpdate($hash, 1);
|
||
}
|
||
elsif($MODE eq "local"){
|
||
my @slaves = devspec2array("TYPE=$TYPE:FILTER=MASTER=$SELF");
|
||
my @sensors;
|
||
push(@sensors, $_->{value_type}) foreach (@{$data->{sensordatavalues}});
|
||
|
||
readingsBeginUpdate($defs{$_}) foreach($SELF, @slaves);
|
||
readingsBulkUpdateIfChanged(
|
||
$hash, "softwareVersion", $data->{software_version}
|
||
);
|
||
readingsBulkUpdateIfChanged($hash, ".sensors", join(" ", sort(@sensors)));
|
||
|
||
foreach (@{$data->{sensordatavalues}}){
|
||
my $knownReading = 1;
|
||
$_->{value} =~ m/^(\S+)(\s|$)/;
|
||
$_->{value} = $1;
|
||
|
||
my $device = (devspec2array(
|
||
"MASTER=$SELF:FILTER=SENSORS=(.+ )?$_->{value_type}( .+)?"
|
||
))[0];
|
||
$device = IsDevice($device, $TYPE) ? $defs{$device} : $hash;
|
||
|
||
if($_->{value_type} =~ /P0$/){
|
||
$_->{value_type} = "PM1";
|
||
}
|
||
elsif($_->{value_type} =~ /P1$/){
|
||
$_->{value_type} = "PM10";
|
||
}
|
||
elsif($_->{value_type} =~ /P2$/){
|
||
$_->{value_type} = "PM2.5";
|
||
}
|
||
elsif($_->{value_type} =~ /_air_quality$/){
|
||
$_->{value_type} = "airQuality";
|
||
}
|
||
elsif($_->{value_type} =~ /_height$/){
|
||
$_->{value_type} = "altitude";
|
||
}
|
||
elsif($_->{value_type} =~ /_date$/){
|
||
$_->{value_type} = "date";
|
||
}
|
||
elsif($_->{value_type} =~ /humidity$/){
|
||
$_->{value_type} = "humidity";
|
||
}
|
||
elsif($_->{value_type} =~ /_Full$/){
|
||
$_->{value_type} = "illuminanceFull";
|
||
}
|
||
elsif($_->{value_type} =~ /_UV$/){
|
||
$_->{value_type} = "illuminanceUV";
|
||
}
|
||
elsif($_->{value_type} =~ /_IR$/){
|
||
$_->{value_type} = "illuminanceIR";
|
||
}
|
||
elsif($_->{value_type} =~ /_Visible$/){
|
||
$_->{value_type} = "illuminanceVisible";
|
||
}
|
||
elsif($_->{value_type} =~ /_lat$/){
|
||
$_->{value_type} = "latitude";
|
||
}
|
||
elsif($_->{value_type} =~ /_lon$/){
|
||
$_->{value_type} = "longitude";
|
||
}
|
||
elsif($_->{value_type} =~ /pressure$/){
|
||
$_->{value} = ($_->{value} > 10000 ? $_->{value} / 100 : $_->{value});
|
||
$_->{value_type} = "pressure";
|
||
}
|
||
elsif($_->{value_type} =~ /pressure_nn$/){
|
||
$_->{value} = ($_->{value} > 10000 ? $_->{value} / 100 : $_->{value});
|
||
$_->{value_type} = "pressureNN";
|
||
}
|
||
elsif($_->{value_type} =~ /_risk/){
|
||
$_->{value_type} = "UVRisk";
|
||
}
|
||
elsif($_->{value_type} eq "signal"){
|
||
$_->{value_type} = "signal";
|
||
}
|
||
elsif($_->{value_type} =~ /temperature$/){
|
||
$_->{value_type} = "temperature";
|
||
}
|
||
elsif($_->{value_type} =~ /_watt/){
|
||
$_->{value_type} = "UVIntensity";
|
||
}
|
||
elsif($_->{value_type} =~ /_time$/){
|
||
$_->{value_type} = "time";
|
||
}
|
||
else{
|
||
$knownReading = 0;
|
||
}
|
||
|
||
readingsBulkUpdate($device, $_->{value_type}, $_->{value})
|
||
if($knownReading || $rawReading);
|
||
}
|
||
|
||
foreach($SELF, @slaves){
|
||
readingsBulkUpdate($defs{$_}, "state", "active");
|
||
readingsEndUpdate($defs{$_}, 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
# module Fn ###################################################################
|
||
sub LuftdatenInfo_statusRequest($) {
|
||
my ($hash) = @_;
|
||
my $SELF = $hash->{NAME};
|
||
my $TYPE = $hash->{TYPE};
|
||
my $MODE = $hash->{MODE};
|
||
my $interval = InternalVal($SELF, "INTERVAL", undef);
|
||
|
||
Log3($SELF, 5, "$TYPE ($SELF) - entering LuftdatenInfo_statusRequest");
|
||
|
||
if($interval){
|
||
RemoveInternalTimer($hash);
|
||
InternalTimer(
|
||
gettimeofday() + $interval, "LuftdatenInfo_statusRequest", $hash
|
||
);
|
||
}
|
||
|
||
return if(IsDisabled($SELF));
|
||
|
||
if($MODE eq "remote"){
|
||
LuftdatenInfo_GetHttpResponse($hash, $_)
|
||
foreach(split(/[\s]+/, $hash->{SENSORIDS}));
|
||
}
|
||
elsif($MODE eq "local"){
|
||
LuftdatenInfo_GetHttpResponse($hash, $hash->{ADDRESS});
|
||
}
|
||
elsif($MODE eq "slave"){
|
||
if( IsDevice($hash->{MASTER}, $TYPE)
|
||
&& InternalVal($hash->{MASTER}, "MODE", "") eq "local"
|
||
){
|
||
readingsSingleUpdate($hash, "state", "active", 1);
|
||
|
||
LuftdatenInfo_statusRequest($defs{$hash->{MASTER}});
|
||
}
|
||
else{
|
||
readingsSingleUpdate($hash, "state", "master not defined", 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
# commandref ##################################################################
|
||
=pod
|
||
=encoding utf8
|
||
=item summary provides data from Luftdaten.info
|
||
=item summary_DE stellt Daten von Luftdaten.info bereit
|
||
|
||
=begin html
|
||
|
||
<a id="LuftdatenInfo"></a>
|
||
<h3>LuftdatenInfo</h3>
|
||
<div>
|
||
<ul>
|
||
LuftdatenInfo is the FHEM module to read particulate matter, temperature
|
||
and humidity values from the self-assembly particulate matter sensors
|
||
from <a href="http://Luftdaten.info"><u>Luftdaten.info</u></a>.<br>
|
||
The values can be queried directly from the server or locally.<br>
|
||
There is an
|
||
<a href="https://forum.fhem.de/index.php/topic,73879">
|
||
<u>alternative Firmware</u>
|
||
</a>
|
||
to support more sensors.<br>
|
||
<br>
|
||
<b>Prerequisites</b>
|
||
<ul>
|
||
The Perl module "JSON" is required.<br>
|
||
Under Debian (based) system, this can be installed using
|
||
<code>"apt-get install libjson-perl"</code>.
|
||
</ul>
|
||
<a id="LuftdatenInfo-define"></a>
|
||
<h4>Define</h4>
|
||
<ul>
|
||
<code>
|
||
define <name> LuftdatenInfo remote
|
||
<SENSORID1> [<SENSORID2> ..]<br>
|
||
define <name> LuftdatenInfo local <IP><br>
|
||
define <name> LuftdatenInfo
|
||
slave <master-name> <sensor1 sensor2 ...>
|
||
</code><br>
|
||
To query the data from the server, all affected SensorIDs must be
|
||
specified. The IDs of the SDS01 stands right at
|
||
<a href="http://maps.luftdaten.info/">
|
||
<u>http://maps.luftdaten.info/</u>
|
||
</a>
|
||
. The DHT22 SensorID is usually the SDS011 SensorID + 1. While parsing
|
||
the data the location values from all sensors will be compared and a
|
||
message will be written into the log if they differ.<br>
|
||
For a local query of the data, the IP address or hostname must be
|
||
specified.<br>
|
||
If several similar sensors are used, the duplicate values can be written
|
||
in another device.
|
||
</ul>
|
||
<a id="LuftdatenInfo-set"></a>
|
||
<h4>Set</h4>
|
||
<ul>
|
||
<a id="LuftdatenInfo-set-statusRequest"></a><li>
|
||
<code>statusRequest</code><br>
|
||
Starts a status request.
|
||
</li>
|
||
</ul>
|
||
<a id="LuftdatenInfo-get"></a>
|
||
<h4>Get</h4>
|
||
<ul>
|
||
<a id="LuftdatenInfo-get-senors"></a><li>
|
||
<code>sensors</code><br>
|
||
Lists all senors.
|
||
</li>
|
||
</ul>
|
||
<a name="LuftdatenInfo-readings"></a>
|
||
<h4>Readings</h4><br>
|
||
<ul>
|
||
<li>
|
||
<code>airQuality</code><br>
|
||
1 => good<br>
|
||
2 => moderate<br>
|
||
3 => unhealthy for sensitive groups<br>
|
||
4 => unhealthy<br>
|
||
5 => very unhealthy<br>
|
||
6 => hazardous<br>
|
||
</li>
|
||
<li>
|
||
<code>altitude</code>
|
||
</li>
|
||
<li>
|
||
<code>humidity</code><br>
|
||
Relative humidity in %
|
||
</li>
|
||
<li>
|
||
<code>illuminanceFull</code><br>
|
||
Illuminace of the full spectrum in lux
|
||
</li>
|
||
<li>
|
||
<code>illuminanceIR</code><br>
|
||
Iilluminace of the IR spectrum in lux
|
||
</li>
|
||
<li>
|
||
<code>illuminanceUV</code><br>
|
||
Iilluminace of the UV spectrum in lux
|
||
</li>
|
||
<li>
|
||
<code>illuminanceVisible</code><br>
|
||
Iilluminace of the visible spectrum in lux
|
||
</li>
|
||
<li>
|
||
<code>latitude</code>
|
||
</li>
|
||
<li>
|
||
<code>location</code><br>
|
||
location as "postcode city"<br>
|
||
Only available with remote query.
|
||
</li>
|
||
<li>
|
||
<code>longitude</code>
|
||
</li>
|
||
<li>
|
||
<code>PM1</code><br>
|
||
Quantity of particles with a diameter of less than 1 μm in μg/m³
|
||
</li>
|
||
<li>
|
||
<code>PM2.5</code><br>
|
||
Quantity of particles with a diameter of less than 2.5 μm in μg/m³
|
||
</li>
|
||
<li>
|
||
<code>PM10</code><br>
|
||
Quantity of particles with a diameter of less than 10 μm in μg/m³
|
||
</li>
|
||
<li>
|
||
<code>pressure</code><br>
|
||
Pressure in hPa
|
||
</li>
|
||
<li>
|
||
<code>pressureNN</code><br>
|
||
Pressure at sea level in hPa<br>
|
||
Is calculated if pressure and temperature sensor are active and the
|
||
sensor is not at sea level.<br>
|
||
The height, can be determined by maps or SmartPhone, needs to be
|
||
specified at the configuration page.
|
||
</li>
|
||
<li>
|
||
<code>signal</code><br>
|
||
WLAN signal strength in dBm<br>
|
||
Only available with local query.
|
||
</li>
|
||
<li>
|
||
<code>temperature</code><br>
|
||
Temperature in °C
|
||
</li>
|
||
<li>
|
||
<code>UVIntensity</code><br>
|
||
UV intensity in W
|
||
</li>
|
||
<li>
|
||
<code>UVRisk</code><br>
|
||
UV risk from 1 to 5
|
||
</li>
|
||
</ul>
|
||
<a id="LuftdatenInfo-attr"></a>
|
||
<h4>Attributes</h4>
|
||
<ul>
|
||
<a id="LuftdatenInfo-attr-disable"></a><li>
|
||
<code>disable 1</code><br>
|
||
No queries are started.
|
||
</li>
|
||
<li>
|
||
<a href="#disabledForIntervals">
|
||
<u><code>disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM ...</code></u>
|
||
</a>
|
||
</li>
|
||
<a id="LuftdatenInfo-attr-interval"></a><li>
|
||
<code>interval <seconds></code><br>
|
||
Interval in seconds in which queries are performed.<br>
|
||
The default and minimum value is 300 seconds for remote request and 30 seconds for local requests.
|
||
</li>
|
||
<a id="LuftdatenInfo-attr-timeout"></a><li>
|
||
<code>timeout <seconds></code><br>
|
||
Timeout in seconds for the queries.<br>
|
||
The default and minimum value is 5 seconds.
|
||
</li>
|
||
</ul>
|
||
</ul>
|
||
</div>
|
||
|
||
=end html
|
||
|
||
=begin html_DE
|
||
|
||
<a id="LuftdatenInfo"></a>
|
||
<h3>LuftdatenInfo</h3>
|
||
<div>
|
||
<ul>
|
||
LuftdatenInfo ist das FHEM Modul um Feinstaub-, Temperatur- und
|
||
Luftfeuchtichkeitswerte von den selbstbau Feinstaub Sensoren von
|
||
<a href="http://Luftdaten.info"><u>Luftdaten.info</u></a> auszulesen.<br>
|
||
Dabei können die Werte direkt vom Server oder auch lokal abgefragt
|
||
werden.<br>
|
||
Bei einer lokalen Abfrage werden durch eine
|
||
<a href="https://forum.fhem.de/index.php/topic,73879">
|
||
<u>alternative Firmware</u>
|
||
</a>
|
||
noch weitere Sensoren unterstützt.<br>
|
||
<br>
|
||
<b>Vorraussetzungen</b>
|
||
<ul>
|
||
Das Perl-Modul "JSON" wird benötigt.<br>
|
||
Unter Debian (basierten) System, kann dies mittels
|
||
<code>"apt-get install libjson-perl"</code> installiert werden.
|
||
</ul>
|
||
<br>
|
||
<a id="LuftdatenInfo-define"></a>
|
||
<h4>Define</h4>
|
||
<ul>
|
||
<code>
|
||
define <name> LuftdatenInfo remote
|
||
<SENSORID1> [<SENSORID2> ..]<br>
|
||
define <name> LuftdatenInfo local <IP><br>
|
||
define <name> LuftdatenInfo
|
||
slave <master-name> <sensor1 sensor2 ...>
|
||
</code><br>
|
||
Für eine Abfrage der Daten vom Server müssem alle betroffenenen
|
||
SensorIDs angegeben werden. Die IDs vom SDS01 stehen rechts auf der Seite
|
||
<a href="http://maps.luftdaten.info/">
|
||
<u>http://maps.luftdaten.info/</u>
|
||
</a>
|
||
. Die DHT22 SensorID entspricht normalerweise der SDS011 SensorID + 1.
|
||
Bei einer Abfrage werden die die Positionsangaben verglichen und bei
|
||
einer Abweichung eine Meldung ins Log geschrieben.<br>
|
||
Für eine lokale Abfrage der Daten muss die IP Addresse oder der
|
||
Hostname angegeben werden.<br>
|
||
Werden mehrere ähnliche Sensoren betrieben lassen sich die doppelten
|
||
Werte in einem anderen Gerät geschrieben werden.
|
||
</ul>
|
||
<a id="LuftdatenInfo-set"></a>
|
||
<h4>Set</h4>
|
||
<ul>
|
||
<a id="LuftdatenInfo-set-statusRequest"></a><li>
|
||
<code>statusRequest</code><br>
|
||
Startet eine Abfrage der Daten.
|
||
</li>
|
||
</ul>
|
||
<a id="LuftdatenInfo-get"></a>
|
||
<h4>Get</h4>
|
||
<ul>
|
||
<a id="LuftdatenInfo-get-senors"></a><li>
|
||
<code>sensors</code><br>
|
||
Listet alle Sensoren auf.
|
||
</li>
|
||
</ul><br>
|
||
<a id="LuftdatenInfo-readings"></a>
|
||
<h4>Readings</h4><br>
|
||
<ul>
|
||
<li>
|
||
<code>airQuality</code><br>
|
||
1 => gut<br>
|
||
2 => mittelmä&suml;ig<br>
|
||
3 => ungesund für empfindliche Menschen<br>
|
||
4 => ungesund<br>
|
||
5 => sehr ungesund<br>
|
||
6 => katastrophal<br>
|
||
</li>
|
||
<li>
|
||
<code>altitude</code><br>
|
||
Höhe über NN
|
||
</li>
|
||
<li>
|
||
<code>humidity</code><br>
|
||
Relative Luftfeuchtgkeit in %
|
||
</li>
|
||
<li>
|
||
<code>illuminanceFull</code><br>
|
||
Helligkeit des vollen Bereich in lux
|
||
</li>
|
||
<li>
|
||
<code>illuminanceIR</code><br>
|
||
Helligkeit des IR Bereich in lux
|
||
</li>
|
||
<li>
|
||
<code>illuminanceUV</code><br>
|
||
Helligkeit des UV Bereich in lux
|
||
</li>
|
||
<li>
|
||
<code>illuminanceVisible</code><br>
|
||
Helligkeit des sichtbaren Bereich in lux
|
||
</li>
|
||
<li>
|
||
<code>latitude</code><br>
|
||
Längengrad
|
||
</li>
|
||
<li>
|
||
<code>location</code><br>
|
||
Standort als "Postleitzahl Ort"<br>
|
||
Nur bei remote Abfrage verfügbar.
|
||
</li>
|
||
<li>
|
||
<code>longitude</code><br>
|
||
Breitengrad
|
||
</li>
|
||
<li>
|
||
<code>PM1</code><br>
|
||
Menge der Partikel mit einem Durchmesser von weniger als 1 µm in µg/m³
|
||
</li>
|
||
<li>
|
||
<code>PM2.5</code><br>
|
||
Menge der Partikel mit einem Durchmesser von weniger als 2.5 µm in µg/m³
|
||
</li>
|
||
<li>
|
||
<code>PM10</code><br>
|
||
Menge der Partikel mit einem Durchmesser von weniger als 10 µm in µg/m³
|
||
</li>
|
||
<li>
|
||
<code>pressure</code><br>
|
||
Luftdruck in hPa
|
||
</li>
|
||
<li>
|
||
<code>pressureNN</code><br>
|
||
Luftdruck für Normal Null in hPa<br>
|
||
Wird bei aktivem Luftdruck- und Temperatursensor berechnet, sofern sich
|
||
der Sensor nicht auf Normal Null befindet.<br>
|
||
Hierzu ist die Höhe, kann über Kartendienste oder SmartPhone ermittelt
|
||
werden, auf der Konfigurationsseite anzugeben.
|
||
</li>
|
||
<li>
|
||
<code>signal</code><br>
|
||
WLAN Signalstärke in dBm<br>
|
||
Nur bei local Abfrage verfügbar.
|
||
</li>
|
||
<li>
|
||
<code>temperature</code><br>
|
||
Temperatur in °C
|
||
</li>
|
||
<li>
|
||
<code>UVIntensity</code><br>
|
||
UV Intensität in W
|
||
</li>
|
||
<li>
|
||
<code>UVRisk</code><br>
|
||
UV Risiko von 1 bis 5
|
||
</li>
|
||
</ul>
|
||
<a id="LuftdatenInfo-attr"></a>
|
||
<h4>Attribute</h4>
|
||
<ul>
|
||
<a id="LuftdatenInfo-attr-disable"></a><li>
|
||
<code>disable 1</code><br>
|
||
Es werden keine Abfragen mehr gestartet.
|
||
</li>
|
||
<li>
|
||
<a href="#disabledForIntervals">
|
||
<u><code>disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM ...</code></u>
|
||
</a>
|
||
</li>
|
||
<a id="LuftdatenInfo-attr-interval"></a><li>
|
||
<code>interval <seconds></code><br>
|
||
Intervall in Sekunden in dem Abfragen durchgeführt werden.<br>
|
||
Der Vorgabe- und Mindestwert beträgt 300 Sekunden für remote Abfragen und 30 Sekunden für local Abfragen.
|
||
</li>
|
||
<a id="LuftdatenInfo-attr-timeout"></a><li>
|
||
<code>timeout <seconds></code><br>
|
||
Timeout in Sekunden für die Abfragen.<br>
|
||
Der Vorgabe- und Mindestwert beträgt 5 Sekunden.
|
||
</li>
|
||
</ul>
|
||
</ul>
|
||
</div>
|
||
|
||
=end html_DE
|
||
=cut
|