Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -919,19 +919,28 @@ class LocationSensorManager @Inject constructor(
val updateLocation: UpdateLocation
val updateLocationString: String
val updateLocationAs: String = getSendLocationAsSetting(serverId)
val zones = getZones(serverId)
val enteredZones = zones
.filter {
val radius = it.attributes["radius"] as? Number
val matchesGps = radius != null && it.containsWithAccuracy(location)
val matchesGeofence = lastEnteredGeoZones.contains("${serverId}_${it.entityId}")
return@filter matchesGps || matchesGeofence
}.sortedWith(
// Smallest zone (radius) first; when two zones share the same radius, prefer the one
// whose center is closest to the current location to break the tie deterministically.
compareBy<Entity> { (it.attributes["radius"] as? Number ?: Int.MAX_VALUE).toFloat() }
.thenBy { distanceToZoneCenter(location, it) },
)
// Send `in_zones` only to versions that support it
// (https://github.com/home-assistant/architecture/discussions/1387).
val inZones = if (serverManager.getServer(serverId)?.version?.isAtLeast(2026, 6, 0) == true) {
enteredZones.map { it.entityId }
} else {
null
}
if (updateLocationAs == SEND_LOCATION_AS_ZONE_ONLY) {
val zones = getZones(serverId)
val inZones = zones
.filter {
val radius = it.attributes["radius"] as? Number
return@filter radius != null && it.containsWithAccuracy(location)
}.sortedWith(
// Smallest zone (radius) first; when two zones share the same radius, prefer the one
// whose center is closest to the current location to break the tie deterministically.
compareBy<Entity> { (it.attributes["radius"] as? Number ?: Int.MAX_VALUE).toFloat() }
.thenBy { distanceToZoneCenter(location, it) },
)
val locationZone = inZones.firstOrNull { it.attributes["passive"] as? Boolean == false }
val locationZone = enteredZones.firstOrNull { it.attributes["passive"] as? Boolean == false }

val locationName = locationZone?.entityId?.split(".")?.getOrNull(1) ?: ZONE_NAME_NOT_HOME
// Send both `location_name` (deprecated) and `in_zones` (its replacement, per
Expand All @@ -941,16 +950,7 @@ class LocationSensorManager @Inject constructor(
gps = null,
gpsAccuracy = null,
locationName = locationName,
inZones = if (serverManager.getServer(serverId)?.version?.isAtLeast(
2026,
6,
0,
) == true
) {
inZones.map { it.entityId }
} else {
null
},
inZones = inZones,
speed = null,
altitude = null,
course = null,
Expand All @@ -962,7 +962,7 @@ class LocationSensorManager @Inject constructor(
gps = listOf(location.latitude, location.longitude),
gpsAccuracy = accuracy,
locationName = null,
inZones = null,
inZones = inZones,
speed = location.speed.toInt(),
altitude = location.altitude.toInt(),
course = location.bearing.toInt(),
Expand All @@ -989,9 +989,9 @@ class LocationSensorManager @Inject constructor(
return
}

if (location.time < (lastLocationSend[serverId] ?: 0)) {
if (location.time < (lastLocationSend[serverId] ?: 0) && trigger?.isGeofence != true) {
Timber.d(
"Skipping old location update since time is before the last one we sent, received: ${location.time} last sent: $lastLocationSend",
"Skipping old location update since time is before the last one we sent, received: ${location.time} last sent: ${lastLocationSend[serverId] ?: 0}",
)
logLocationUpdate(location, updateLocation, serverId, trigger, LocationHistoryItemResult.SKIPPED_NOT_LATEST)
return
Expand All @@ -1002,7 +1002,7 @@ class LocationSensorManager @Inject constructor(
"Received location that is ${now - location.time} milliseconds old, ${location.time} compared to $now with source ${location.provider}",
)
if (lastUpdateLocation[serverId] == updateLocationString) {
if (now < (lastLocationSend[serverId] ?: 0) + 900000) {
if (now < (lastLocationSend[serverId] ?: 0) + 900000 && trigger?.isGeofence != true) {
Timber.d("Duplicate location received, not sending to HA")
logLocationUpdate(
location,
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/xml/changelog_master.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<changelog xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingDefaultResource">
<release version="2026.8.4 - Main" versioncode="3">
<change>Fix missing zone on the first location update after high accuracy mode turns off</change>
<change>Android 17: added assistant volume level sensor + notification command for control</change>
<change>Health Connect sleep duration sensor now ignores awake and out of bed time</change>
<change>Modernized settings for entity widgets and tiles</change>
Expand All @@ -12,6 +13,7 @@
<change>Bug fixes and dependency updates</change>
</release>
<release version="2026.8.4 - Automotive" versioncode="1">
<change>Fix missing zone on the first location update after high accuracy mode turns off</change>
<change>Android 17: added assistant volume level sensor + notification command for control</change>
<change>Health Connect sleep duration sensor now ignores awake and out of bed time</change>
<change>Bug fixes and dependency updates</change>
Expand Down
Loading