mirror of
https://github.com/home-assistant/android
synced 2024-09-19 16:11:37 +00:00
Geofencing Improvements (#1048)
* Send an event when we enter or exit a zone * Add more event data * Change event name, update geofence registration logic, add zone entity ID to event * Track geofence registration * Remove geofences as needed, ignore updates within 5 seconds unless geofence event * Reset variable when sending location * Review comments
This commit is contained in:
parent
6cf4b41d92
commit
48afca5427
|
@ -9,6 +9,7 @@ import android.location.Location
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.core.content.ContextCompat.getSystemService
|
import androidx.core.content.ContextCompat.getSystemService
|
||||||
import com.google.android.gms.location.Geofence
|
import com.google.android.gms.location.Geofence
|
||||||
import com.google.android.gms.location.GeofencingEvent
|
import com.google.android.gms.location.GeofencingEvent
|
||||||
|
@ -72,6 +73,8 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
|
||||||
|
|
||||||
private var lastLocationSend = 0L
|
private var lastLocationSend = 0L
|
||||||
private var lastUpdateLocation = ""
|
private var lastUpdateLocation = ""
|
||||||
|
|
||||||
|
private var geofenceRegistered = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
@ -122,6 +125,11 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
|
||||||
isBackgroundLocationSetup = false
|
isBackgroundLocationSetup = false
|
||||||
isZoneLocationSetup = false
|
isZoneLocationSetup = false
|
||||||
}
|
}
|
||||||
|
if (backgroundEnabled && !zoneEnabled && isZoneLocationSetup) {
|
||||||
|
removeGeofenceUpdateRequests()
|
||||||
|
isZoneLocationSetup = false
|
||||||
|
Log.d(TAG, "Removing geofence update requests")
|
||||||
|
}
|
||||||
if (backgroundEnabled && !isBackgroundLocationSetup) {
|
if (backgroundEnabled && !isBackgroundLocationSetup) {
|
||||||
isBackgroundLocationSetup = true
|
isBackgroundLocationSetup = true
|
||||||
requestLocationUpdates()
|
requestLocationUpdates()
|
||||||
|
@ -143,9 +151,14 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
|
||||||
|
|
||||||
fusedLocationProviderClient.removeLocationUpdates(backgroundIntent)
|
fusedLocationProviderClient.removeLocationUpdates(backgroundIntent)
|
||||||
|
|
||||||
|
removeGeofenceUpdateRequests()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeGeofenceUpdateRequests() {
|
||||||
val geofencingClient = LocationServices.getGeofencingClient(latestContext)
|
val geofencingClient = LocationServices.getGeofencingClient(latestContext)
|
||||||
val zoneIntent = getLocationUpdateIntent(true)
|
val zoneIntent = getLocationUpdateIntent(true)
|
||||||
geofencingClient.removeGeofences(zoneIntent)
|
geofencingClient.removeGeofences(zoneIntent)
|
||||||
|
geofenceRegistered = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requestLocationUpdates() {
|
private fun requestLocationUpdates() {
|
||||||
|
@ -170,6 +183,11 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (geofenceRegistered) {
|
||||||
|
Log.w(TAG, "Not registering for zones as we already have")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
Log.d(TAG, "Registering for zone based location updates")
|
Log.d(TAG, "Registering for zone based location updates")
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -204,12 +222,48 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
|
||||||
|
|
||||||
private fun handleGeoUpdate(intent: Intent) {
|
private fun handleGeoUpdate(intent: Intent) {
|
||||||
Log.d(TAG, "Received geofence update.")
|
Log.d(TAG, "Received geofence update.")
|
||||||
|
if (!isEnabled(latestContext, zoneLocation.id)) {
|
||||||
|
isZoneLocationSetup = false
|
||||||
|
Log.w(TAG, "Unregistering geofences as zone tracking is disabled and intent was received")
|
||||||
|
removeGeofenceUpdateRequests()
|
||||||
|
return
|
||||||
|
}
|
||||||
val geofencingEvent = GeofencingEvent.fromIntent(intent)
|
val geofencingEvent = GeofencingEvent.fromIntent(intent)
|
||||||
if (geofencingEvent.hasError()) {
|
if (geofencingEvent.hasError()) {
|
||||||
Log.e(TAG, "Error getting geofence broadcast status code: ${geofencingEvent.errorCode}")
|
Log.e(TAG, "Error getting geofence broadcast status code: ${geofencingEvent.errorCode}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val validGeofencingEvents = listOf(Geofence.GEOFENCE_TRANSITION_ENTER, Geofence.GEOFENCE_TRANSITION_EXIT)
|
||||||
|
if (geofencingEvent.geofenceTransition in validGeofencingEvents) {
|
||||||
|
val zoneStatusEvent = when (geofencingEvent.geofenceTransition) {
|
||||||
|
Geofence.GEOFENCE_TRANSITION_ENTER -> "android.zone_entered"
|
||||||
|
Geofence.GEOFENCE_TRANSITION_EXIT -> "android.zone_exited"
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
val zoneAttr = mapOf(
|
||||||
|
"accuracy" to geofencingEvent.triggeringLocation.accuracy,
|
||||||
|
"altitude" to geofencingEvent.triggeringLocation.altitude,
|
||||||
|
"bearing" to geofencingEvent.triggeringLocation.bearing,
|
||||||
|
"latitude" to geofencingEvent.triggeringLocation.latitude,
|
||||||
|
"longitude" to geofencingEvent.triggeringLocation.longitude,
|
||||||
|
"provider" to geofencingEvent.triggeringLocation.provider,
|
||||||
|
"time" to geofencingEvent.triggeringLocation.time,
|
||||||
|
"vertical_accuracy" to if (Build.VERSION.SDK_INT >= 26) geofencingEvent.triggeringLocation.verticalAccuracyMeters.toInt() else 0,
|
||||||
|
"zone" to geofencingEvent.triggeringGeofences[0].requestId
|
||||||
|
)
|
||||||
|
runBlocking {
|
||||||
|
try {
|
||||||
|
integrationUseCase.fireEvent(zoneStatusEvent, zoneAttr as Map<String, Any>)
|
||||||
|
Log.d(TAG, "Event sent to Home Assistant")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Unable to send event to Home Assistant", e)
|
||||||
|
Toast.makeText(latestContext, R.string.zone_event_failure, Toast.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val sensorDao = AppDatabase.getInstance(latestContext).sensorDao()
|
val sensorDao = AppDatabase.getInstance(latestContext).sensorDao()
|
||||||
val sensorSettings = sensorDao.getSettings(zoneLocation.id)
|
val sensorSettings = sensorDao.getSettings(zoneLocation.id)
|
||||||
val minAccuracy = sensorSettings
|
val minAccuracy = sensorSettings
|
||||||
|
@ -224,11 +278,11 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
|
||||||
)
|
)
|
||||||
requestSingleAccurateLocation()
|
requestSingleAccurateLocation()
|
||||||
} else {
|
} else {
|
||||||
sendLocationUpdate(geofencingEvent.triggeringLocation)
|
sendLocationUpdate(geofencingEvent.triggeringLocation, "", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendLocationUpdate(location: Location, name: String = "") {
|
private fun sendLocationUpdate(location: Location, name: String = "", geofenceUpdate: Boolean = false) {
|
||||||
Log.d(
|
Log.d(
|
||||||
TAG, "Last Location: " +
|
TAG, "Last Location: " +
|
||||||
"\nCoords:(${location.latitude}, ${location.longitude})" +
|
"\nCoords:(${location.latitude}, ${location.longitude})" +
|
||||||
|
@ -256,6 +310,11 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
|
||||||
Log.d(TAG, "Duplicate location received, not sending to HA")
|
Log.d(TAG, "Duplicate location received, not sending to HA")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (now < lastLocationSend + 5000 && !geofenceUpdate) {
|
||||||
|
Log.d(TAG, "New location update not possible within 5 seconds, not sending to HA")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lastLocationSend = now
|
lastLocationSend = now
|
||||||
lastUpdateLocation = updateLocation.gps.contentToString()
|
lastUpdateLocation = updateLocation.gps.contentToString()
|
||||||
|
@ -304,6 +363,7 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
geofenceRegistered = true
|
||||||
return geofencingRequestBuilder.build()
|
return geofencingRequestBuilder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,7 @@ to your home internet.</string>
|
||||||
<string name="connected_to_home_assistant">Connected to Home Assistant</string>
|
<string name="connected_to_home_assistant">Connected to Home Assistant</string>
|
||||||
<string name="create_template">Create Template</string>
|
<string name="create_template">Create Template</string>
|
||||||
<string name="database_event_failure">Unable to send migration failure event to Home Assistant</string>
|
<string name="database_event_failure">Unable to send migration failure event to Home Assistant</string>
|
||||||
|
<string name="zone_event_failure">Unable to send zone event to Home Assistant</string>
|
||||||
<string name="database_migration_failed">Database migration failed, all sensor and widget data has been reset. Please re-enable your sensors and recreate your widgets.</string>
|
<string name="database_migration_failed">Database migration failed, all sensor and widget data has been reset. Please re-enable your sensors and recreate your widgets.</string>
|
||||||
<string name="developer_tools">Developer Tools</string>
|
<string name="developer_tools">Developer Tools</string>
|
||||||
<string name="device_class">Device Class</string>
|
<string name="device_class">Device Class</string>
|
||||||
|
|
Loading…
Reference in a new issue