Straßenverkehr Blitzer

Aus FHEMWiki
Version vom 8. Februar 2019, 08:14 Uhr von Ph1959de (Diskussion | Beiträge) (Source-Formatierung korrigiert (lang=...); Umstellung auf Vorlagen für Links ins Forum)

Der Code "Blitzer" (Autor: bismosa ]) ist ein Code zur listenförmigen Anzeige mobiler Geschwindigkeitsüberwachungen (Radarfallen) im Straßenverkehr. Er kann problemlos in FHEM Tablet UI genutzt werden. 2019-02 wurde es geprüft und war funktional.

Es wird ausdrücklich auf den Thread Blitzer anzeigen im FHEM-Forum verwiesen: Im ersten Beitrag pflegt der Autor den Code nach.

Funktionalität

Ausgehend von einer vorgegebenen Koordinate werden alle gemeldeten Blitzer im beliebigen Umkreis (bis 99 Kilometer) aufgelistet. Zusätzlich existiert ein Reading "Anzeige": "0", wenn keine Blitzer im definierten Umkreis vorliegen, "1" wenn dort Blitzer vorliegen.

Code mit Erläuterungen

defmod blitzer dummy
attr blitzer userattr lat lng maxkm
attr blitzer icon ampel_rot
attr blitzer lat 51.8644
attr blitzer lng 12.6346
attr blitzer maxkm 25
attr blitzer stateFormat Text
attr blitzer room 61 Verkehr

Damit wird die Definition des basierenden Dummy-Devices vorgenommen. Hier ist die Mittelpunktskoordinate (lat/lon) an die eigenen Bedürfnisse anzupassen: HIer bin ich, welche Blitzer sind im Umkreis? - "maxkm" definiert den Radius um die Koordinate, in dessen Kreisfläche alle gemeldeten Blitzer gelistet werden sollen. "room" kann den eigenen Bedürfnissen angepasst werden.

defmod httpmod_blitzer HTTPMOD https://cdn2.atudo.net/api/1.0/vl.php?type=0,1,2,3,4,5,6&box=51.6,12.1,52.0,13.0 0
attr httpmod_blitzer userattr getData getHeader1 getHeader2 getURL reading01DeleteIfUnmatched reading01JSON reading01Name reading01Regex reading02Name reading02RegOpt reading02Regex reading03JSON reading03Name readingEncode requestHeader1 requestHeader2 setParseResponse:0,1
attr httpmod_blitzer enableControlSet 1
attr httpmod_blitzer extractAllJSON 1
attr httpmod_blitzer getHeader1 Content-Type: application/json
attr httpmod_blitzer getHeader2 Accept: */*
attr httpmod_blitzer readingEncode utf8
attr httpmod_blitzer room 61 Verkehr

Mit dieser Device wird die Internetabfrage definiert. Der "room" kann an eigene Befürfnisse angepasst werden. Die Definition selbst (defmod httpmod_blitzer) muss angepasst werden, es geht um den letzten Teil: "box=51.6,12.1,52.0,13.0 0". Gedanklich bildet man ein Quadrat um die Mittelpunktkoordinate. Für die ersten beiden Parameter bestimmt man die Koordinate der linken unteren Ecke. Für die beiden folgenden Parameter bestimmt man die Koordinaten der rechten oberen Ecke und trägt auch sie ein. Dabei muss man nicht sehr genau vorgehen: Ein ungefähres Rechteck reicht völlig. - Die abschließende Null muss unverändert bleiben: Der Abruf wird von einem Script gesteuert.

defmod at_Blitzer at +*00:10:00 {\
        fhem("deletereading httpmod_blitzer .*", 1);;\
        fhem("set httpmod_blitzer reread");;;;\
    fhem("sleep 2;; {getBlitzer};;");;;;\
}
attr at_Blitzer room 99_System

Dieser Code-Teil sollte nicht geändert werden: Alle 10 Minuten werden alle Readings (Blitzer) gelöscht und via Web der aktuelle Stand erfragt.

99_myUtils.pm

In 99_myUtils.pm muss ein längerer Codeblock eingefügt werden. Er sollte ganz unten vor dem Codeteil

1;

stehen.

################################################################
###                        Blitzer                           ###
################################################################
sub getBlitzer(){
    my $httpDev = "httpmod_blitzer";
    my $BlitzerDev = "blitzer";
    my $lat = AttrVal($BlitzerDev,"lat",undef);
    my $lng = AttrVal($BlitzerDev,"lng",undef);
	my $maxkm = AttrVal($BlitzerDev,"maxkm",undef);
    if (!defined $lat){
        Log 5,"[getBlitzer] lat ist nicht definiert!"; 
    }
    if (!defined $lng){
        Log 5,"[getBlitzer] lng ist nicht definiert!"; 
    }
	if (!defined $maxkm){
        Log 5,"[getBlitzer] maxkm ist nicht definiert!"; 
    }
    # Da unbekannt ist, wie viele es gibt...durchprobieren
    my @Liste;
    for(my $i=1;$i<100;$i++){
        my $num = sprintf("%02d", $i);
        Log 5,"[getBlitzer] Reading: $num"; 
        my $Poi_lat = ReadingsVal($httpDev,"pois_".$num."_lat",undef);
        my $Poi_lng = ReadingsVal($httpDev,"pois_".$num."_lng",undef);
        last if !defined $Poi_lat;
		#Log 1,"[getBlitzer] Reading: $Poi_lat"; 
        last if !defined $Poi_lng;
        Log 5,"[getBlitzer] lat/lng: $Poi_lat $Poi_lng"; 
        my $Poi_street = ReadingsVal($httpDev,"pois_".$num."_street","keine");
        my $Poi_vmax = ReadingsVal($httpDev,"pois_".$num."_vmax","kA");
        if (!defined $Poi_vmax){
            $Poi_vmax = ".";
        }
        if ($Poi_vmax eq ""){
            $Poi_vmax = ".";
        }
        Log 5,"[getBlitzer] $Poi_street $Poi_vmax"; 
               
        #Entfernung zur Home-Koordinate (Luftlinie)
        #Berechnung nach: https://www.kompf.de/gps/distcalc.html
        #Einfache Variante
        my $dx = 71.5 * abs($lng - $Poi_lng);
        my $dy = 111.3 * abs($lat - $Poi_lat);
		my $distance = sqrt($dx * $dx + $dy * $dy);
       
		#MaxEntfernung einbeziehen
		if (not $distance > $maxkm){
			Log 5,"[getBlitzer] distance: $distance"; 
        	push @Liste, [ $distance, $Poi_street, $Poi_vmax, $Poi_lat, $Poi_lng ];	
		} else {
			Log 5,"[getBlitzer] $distance > $maxkm"; 
		}
		
       
    }
    my $out = join(", ", @Liste)."\n";
    Log 5,"[getBlitzer] $out"; 
    my @ListeSort = sort {$a->[0] <=> $b->[0]} @Liste;
    $out = join(", ", @ListeSort)."\n";
    Log 5,"[getBlitzer] $out"; 
   
    #Eintragen ins Dummy-Device
    #Eintragungen erst löschen
    fhem("deletereading $BlitzerDev .*", 1);
   
    my $Text="";
    my $Anzahl = scalar(@ListeSort);
    for (my $i=0;$i<$Anzahl;$i++) {
        my $num = sprintf("%02d", $i);
        Log 5,"[getBlitzer] Num: $num"; 
        fhem("setreading $BlitzerDev ".$num."Entfernung ".$ListeSort[$i][0]);
        fhem("setreading $BlitzerDev ".$num."Strasse ".$ListeSort[$i][1]);
        fhem("setreading $BlitzerDev ".$num."VMax ".$ListeSort[$i][2]);
       
        #Ort
        fhem("sleep 1; \{getBlitzerOrte(".$ListeSort[$i][3].",".$ListeSort[$i][4].",'$num','$BlitzerDev')};");
       
    }
    fhem("sleep 3; \{getBlitzerText('$BlitzerDev')};");
    #fhem("setreading $BlitzerDev Text $Text");
   
}
sub getBlitzerOrte($$$$){
#https://nominatim.openstreetmap.org/search/52.xxxxx%208.xxxx?format=json&addressdetails=1
    my $Poi_lat = shift;
    my $Poi_lng = shift;
    my $num = shift;
    $num = sprintf("%02d", $num);
    my $BlitzerDev = shift;
	
	
	my $hash = {};
  	$hash->{'blitzerdev'} = $BlitzerDev;
	$hash->{'num'} = $num;
	my $param = {
           url        => "https://nominatim.openstreetmap.org/reverse?format=json&lat=".$Poi_lat."&lon=".$Poi_lng,
           timeout    => 5,
           method     => "GET",            # Lesen von Inhalten
		   hash       => $hash,            # Muss gesetzt werden, damit die Callback funktion wieder $hash hat
           header     => "",
           callback   =>  \&getBlitzerOrteCallback   # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten
    };
	#agent: FHEM/1.0\r\nUser-Agent: FHEM/1.0\r\nAccept: application/json

    HttpUtils_NonblockingGet($param);      # Starten der HTTP Abfrage. Es gibt keinen Return-Code.

}
sub getBlitzerOrteCallback($) {
    my ($param, $err, $data) = @_;
    my $hash = $param->{hash};
    my $BlitzerDev = $hash->{blitzerdev};
	my $num = $hash->{num};

    if($err ne "")      # wenn ein Fehler bei der HTTP Abfrage aufgetreten ist
    {
        Log3 "[getBlitzerOrte]", 3, "error while requesting ".$param->{url}." - $err";   # Eintrag fürs Log
    }
	#Log 1,"[getBlitzerOrte] $BlitzerDev ".$param->{data}." ".$param->{url}." ".$param->{httpheader}." ".$param->{code};
	#Log 1,"$data";

	my $Stadtteil = "";
	my $Stadt = "";
	
	my ($Stadtteil) = $data =~ m/suburb":"([^"]+)"/;
	if ((!defined $Stadtteil) or ($Stadtteil eq "")){
		#Log 1, "[getBlitzerOrteCallback] search city_district";
       ($Stadtteil) = $data =~ m/city_district":"([^"]+)"/;
		#Log 1, "[getBlitzerOrteCallback] $Stadtteil";
    }
	if ((!defined $Stadtteil) or ($Stadtteil eq "")){
		#Log 1, "[getBlitzerOrteCallback] $Stadtteil";
		Log 5, "[getBlitzerOrteCallback] ".$param->{url};
		Log 5, "[getBlitzerOrteCallback] $data";
       $Stadtteil = ".";
    }
 
       my ($Stadt) = $data =~ m/city":"([^"]+)"/;
	if ((!defined $Stadt) or ($Stadt eq "")){
		#Log 1, "[getBlitzerOrteCallback] search village $data";
        ($Stadt) = $data =~ m/town":"([^"]+)"/;
		#Log 1, "[getBlitzerOrteCallback] $Stadt";
    }
	if ((!defined $Stadt) or ($Stadt eq "")){
		#Log 1, "[getBlitzerOrteCallback] search village $data";
        ($Stadt) = $data =~ m/village":"([^"]+)"/;
		#Log 1, "[getBlitzerOrteCallback] $Stadt";
    }
    if ((!defined $Stadt) or ($Stadt eq "")){
		#Log 1, "[getBlitzerOrteCallback] $Stadt";
		Log 5, "[getBlitzerOrteCallback] ".$param->{url};
		Log 5, "[getBlitzerOrteCallback] $data";
       $Stadt = ".";
    }
    my ($building) = $data =~ m/building":"([^"]+)"/;
    if ((!defined $building) or ($building eq "")){
        $building = ".";
    }
    Log 5,"[getBlitzerOrteCallback] $Stadt $Stadtteil $building";
    #Log 1,"[getBlitzerOrte] ".$decoded_json->{address}->{suburb}->[0];
	if ($Stadt eq "."){$Stadt = " "};
	if ($Stadtteil eq "."){$Stadtteil = " "};
    fhem("setreading $BlitzerDev ".$num."Ort $Stadt $Stadtteil");
	fhem("setreading $BlitzerDev ".$num."Building $building");
}
sub getBlitzerText($){
    my $BlitzerDev = shift;
    my $Text="<html> <p align='left'>";
    my $SollAnzeige=0;
    for(my $i=0;$i<100;$i++){
        my $num = sprintf("%02d", $i);
        my $Entf = ReadingsVal($BlitzerDev,$num."Entfernung",undef);
		last if !defined $Entf;
		my $Ort = ReadingsVal($BlitzerDev,$num."Ort",".");
		if ($Ort eq "."){$Ort = " "};
		my $building = ReadingsVal($BlitzerDev,$num."Building",0);
		if ($building eq "."){$building = " "};
        my $Strasse = ReadingsVal($BlitzerDev,$num."Strasse"," ");
        my $VMax = ReadingsVal($BlitzerDev,$num."VMax"," ");
        if (not $Text eq "<html> <p align='left'>"){
            $Text = $Text."\n <br>";   
        }
        $Text = $Text."$num $Ort $Strasse $building Max $VMax km/h (".sprintf("%.1f", "$Entf")."km) !!";
        $SollAnzeige=1;
    }
	$Text = $Text."</p></html>";
    fhem("setreading $BlitzerDev Text $Text");
    fhem("setreading $BlitzerDev Anzeige $SollAnzeige");
}

Von besonderem Interesse ist hier die Zeile

$Text = $Text."$num $Ort $Strasse $building Max $VMax km/h (".sprintf("%.1f", "$Entf")."km) !!";

Diese Zeile kann man den eigenen Bedürfnissen anpassen, beispielhaft so:

$Text = $Text."$Ort $Strasse $building $VMax km/h";

Dieser Version ist günstiger für FTUI, da die Zeilenausgaben kürzer ist.

Code für FTUI

<div data-type="label"
     data-device="blitzer"
     data-get="Text">

Hinweis

Es gibt mehrere Anpassungsvorschäge. Diese sind im Forum zu finden: Blitzer anzeigen. Fragen zum Code bitte dort stellen.

Screenshot fehlt