mirror of
https://github.com/home-assistant/android
synced 2024-10-15 20:43:06 +00:00
Breaking change: send sensor list attributes as list to server (#2478)
* Breaking change: send sensor list attributes as list to server - Send a sensor attribute that is managed by the app as a list, to the server as a list as well instead of a stringified version of a list. * Fallback to string for lists that include separator - To prevent issues where we can't distinguish the list items separator from a value that includes the separator, don't try to convert a value to a list if that is the case but instead use string * Improve string fallback for lists that include separator - Instead of only falling back when a list includes a String with the separator, just use toString() to also support other objects which might include ", " when stringified, such as nested lists * Store list data as JSON - To remove any confusion when sending individual list items, store data as JSON to escape characters if necessary - Map Any data in a list that is not any of the specific types to string, for consistency with the same types when not in a list and to prevent JSON serialization issues
This commit is contained in:
parent
d6add75168
commit
b418491667
|
@ -130,12 +130,12 @@ class BluetoothSensorManager : SensorManager {
|
|||
var totalConnectedDevices = 0
|
||||
var connectedPairedDevices: List<String> = ArrayList()
|
||||
var connectedNotPairedDevices: List<String> = ArrayList()
|
||||
var bondedString = ""
|
||||
var pairedDevices: List<String> = ArrayList()
|
||||
|
||||
if (checkPermission(context, bluetoothConnection.id)) {
|
||||
|
||||
val bluetoothDevices = BluetoothUtils.getBluetoothDevices(context)
|
||||
bondedString = bluetoothDevices.filter { b -> b.paired }.map { it.address }.toString()
|
||||
pairedDevices = bluetoothDevices.filter { b -> b.paired }.map { it.address }
|
||||
connectedPairedDevices = bluetoothDevices.filter { b -> b.paired && b.connected }.map { it.address }
|
||||
connectedNotPairedDevices = bluetoothDevices.filter { b -> !b.paired && b.connected }.map { it.address }
|
||||
totalConnectedDevices = bluetoothDevices.filter { b -> b.connected }.count()
|
||||
|
@ -148,7 +148,7 @@ class BluetoothSensorManager : SensorManager {
|
|||
mapOf(
|
||||
"connected_paired_devices" to connectedPairedDevices,
|
||||
"connected_not_paired_devices" to connectedNotPairedDevices,
|
||||
"paired_devices" to bondedString
|
||||
"paired_devices" to pairedDevices
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -55,6 +55,8 @@ import androidx.compose.ui.text.input.KeyboardType
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.compose.Image
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
|
@ -78,6 +80,7 @@ fun SensorDetailView(
|
|||
) {
|
||||
val context = LocalContext.current
|
||||
var sensorUpdateTypeInfo by remember { mutableStateOf(false) }
|
||||
val jsonMapper by lazy { jacksonObjectMapper() }
|
||||
|
||||
val sensorEnabled = viewModel.sensor?.sensor?.enabled
|
||||
?: (
|
||||
|
@ -145,9 +148,17 @@ fun SensorDetailView(
|
|||
}
|
||||
sensor.attributes.forEach { attribute ->
|
||||
item {
|
||||
val summary = when (attribute.valueType) {
|
||||
"listboolean" -> jsonMapper.readValue<List<Boolean>>(attribute.value).toString()
|
||||
"listfloat" -> jsonMapper.readValue<List<Number>>(attribute.value).toString()
|
||||
"listlong" -> jsonMapper.readValue<List<Long>>(attribute.value).toString()
|
||||
"listint" -> jsonMapper.readValue<List<Int>>(attribute.value).toString()
|
||||
"liststring" -> jsonMapper.readValue<List<String>>(attribute.value).toString()
|
||||
else -> attribute.value
|
||||
}
|
||||
SensorDetailRow(
|
||||
title = attribute.name,
|
||||
summary = attribute.value,
|
||||
summary = summary,
|
||||
clickable = false,
|
||||
selectingEnabled = true
|
||||
)
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.content.pm.PackageManager
|
|||
import android.os.Process.myPid
|
||||
import android.os.Process.myUid
|
||||
import androidx.core.content.getSystemService
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import io.homeassistant.companion.android.database.AppDatabase
|
||||
import io.homeassistant.companion.android.database.sensor.Attribute
|
||||
import io.homeassistant.companion.android.database.sensor.SensorSetting
|
||||
|
@ -215,13 +216,31 @@ interface SensorManager {
|
|||
is Int -> "int"
|
||||
is Long -> "long"
|
||||
is Number -> "float"
|
||||
is List<*> -> {
|
||||
when {
|
||||
(item.value as List<*>).all { it is Boolean } -> "listboolean"
|
||||
(item.value as List<*>).all { it is Int } -> "listint"
|
||||
(item.value as List<*>).all { it is Long } -> "listlong"
|
||||
(item.value as List<*>).all { it is Number } -> "listfloat"
|
||||
else -> "liststring"
|
||||
}
|
||||
}
|
||||
else -> "string" // Always default to String for attributes
|
||||
}
|
||||
val value =
|
||||
when {
|
||||
valueType == "liststring" ->
|
||||
jacksonObjectMapper().writeValueAsString((item.value as List<*>).map { it.toString() })
|
||||
valueType.startsWith("list") ->
|
||||
jacksonObjectMapper().writeValueAsString(item.value)
|
||||
else ->
|
||||
item.value.toString()
|
||||
}
|
||||
|
||||
Attribute(
|
||||
basicSensor.id,
|
||||
item.key,
|
||||
item.value.toString(),
|
||||
value,
|
||||
valueType
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@ package io.homeassistant.companion.android.database.sensor
|
|||
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Relation
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import io.homeassistant.companion.android.common.data.integration.SensorRegistration
|
||||
|
||||
data class SensorWithAttributes(
|
||||
|
@ -14,8 +17,21 @@ data class SensorWithAttributes(
|
|||
val attributes: List<Attribute>
|
||||
) {
|
||||
fun toSensorRegistration(): SensorRegistration<Any> {
|
||||
var objectMapper: ObjectMapper? = null
|
||||
val attributes = attributes.map {
|
||||
val attributeValue = when (it.valueType) {
|
||||
"listboolean", "listfloat", "listlong", "listint", "liststring" -> {
|
||||
if (objectMapper == null) objectMapper = jacksonObjectMapper()
|
||||
objectMapper?.let { mapper ->
|
||||
when (it.valueType) {
|
||||
"listboolean" -> mapper.readValue<List<Boolean>>(it.value)
|
||||
"listfloat" -> mapper.readValue<List<Number>>(it.value)
|
||||
"listlong" -> mapper.readValue<List<Long>>(it.value)
|
||||
"listint" -> mapper.readValue<List<Int>>(it.value)
|
||||
else -> mapper.readValue<List<String>>(it.value)
|
||||
}
|
||||
} ?: it.value // Fallback: provide JSON string, but shouldn't happen
|
||||
}
|
||||
"boolean" -> it.value.toBoolean()
|
||||
"float" -> it.value.toFloat()
|
||||
"long" -> it.value.toLong()
|
||||
|
|
Loading…
Reference in a new issue