| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868 |
- # $Id: 98_Verkehrsinfo.pm 13112 2017-01-16 19:18:49Z martins $
- ############################################################################
- #
- # 98_Verkehrsinfo.pm
- #
- # Copyright (C) 2016 by Martin Schubert
- # e-mail: martin@dermschub.de
- #
- # This program 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.
- #
- # This program 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/>.
- #
- ############################################################################
- ############################################################################
- #
- # Changelog:
- # 2017-01-16, v2.2
- # Feature: Quelle http://www.radiosaw.de/verkehrsmeldungen added
- #
- # 2016-12-26, v2.1
- # Bugfix: update state with readings update
- # CHANGE: remove requirement perl-module json
- # CHANGE: update commandref with link to readingFn-Attributen
- #
- # Changelog:
- # 2016-12-13, v2.0RC1
- # Bugfix: Bugfix Hessenschau Message
- #
- # 2016-11-17, v2.0
- # CHANGE: Module change to HttpNonBlocking
- # CHANGE: remove requirement perl-module json
- # CHANGE: update commandref
- #
- # 2016-11-10, v1.9
- # Bugfix: hessenschau.de, messages end with a point
- #
- # Changelog:
- # 2016-10-24, v1.8
- # Bugfix: hessenschau.de, messages end with a point
- #
- # 2016-10-23, v1.7RC2
- # CHANGE: Module change to NonBlocking
- # CHANGE: Code optimization
- # CHANGE: update commandref
- # Bugfix: hessenschau.de, Cant call method "as_trimmed_text" fixed
- #
- # 2016-08-17, v1.7RC1
- # Feature: New Reading for humanly readable message
- # Feature: New Attribut for Messageformat
- # Feature: New Attribut for Sorting added
- # CHANGE: State Value
- # CHANGE: LWP::Simple replace to HttpUtils
- # CHANGE: check if HTML::TreeBuilder::XPath is installed
- # CHANGE: update commandref
- #
- # 2016-08-17, v1.6
- # Bugfix: verkehrsinfo.de, Display of the zone has been corrected
- # Bugfix: Characterset has been corrected
- #
- # 2016-08-16, v1.5
- # Bugfix: verkehrsinfo.de, URL changed to the new address
- #
- # 2016-08-04, v1.4
- # Bugfix: hessenschau.de, Message Sperrung added
- #
- # 2016-07-29, v1.3
- # Bugfix: hessenschau.de, Message Warnung added
- #
- # 2016-07-11, v1.2
- # Feature: Quelle http://hessenschau.de/verkehr/index.html added
- #
- # 2016-07-03, v1.1
- # Bugfix: Check if a valid URL was passed
- # Feature: Include Filterattribut added, regex available, Pipe as delimiter
- # Feature: Exclude Filterattribut added, regex available, Pipe as delimiter
- #
- # 2016-06-29, v1.0
- # Initzial Version
- #
- ############################################################################
- package main;
- use strict;
- use warnings;
- #use Encode qw(decode encode);
- use HttpUtils;
- my $missingModul = "";
- eval "use HTML::TreeBuilder::XPath;1" or $missingModul .= "HTML::TreeBuilder::XPath ";
- my %Verkehrsinfo_gets = (
- "update" => "noArg",
- "info" => "noArg"
- );
- #my $encode = 'UTF-8';
- sub Verkehrsinfo_Initialize($) {
- my ($hash) = @_;
- $hash->{DefFn} = 'Verkehrsinfo_Define';
- $hash->{UndefFn} = 'Verkehrsinfo_Undef';
- $hash->{SetFn} = 'Verkehrsinfo_Set';
- $hash->{GetFn} = 'Verkehrsinfo_Get';
- $hash->{AttrFn} = 'Verkehrsinfo_Attr';
- $hash->{ReadFn} = 'Verkehrsinfo_Read';
- $hash->{AttrList} =
- "filter_exclude filter_include orderby "
- . "msg_format:road,head,both "
- . $readingFnAttributes;
- }
- sub Verkehrsinfo_Define($$) {
- my ($hash, $def) = @_;
- my @param = split('[ \t]+', $def);
-
- if(int(@param) < 4) {
- return "too few parameters: define <name> Verkehrsinfo <url> <interval>";
- }
-
- $hash->{name} = $param[0];
- $hash->{url} = $param[2];
- $hash->{Interval} = $param[3];
-
- # check Module is installed
- if ( $missingModul ) {
- my $returnmsg = "Cannot define $hash->{name} device. Perl modul $missingModul is missing.";
- Log3 $hash->{name}, 1, $returnmsg;
- return $returnmsg;
- }
-
- # check if the url is ok
- if ($hash->{url} !~ /verkehrsinfo\.de\/httpsmobil\/index\.php/ &&
- $hash->{url} !~ /hessenschau\.de\/verkehr\/index\.html/ &&
- $hash->{url} !~ /radiosaw/){
- my $returnmsg = "Diese URL wird nicht unterstützt. Bitte schauen Sie in die Modulbeschreibung.";
- Log3 $hash->{name}, 1, $returnmsg;
- return $returnmsg;
- }
-
- # get Zone name
- if ($hash->{url} =~ /verkehrsinfo.de/i){
- my $param = {
- url => "https://www.verkehrsinfo.de/httpsmobil/index.php?c=1&lat=&lon=",
- timeout => 5,
- hash => $hash,
- callback => \&Verkehrsinfo_HttpNbDefineZone
- };
- HttpUtils_NonblockingGet($param);
- }
- elsif ($hash->{url} =~ /hessenschau.de/i) {
- readingsSingleUpdate( $hash, "zone", "Hessen", 1 );
- }
- elsif ($hash->{url} =~ /radiosaw/i) {
- readingsSingleUpdate( $hash, "zone", "SAW", 1 );
- $hash->{url} = 'http://www.radiosaw.de/verkehrsmeldungen';
- }
-
- InternalTimer(gettimeofday()+4, "Verkehrsinfo_GetUpdate", $hash, 0);
-
- readingsSingleUpdate($hash, "state", 'initialized',1 );
-
- return undef;
- }
- # recieve zone from www http nonblocking
- sub Verkehrsinfo_HttpNbDefineZone($) {
- my ($param, $err, $content) = @_;
- my $hash = $param->{hash};
- my $name = $hash->{NAME};
-
- Log3 $hash, 4, "Verkehrsinfo: ($name) Verkehrsinfo_HttpNbDefineZone start";
-
- if($err ne "") {
- Log3 $name, 3, "error while requesting ".$param->{url}." - $err";
- readingsSingleUpdate($hash, "state", 'ERROR Update Zone ' . FmtDateTime(time()), 1);
- }
-
- elsif($content ne "")
- {
-
- my $tree = HTML::TreeBuilder->new;
- my @arrzone = split(/[=&]/, $hash->{url});
- my $zone = '';
- if ($arrzone[2] eq "bl")
- {
-
- # prepare HTML Code
- $content =~ s/getLocation\(\)\;//g;
- #####################
- $tree->parse($content); #<-- Testen !
- #$tree->parse(encode($encode, $content));
- $zone = $tree->findnodes('//button[contains(@onclick, "'.$arrzone[3].'")]')->[0]->as_trimmed_text;
- $zone =~ s/\s\[.*\]//;
- }
- else {
- $zone = $arrzone[3];
- }
- readingsSingleUpdate( $hash, "zone", $zone, 1 );
- }
- Log3 $hash, 4, "Verkehrsinfo: ($name) Verkehrsinfo_HttpNbDefineZone done";
- }
- sub Verkehrsinfo_Undef($$) {
- my ($hash, $arg) = @_;
- RemoveInternalTimer($hash);
- return undef;
- }
- sub Verkehrsinfo_Get($@) {
- my ($hash, @param) = @_;
-
- return '"get Verkehrsinfo" needs at least one argument' if (int(@param) < 2);
-
- my $name = shift @param;
- my $opt = shift @param;
- if(!$Verkehrsinfo_gets{$opt}) {
- return "Unknown argument $opt, choose one of info:noArg";
- }
-
- if ($opt eq "info"){
- return Verkehrsinfo_GetData($hash->{NAME});
- }
-
- }
- sub Verkehrsinfo_Set($@) {
- my ($hash, @param) = @_;
-
- return '"set Verkehrsinfo" needs at least one argument' if (int(@param) < 2);
-
- my $name = shift @param;
- my $opt = shift @param;
- my $value = join("", @param);
-
-
- if(!defined($Verkehrsinfo_gets{$opt})) {
- return "Unknown argument $opt, choose one of update:noArg";
- }
- if ($opt eq "update"){
- Verkehrsinfo_GetUpdate($hash);
- #return "Update is runing";
- return undef;
- }
- }
- sub Verkehrsinfo_Attr(@) {
- my ($cmd,$name,$attr_name,$attr_value) = @_;
- if($cmd eq "set") {
- if($attr_name eq "filter_exclude" || $attr_name eq "filter_include") {
- eval { qr/$attr_value/ };
- if ($@) {
- my $err = "Verkehrsinfo: Ungültiger Filter in attr $name $attr_name $attr_value: $@";
- Log3 $name, 3, $err;
- return $err;
- }
- }
- elsif($attr_name eq "msg_format" && $attr_value !~ "road|head|both") {
- my $err = "Verkehrsinfo: Ungültiges Message Format in attr $name $attr_name $attr_value: $@";
- Log3 $name, 3, $err;
- return $err;
- }
- elsif($attr_name eq "msg_format" && InternalVal($name, 'url', '') =~ 'hessenschau.de/verkehr') {
- my $err = "Verkehrsinfo: Message Format ist für " . InternalVal($name, 'url', '') . " nicht Verfügbar";
- Log3 $name, 3, $err;
- return $err;
- }
- }
- return undef;
- }
- # recieve data from www http nonblocking
- sub Verkehrsinfo_HttpNbUpdateData ($) {
- my ($param, $err, $content) = @_;
- my $hash = $param->{hash};
- my $name = $hash->{NAME};
-
- my $headline;
- my @toc;
- my @toc2;
- my $message = '';
- my $message_zone = '';
- my $message_head = '';
- my $dataarray;
-
- Log3 $hash, 4, "Verkehrsinfo: ($name) Verkehrsinfo_HttpNbUpdateData start";
-
- if($err ne "") {
- Log3 $name, 3, "error while requesting ".$param->{url}." - $err";
- readingsSingleUpdate($hash, "state", 'ERROR Update Readings ' . FmtDateTime(time()), 1);
- }
-
- elsif($content ne "")
- {
- # read attribut filter
- my $filterexclude = AttrVal($name,"filter_exclude","");
- my $filterinclude = AttrVal($name,"filter_include",".*");
- my $orderby = AttrVal($name,"orderby","");
- my $tree = HTML::TreeBuilder->new;
- my $i = 1;
-
- ##################
- # verkehrsinfo.de
- ##################
- if ($hash->{url} =~ /verkehrsinfo.de/i){
-
- # prepare HTML Code
- $content =~ s/getLocation\(\)\;//g;
-
- $tree->parse($content);
- @toc = $tree->findnodes('//div[contains(@class, "panel-body")]/ul/li');
- shift(@toc); # delete advertising
-
- for my $el ( Verkehrsinfo_hf_orderby($orderby, @toc) ) {
- if (grep(!/$filterexclude/i, $el->as_trimmed_text) && grep(/$filterinclude/i, $el->as_trimmed_text)){
- if (exists $el->findnodes('div/div')->[0] && exists $el->findnodes('div')->[1]->findnodes('span')->[0] && exists $el->findnodes('div')->[1]->findnodes('span')->[1]){
- $dataarray->{"e_".$i."_road"} = $el->findnodes('div/div')->[0]->as_trimmed_text;
- $dataarray->{"e_".$i."_head"} = $el->findnodes('div')->[1]->findnodes('span')->[0]->as_trimmed_text;
- $dataarray->{"e_".$i."_msg"} = $el->findnodes('div')->[1]->findnodes('span')->[1]->as_trimmed_text;
- $message .= (AttrVal($name,"msg_format","") =~ "road|both") ? $el->findnodes('div/div')->[0]->as_trimmed_text .', ' : '';
- $message .= (AttrVal($name,"msg_format","") =~ "head|both") ? $el->findnodes('div')->[1]->findnodes('span')->[1]->as_trimmed_text .', ' : '';
- $message .= $el->findnodes('div')->[1]->findnodes('span')->[1]->as_trimmed_text .'. ' ;
- $i++;
- }
- else{
- Log3 $hash, 3, "Verkehrsinfo: ($name) Verkehrsinfo_HttpNbUpdateData DataNodeElements not found";
- }
- }
- }
- $message =~ s/ \(.*?\)//g; # Remove number of exits
- $message_zone = (ReadingsVal($name, 'zone', '') =~ /[0-9]/i) ? ' für die ' : ' für ';
- $message_zone .= ReadingsVal($name, 'zone', '');
- }
-
- ##################
- # hessenschau.de
- ##################
- elsif ($hash->{url} =~ /hessenschau.de/i) {
-
- # prepare HTML Code
- $content =~ s/<\/title>/<\/span>/g;
- $content =~ s/<title id="iconTitle--[0-9]+">/<span>/g;
- $content =~ s/<text/<p/g;
- $content =~ s/<\/text>/<\/p>/g;
- $content =~ s/<use.*traffic-arrow.*>.*<\/use>/Richtung/g;
-
- #$tree->parse_content(encode($encode, $content));
- $tree->parse_content($content);
-
- $message_zone = ' für Hessen';
-
- @toc = $tree->findnodes('//li[contains(@class, "trafficInfo__item")]');
-
- for my $el ( Verkehrsinfo_hf_orderby($orderby, @toc) ) {
- if (grep(!/$filterexclude/i, $el->as_trimmed_text) && grep(/$filterinclude/i, $el->as_trimmed_text)){
- if (exists $el->findnodes('div/p')->[0] && exists $el->findnodes('div/span')->[0]){
- # check message if it's road or information
- if ($el->findnodes('div/p')->[0]->as_trimmed_text =~ /^[0-9]/){
- $dataarray->{"e_".$i."_road"} = substr($el->findnodes('div/span')->[0]->as_trimmed_text, 0 ,1).
- $el->findnodes('div/p')->[0]->as_trimmed_text;
- $dataarray->{"e_".$i."_head"} = (exists $el->findnodes('div/strong')->[0]) ? $el->findnodes('div/strong')->[0]->as_trimmed_text : '';
- $dataarray->{"e_".$i."_msg"} = (exists $el->findnodes('div/p')->[1]) ? $el->findnodes('div/p')->[1]->as_trimmed_text : '';
- $message .= (exists $el->findnodes('div/p')->[1]) ? $el->findnodes('div/p')->[1]->as_trimmed_text : '';
- $message .= ($el->findnodes('div/p')->[1]->as_trimmed_text =~ /\.$/) ? ' ' : '. ';
- }
- else {
- $dataarray->{"e_".$i."_road"} = '-';
- $dataarray->{"e_".$i."_head"} = $el->findnodes('div/span')->[0]->as_trimmed_text;
- $dataarray->{"e_".$i."_msg"} = $el->findnodes('div/p')->[0]->as_trimmed_text;
- $message .= (AttrVal($name,"msg_format","") =~ "head|both") ? $el->findnodes('div/span')->[0]->as_trimmed_text .', ' : '';
- $message .= $el->findnodes('div/p')->[0]->as_trimmed_text;
- $message .= ($el->findnodes('div/p')->[0]->as_trimmed_text =~ /\.$/) ? ' ' : '. ' ;
- }
- $i++;
- }
- else{
- Log3 $hash, 3, "Verkehrsinfo: ($name) Verkehrsinfo_HttpNbUpdateData DataNodeElements not found";
- }
- }
- }
- }
-
-
- ##################
- # radiosaw.de
- ##################
- elsif ($hash->{url} =~ /radiosaw.de/i) {
-
- $message_zone = ' für SAW';
-
- # part one meldungen
- $tree->parse_content($content);
- @toc = $tree->findnodes('//div[contains(@id, "block-system-main")]/div/div[2]/div[2]/div/div/div');
- # part two baustellen
- @toc2 = $tree->findnodes('//div[contains(@id, "block-system-main")]/div/div[3]/div[1]/div/div[1]/div/div[2]/div/div/div/ul/li');
- push (@toc, @toc2);
- for my $el ( Verkehrsinfo_hf_orderby($orderby, @toc) ) {
- if (grep(!/$filterexclude/i, $el->as_trimmed_text) && grep(/$filterinclude/i, $el->as_trimmed_text)){
-
- if ($el->as_trimmed_text =~ /^Aktuelle Baustelle/){
- my $tmp = $el->as_HTML;
- $tmp =~ s/<br \/>-+<br \/>/\|/g;
- $tmp =~ s/<br \/>/###/g;
-
- my $subtree = HTML::TreeBuilder->new;
- $subtree->parse_content($tmp);
- my @tmp2 = split(/\|/, $subtree->as_trimmed_text);
- shift @tmp2;
-
- for my $sel ( @tmp2 ){
-
- $dataarray->{"e_".$i."_road"} = ((split(/\s/, $sel))[0] =~ /^.[0-9]+/) ? (split(/\s/, $sel))[0] : '-';
- $dataarray->{"e_".$i."_head"} = (split(/\###/, $sel))[0];
-
- $dataarray->{"e_".$i."_msg"} = $sel;
- $dataarray->{"e_".$i."_msg"} =~ s/^.*?###//;
- $dataarray->{"e_".$i."_msg"} =~ s/###/ /g;
-
- $message .= (AttrVal($name,"msg_format","") =~ "road|both") ? $dataarray->{"e_".$i."_road"} .', ' : '';
- $message .= (AttrVal($name,"msg_format","") =~ "head|both") ? $dataarray->{"e_".$i."_head"} .', ' : '';
- $message .= $dataarray->{"e_".$i."_msg"};
- $message .= ($dataarray->{"e_".$i."_msg"} =~ /\.$/) ? ' ' : '. ' ;
-
- $i++;
- }
- $i--;
- }
- elsif ($el->findnodes('../li')->[0]){
- if (exists $el->findnodes('strong')->[0]){
- $dataarray->{"e_".$i."_road"} = ((split(/\s/, $el->findnodes('strong')->[0]->as_trimmed_text .' -'))[1] =~ /^[0-9]+/) ? (split(/\s/, $el->findnodes('strong')->[0]->as_trimmed_text))[0] . ' ' . (split(/\s/, $el->findnodes('strong')->[0]->as_trimmed_text))[1] : '-';
- $dataarray->{"e_".$i."_head"} = $el->findnodes('strong')->[0]->as_trimmed_text;
- $dataarray->{"e_".$i."_msg"} = $el->as_trimmed_text;
- $dataarray->{"e_".$i."_msg"} =~ s/\(/_ko_/g;
- $dataarray->{"e_".$i."_msg"} =~ s/\)/_kc_/g;
- my $tmp = $el->findnodes('strong')->[0]->as_trimmed_text;
- $tmp =~ s/\(/_ko_/g;
- $tmp =~ s/\)/_kc_/g;
- $dataarray->{"e_".$i."_msg"} =~ s/$tmp//;
- }
- else{
- $dataarray->{"e_".$i."_road"} = '-';
- $dataarray->{"e_".$i."_head"} = '-';
- $dataarray->{"e_".$i."_msg"} = $el->as_trimmed_text;
- }
- $dataarray->{"e_".$i."_msg"} =~ s/_ko_/\(/g;
- $dataarray->{"e_".$i."_msg"} =~ s/_kc_/\)/g;
-
- $message .= (AttrVal($name,"msg_format","") =~ "road|both") ? $dataarray->{"e_".$i."_road"} .', ' : '';
- $message .= (AttrVal($name,"msg_format","") =~ "head|both") ? $dataarray->{"e_".$i."_head"} .', ' : '';
- $message .= $dataarray->{"e_".$i."_msg"};
- $message .= ($dataarray->{"e_".$i."_msg"} =~ /\.$/) ? ' ' : '. ' ;
-
- $i++;
- }
- else {
- my $tmp = $el->as_HTML;
- $tmp =~ s/<br \/>/###/g;
-
- my $subtree = HTML::TreeBuilder->new;
- $subtree->parse_content($tmp);
- my $anz = scalar(split(/\###/, $subtree->as_trimmed_text));
- $dataarray->{"e_".$i."_road"} = ((split(/\s/, $subtree->as_trimmed_text))[0] =~ /^.[0-9]+/) ? (split(/\s/, $subtree->as_trimmed_text))[0] : '-';
- $dataarray->{"e_".$i."_head"} = ($anz == 2) ? (split(/\###/, $subtree->as_trimmed_text))[0] : '-';
- $dataarray->{"e_".$i."_msg"} = ($anz == 2) ? (split(/\###/, $subtree->as_trimmed_text))[1] : $subtree->as_trimmed_text;
-
- $message .= (AttrVal($name,"msg_format","") =~ "road|both") ? $dataarray->{"e_".$i."_road"} .', ' : '';
- $message .= (AttrVal($name,"msg_format","") =~ "head|both") ? $dataarray->{"e_".$i."_head"} .', ' : '';
- $message .= $dataarray->{"e_".$i."_msg"};
- $message .= ($dataarray->{"e_".$i."_msg"} =~ /\.$/) ? ' ' : '. ' ;
-
- $i++;
- }
- # else{
- # Log3 $hash, 3, "Verkehrsinfo: ($name) Verkehrsinfo_HttpNbUpdateData DataNodeElements not found";
- # }
- }
- }
- }
-
-
- if ($i - 1 == 0){
- $message_head = "Es liegen um " . strftime('%H:%M', localtime) . $message_zone . " keine Staumeldungen vor.";
- }
- elsif ($i - 1 == 1){
- $message_head = "Es liegt um " . strftime('%H:%M', localtime) . $message_zone . " eine Staumeldung vor:\n";
- }
- else{
- my $anz_msg = $i - 1;
- $message_head = "Es liegen um " . strftime('%H:%M', localtime) . $message_zone . ', ' . $anz_msg ." Staumeldungen vor:\n";
- }
-
- $dataarray->{'message'} = $message_head . ' ' . $message;
- $dataarray->{'message'} =~ s/\<pre\>//;
- $dataarray->{'message'} =~ s/\<\/pre\>//;
- $dataarray->{'count'} = $i - 1;
-
-
- # delete old readings
- Log3 $hash, 4, "Verkehrsinfo: ($name) Delete old Readings";
- CommandDeleteReading(undef, "$hash->{NAME} e_.*_.*");
-
- Log3 $hash, 4, "Verkehrsinfo: ($name) Create new Readings";
-
- # update readings
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "date_time", FmtDateTime(time()) );
-
- foreach my $readingName (keys %{$dataarray}){
- Log3 $hash, 4, "Verkehrsinfo: ($name) ReadingsUpdate: $readingName - ".$dataarray->{$readingName};
- readingsBulkUpdate($hash,$readingName,$dataarray->{$readingName});
- }
- readingsBulkUpdate($hash, "state", 'update ' . FmtDateTime(time()));
- readingsEndUpdate($hash, 1);
-
- }
- Log3 $hash, 4, "Verkehrsinfo: ($name) Verkehrsinfo_HttpNbUpdateData done";
- }
- sub Verkehrsinfo_GetUpdate($) {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- if ( $hash->{Interval}) {
- RemoveInternalTimer ($hash);
- }
- InternalTimer(gettimeofday()+$hash->{Interval}, "Verkehrsinfo_GetUpdate", $hash, 1);
- Log3 $hash, 4, "Verkehrsinfo: ($name) internal interval timer set to call GetUpdate again in " . int($hash->{Interval}). " seconds";
-
- my $param = {
- url => $hash->{url},
- timeout => 5,
- hash => $hash,
- callback => \&Verkehrsinfo_HttpNbUpdateData
- };
- HttpUtils_NonblockingGet($param);
- }
- # give back all traffic information as formated text
- sub Verkehrsinfo_GetData($){
- my ($device) = @_;
- my $hash = $defs{$device};
- if (!defined $device){
- Log3 $hash, 1, "Verkehrsinfo: ($device) Device not found";
- return "Device not found";
- }
-
- my $msg = '';
- my $i = 1;
-
- $msg = ReadingsVal($device, 'count', '') . " Meldungen für ". ReadingsVal($device, 'zone', '') .":\n\n";
-
- for ($i=1; $i <= ReadingsVal($device, 'count', ''); $i++){
- $msg = $msg . ReadingsVal($device, 'e_'.$i.'_road', '') . " - ";
- $msg = $msg . ReadingsVal($device, 'e_'.$i.'_head', '') . "\n";
- $msg = $msg . ReadingsVal($device, 'e_'.$i.'_msg', '') . "\n\n";
- }
-
- return $msg;
- }
- ##################
- # helper function
- ##################
- # sort messages
- sub Verkehrsinfo_hf_orderby ($@) {
- my ($order, @inp) = @_;
- my @res;
- my %diff;
- for my $oel (split(/\|/, $order)) {
- for my $ael ( @inp ) {
- push(@res, $ael) if (grep (/$oel/i, $ael->as_trimmed_text));
- }
- }
- @diff{ @inp } = @inp;
- delete @diff{ @res };
-
- return (@res, values %diff);
- }
- 1;
- =pod
- =item device
- =item summary read trafficinformation from various sources
- =item summary_DE Verkehrsinformationen von verschiedenen Quellen auslesen.
- =begin html
- <a name="Verkehrsinfo"></a>
- <h3>Verkehrsinfo</h3>
- <ul>
- <i>Verkehrsinfo</i> can read trafficinformation from various source.
- <br><br>
- <ul>
- <li>Verkehrsinfo.de</li>
- For receiving the traffic informationen, following website https://www.verkehrsinfo.de/httpsmobil will be called on.<br>
- There you can select streets or federal states. Afterwards the URL will be committed as a parameter.
- <br><br>
- <li>Hessenschau.de</li>
- Here is no configuration necessary, the URL http://hessenschau.de/verkehr/index.html will be used as a parameter.
- <br><br>
- <li>RadioSAW.de</li>
- Here is no configuration necessary, the keyword radiosaw will be used as a parameter.
- </ul>
- <br><br>
-
- <b>Requirement:</b>
- <ul><br>
- For this module, following perl-modules are required:<br>
- <li>HTML::TreeBuilder::XPath<br>
- <code>sudo apt-get install libxml-treebuilder-perl libhtml-treebuilder-xpath-perl</code>
- </li>
- </ul>
- <br><br>
-
- <a name="Verkehrsinfodefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> Verkehrsinfo <url> <interval></code>
- <br><br>
- example: <code>define A8 Verkehrsinfo https://www.verkehrsinfo.de/httpsmobil/index.php?c=staulist&street=A8&lat=&lon= 3600 </code>
- <br><br>
- Options:
- <ul>
- <li><i>url</i><br>
- URL regarding the traffic information</li>
- <li><i>interval</i><br>
- How often the data will be updated in seconds</li>
- </ul>
- </ul>
- <br>
-
- <a name="Verkehrsinfoset"></a>
- <b>Set</b><br>
- <ul>
- <code>set <name> <option></code>
- <br><br>
- Options:
- <ul>
- <li><i>update</i><br>
- update will be executed right away</li>
- </ul>
- </ul>
- <br>
-
- <a name="Verkehrsinfoget"></a>
- <b>Get</b><br>
- <ul>
- <code>get <name> <option></code>
- <br><br>
- Options:
- <ul>
- <li><i>info</i><br>
- output currently traffic information</li>
- </ul>
- </ul>
- <br>
-
- <a name="Verkehrsinfoattr"></a>
- <b>Attributes</b><br>
- <ul>
- <code>attr <name> <option> <value></code>
- <br><br>
- Options:
- <ul>
- <li><i>filter_exclude</i><br>
- This is an exclusion filter. Traffic information containing these words, will not be displayed.<br>
- The filter supports regular expressions. Attention: regex control character, for example brackets have to be masked with a backslash "\".<br>
- Multiple searching keywords can be seperated with the pipe "|".<br><br></li>
- <li><i>filter_include</i><br>
- This is an inclusion filter. Traffic information containing these words, will be displayed.<br>
- The filter supports regular expressions. Attention: regex control character, for example brackets have to be masked with a backslash "\".<br>
- Multiple searching keywords can be seperated with the pipe "|".<br><br></li>
- <li>Hint: Both filters can be used at the same time, or optional just one.<br>
- The filters are linked with a logical and. That means, for example, when something is excluded, it can be reincluded with the other filter.<br><br></li>
- <li><i>orderby</i><br>
- Messages will be sorted by relevance by reference to the string.<br>
- The sort supports regular expressions.<br>
- Multiple searching keywords can be seperated with the pipe "|".<br><br></li>
- <li><i>msg_format [ road | head | both ]</i> (only Verkehrsinfo.de and RadioSAW.de)<br>
- Using this parameter you can format the output, regarding streets, direction or both.<br><br></li>
- <li><i><a href="#readingFnAttributes">readingFnAttributes</a></i><br><br></li>
- </ul>
- </ul>
- <br>
-
- <a name="Verkehrsinforeading"></a>
- <b>Readings</b>
- <ul>
- <br>
- <li><b>e_</b><i>0|1|2|3...|9</i><b>_...</b> - aktiv message</li>
- <li><b>count</b> - number of aktiv messages</li>
- <li><b>e_</b><i>0</i><b>_road</b> - street</li>
- <li><b>e_</b><i>0</i><b>_head</b> - direction</li>
- <li><b>e_</b><i>0</i><b>_msg</b> - message</li>
- </ul>
- <br>
-
- <a name="Verkehrsinfofunktion"></a>
- <b>Funktion</b>
- <ul>
- <code>Verkehrsinfo_GetData(<devicename>)</code>
- <br><br>
- The function can be accessed anywhere in FHEM.
- The output of this function is the same as get <name> info and the string can be used for further forwarding.
- <br><br>
- example: <code>my $result = Verkehrsinfo_GetData('A8')</code>
- </ul>
- <br>
- </ul>
- =end html
- =begin html_DE
- <a name="Verkehrsinfo"></a>
- <h3>Verkehrsinfo</h3>
- <ul>
- <i>Verkehrsinfo</i> kann die aktuellen Verkehrsinformationen von verschiedenen Quellen auslesen.
- <br><br>
- <ul>
- <li>Verkehrsinfo.de</li>
- Um die gewünschten Verkehrsinformation zu erhalten wird die Webseite https://www.verkehrsinfo.de/httpsmobil besucht.
- Hier können Sie dann entweder Straßen oder Bundesländer auswählen. Anschließend wird die URL als Parameter übergeben.
- <br><br>
- <li>Hessenschau.de</li>
- Hier ist keine Konfiguration notwendig, man verwendet die URL http://hessenschau.de/verkehr/index.html als Parameter.
- <br><br>
- <li>RadioSAW.de</li>
- Hier ist keine Konfiguration notwendig, man verwendet als Parameter radiosaw.
- </ul>
- <br><br>
-
- <b>Voraussetzung:</b>
- <ul><br>
- Für dieses Modul werden folgende Perlmodule benötigt:<br>
- <li>HTML::TreeBuilder::XPath<br>
- <code>sudo apt-get install libxml-treebuilder-perl libhtml-treebuilder-xpath-perl</code>
- </li>
- <li>JSON<br>
- <code>sudo apt-get install libjson-perl</code>
- </li>
- </ul>
- <br><br>
-
- <a name="Verkehrsinfodefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> Verkehrsinfo <url> <interval></code>
- <br><br>
- Beispiel: <code>define A8 Verkehrsinfo https://www.verkehrsinfo.de/httpsmobil/index.php?c=staulist&street=A8&lat=&lon= 3600 </code>
- <br><br>
- Options:
- <ul>
- <li><i>url</i><br>
- URL der auszulesenden Verkehrsinformationen</li>
- <li><i>interval</i><br>
- Alle wieviel Sekunden die Daten aktualisiert werden</li>
- </ul>
- </ul>
- <br>
-
- <a name="Verkehrsinfoset"></a>
- <b>Set</b><br>
- <ul>
- <code>set <name> <option></code>
- <br><br>
- Options:
- <ul>
- <li><i>update</i><br>
- Update wird sofort ausgeführt</li>
- </ul>
- </ul>
- <br>
-
- <a name="Verkehrsinfoget"></a>
- <b>Get</b><br>
- <ul>
- <code>get <name> <option></code>
- <br><br>
- Options:
- <ul>
- <li><i>info</i><br>
- Ausgeben der aktuellen Verkehrsinformationen</li>
- </ul>
- </ul>
- <br>
-
- <a name="Verkehrsinfoattr"></a>
- <b>Attributes</b><br>
- <ul>
- <code>attr <name> <option> <value></code>
- <br><br>
- Options:
- <ul>
- <li><i>filter_exclude</i><br>
- Dies ist ein Ausschlussfilter. Verkehrsmeldung die eines der Wörter enthalten, werden nicht angezeigt.<br>
- Der Filter unterstütz Regulärer Ausdrücke. Achtung: Regex Steuerzeichen, z.B. Klammern müssen mit einem Backslash "\" maskiert werden.<br>
- Mehrer Suchbegriffe können mit einer Pipe "|" getrennt werden.<br><br></li>
- <li><i>filter_include</i><br>
- Dies ist ein Einschlussfilter. Es werden nur Verkehrsmeldung angezeigt die eines der Wörter enthalten.<br>
- Der Filter unterstütz Regulärer Ausdrücke. Achtung: Regex Steuerzeichen, z.B. Klammern müssen mit einem Backslash "\" maskiert werden.<br>
- Mehrer Suchbegriffe können mit einer Pipe "|" getrennt werden.<br><br></li>
- <li>Hinweis: Beide Filter können gleichzeitig benutzt werden, aber es kann auch wahlweise nur einer verwendet werden.<br>
- Die Filter sind mit einem Logischen UND verknüpft. Das heist z.B.: wenn etwas ausgeschlossen wurde, kann es nicht mit dem Einschlussfilter wiedergeholt werden.<br><br></li>
- <li><i>orderby</i><br>
- Anhand von Zeichefolgen wird eine Sortierung der Meldungen nach Relevanz vorgenommen.<br>
- Die Sortierung unterstützt Regulärer Ausdrücke.<br>
- Mehrer Suchbegriffe können mit einer Pipe "|" getrennt werden.<br><br></li>
- <li><i>msg_format [ road | head | both ]</i> (Nur Verkehrsinfo.de und RadioSAW.de)<br>
- Über diesen Parameter kann die Meldung formatiert werden nach Strasse, Richtung oder beides<br><br></li>
- <li><i><a href="#readingFnAttributes">readingFnAttributes</a></i><br><br></li>
- </ul>
- </ul>
- <br>
-
- <a name="Verkehrsinforeading"></a>
- <b>Readings</b>
- <ul>
- <br>
- <li><b>e_</b><i>0|1|2|3...|9</i><b>_...</b> - aktive Meldungen</li>
- <li><b>count</b> - Anzahl der aktiven Meldungen</li>
- <li><b>e_</b><i>0</i><b>_road</b> - Straße</li>
- <li><b>e_</b><i>0</i><b>_head</b> - Fahrtrichtung</li>
- <li><b>e_</b><i>0</i><b>_msg</b> - Meldung</li>
- </ul>
- <br>
-
- <a name="Verkehrsinfofunktion"></a>
- <b>Funktion</b>
- <ul>
- <code>Verkehrsinfo_GetData(<devicename>)</code>
- <br><br>
- Die Funktion kann überall in FHEM aufgerufen werden und liefert als Rückgabewert das gleiche Ergebnis wie der get <name> info Aufruf.
- Der Rückgabewert als Text, kann dann für weiteres verwendet werden.
- <br><br>
- Beispiel: <code>my $result = Verkehrsinfo_GetData('A8')</code>
- </ul>
- <br>
- </ul>
- =end html_DE
- =cut
|