refactor: replace `MyNodeInfo` with `MyNodeEntity` (#1277)

pull/1281/head
Andre K 2024-10-02 06:18:30 -03:00 zatwierdzone przez GitHub
rodzic d89d4b7baa
commit c30ee2f55f
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
14 zmienionych plików z 550 dodań i 129 usunięć

Wyświetl plik

@ -0,0 +1,458 @@
{
"formatVersion": 1,
"database": {
"version": 13,
"identityHash": "23eb673bdcd4e1af18a662f0b49bfebf",
"entities": [
{
"tableName": "my_node",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`myNodeNum` INTEGER NOT NULL, `model` TEXT, `firmwareVersion` TEXT, `couldUpdate` INTEGER NOT NULL, `shouldUpdate` INTEGER NOT NULL, `currentPacketId` INTEGER NOT NULL, `messageTimeoutMsec` INTEGER NOT NULL, `minAppVersion` INTEGER NOT NULL, `maxChannels` INTEGER NOT NULL, `hasWifi` INTEGER NOT NULL, PRIMARY KEY(`myNodeNum`))",
"fields": [
{
"fieldPath": "myNodeNum",
"columnName": "myNodeNum",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "model",
"columnName": "model",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "firmwareVersion",
"columnName": "firmwareVersion",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "couldUpdate",
"columnName": "couldUpdate",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "shouldUpdate",
"columnName": "shouldUpdate",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "currentPacketId",
"columnName": "currentPacketId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "messageTimeoutMsec",
"columnName": "messageTimeoutMsec",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minAppVersion",
"columnName": "minAppVersion",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "maxChannels",
"columnName": "maxChannels",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "hasWifi",
"columnName": "hasWifi",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"myNodeNum"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "nodes",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`num` INTEGER NOT NULL, `user` BLOB NOT NULL, `long_name` TEXT, `short_name` TEXT, `position` BLOB NOT NULL, `latitude` REAL NOT NULL, `longitude` REAL NOT NULL, `snr` REAL NOT NULL, `rssi` INTEGER NOT NULL, `last_heard` INTEGER NOT NULL, `device_metrics` BLOB NOT NULL, `channel` INTEGER NOT NULL, `via_mqtt` INTEGER NOT NULL, `hops_away` INTEGER NOT NULL, `is_favorite` INTEGER NOT NULL, `environment_metrics` BLOB NOT NULL, `power_metrics` BLOB NOT NULL, `paxcounter` BLOB NOT NULL, PRIMARY KEY(`num`))",
"fields": [
{
"fieldPath": "num",
"columnName": "num",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "user",
"columnName": "user",
"affinity": "BLOB",
"notNull": true
},
{
"fieldPath": "longName",
"columnName": "long_name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "shortName",
"columnName": "short_name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "BLOB",
"notNull": true
},
{
"fieldPath": "latitude",
"columnName": "latitude",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "longitude",
"columnName": "longitude",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snr",
"columnName": "snr",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "rssi",
"columnName": "rssi",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastHeard",
"columnName": "last_heard",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "deviceTelemetry",
"columnName": "device_metrics",
"affinity": "BLOB",
"notNull": true
},
{
"fieldPath": "channel",
"columnName": "channel",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "viaMqtt",
"columnName": "via_mqtt",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "hopsAway",
"columnName": "hops_away",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isFavorite",
"columnName": "is_favorite",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "environmentTelemetry",
"columnName": "environment_metrics",
"affinity": "BLOB",
"notNull": true
},
{
"fieldPath": "powerTelemetry",
"columnName": "power_metrics",
"affinity": "BLOB",
"notNull": true
},
{
"fieldPath": "paxcounter",
"columnName": "paxcounter",
"affinity": "BLOB",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"num"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "packet",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `myNodeNum` INTEGER NOT NULL DEFAULT 0, `port_num` INTEGER NOT NULL, `contact_key` TEXT NOT NULL, `received_time` INTEGER NOT NULL, `read` INTEGER NOT NULL DEFAULT 1, `data` TEXT NOT NULL, `packet_id` INTEGER NOT NULL DEFAULT 0, `routing_error` INTEGER NOT NULL DEFAULT -1)",
"fields": [
{
"fieldPath": "uuid",
"columnName": "uuid",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "myNodeNum",
"columnName": "myNodeNum",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "port_num",
"columnName": "port_num",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "contact_key",
"columnName": "contact_key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "received_time",
"columnName": "received_time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "read",
"columnName": "read",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "1"
},
{
"fieldPath": "data",
"columnName": "data",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "packetId",
"columnName": "packet_id",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "routingError",
"columnName": "routing_error",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "-1"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"uuid"
]
},
"indices": [
{
"name": "index_packet_myNodeNum",
"unique": false,
"columnNames": [
"myNodeNum"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_packet_myNodeNum` ON `${TABLE_NAME}` (`myNodeNum`)"
},
{
"name": "index_packet_port_num",
"unique": false,
"columnNames": [
"port_num"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_packet_port_num` ON `${TABLE_NAME}` (`port_num`)"
},
{
"name": "index_packet_contact_key",
"unique": false,
"columnNames": [
"contact_key"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_packet_contact_key` ON `${TABLE_NAME}` (`contact_key`)"
}
],
"foreignKeys": []
},
{
"tableName": "contact_settings",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`contact_key` TEXT NOT NULL, `muteUntil` INTEGER NOT NULL, PRIMARY KEY(`contact_key`))",
"fields": [
{
"fieldPath": "contact_key",
"columnName": "contact_key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "muteUntil",
"columnName": "muteUntil",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"contact_key"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "log",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `type` TEXT NOT NULL, `received_date` INTEGER NOT NULL, `message` TEXT NOT NULL, `from_num` INTEGER NOT NULL DEFAULT 0, `port_num` INTEGER NOT NULL DEFAULT 0, `from_radio` BLOB NOT NULL DEFAULT x'', PRIMARY KEY(`uuid`))",
"fields": [
{
"fieldPath": "uuid",
"columnName": "uuid",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "message_type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "received_date",
"columnName": "received_date",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "raw_message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "fromNum",
"columnName": "from_num",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "portNum",
"columnName": "port_num",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "fromRadio",
"columnName": "from_radio",
"affinity": "BLOB",
"notNull": true,
"defaultValue": "x''"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"uuid"
]
},
"indices": [
{
"name": "index_log_from_num",
"unique": false,
"columnNames": [
"from_num"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_log_from_num` ON `${TABLE_NAME}` (`from_num`)"
},
{
"name": "index_log_port_num",
"unique": false,
"columnNames": [
"port_num"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_log_port_num` ON `${TABLE_NAME}` (`port_num`)"
}
],
"foreignKeys": []
},
{
"tableName": "quick_chat",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `message` TEXT NOT NULL, `mode` TEXT NOT NULL, `position` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "uuid",
"columnName": "uuid",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "mode",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"uuid"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '23eb673bdcd4e1af18a662f0b49bfebf')"
]
}
}

Wyświetl plik

@ -5,6 +5,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.geeksville.mesh.database.MeshtasticDatabase
import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.model.NodeSortOption
import kotlinx.coroutines.flow.first
@ -35,9 +36,8 @@ class NodeInfoDaoTest {
latitude = 30.267153, longitude = -97.743057 // Austin
)
private val myNodeInfo: MyNodeInfo = MyNodeInfo(
private val myNodeInfo: MyNodeEntity = MyNodeEntity(
myNodeNum = ourNode.num,
hasGPS = false,
model = null,
firmwareVersion = null,
couldUpdate = false,
@ -47,8 +47,6 @@ class NodeInfoDaoTest {
minAppVersion = 1,
maxChannels = 8,
hasWifi = false,
channelUtilization = 0f,
airUtilTx = 0f,
)
private val testPositions = arrayOf(

Wyświetl plik

@ -6,6 +6,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import com.geeksville.mesh.database.MeshtasticDatabase
import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.dao.PacketDao
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.Packet
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
@ -22,9 +23,8 @@ class PacketDaoTest {
private lateinit var nodeInfoDao: NodeInfoDao
private lateinit var packetDao: PacketDao
private val myNodeInfo: MyNodeInfo = MyNodeInfo(
private val myNodeInfo: MyNodeEntity = MyNodeEntity(
myNodeNum = 42424242,
hasGPS = false,
model = null,
firmwareVersion = null,
couldUpdate = false,
@ -34,8 +34,6 @@ class PacketDaoTest {
minAppVersion = 1,
maxChannels = 8,
hasWifi = false,
channelUtilization = 0f,
airUtilTx = 0f,
)
private val myNodeNum: Int get() = myNodeInfo.myNodeNum

Wyświetl plik

@ -1,20 +1,11 @@
package com.geeksville.mesh
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
import kotlinx.parcelize.Parcelize
/**
* Room [Entity] and [PrimaryKey] annotations and imports can be removed when only using the API.
* For details check the AIDL interface in [com.geeksville.mesh.IMeshService]
*/
// MyNodeInfo sent via special protobuf from radio
@Parcelize
@Entity(tableName = "MyNodeInfo")
data class MyNodeInfo(
@PrimaryKey(autoGenerate = false)
val myNodeNum: Int,
val hasGPS: Boolean,
val model: String?,

Wyświetl plik

@ -2,22 +2,12 @@ package com.geeksville.mesh
import android.graphics.Color
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.geeksville.mesh.util.GPSFormat
import com.geeksville.mesh.util.bearing
import com.geeksville.mesh.util.latLongToMeter
import com.geeksville.mesh.util.anonymize
import kotlinx.parcelize.Parcelize
/**
* Room [Embedded], [Entity] and [PrimaryKey] annotations and imports, as well as any protobuf
* reference [MeshProtos], [TelemetryProtos], [ConfigProtos] can be removed when only using the API.
* For details check the AIDL interface in [com.geeksville.mesh.IMeshService]
*/
//
// model objects that directly map to the corresponding protobufs
//
@ -29,7 +19,6 @@ data class MeshUser(
val shortName: String,
val hwModel: MeshProtos.HardwareModel,
val isLicensed: Boolean = false,
@ColumnInfo(name = "role", defaultValue = "0")
val role: Int = 0,
) : Parcelable {
@ -53,16 +42,6 @@ data class MeshUser(
p.roleValue
)
fun toProto(): MeshProtos.User =
MeshProtos.User.newBuilder()
.setId(id)
.setLongName(longName)
.setShortName(shortName)
.setHwModel(hwModel)
.setIsLicensed(isLicensed)
.setRoleValue(role)
.build()
/** a string version of the hardware model, converted into pretty lowercase and changing _ to -, and p to dot
* or null if unset
* */
@ -172,67 +151,19 @@ data class EnvironmentMetrics(
companion object {
fun currentTime() = (System.currentTimeMillis() / 1000).toInt()
}
/** Create our model object from a protobuf.
*/
constructor(t: TelemetryProtos.EnvironmentMetrics, telemetryTime: Int = currentTime()) : this(
telemetryTime,
t.temperature,
t.relativeHumidity,
t.barometricPressure,
t.gasResistance,
t.voltage,
t.current,
t.iaq,
)
fun getDisplayString(inFahrenheit: Boolean = false): String {
val temp = if (temperature != 0f) {
if (inFahrenheit) {
val fahrenheit = temperature * 1.8F + 32
String.format("%.1f°F", fahrenheit)
} else {
String.format("%.1f°C", temperature)
}
} else null
val humidity = if (relativeHumidity != 0f) String.format("%.0f%%", relativeHumidity) else null
val pressure = if (barometricPressure != 0f) String.format("%.1fhPa", barometricPressure) else null
val gas = if (gasResistance != 0f) String.format("%.0fMΩ", gasResistance) else null
val voltage = if (voltage != 0f) String.format("%.2fV", voltage) else null
val current = if (current != 0f) String.format("%.1fmA", current) else null
val iaq = if (iaq != 0) "IAQ: $iaq" else null
return listOfNotNull(
temp,
humidity,
pressure,
gas,
voltage,
current,
iaq,
).joinToString(" ")
}
}
@Parcelize
@Entity(tableName = "NodeInfo")
data class NodeInfo(
@PrimaryKey(autoGenerate = false)
val num: Int, // This is immutable, and used as a key
@Embedded(prefix = "user_")
var user: MeshUser? = null,
@Embedded(prefix = "position_")
var position: Position? = null,
var snr: Float = Float.MAX_VALUE,
var rssi: Int = Int.MAX_VALUE,
var lastHeard: Int = 0, // the last time we've seen this node in secs since 1970
@Embedded(prefix = "devMetrics_")
var deviceMetrics: DeviceMetrics? = null,
var channel: Int = 0,
@Embedded(prefix = "envMetrics_")
var environmentMetrics: EnvironmentMetrics? = null,
@ColumnInfo(name = "hopsAway", defaultValue = "0")
var hopsAway: Int = 0
) : Parcelable {

Wyświetl plik

@ -3,25 +3,25 @@ package com.geeksville.mesh.database
import android.content.Context
import androidx.room.AutoMigration
import androidx.room.Database
import androidx.room.DeleteTable
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.geeksville.mesh.MyNodeInfo
import com.geeksville.mesh.NodeInfo
import androidx.room.migration.AutoMigrationSpec
import com.geeksville.mesh.database.dao.PacketDao
import com.geeksville.mesh.database.dao.MeshLogDao
import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.dao.QuickChatActionDao
import com.geeksville.mesh.database.entity.ContactSettings
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.QuickChatAction
@Database(
entities = [
MyNodeInfo::class,
NodeInfo::class,
MyNodeEntity::class,
NodeEntity::class,
Packet::class,
ContactSettings::class,
@ -38,8 +38,9 @@ import com.geeksville.mesh.database.entity.QuickChatAction
AutoMigration (from = 9, to = 10),
AutoMigration (from = 10, to = 11),
AutoMigration (from = 11, to = 12),
AutoMigration(from = 12, to = 13, spec = AutoMigration12to13::class),
],
version = 12,
version = 13,
exportSchema = true,
)
@TypeConverters(Converters::class)
@ -62,3 +63,9 @@ abstract class MeshtasticDatabase : RoomDatabase() {
}
}
}
@DeleteTable.Entries(
DeleteTable(tableName = "NodeInfo"),
DeleteTable(tableName = "MyNodeInfo")
)
class AutoMigration12to13 : AutoMigrationSpec

Wyświetl plik

@ -6,27 +6,27 @@ import androidx.room.MapColumn
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Upsert
import com.geeksville.mesh.MyNodeInfo
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import kotlinx.coroutines.flow.Flow
@Dao
interface NodeInfoDao {
@Query("SELECT * FROM MyNodeInfo")
fun getMyNodeInfo(): Flow<MyNodeInfo?>
@Query("SELECT * FROM my_node")
fun getMyNodeInfo(): Flow<MyNodeEntity?>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun setMyNodeInfo(myInfo: MyNodeInfo)
fun setMyNodeInfo(myInfo: MyNodeEntity)
@Query("DELETE FROM MyNodeInfo")
@Query("DELETE FROM my_node")
fun clearMyNodeInfo()
@Query(
"""
SELECT * FROM nodes
ORDER BY CASE
WHEN num = (SELECT myNodeNum FROM MyNodeInfo LIMIT 1) THEN 0
WHEN num = (SELECT myNodeNum FROM my_node LIMIT 1) THEN 0
ELSE 1
END,
last_heard DESC
@ -39,7 +39,7 @@ interface NodeInfoDao {
WITH OurNode AS (
SELECT latitude, longitude
FROM nodes
WHERE num = (SELECT myNodeNum FROM MyNodeInfo LIMIT 1)
WHERE num = (SELECT myNodeNum FROM my_node LIMIT 1)
)
SELECT * FROM nodes
WHERE (:includeUnknown = 1 OR short_name IS NOT NULL)
@ -47,7 +47,7 @@ interface NodeInfoDao {
OR (long_name LIKE '%' || :filter || '%'
OR short_name LIKE '%' || :filter || '%'))
ORDER BY CASE
WHEN num = (SELECT myNodeNum FROM MyNodeInfo LIMIT 1) THEN 0
WHEN num = (SELECT myNodeNum FROM my_node LIMIT 1) THEN 0
ELSE 1
END,
CASE

Wyświetl plik

@ -19,7 +19,7 @@ interface PacketDao {
@Query(
"""
SELECT * FROM packet
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM MyNodeInfo))
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
AND port_num = :portNum
ORDER BY received_time ASC
"""
@ -29,7 +29,7 @@ interface PacketDao {
@Query(
"""
SELECT * FROM packet
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM MyNodeInfo))
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
AND port_num = 1
ORDER BY received_time DESC
"""
@ -39,7 +39,7 @@ interface PacketDao {
@Query(
"""
SELECT COUNT(*) FROM packet
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM MyNodeInfo))
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
AND port_num = 1 AND contact_key = :contact
"""
)
@ -48,7 +48,7 @@ interface PacketDao {
@Query(
"""
SELECT COUNT(*) FROM packet
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM MyNodeInfo))
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
AND port_num = 1 AND contact_key = :contact AND read = 0
"""
)
@ -58,7 +58,7 @@ interface PacketDao {
"""
UPDATE packet
SET read = 1
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM MyNodeInfo))
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
AND port_num = 1 AND contact_key = :contact AND read = 0 AND received_time <= :timestamp
"""
)
@ -70,7 +70,7 @@ interface PacketDao {
@Query(
"""
SELECT * FROM packet
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM MyNodeInfo))
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
AND port_num = 1 AND contact_key = :contact
ORDER BY received_time DESC
"""
@ -80,7 +80,7 @@ interface PacketDao {
@Query(
"""
SELECT * FROM packet
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM MyNodeInfo))
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
AND data = :data
"""
)
@ -92,7 +92,7 @@ interface PacketDao {
@Query(
"""
DELETE FROM packet
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM MyNodeInfo))
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
AND contact_key IN (:contactList)
"""
)
@ -124,7 +124,7 @@ interface PacketDao {
@Query(
"""
SELECT data FROM packet
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM MyNodeInfo))
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
ORDER BY received_time ASC
"""
)
@ -133,7 +133,7 @@ interface PacketDao {
@Query(
"""
SELECT * FROM packet
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM MyNodeInfo))
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
AND packet_id = :requestId
ORDER BY received_time DESC
"""
@ -147,7 +147,7 @@ interface PacketDao {
@Query(
"""
SELECT * FROM packet
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM MyNodeInfo))
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
AND port_num = 8
ORDER BY received_time ASC
"""

Wyświetl plik

@ -0,0 +1,39 @@
package com.geeksville.mesh.database.entity
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.geeksville.mesh.MyNodeInfo
@Entity(tableName = "my_node")
data class MyNodeEntity(
@PrimaryKey(autoGenerate = false)
val myNodeNum: Int,
val model: String?,
val firmwareVersion: String?,
val couldUpdate: Boolean, // this application contains a software load we _could_ install if you want
val shouldUpdate: Boolean, // this device has old firmware
val currentPacketId: Long,
val messageTimeoutMsec: Int,
val minAppVersion: Int,
val maxChannels: Int,
val hasWifi: Boolean,
) {
/** A human readable description of the software/hardware version */
val firmwareString: String get() = "$model $firmwareVersion"
fun toMyNodeInfo() = MyNodeInfo(
myNodeNum = myNodeNum,
hasGPS = false,
model = model,
firmwareVersion = firmwareVersion,
couldUpdate = couldUpdate,
shouldUpdate = shouldUpdate,
currentPacketId = currentPacketId,
messageTimeoutMsec = messageTimeoutMsec,
minAppVersion = minAppVersion,
maxChannels = maxChannels,
hasWifi = hasWifi,
channelUtilization = 0f,
airUtilTx = 0f,
)
}

Wyświetl plik

@ -2,8 +2,8 @@ package com.geeksville.mesh.model
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import com.geeksville.mesh.MyNodeInfo
import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
@ -20,8 +20,8 @@ class NodeDB @Inject constructor(
private val nodeInfoDao: NodeInfoDao,
) {
// hardware info about our local device (can be null)
private val _myNodeInfo = MutableStateFlow<MyNodeInfo?>(null)
val myNodeInfo: StateFlow<MyNodeInfo?> get() = _myNodeInfo
private val _myNodeInfo = MutableStateFlow<MyNodeEntity?>(null)
val myNodeInfo: StateFlow<MyNodeEntity?> get() = _myNodeInfo
// our node info
private val _ourNodeInfo = MutableStateFlow<NodeEntity?>(null)
@ -65,9 +65,9 @@ class NodeDB @Inject constructor(
nodeInfoDao.upsert(node)
}
suspend fun installNodeDB(mi: MyNodeInfo, nodes: List<NodeEntity>) = withContext(Dispatchers.IO) {
suspend fun installNodeDB(mi: MyNodeEntity, nodes: List<NodeEntity>) = withContext(Dispatchers.IO) {
nodeInfoDao.clearMyNodeInfo()
nodeInfoDao.setMyNodeInfo(mi) // set MyNodeInfo first
nodeInfoDao.setMyNodeInfo(mi) // set MyNodeEntity first
nodeInfoDao.clearNodeInfo()
nodeInfoDao.putAll(nodes)
}

Wyświetl plik

@ -12,12 +12,12 @@ import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.IMeshService
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.ModuleConfigProtos
import com.geeksville.mesh.MyNodeInfo
import com.geeksville.mesh.Portnums
import com.geeksville.mesh.Position
import com.geeksville.mesh.R
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.config
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.deviceProfile
import com.geeksville.mesh.moduleConfig
@ -102,7 +102,7 @@ class RadioConfigViewModel @Inject constructor(
debug("RadioConfigViewModel created")
}
private val myNodeInfo: StateFlow<MyNodeInfo?> get() = radioConfigRepository.myNodeInfo
private val myNodeInfo: StateFlow<MyNodeEntity?> get() = radioConfigRepository.myNodeInfo
val myNodeNum get() = myNodeInfo.value?.myNodeNum
val maxChannels get() = myNodeInfo.value?.maxChannels ?: 8

Wyświetl plik

@ -21,6 +21,7 @@ import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.database.QuickChatActionRepository
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.QuickChatAction
@ -238,7 +239,7 @@ class UIViewModel @Inject constructor(
)
// hardware info about our local device (can be null)
val myNodeInfo: StateFlow<MyNodeInfo?> get() = nodeDB.myNodeInfo
val myNodeInfo: StateFlow<MyNodeEntity?> get() = nodeDB.myNodeInfo
val ourNodeInfo: StateFlow<NodeEntity?> get() = nodeDB.ourNodeInfo
val nodesWithPosition get() = nodeDB.nodeDBbyNum.value.values.filter { it.validPosition != null }

Wyświetl plik

@ -10,7 +10,7 @@ import com.geeksville.mesh.LocalOnlyProtos.LocalConfig
import com.geeksville.mesh.LocalOnlyProtos.LocalModuleConfig
import com.geeksville.mesh.MeshProtos.MeshPacket
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig
import com.geeksville.mesh.MyNodeInfo
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.deviceProfile
import com.geeksville.mesh.model.NodeDB
@ -47,9 +47,9 @@ class RadioConfigRepository @Inject constructor(
val myId: StateFlow<String?> get() = nodeDB.myId
/**
* Flow representing the [MyNodeInfo] database.
* Flow representing the [MyNodeEntity] database.
*/
val myNodeInfo: StateFlow<MyNodeInfo?> get() = nodeDB.myNodeInfo
val myNodeInfo: StateFlow<MyNodeEntity?> get() = nodeDB.myNodeInfo
/**
* Flow representing the [NodeEntity] database.
@ -57,7 +57,7 @@ class RadioConfigRepository @Inject constructor(
val nodeDBbyNum: StateFlow<Map<Int, NodeEntity>> get() = nodeDB.nodeDBbyNum
suspend fun upsert(node: NodeEntity) = nodeDB.upsert(node)
suspend fun installNodeDB(mi: MyNodeInfo, nodes: List<NodeEntity>) {
suspend fun installNodeDB(mi: MyNodeEntity, nodes: List<NodeEntity>) {
nodeDB.installNodeDB(mi, nodes)
}

Wyświetl plik

@ -22,6 +22,7 @@ import com.geeksville.mesh.android.hasLocationPermission
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.toNodeInfo
@ -352,7 +353,7 @@ class MeshService : Service(), Logging {
haveNodeDB = false
}
private var myNodeInfo: MyNodeInfo? = null
private var myNodeInfo: MyNodeEntity? = null
private val configTotal by lazy { ConfigProtos.Config.getDescriptor().fields.size }
private val moduleTotal by lazy { ModuleConfigProtos.ModuleConfig.getDescriptor().fields.size }
@ -1316,7 +1317,7 @@ class MeshService : Service(), Logging {
}
/// A provisional MyNodeInfo that we will install if all of our node config downloads go okay
private var newMyNodeInfo: MyNodeInfo? = null
private var newMyNodeInfo: MyNodeEntity? = null
/// provisional NodeInfos we will install if all goes well
private val newNodes = mutableListOf<MeshProtos.NodeInfo>()
@ -1436,9 +1437,8 @@ class MeshService : Service(), Logging {
val myInfo = rawMyNodeInfo
if (myInfo != null) {
val mi = with(myInfo) {
MyNodeInfo(
MyNodeEntity(
myNodeNum = myNodeNum,
hasGPS = false,
model = rawDeviceMetadata?.hwModel?.let { hwModel ->
if (hwModel == MeshProtos.HardwareModel.UNSET) null
else hwModel.name.replace('_', '-').replace('p', '.').lowercase()
@ -1451,8 +1451,6 @@ class MeshService : Service(), Logging {
minAppVersion = minAppVersion,
maxChannels = 8,
hasWifi = rawDeviceMetadata?.hasWifi ?: false,
channelUtilization = 0f,
airUtilTx = 0f,
)
}
newMyNodeInfo = mi
@ -1743,7 +1741,7 @@ class MeshService : Service(), Logging {
// TODO reimplement this after we have a new firmware update mechanism
}
override fun getMyNodeInfo(): MyNodeInfo? = this@MeshService.myNodeInfo
override fun getMyNodeInfo(): MyNodeInfo? = this@MeshService.myNodeInfo?.toMyNodeInfo()
override fun getMyId() = toRemoteExceptions { myNodeID }