.*<\/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/
-+
/\|/g;
$tmp =~ s/
/###/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/
/###/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/\//;
$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
Verkehrsinfo
Verkehrsinfo can read trafficinformation from various source.
- Verkehrsinfo.de
For receiving the traffic informationen, following website https://www.verkehrsinfo.de/httpsmobil will be called on.
There you can select streets or federal states. Afterwards the URL will be committed as a parameter.
- Hessenschau.de
Here is no configuration necessary, the URL http://hessenschau.de/verkehr/index.html will be used as a parameter.
- RadioSAW.de
Here is no configuration necessary, the keyword radiosaw will be used as a parameter.
Requirement:
For this module, following perl-modules are required:
- HTML::TreeBuilder::XPath
sudo apt-get install libxml-treebuilder-perl libhtml-treebuilder-xpath-perl
Define
define <name> Verkehrsinfo <url> <interval>
example: define A8 Verkehrsinfo https://www.verkehrsinfo.de/httpsmobil/index.php?c=staulist&street=A8&lat=&lon= 3600
Options:
- url
URL regarding the traffic information
- interval
How often the data will be updated in seconds
Set
set <name> <option>
Options:
- update
update will be executed right away
Get
get <name> <option>
Options:
- info
output currently traffic information
Attributes
attr <name> <option> <value>
Options:
- filter_exclude
This is an exclusion filter. Traffic information containing these words, will not be displayed.
The filter supports regular expressions. Attention: regex control character, for example brackets have to be masked with a backslash "\".
Multiple searching keywords can be seperated with the pipe "|".
- filter_include
This is an inclusion filter. Traffic information containing these words, will be displayed.
The filter supports regular expressions. Attention: regex control character, for example brackets have to be masked with a backslash "\".
Multiple searching keywords can be seperated with the pipe "|".
- Hint: Both filters can be used at the same time, or optional just one.
The filters are linked with a logical and. That means, for example, when something is excluded, it can be reincluded with the other filter.
- orderby
Messages will be sorted by relevance by reference to the string.
The sort supports regular expressions.
Multiple searching keywords can be seperated with the pipe "|".
- msg_format [ road | head | both ] (only Verkehrsinfo.de and RadioSAW.de)
Using this parameter you can format the output, regarding streets, direction or both.
- readingFnAttributes
Readings
- e_0|1|2|3...|9_... - aktiv message
- count - number of aktiv messages
- e_0_road - street
- e_0_head - direction
- e_0_msg - message
Funktion
Verkehrsinfo_GetData(<devicename>)
The function can be accessed anywhere in FHEM.
The output of this function is the same as get info and the string can be used for further forwarding.
example: my $result = Verkehrsinfo_GetData('A8')
=end html
=begin html_DE
Verkehrsinfo
Verkehrsinfo kann die aktuellen Verkehrsinformationen von verschiedenen Quellen auslesen.
- Verkehrsinfo.de
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.
- Hessenschau.de
Hier ist keine Konfiguration notwendig, man verwendet die URL http://hessenschau.de/verkehr/index.html als Parameter.
- RadioSAW.de
Hier ist keine Konfiguration notwendig, man verwendet als Parameter radiosaw.
Voraussetzung:
Für dieses Modul werden folgende Perlmodule benötigt:
- HTML::TreeBuilder::XPath
sudo apt-get install libxml-treebuilder-perl libhtml-treebuilder-xpath-perl
- JSON
sudo apt-get install libjson-perl
Define
define <name> Verkehrsinfo <url> <interval>
Beispiel: define A8 Verkehrsinfo https://www.verkehrsinfo.de/httpsmobil/index.php?c=staulist&street=A8&lat=&lon= 3600
Options:
- url
URL der auszulesenden Verkehrsinformationen
- interval
Alle wieviel Sekunden die Daten aktualisiert werden
Set
set <name> <option>
Options:
- update
Update wird sofort ausgeführt
Get
get <name> <option>
Options:
- info
Ausgeben der aktuellen Verkehrsinformationen
Attributes
attr <name> <option> <value>
Options:
- filter_exclude
Dies ist ein Ausschlussfilter. Verkehrsmeldung die eines der Wörter enthalten, werden nicht angezeigt.
Der Filter unterstütz Regulärer Ausdrücke. Achtung: Regex Steuerzeichen, z.B. Klammern müssen mit einem Backslash "\" maskiert werden.
Mehrer Suchbegriffe können mit einer Pipe "|" getrennt werden.
- filter_include
Dies ist ein Einschlussfilter. Es werden nur Verkehrsmeldung angezeigt die eines der Wörter enthalten.
Der Filter unterstütz Regulärer Ausdrücke. Achtung: Regex Steuerzeichen, z.B. Klammern müssen mit einem Backslash "\" maskiert werden.
Mehrer Suchbegriffe können mit einer Pipe "|" getrennt werden.
- Hinweis: Beide Filter können gleichzeitig benutzt werden, aber es kann auch wahlweise nur einer verwendet werden.
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.
- orderby
Anhand von Zeichefolgen wird eine Sortierung der Meldungen nach Relevanz vorgenommen.
Die Sortierung unterstützt Regulärer Ausdrücke.
Mehrer Suchbegriffe können mit einer Pipe "|" getrennt werden.
- msg_format [ road | head | both ] (Nur Verkehrsinfo.de und RadioSAW.de)
Über diesen Parameter kann die Meldung formatiert werden nach Strasse, Richtung oder beides
- readingFnAttributes
Readings
- e_0|1|2|3...|9_... - aktive Meldungen
- count - Anzahl der aktiven Meldungen
- e_0_road - Straße
- e_0_head - Fahrtrichtung
- e_0_msg - Meldung
Funktion
Verkehrsinfo_GetData(<devicename>)
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.
Beispiel: my $result = Verkehrsinfo_GetData('A8')
=end html_DE
=cut