fhem-mirror/FHEM/97_TrashCal.pm
Tobias.Faust 178626e23a 97_TrashCal.pm: changed to new format
git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@18014 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2018-12-20 16:04:04 +00:00

420 lines
12 KiB
Perl

##############################################
# $Id$
#
# 97_TrashCal.pm
#
# written by Tobias Faust 2013-10-23
# e-mail: tobias dot faust at online dot de
#
##############################################
#
##############################################
#
# Log-Levels
# 0 - server start/stop
# 1 - error messages or unknown packets
# 2 - major events/alarms.
# 3 - commands sent out will be logged.
# 4 - you'll see whats received by the different devices.
# 5 - debugging.
##############################################
###############################################
# parser for the Trash
package MyTrashCalParser;
use base qw(HTML::Parser);
our %dates = ();
my $lookupTag = "div";
my $curTag = "";
my $category = "--";
# here HTML::text/start/end are overridden
sub text
{
my ( $self, $text ) = @_;
if ( $curTag eq $lookupTag )
{
#print "MyTrashCalParser_Text: original: $text \n";
$text =~ s/[^0-9]*([0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4}).*/$1/;
#print "MyTrashCalParser_Text: Modifiziert: $text \n";
if($category ne "" && $text =~ m/([0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4})/) {
push(@{$dates{$category}}, $text);
#print "MyTrashCalParser_Text: Values of $category: ". keys(%{$data{$category}}) ."\n";
}
} elsif ($curTag eq "h3") {
$category = $text;
#print "MyTrashCalParser_Text: neue Kategorie: $text \n";
}
}
sub start
{
my ( $self, $tagname, $attr, $attrseq, $origtext ) = @_;
$curTag = $tagname;
#print "MyTrashCalParser_Start: $tagname, $attr, $attrseq, $origtext";
}
sub end
{
$curTag = "";
#print "MyTrashCalParser_End: ----- done -----";
}
##############################################
package main;
use strict;
use feature qw/say switch/;
use warnings;
use Data::Dumper;
use LWP::UserAgent;
use HTTP::Request;
require 'Blocking.pm';
require 'HttpUtils.pm';
use vars qw($readingFnAttributes);
# use vars qw(%attr);
use vars qw(%defs);
my $MODUL = "TrashCal";
###################################
sub TrashCal_Initialize($)
{
my ($hash) = @_;
$hash->{DefFn} = "TrashCal_Define";
$hash->{UndefFn} = "TrashCal_Undef";
$hash->{AttrList} = " TrashCal_Link".
" TrashCal_Interval".
" disable:0,1".
" ".$readingFnAttributes;
}
###################################
sub TrashCal_Define($$)
{
my ( $hash, $def ) = @_;
my $name = $hash->{NAME};
my @a = split( "[ \t][ \t]*", $def );
my $type = $a[2];
if ( int(@a) < 3 )
{
return "Wrong syntax: use define <name> TrashCal <type>";
}
my $nt = time;
$nt += 20; # aquire in 20sec
my @lt = localtime($nt);
my $ntm = sprintf("%02d.%02d.%04d %02d:%02d:%02d", $lt[3], ($lt[4]+1), ($lt[5]+1900), $lt[2], $lt[1], $lt[0]);
$hash->{TriggerTime_FMT} = $ntm;
$hash->{TriggerTime} = $nt;
InternalTimer( $nt, "TrashCal_Timer", $hash, 0 );
Log3 $hash, 4, "TrashCal_Define: InternalTimer auf in 20sek gesetzt: $ntm";
return undef;
}
#####################################
sub TrashCal_Undef($$)
{
my ( $hash, $arg ) = @_;
RemoveInternalTimer( $hash );
BlockingKill( $hash->{helper}{RUNNING_PID} ) if ( defined( $hash->{helper}{RUNNING_PID} ) );
Log3 $hash, 4, "TrashCal_Undef: --- done ---";
return undef;
}
#####################################
sub TrashCal_Timer(@)
{
my ($hash) = @_;
my $me = $hash->{NAME};
Log3 $hash, 4, "TrashCal_Timer: GrTimer aufgerufen.....";
return unless (defined($hash->{NAME}));
Log3 $hash, 4, "TrashCal_Timer: --- started ---";
$hash->{helper}{TimerGRInterval} = AttrVal( $me, "TrashCal_Interval", 3600 );
TrashCal_Start($hash) if(!IsDisabled($me));
# setup timer
RemoveInternalTimer( $hash );
my $nt = time;
$nt += $hash->{helper}{TimerGRInterval};
my @lt = localtime($nt);
my $ntm = sprintf("%02d.%02d.%04d %02d:%02d:%02d", $lt[3], ($lt[4]+1), ($lt[5]+1900), $lt[2], $lt[1], $lt[0]);
$hash->{TriggerTime_FMT} = $ntm;
$hash->{TriggerTime} = $nt;
InternalTimer($nt, "TrashCal_Timer", $hash, 0 );
Log3 $hash, 4, "TrashCal_Timer: --- done ---";
}
#####################################
# acquires the html page
sub TrashCal_HtmlAcquire($)
{
my ($hash) = @_;
my $name = $hash->{NAME};
return unless (defined($hash->{NAME}));
my $URL = AttrVal( $name, 'TrashCal_Link', "" );
# abbrechen, wenn wichtig parameter nicht definiert sind
return "" if ( !defined($URL) );
return "" if ( $URL eq "" );
my $err_log = "";
my $agent = LWP::UserAgent->new( env_proxy => 1, keep_alive => 1, timeout => 3 );
my $header = HTTP::Request->new( GET => $URL );
my $request = HTTP::Request->new( 'GET', $URL, $header );
my $response = $agent->request($request);
$err_log = "Can't get $URL -- " . $response->status_line
unless $response->is_success;
if ( $err_log ne "" )
{
Log3 $hash, 1, "TrashCal_HtmlAcquire: Error: $err_log";
return "";
}
return $response->content;
}
#####################################
sub TrashCal_Start($)
{
my ($hash) = @_;
return unless (defined($hash->{NAME}));
my $me = $hash->{NAME};
if (AttrVal( $me, 'TrashCal_Link', "" ) eq "") {
Log3 $hash, 3, "$me: Kein Link im Attribut 'TrashCal_Link' angebeben, breche Ausführung ab.";
return;
}
while (1)
{
Log3 $hash, 4, "TrashCal_Start: --- started ---";
$hash->{helper}{RUNNING_PID} =
BlockingCall(
"TrashCal_Run", # callback worker task
$me, # name of the device
"TrashCal_Done", # callback result method
50, # timeout seconds
"TrashCal_Aborted", # callback for abortion
$hash ); # parameter for abortion
last;
}
Log3 $hash, 4, "TrashCal_Start: --- done ---";
}
#####################################
sub TrashCal_Run($) {
my ($string) = @_;
my ( $me, $server ) = split( "\\|", $string );
my $ptext = $me ."+";
return unless ( defined($me) );
my $hash = $defs{$me};
return unless (defined($hash->{NAME}));
Log3 $hash, 4, "TrashCal_Run: --- started ---";
while (1)
{
# acquire the html-page
my $response = TrashCal_HtmlAcquire($hash);
last if ($response eq "");
my $parser = MyTrashCalParser->new;
%MyTrashCalParser::dates = ();
# parsing the complete html-page-response, needs some time
# only <td> tags will be regarded
$parser->parse($response);
Log3 $hash, 4, "TrashCal_Run: parsed terms:" . keys(%MyTrashCalParser::dates);
foreach my $cat (keys(%MyTrashCalParser::dates) ) {
$ptext .= $cat . '|';
#Log3 $hash, 4, "TrashCal_Run: Values of $cat: ". keys(%{$MyTrashCalParser::data{$cat}});
#foreach my $dat (keys(%{$MyTrashCalParser::dates{$cat}}) ) {
# $ptext .= "|".$dat;
#}
$ptext .= join('|', @{$MyTrashCalParser::dates{$cat}});
$ptext .= "+";
}
last;
}
Log3 $hash, 4, "TrashCal_Run: return value: $ptext";
Log3 $hash, 4, "TrashCal_Run: --- done ---";
return $ptext;
#return "TrashCal|Altpapier|12.09.2014|07.11.2014|05.12.2014|18.07.2014|10.10.2014|15.08.2014";
}
#####################################
# assyncronous callback by blocking
sub TrashCal_Done($) {
my ($string) = @_;
Log3 undef, 4, "TrashCal_Done: --- begin ---";
return unless ( defined($string) );
# all term are separated by "#" , the first is the name of the instance
my ( $me, @values ) = split("\\+", $string );
my $hash = $defs{$me};
return unless (defined($hash->{NAME}));
# delete the marker for running process
delete( $hash->{helper}{RUNNING_PID} );
Log3 $hash, 4, "TrashCal_Done: --- started ---";
#Log3 $hash, 5, "TrashCal_Done: values:".join(', ', @values);
# Aktualisierung der Readings
my $category;
my $tstamp;
my $NextEvent_Tstamp = time() + (28*86400); #hoher Initialwert
my $NextEvent_Cat = "";
my $NextEvent_Dat = "";
my %hashValues = ();
# Durch jede Kategorie
for(my $i=0; $i<int(@values); $i++) {
# show the values
Log3 $hash, 5, "TrashCal_Done: Category with all values:".$values[$i];
my @dates = split( "\\|", $values[$i] );
$category = shift(@dates);
for(my $j=0; $j<int(@dates); $j++) {
if ( $dates[$j] =~ /([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{4})/i ) {
#berechne dazu passenden Unix-Timestamp
$tstamp = mktime(0, 0, 12, $1, ($2 -1), ($3 -1900), 0, 0, -1);
if($tstamp < $NextEvent_Tstamp) {
# das nächste/jüngste Event ermitteln
$NextEvent_Dat = $dates[$j];
$NextEvent_Cat = $category;
$NextEvent_Tstamp = $tstamp;
}
if(!defined($hashValues{$category}{TSTAMP}) || (($tstamp > time()) && ($tstamp < $hashValues{$category}{TSTAMP}))) {
# nur den zeitlich nächsten Wert in die Readings pro Categorie uebernehmen
$hashValues{$category}{DATE} = $dates[$j];
$hashValues{$category}{TSTAMP} = $tstamp;
}
}
# show the values
Log3 $hash, 5, "TrashCal_Done: category:$category - date: ".$dates[$j];
}
}
readingsBeginUpdate($hash);
foreach my $xxx ( sort keys %hashValues ) {
#my $daysleft = ($hashValues{$xxx}{TSTAMP} - time()) / 60 / 24;
readingsBulkUpdate( $hash, $xxx, $hashValues{$xxx}{DATE} );
readingsBulkUpdate( $hash, $xxx."_Tstamp", $hashValues{$xxx}{TSTAMP} );
#readingsBulkUpdate( $hash, $xxx."_DaysLeft", $daysleft);
}
readingsBulkUpdate( $hash, "NextEvent Category", $NextEvent_Cat );
readingsBulkUpdate( $hash, "NextEvent Date", $NextEvent_Dat );
readingsBulkUpdate( $hash, "NextEvent Tstamp", $NextEvent_Tstamp );
readingsBulkUpdate( $hash, "state", $NextEvent_Cat .": ". $NextEvent_Dat );
readingsEndUpdate( $hash, 1 );
Log3 $hash, 4, "TrashCal_Done: --- done ---";
}
#####################################
sub TrashCal_Aborted($)
{
my ($hash) = @_;
delete( $hash->{helper}{RUNNING_PID} );
Log3 $hash, 3, "TrashCal_Aborted: --- done ---";
}
#####################################
1;
=pod
=item helper
=item summary fetches shared dates at an public webpage of waste disposal
=item summary_DE holt auf einer Webseite bereitgestellte Abfalltermine ab
=begin html
<a name="TrashCal"></a>
<h3>TrashCal</h3>
<ul>
Note: this module needs the HTTP::Request,HTML::Parser and LWP::UserAgent perl modules.
<br>
At this moment only city "Magdeburg" is supported at this site:<br>
<i>http://sab.metageneric.de/app/sab_i_tp/index.php</i>
<br><br>
<a name="TrashCal define"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; TrashCal &lt;type&gt; </code>
<br><br>
Defines a new instanze of Trashcalendar. At this time the &lt;type&gt; is not used
<br>
Examples:
<ul>
<code>define MyTrashCal TrashCal Restabfall</code><br>
</ul>
</ul>
<br>
<a name="TrashCalset"></a>
<b>Set</b>
<ul>N/A</ul><br>
<a name="TrashCalget"></a>
<b>Get</b>
<ul>N/A</ul><br>
<a name="TrashCalattr"></a>
<b>Attributes</b>
<ul>
<li>TrashCal_Link<br>
setting up the URL to grab the Trashcalendar
<br>Example:
<ul>
<code>http://sab.metageneric.de/app/sab_i_tp/index.php?r=getHausnummerInfo&strasse=Torplatz&hausnummer=1&stadtteil_id=1609&dsd_behaelter_value=b120_b240</code>
<br>
</ul>
</li>
<li><a href="#readingFnAttributes">readingFnAttributes</a></li><br>
<li><a href="#disable">disable</a><br>
If this attribute is activated, the module will be disabled.<br>
Possible values: 0 => not disabled , 1 => disabled<br>
Default Value is 0 (not disabled)<br><br>
</li>
<li><a href="#verbose">verbose</a><br>
<b>4:</b> each major step will be logged<br>
<b>5:</b> Additionally some minor steps will be logged
</li>
</ul>
</ul>
=end html
=cut