## no critic (RequireFilenameMatchesPackage, CodeLayout::RequireTidyCode, Documentation::PodSpelling) # # JFTR: # # ATM, it's not possible to comply to this Perl::Critic rule, because # the current state of the FHEM API does require this bogus XX_Name.pm convention # # Disabled spell checkers # # Perl::Tidy sucks 🗿 package FHEM::Buienradar; use strict; use warnings; use HttpUtils; use JSON; use List::Util; use Time::Seconds; use POSIX; use Data::Dumper; use English qw( -no_match_vars ); use Storable; use GPUtils; use experimental qw( switch ); use 5.0139; # we do not want perl be older than from 2007, so > 5.13.9 use Readonly; use FHEM::Meta; ############################################################ Default values Readonly our $VERSION => q{3.0.8}; Readonly our $DEFAULT_INTERVAL => ONE_MINUTE * 2; Readonly our $DEBUGGING_MIN_VERBOSE => 4; Readonly our $DEFAULT_REGION => q{de}; Readonly our $DEFAULT_TEXT_BAR_CHAR => q{=}; Readonly our $DEFAULT_LANGUAGE => q{en}; Readonly our $DEFAULT_LATITUDE => 51.0; Readonly our $DEFAULT_LONGITUDE => 7.0; Readonly our $MAX_TEXT_BAR_LENGTH => 50; ############################################################ Translations Readonly my %TRANSLATIONS => ( 'general' => { 'unknown' => { 'de' => q{unbekannt}, 'en' => q{unknown}, }, 'at' => { 'de' => q{um}, 'en' => q{at}, } }, 'chart_html_bar' => { 'title' => { 'de' => q{Niederschlagsdiagramm}, 'en' => q{Precipitation chart} }, 'data_start' => { 'de' => q{Datenbeginn}, 'en' => q{Data start}, } }, 'chart_gchart' => { 'legend_time_axis' => { 'de' => 'Uhrzeit', 'en' => 'Time', }, 'legend_volume_axis' => { 'de' => 'mm/h', 'en' => 'mm/h', }, 'title' => { 'de' => 'Niederschlagsvorhersage für %s, %s', 'en' => 'Precipitation forecast for %s, %s', }, 'legend' => { 'de' => 'Niederschlag', 'en' => 'Precipitation', }, }, 'handle_attributes' => { 'interval' => { 'de' => 'ist kein valider Wert für den Intervall. Einzig 10, 60, 120, 180, 240 oder 300 sind erlaubt!', 'en' => 'is no valid value for interval. Only 10, 60, 120, 180, 240 or 300 are allowed!', }, 'region' => { 'de' => q{ist kein valider Wert für die Region. Einzig 'de' oder 'nl' werden unterstützt!}, 'en' => q{is no valid value for region. Only 'de' or 'nl' are allowed!}, }, 'default_chart' => { 'de' => q{ist kein valider Wert für den Standard-Graphen. Valide Werte sind none, GChart,TextChart oder HTMLChart}, 'en' => q{is not a valid value for the default chart. Valid values are none, GChart,TextChart or HTMLChart}, }, }, ); ############################################################ Global variables my @errors; my $global_hash; GPUtils::GP_Export( qw( Initialize ) ); ############################################################ FHEM API related # JFTR: # ATM the FHEM API does need an Initialize() subroutine, so this is mandatory # ## no critic (NamingConventions::Capitalization) sub Initialize { my $hash = shift; $hash->{DefFn} = \&FHEM::Buienradar::handle_define; $hash->{UndefFn} = \&FHEM::Buienradar::handle_undefine; $hash->{GetFn} = \&FHEM::Buienradar::handle_get; $hash->{SetFn} = \&FHEM::Buienradar::handle_set; $hash->{AttrFn} = \&FHEM::Buienradar::handle_attributes; $hash->{FW_detailFn} = \&FHEM::Buienradar::handle_fhemweb_details; $hash->{AttrList} = join( q{ }, ( 'disabled:on,off', 'region:nl,de', 'interval:10,60,120,180,240,300', 'default_chart:none,HTMLChart,GChart,TextChart' ) ) . qq[ $::readingFnAttributes ]; $hash->{REGION} = $DEFAULT_REGION; return FHEM::Meta::InitMod( __FILE__, $hash ); } ## use critic sub handle_fhemweb_details { my $fhemweb_name = shift; my $name = shift; my $room = shift; my $page_definition = shift; my $hash = get_device_definition($name); return if ( !defined( $hash->{URL} ) ); # @todo error in the second return: missing target attribute # @todo I18N if ( ::ReadingsVal( $name, 'rainData', 'unknown' ) ne q{unknown} ) { for ( ::AttrVal( $name, q{default_chart}, q{none} ) ) { when (q{HTMLChart}) { return chart_html_bar($name) } when (q{GChart}) { return chart_gchart($name) } when (q{TextChart}) { return q[
] . chart_textbar( $name, q{#} ) . q[] } default { return q{} } } } return; } sub handle_define { my $hash = shift; my $def = shift; $global_hash = $hash; if ( !FHEM::Meta::SetInternals($hash) ) { return $EVAL_ERROR; } my @arguments = split m{ \s+ }xms, $def; my $name = $arguments[0]; my $arguments_length = scalar @arguments; my $latitude; my $longitude; my $language = get_global_language(); Readonly my $ARGUMENT_LENGTH_WITHOUT_LOC => 2; Readonly my $ARGUMENT_LENGHT_WITH_LOC => 4; Readonly my $ARGUMENT_POSITION_LATITUDE => 2; Readonly my $ARGUMENT_POSITION_LONGITUDE => 3; # todo: Refactor to for() if ( $arguments_length == $ARGUMENT_LENGTH_WITHOUT_LOC ) { $latitude = ::AttrVal( 'global', 'latitude', $DEFAULT_LATITUDE ); $longitude = ::AttrVal( 'global', 'longitude', $DEFAULT_LONGITUDE ); } elsif ( $arguments_length == $ARGUMENT_LENGHT_WITH_LOC ) { $latitude = $arguments[$ARGUMENT_POSITION_LATITUDE]; $longitude = $arguments[$ARGUMENT_POSITION_LONGITUDE]; } else { return handle_error( $name, q{Syntax: define
$name]; $as_html .= sprintf q{
%s %s %s
}, $TRANSLATIONS{'chart_html_bar'}{'data_start'}{$language}, $TRANSLATIONS{'general'}{'at'}{$language}, ::ReadingsVal( $name, 'rainDataStart', $TRANSLATIONS{'general'}{'unknown'}{$language} ); my $factor = ( $width ? $width : $HTML_MAX_SIZE_PX ) / ( 1 + ::ReadingsVal( $name, 'rainMax', q{0} ) ); $as_html .= q[Buienradar provides access to precipitation forecasts by the dutch service Buienradar.nl.
define <devicename> Buienradar [latitude] [longitude]
latitude and longitude are facultative and will gathered from global if not set. So the smallest possible definition is:
define <devicename> Buienradar
Set will get you the following:
refresh
- get new data from Buienradar.nl.
Get will get you the following:
rainDuration
- predicted duration of the next precipitation in minutes.startsIn
- next precipitation starts in n minutes. Obsolete!version
- get current version of the Buienradar module.
Buienradar provides several readings:
rainAmount
- amount of predicted precipitation in mm/h for the next 5 minute interval.
rainBegin
- starting time of the next precipitation, unknown if no precipitation is predicted.
raindEnd
- ending time of the next precipitation, unknown if no precipitation is predicted.
rainDataStart
- starting time of gathered data.
rainDataEnd
- ending time of gathered data.
rainLaMetric
- data formatted for a LaMetric device.
rainMax
- maximal amount of precipitation for any 5 minute interval of the gathered data in mm/h.
rainNow
- amount of precipitation for the current 5 minute interval in mm/h.
rainTotal
- total amount of precipition for the gathered data in mm/h.
rainDuration
- duration of the precipitation contained in the forecast
rainDurationTime
- duration of the precipitation contained in the forecast in HH:MM
rainDurationIntervals
- amount of intervals with precipitation
rainDurationPercent
- percentage of interavls with precipitation
disabled on|off
- If disabled
is set to on
, no further requests to Buienradar.nl will be performed. off
reactivates the device, also if the attribute ist simply deleted.
Caution! To be compatible with FHEM::IsDisabled()
, any set or delete with disabled
will also create or delete an additional disable
attribute. Is disable
(without d) set or deleted, disabled
(with d) will not be affected. Just don't use disable
.
region nl|de
- Allowed values are nl
(default value) and de
. In some cases, especially in the south and east of Germany, de
returns values at all.
interval 10|60|120|180|240|300
- Data update every n seconds. Attention! 10 seconds is a very aggressive value and should be chosen carefully, e.g. when troubleshooting. The default value is 120 seconds.
Buienradar offers besides the usual view as device also the possibility to visualize the data as charts in different formats. * An HTML version that is displayed in the detail view by default and can be viewed with
{ FHEM::Buienradar::HTML("buienradar device name")}
can be retrieved.
A chart generated by Google Charts in PNG format, which can be viewed with
{ FHEM::Buienradar::GChart("buienradar device name")}
can be retrieved. Caution! Please note that data is transferred to Google for this purpose!
FTUI is supported by the LogProxy format:
{ FHEM::Buienradar::LogProxy("buienradar device name")}
A plain text representation can be displayed with
{ FHEM::Buienradar::TextChart(q{buienradar device name}, q{bar chart character})}
The bar chart character is optional and defaults to =
.
Every line represents a record of the whole set, i.e. if called by
{ FHEM::Buienradar::TextChart(q{buienradar_test_device}, q{#})}
the result will look similar to
22:25 | 0.060 | #
22:30 | 0.370 | ####
22:35 | 0.650 | #######
For every 0.1 mm/h precipitation a #
is displayed, but the output is capped to 50 units. If more than 50 units would be display, the bar is truncated and appended with a >
.
23:00 | 11.800 | ##################################################>
Das Buienradar-Modul bindet die Niederschlagsvorhersagedaten der freien API von Buienradar.nl an.
define <devicename> Buienradar [latitude] [longitude]
Die Werte für latitude und longitude sind optional und werden, wenn nicht explizit angegeben, von global bezogen. Die minimalste Definition lautet demnach:
define <devicename> Buienradar
Folgende Set-Aufrufe werden unterstützt:
refresh
- Neue Daten abfragen.
Aktuell lassen sich folgende Daten mit einem Get-Aufruf beziehen:
rainDuration
- Die voraussichtliche Dauer des nächsten Niederschlags in Minuten.startsIn
- Der nächste Niederschlag beginnt in n Minuten. Obsolet!version
- Aktuelle Version abfragen.
Aktuell liefert Buienradar folgende Readings:
rainAmount
- Menge des gemeldeten Niederschlags in mm/h für den nächsten 5-Minuten-Intervall.
rainBegin
- Beginn des nächsten Niederschlag. Wenn kein Niederschlag gemeldet ist, unknown.
raindEnd
- Ende des nächsten Niederschlag. Wenn kein Niederschlag gemeldet ist, unknown.
rainDataStart
- Zeitlicher Beginn der gelieferten Niederschlagsdaten.
rainDataEnd
- Zeitliches Ende der gelieferten Niederschlagsdaten.
rainLaMetric
- Aufbereitete Daten für LaMetric-Devices.
rainMax
- Die maximale Niederschlagsmenge in mm/h für ein 5 Min. Intervall auf Basis der vorliegenden Daten.
rainNow
- Die vorhergesagte Niederschlagsmenge für das aktuelle 5 Min. Intervall in mm/h.
rainTotal
- Die gesamte vorhergesagte Niederschlagsmenge in mm/h
rainDuration
- Dauer der gemeldeten Niederschläge in Minuten
rainDurationTime
- Dauer der gemeldeten Niederschläge in HH:MM
rainDurationIntervals
- Anzahl der Intervalle mit gemeldeten Niederschlägen
rainDurationPercent
- Prozentualer Anteil der Intervalle mit Niederschlägen
disabled on|off
- Wenn disabled
auf on
gesetzt wird, wird das Device keine weiteren Anfragen mehr an Buienradar.nl durchführen. off
reaktiviert das Modul, ebenso wenn das Attribut gelöscht wird.
Achtung! Aus Kompatibilitätsgründen zu FHEM::IsDisabled()
wird bei einem Aufruf von disabled
auch disable
als weiteres Attribut gesetzt. Wird disable
gesetzt oder gelöscht, beeinflusst dies disabled
nicht! disable
sollte nicht verwendet werden!
region nl|de
- Erlaubte Werte sind nl
(Standardwert) und de
. In einigen Fällen, insbesondere im Süden und Osten Deutschlands, liefert de
überhaupt Werte.
interval 10|60|120|180|240|300
- Aktualisierung der Daten alle n Sekunden. Achtung! 10 Sekunden ist ein sehr aggressiver Wert und sollte mit Bedacht gewählt werden, z.B. bei der Fehlersuche. Standardwert sind 120 Sekunden.
Buienradar bietet neben der üblichen Ansicht als Device auch die Möglichkeit, die Daten als Charts in verschiedenen Formaten zu visualisieren. * Eine HTML-Version die in der Detailansicht standardmäßig eingeblendet wird und mit
{ FHEM::Buienradar::HTML("name des buienradar device")}
abgerufen werden.
Ein von Google Charts generiertes Diagramm im PNG-Format, welcher mit
{ FHEM::Buienradar::GChart("name des buienradar device")}
abgerufen werden kann. Achtung! Dazu werden Daten an Google übertragen!
Für FTUI werden die Daten im LogProxy-Format bereitgestellt:
{ FHEM::Buienradar::LogProxy("name des buienradar device")}
Für eine reine Text-Ausgabe der Daten als Graph, kann
{ FHEM::Buienradar::TextChart(q{name des buienradar device}, q{verwendetes zeichen})}
verwendet werden. Das verwendete zeichen
ist optional und mit =
vorbelegt. Ausgegeben wird beispielsweise für den Aufruf
{ FHEM::Buienradar::TextChart(q{buienradar_test}, q{#}) }
für jeden Datensatz eine Zeile im Muster
22:25 | 0.060 | #
22:30 | 0.370 | ###
22:35 | 0.650 | #######
wobei für jede 0.1 mm/h Niederschlag das #
verwendet wird, maximal jedoch 50 Einheiten. Mehr werden mit einem >
abgekürzt.
23:00 | 11.800 | ##################################################>