From 924862c211f71ef447f70d065b4660ffa005969a Mon Sep 17 00:00:00 2001 From: jpawlowski Date: Sat, 20 Oct 2018 12:41:57 +0000 Subject: [PATCH] 98_GEOFANCY: fix last* readings and add new features from Geofency.app git-svn-id: https://svn.fhem.de/fhem/trunk@17571 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 6 ++ fhem/FHEM/98_GEOFANCY.pm | 165 +++++++++++++++++++++++++++++++++++---- fhem/FHEM/RESIDENTStk.pm | 29 ++++--- 3 files changed, 172 insertions(+), 28 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index 0d2d351d5..5c0b92883 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,11 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: 98_GEOFANCY: add new reading LocTravDist; add support for + Geofency.app webhook attributes currentLatitude, + currentLongitude, motion, wifiSSID and wifiBSSID. + New readings: PosBSSID, PosLat, PosLocDist, PosLong, PosMotion, + PosSSID, PosTravDist + - bugfix: 98_GEOFANCY: fixed last* readings - feature: 89_FULLY: New commands for sound playback and photo. - bugfix: 74_XiaomiBTLESens: fix disableForTimer Problem after reboot - feature: 31_HUEDevice: added water reading for Xiaomi Aqara Water sensor diff --git a/fhem/FHEM/98_GEOFANCY.pm b/fhem/FHEM/98_GEOFANCY.pm index 1f313cc89..c21fe0f88 100755 --- a/fhem/FHEM/98_GEOFANCY.pm +++ b/fhem/FHEM/98_GEOFANCY.pm @@ -5,6 +5,7 @@ use strict; use warnings; use Data::Dumper; use Time::Local; +use UConv; use HttpUtils; @@ -106,12 +107,20 @@ sub GEOFANCY_CGI() { my $id = ""; my $lat = ""; my $long = ""; + my $posLat = ""; + my $posLong = ""; + my $posTravDist = ""; my $address = "-"; my $entry = ""; my $msg = ""; my $date = ""; my $time = ""; my $locName = ""; + my $posLocDist = ""; + my $locTravDist = ""; + my $motion = ""; + my $wifiSSID = ""; + my $wifiBSSID = ""; # data received if ( $request =~ m,^(\/[^/]+?)(?:\&|\?|\/\?|\/)(.*)?$, ) { @@ -258,6 +267,34 @@ m/(19|20)\d\d-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):([0-5 || $webArgs->{longitude} > 180 ) ); + # validate posLAT + return ( + "text/plain; charset=utf-8", + "NOK Specified latitude '" + . $webArgs->{currentLatitude} + . "' has unexpected format" + ) + if ( + defined $webArgs->{currentLatitude} + && ( $webArgs->{currentLatitude} !~ m/^-?\d+(\.\d+)?$/ + || $webArgs->{currentLatitude} < -90 + || $webArgs->{currentLatitude} > 90 ) + ); + + # validate posLONG + return ( + "text/plain; charset=utf-8", + "NOK Specified longitude '" + . $webArgs->{currentLongitude} + . "' has unexpected format" + ) + if ( + defined $webArgs->{currentLongitude} + && ( $webArgs->{currentLongitude} !~ m/^-?\d+(\.\d+)?$/ + || $webArgs->{currentLongitude} < -180 + || $webArgs->{currentLongitude} > 180 ) + ); + # validate device return ( "text/plain; charset=utf-8", "NOK Expected value for 'device' cannot be empty" ) @@ -270,6 +307,18 @@ m/(19|20)\d\d-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):([0-5 if ( defined( $webArgs->{device} ) && $webArgs->{device} =~ m/(?:\s)/ ); + # validate motion + if ( defined( $webArgs->{motion} ) ) { + my @motions = ( + "unknown", "stationary", "walking", "running", + "automotive", "cycling" + ); + my $motion = lc( $webArgs->{motion} ); + return ( "text/plain; charset=utf-8", + "NOK Unknown motion type '" . $webArgs->{motion} . "'" ) + if ( !grep( /^$motion$/, @motions ) ); + } + # Locative.app if ( defined $webArgs->{trigger} ) { Log3 $name, 5, "GEOFANCY $name: detected data format: Locative.app"; @@ -298,6 +347,27 @@ m/(19|20)\d\d-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):([0-5 $address = $webArgs->{address} if ( defined( $webArgs->{address} ) ); $device = $webArgs->{device}; + $motion = $webArgs->{motion} + if ( defined( $webArgs->{motion} ) ); + $wifiSSID = $webArgs->{wifiSSID} + if ( defined( $webArgs->{wifiSSID} ) ); + $wifiBSSID = $webArgs->{wifiBSSID} + if ( defined( $webArgs->{wifiBSSID} ) ); + + if ( defined( $webArgs->{currentLatitude} ) + && defined( $webArgs->{currentLongitude} ) ) + { + if ( $webArgs->{currentLatitude} == 0 + && $webArgs->{currentLongitude} == 0 ) + { + $posLat = $webArgs->{latitude}; + $posLong = $webArgs->{longitude}; + } + else { + $posLat = $webArgs->{currentLatitude}; + $posLong = $webArgs->{currentLongitude}; + } + } } # SMART Geofences.app @@ -406,15 +476,50 @@ m/(19|20)\d\d-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):([0-5 } $deviceAlias = $hash->{helper}{device_aliases}{$device} - if ( $hash->{helper}{device_aliases}{$device} && $matchingResident == 0 ); + if ( $hash->{helper}{device_aliases}{$device} + && $matchingResident == 0 ); Log3 $name, 4, -"GEOFANCY $name: id=$id name=$locName trig=$entry date=$date lat=$lat long=$long address:$address dev=$device devAlias=$deviceAlias"; +"GEOFANCY $name: id=$id name=$locName trig=$entry date=$date lat=$lat long=$long posLat=$posLat posLong=$posLong address:$address dev=$device devAlias=$deviceAlias motion=$motion wifiSSID=$wifiSSID wifiBSSID=$wifiBSSID"; Log3 $name, 3, "GEOFANCY $name: Unknown device UUID $device: Set attribute devAlias for $name or assign $device to any ROOMMATE or GUEST device using attribute r*_geofenceUUIDs" if ( $deviceAlias eq "-" ); + # distance between location and position + if ( $lat ne "" && $long ne "" && $posLat ne "" && $posLong ne "" ) { + $posLocDist = UConv::distance( $posLat, $posLong, $lat, $long, 2 ); + } + + # travelled distance for location + if ( $lat ne "" && $long ne "" ) { + my $locLatVal = ReadingsVal( $name, "currLocLat_" . $deviceAlias, "-" ); + $locLatVal = ReadingsVal( $name, "lastLocLat_" . $deviceAlias, "-" ) + if ( $locLatVal eq "-" ); + my $locLongVal = + ReadingsVal( $name, "currLocLong_" . $deviceAlias, "-" ); + $locLongVal = ReadingsVal( $name, "lastLocLong_" . $deviceAlias, "-" ) + if ( $locLongVal eq "-" ); + + if ( $locLatVal ne "-" && $locLongVal ne "-" ) { + $locTravDist = + UConv::distance( $lat, $long, $locLatVal, $locLongVal, 2 ); + } + } + + # travelled distance for position + if ( $posLat ne "" && $posLong ne "" ) { + my $currPosLatVal = + ReadingsVal( $name, "currPosLat_" . $deviceAlias, "" ); + my $currPosLongVal = + ReadingsVal( $name, "currPosLong_" . $deviceAlias, "" ); + + if ( $currPosLatVal ne "" && $currPosLongVal ne "" ) { + $posTravDist = UConv::distance( $posLat, $posLong, $currPosLatVal, + $currPosLongVal, 2 ); + } + } + readingsBeginUpdate($hash); # use date for readings @@ -452,6 +557,34 @@ m/(19|20)\d\d-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):([0-5 || lc($entry) eq "0" || lc($entry) eq "leaving" ); + my $currReading; + my $lastReading; + my $currVal; + + # backup last known position + foreach ( + 'PosSSID', 'PosBSSID', 'PosMotion', 'PosLat', + 'PosLong', 'PosLocDist', 'PosTravDist', 'LocTravDist' + ) + { + $currReading = "curr" . $_ . "_" . $deviceAlias; + $lastReading = "last" . $_ . "_" . $deviceAlias; + $currVal = ReadingsVal( $name, $currReading, "" ); + readingsBulkUpdate( $hash, $lastReading, $currVal ); + } + + readingsBulkUpdate( $hash, "currPosSSID_" . $deviceAlias, $wifiSSID ); + readingsBulkUpdate( $hash, "currPosBSSID_" . $deviceAlias, $wifiBSSID ); + readingsBulkUpdate( $hash, "currPosMotion_" . $deviceAlias, $motion ); + readingsBulkUpdate( $hash, "currPosLat_" . $deviceAlias, $posLat ); + readingsBulkUpdate( $hash, "currPosLong_" . $deviceAlias, $posLong ); + readingsBulkUpdate( $hash, "currPosLocDist_" . $deviceAlias, + $posLocDist ); + readingsBulkUpdate( $hash, "currLocTravDist_" . $deviceAlias, + $locTravDist ); + readingsBulkUpdate( $hash, "currPosTravDist_" . $deviceAlias, + $posTravDist ); + if ( lc($entry) eq "enter" || lc($entry) eq "1" || lc($entry) eq "entered" @@ -470,26 +603,26 @@ m/(19|20)\d\d-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):([0-5 || lc($entry) eq "0" || lc($entry) eq "leaving" ) { - my $currReading; - my $lastReading; - Log3 $name, 4, "GEOFANCY $name: $deviceAlias left $id and is in transit"; # backup last known location if not "underway" - $currReading = "currLoc_" . $deviceAlias; - my $currVal = ReadingsVal( $name, $currReading, undef ); + $currReading = "currLocTime_" . $deviceAlias; + $currVal = ReadingsVal( $name, $currReading, undef ); if ( $currVal && $currVal ne "underway" ) { - foreach ( 'Loc', 'LocLat', 'LocLong', 'LocAddr' ) { - $currReading = "curr" . $_ . "_" . $deviceAlias; - $lastReading = "last" . $_ . "_" . $deviceAlias; - readingsBulkUpdate( $hash, $lastReading, $currVal ); - } - $currReading = "currLocTime_" . $deviceAlias; readingsBulkUpdate( $hash, "lastLocArr_" . $deviceAlias, $currVal ); readingsBulkUpdate( $hash, "lastLocDep_" . $deviceAlias, $time ); + + foreach ( 'Loc', 'LocLat', 'LocLong', 'LocAddr' ) { + $currReading = "curr" . $_ . "_" . $deviceAlias; + $lastReading = "last" . $_ . "_" . $deviceAlias; + $currVal = ReadingsVal( $name, $currReading, "" ); + $currVal = ReadingsVal( $name, $lastReading, "" ) + if ( $currVal eq "-" || $currVal eq "" ); + readingsBulkUpdate( $hash, $lastReading, $currVal ); + } } readingsBulkUpdate( $hash, $deviceAlias, "left " . $id ); @@ -514,8 +647,10 @@ m/(19|20)\d\d-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):([0-5 $locName = $id if ( $locName eq "" ); RESIDENTStk_SetLocation( - $deviceAlias, $locName, $trigger, $id, $time, - $lat, $long, $address, $device + $deviceAlias, $locName, $trigger, $id, + $time, $lat, $long, $address, + $device, $posLat, $posLong, $posLocDist, + $motion, $wifiSSID, $wifiBSSID ) if ( IsDevice( $deviceAlias, "ROOMMATE|GUEST" ) ); } diff --git a/fhem/FHEM/RESIDENTStk.pm b/fhem/FHEM/RESIDENTStk.pm index e0ccaec04..45d2899a4 100644 --- a/fhem/FHEM/RESIDENTStk.pm +++ b/fhem/FHEM/RESIDENTStk.pm @@ -1476,19 +1476,22 @@ sub RESIDENTStk_DurationTimer($;$) { return undef; } -sub RESIDENTStk_SetLocation($$$;$$$$$$) { - my ( $name, $location, $trigger, $id, $time, - $lat, $long, $address, $device ) = @_; - my $hash = $defs{$name}; - my $TYPE = GetType($name); - my $prefix = RESIDENTStk_GetPrefixFromType($name); - my $state = ReadingsVal( $name, "state", "initialized" ); - my $presence = ReadingsVal( $name, "presence", "present" ); - my $currLocation = ReadingsVal( $name, "location", "-" ); - my $currWayhome = ReadingsVal( $name, "wayhome", "0" ); - my $currLat = ReadingsVal( $name, "locationLat", "-" ); - my $currLong = ReadingsVal( $name, "locationLong", "-" ); - my $currAddr = ReadingsVal( $name, "locationAddr", "" ); +sub RESIDENTStk_SetLocation(@) { + my ( + $name, $location, $trigger, $id, $time, + $lat, $long, $address, $device, $posLat, + $posLong, $posLocDist, $motion, $wifiSSID, $wifiBSSID + ) = @_; + my $hash = $defs{$name}; + my $TYPE = GetType($name); + my $prefix = RESIDENTStk_GetPrefixFromType($name); + my $state = ReadingsVal( $name, "state", "initialized" ); + my $presence = ReadingsVal( $name, "presence", "present" ); + my $currLocation = ReadingsVal( $name, "location", "-" ); + my $currWayhome = ReadingsVal( $name, "wayhome", "0" ); + my $currLat = ReadingsVal( $name, "locationLat", "-" ); + my $currLong = ReadingsVal( $name, "locationLong", "-" ); + my $currAddr = ReadingsVal( $name, "locationAddr", "" ); $id = "-" if ( !$id || $id eq "" ); $lat = "-" if ( !$lat || $lat eq "" ); $long = "-" if ( !$long || $long eq "" );