mirror of
https://github.com/home-assistant/android
synced 2024-09-19 16:11:37 +00:00
Fix a race condition Sensor Update (#907)
* Fix a race condition between a sensor updating and sending the data to Home Assistant. * ktlint * UI enhancements + force update if re-enabled.
This commit is contained in:
parent
01d33067e7
commit
2c990e2c7b
|
@ -64,7 +64,8 @@ abstract class AppDatabase : RoomDatabase() {
|
|||
MIGRATION_5_6,
|
||||
MIGRATION_6_7,
|
||||
MIGRATION_7_8,
|
||||
MIGRATION_8_9
|
||||
MIGRATION_8_9,
|
||||
MIGRATION_9_10
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
@ -168,5 +169,30 @@ abstract class AppDatabase : RoomDatabase() {
|
|||
database.execSQL("ALTER TABLE `sensors` ADD `state_changed` INTEGER NOT NULL DEFAULT ''")
|
||||
}
|
||||
}
|
||||
private val MIGRATION_9_10 = object : Migration(9, 10) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
val cursor = database.query("SELECT * FROM sensors")
|
||||
val sensors = mutableListOf<ContentValues>()
|
||||
while (cursor.moveToNext()) {
|
||||
sensors.add(ContentValues().also {
|
||||
it.put("id", cursor.getString(cursor.getColumnIndex("id")))
|
||||
it.put("enabled", cursor.getInt(cursor.getColumnIndex("enabled")))
|
||||
it.put("registered", cursor.getInt(cursor.getColumnIndex("registered")))
|
||||
it.put("state", "")
|
||||
it.put("last_sent_state", "")
|
||||
it.put("state_type", "")
|
||||
it.put("type", "")
|
||||
it.put("icon", "")
|
||||
it.put("name", "")
|
||||
})
|
||||
}
|
||||
cursor.close()
|
||||
database.execSQL("DROP TABLE IF EXISTS `sensors`")
|
||||
database.execSQL("CREATE TABLE IF NOT EXISTS `sensors` (`id` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `registered` INTEGER NOT NULL, `state` TEXT NOT NULL, `last_sent_state` TEXT NOT NULL, `state_type` TEXT NOT NULL, `type` TEXT NOT NULL, `icon` TEXT NOT NULL, `name` TEXT NOT NULL, `device_class` TEXT, `unit_of_measurement` TEXT, PRIMARY KEY(`id`))")
|
||||
sensors.forEach {
|
||||
database.insert("sensors", OnConflictStrategy.REPLACE, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@ data class Sensor(
|
|||
var enabled: Boolean,
|
||||
@ColumnInfo(name = "registered")
|
||||
var registered: Boolean,
|
||||
@ColumnInfo(name = "state_changed")
|
||||
var stateChanged: Boolean,
|
||||
@ColumnInfo(name = "state")
|
||||
var state: String,
|
||||
@ColumnInfo(name = "last_sent_state")
|
||||
var lastSentState: String = "",
|
||||
@ColumnInfo(name = "state_type")
|
||||
var stateType: String = "",
|
||||
@ColumnInfo(name = "type")
|
||||
|
|
|
@ -28,4 +28,7 @@ interface SensorDao {
|
|||
|
||||
@Query("DELETE FROM sensor_attributes WHERE sensor_id = :sensorId")
|
||||
fun clearAttributes(sensorId: String)
|
||||
|
||||
@Query("UPDATE sensors SET last_sent_state = :state WHERE id = :sensorId")
|
||||
fun updateLastSendState(sensorId: String, state: String)
|
||||
}
|
||||
|
|
|
@ -251,7 +251,6 @@ class MobileAppIntegrationFragment : Fragment(), MobileAppIntegrationView {
|
|||
uniqueId,
|
||||
isChecked,
|
||||
false,
|
||||
true,
|
||||
""
|
||||
)
|
||||
sensorDao.add(sensor)
|
||||
|
|
|
@ -69,7 +69,6 @@ class SensorDetailFragment(
|
|||
}
|
||||
|
||||
updateSensorEntity(isEnabled)
|
||||
this@SensorDetailFragment.refreshSensorData()
|
||||
|
||||
return@setOnPreferenceChangeListener true
|
||||
}
|
||||
|
@ -115,22 +114,24 @@ class SensorDetailFragment(
|
|||
}
|
||||
}
|
||||
findPreference<Preference>("device_class")?.let {
|
||||
if (sensorData.deviceClass == null)
|
||||
it.isVisible = false
|
||||
else
|
||||
if (sensorData.enabled && sensorData.deviceClass != null) {
|
||||
it.summary = sensorData.deviceClass
|
||||
it.isVisible = true
|
||||
} else {
|
||||
it.isVisible = false
|
||||
}
|
||||
}
|
||||
findPreference<Preference>("icon")?.let {
|
||||
if (sensorData.icon == "")
|
||||
it.isVisible = false
|
||||
else
|
||||
if (sensorData.enabled && sensorData.icon != "") {
|
||||
it.summary = sensorData.icon
|
||||
it.isVisible = true
|
||||
} else {
|
||||
it.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
findPreference<PreferenceCategory>("attributes")?.let {
|
||||
if (attributes.isNullOrEmpty())
|
||||
it.isVisible = false
|
||||
else {
|
||||
if (sensorData.enabled && !attributes.isNullOrEmpty()) {
|
||||
attributes.forEach { attribute ->
|
||||
val key = "attribute_${attribute.name}"
|
||||
val pref = findPreference(key) ?: Preference(requireContext())
|
||||
|
@ -143,7 +144,9 @@ class SensorDetailFragment(
|
|||
if (!it.contains(pref))
|
||||
it.addPreference(pref)
|
||||
}
|
||||
}
|
||||
it.isVisible = true
|
||||
} else
|
||||
it.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,9 +156,10 @@ class SensorDetailFragment(
|
|||
var sensorEntity = sensorDao.get(basicSensor.id)
|
||||
if (sensorEntity != null) {
|
||||
sensorEntity.enabled = isEnabled
|
||||
sensorEntity.lastSentState = ""
|
||||
sensorDao.update(sensorEntity)
|
||||
} else {
|
||||
sensorEntity = Sensor(basicSensor.id, isEnabled, false, true, "")
|
||||
sensorEntity = Sensor(basicSensor.id, isEnabled, false, "")
|
||||
sensorDao.add(sensorEntity)
|
||||
}
|
||||
refreshSensorData()
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.content.Context
|
|||
import android.content.pm.PackageManager
|
||||
import android.os.Process.myPid
|
||||
import android.os.Process.myUid
|
||||
import android.util.Log
|
||||
import io.homeassistant.companion.android.R
|
||||
import io.homeassistant.companion.android.database.AppDatabase
|
||||
import io.homeassistant.companion.android.database.sensor.Attribute
|
||||
|
@ -40,7 +39,7 @@ interface SensorManager {
|
|||
|
||||
// If we haven't created the entity yet do so and default to enabled if required
|
||||
if (sensor == null) {
|
||||
sensor = Sensor(sensorId, permission && enabledByDefault, false, true, "")
|
||||
sensor = Sensor(sensorId, permission && enabledByDefault, false, "")
|
||||
sensorDao.add(sensor)
|
||||
}
|
||||
|
||||
|
@ -68,8 +67,6 @@ interface SensorManager {
|
|||
) {
|
||||
val sensorDao = AppDatabase.getInstance(context).sensorDao()
|
||||
val sensor = sensorDao.get(basicSensor.id) ?: return
|
||||
Log.d("SensorManager", "Old sensor state ${sensor.state} compared to new state $state for ${sensor.name}")
|
||||
sensor.stateChanged = sensor.stateChanged || (sensor.state != state.toString())
|
||||
sensor.id = basicSensor.id
|
||||
sensor.state = state.toString()
|
||||
sensor.stateType = when (state) {
|
||||
|
|
|
@ -131,7 +131,7 @@ class SensorReceiver : BroadcastReceiver() {
|
|||
Log.e(TAG, "Issue registering sensor: ${reg.uniqueId}", e)
|
||||
}
|
||||
}
|
||||
if (sensor?.enabled == true && fullSensor != null && sensor?.registered && sensor?.stateChanged) {
|
||||
if (sensor?.enabled == true && sensor.registered && sensor.state != sensor.lastSentState) {
|
||||
enabledRegistrations.add(fullSensor.toSensorRegistration())
|
||||
}
|
||||
}
|
||||
|
@ -141,6 +141,9 @@ class SensorReceiver : BroadcastReceiver() {
|
|||
var success = false
|
||||
try {
|
||||
success = integrationUseCase.updateSensors(enabledRegistrations.toTypedArray())
|
||||
enabledRegistrations.forEach {
|
||||
sensorDao.updateLastSendState(it.uniqueId, it.state.toString())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Exception while updating sensors.", e)
|
||||
}
|
||||
|
@ -151,7 +154,7 @@ class SensorReceiver : BroadcastReceiver() {
|
|||
val sensor = sensorDao.get(it.uniqueId)
|
||||
if (sensor != null) {
|
||||
sensor.registered = false
|
||||
sensor.stateChanged = false
|
||||
sensor.lastSentState = ""
|
||||
sensorDao.update(sensor)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue