add ModuleConfig settings (#526)

This commit is contained in:
Andre K 2022-11-22 22:01:37 -03:00 committed by GitHub
parent 36cb78a332
commit 689e7e7eca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 938 additions and 74 deletions

View file

@ -7,6 +7,7 @@ import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
import androidx.datastore.dataStoreFile
import com.geeksville.mesh.AppOnlyProtos.ChannelSet
import com.geeksville.mesh.LocalOnlyProtos.LocalConfig
import com.geeksville.mesh.LocalOnlyProtos.LocalModuleConfig
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -34,6 +35,19 @@ object DataStoreModule {
)
}
@Singleton
@Provides
fun provideModuleConfigDataStore(@ApplicationContext appContext: Context): DataStore<LocalModuleConfig> {
return DataStoreFactory.create(
serializer = ModuleConfigSerializer,
produceFile = { appContext.dataStoreFile("module_config.pb") },
corruptionHandler = ReplaceFileCorruptionHandler(
produceNewData = { LocalModuleConfig.getDefaultInstance() }
),
scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
)
}
@Singleton
@Provides
fun provideChannelSetDataStore(@ApplicationContext appContext: Context): DataStore<ChannelSet> {

View file

@ -2,13 +2,13 @@ package com.geeksville.mesh.repository.datastore
import androidx.datastore.core.DataStore
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.ConfigProtos.Config
import com.geeksville.mesh.LocalOnlyProtos.LocalConfig
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.asSharedFlow
import java.io.IOException
import javax.inject.Inject
@ -30,20 +30,15 @@ class LocalConfigRepository @Inject constructor(
}
}
private val _sendDeviceConfigFlow = MutableSharedFlow<ConfigProtos.Config>()
val sendDeviceConfigFlow = _sendDeviceConfigFlow.asSharedFlow()
private suspend fun sendDeviceConfig(config: ConfigProtos.Config) {
debug("Sending device config!")
_sendDeviceConfigFlow.emit(config)
}
private val _setConfigFlow = MutableSharedFlow<Config>()
val setConfigFlow: SharedFlow<Config> = _setConfigFlow
/**
* Update LocalConfig and send ConfigProtos.Config Oneof to the radio
*/
suspend fun setRadioConfig(config: ConfigProtos.Config) {
suspend fun setConfig(config: Config) {
setLocalConfig(config)
sendDeviceConfig(config)
_setConfigFlow.emit(config)
}
suspend fun clearLocalConfig() {
@ -55,7 +50,7 @@ class LocalConfigRepository @Inject constructor(
/**
* Update LocalConfig from each ConfigProtos.Config Oneof
*/
suspend fun setLocalConfig(config: ConfigProtos.Config) {
suspend fun setLocalConfig(config: Config) {
if (config.hasDevice()) setDeviceConfig(config.device)
if (config.hasPosition()) setPositionConfig(config.position)
if (config.hasPower()) setPowerConfig(config.power)
@ -65,44 +60,44 @@ class LocalConfigRepository @Inject constructor(
if (config.hasBluetooth()) setBluetoothConfig(config.bluetooth)
}
private suspend fun setDeviceConfig(config: ConfigProtos.Config.DeviceConfig) {
private suspend fun setDeviceConfig(config: Config.DeviceConfig) {
localConfigStore.updateData { preference ->
preference.toBuilder().setDevice(config).build()
}
}
private suspend fun setPositionConfig(config: ConfigProtos.Config.PositionConfig) {
private suspend fun setPositionConfig(config: Config.PositionConfig) {
localConfigStore.updateData { preference ->
preference.toBuilder().setPosition(config).build()
}
}
private suspend fun setPowerConfig(config: ConfigProtos.Config.PowerConfig) {
private suspend fun setPowerConfig(config: Config.PowerConfig) {
localConfigStore.updateData { preference ->
preference.toBuilder().setPower(config).build()
}
}
private suspend fun setWifiConfig(config: ConfigProtos.Config.NetworkConfig) {
private suspend fun setWifiConfig(config: Config.NetworkConfig) {
localConfigStore.updateData { preference ->
preference.toBuilder().setNetwork(config).build()
}
}
private suspend fun setDisplayConfig(config: ConfigProtos.Config.DisplayConfig) {
private suspend fun setDisplayConfig(config: Config.DisplayConfig) {
localConfigStore.updateData { preference ->
preference.toBuilder().setDisplay(config).build()
}
}
private suspend fun setLoraConfig(config: ConfigProtos.Config.LoRaConfig) {
private suspend fun setLoraConfig(config: Config.LoRaConfig) {
localConfigStore.updateData { preference ->
preference.toBuilder().setLora(config).build()
}
channelSetRepository.setLoraConfig(config)
}
private suspend fun setBluetoothConfig(config: ConfigProtos.Config.BluetoothConfig) {
private suspend fun setBluetoothConfig(config: Config.BluetoothConfig) {
localConfigStore.updateData { preference ->
preference.toBuilder().setBluetooth(config).build()
}

View file

@ -0,0 +1,100 @@
package com.geeksville.mesh.repository.datastore
import androidx.datastore.core.DataStore
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig
import com.geeksville.mesh.LocalOnlyProtos.LocalModuleConfig
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.first
import java.io.IOException
import javax.inject.Inject
/**
* Class that handles saving and retrieving config settings
*/
class ModuleConfigRepository @Inject constructor(
private val moduleConfigStore: DataStore<LocalModuleConfig>,
) : Logging {
val moduleConfigFlow: Flow<LocalModuleConfig> = moduleConfigStore.data
.catch { exception ->
// dataStore.data throws an IOException when an error is encountered when reading data
if (exception is IOException) {
errormsg("Error reading LocalConfig settings: ${exception.message}")
emit(LocalModuleConfig.getDefaultInstance())
} else {
throw exception
}
}
suspend fun clearLocalModuleConfig() {
moduleConfigStore.updateData { preference ->
preference.toBuilder().clear().build()
}
}
/**
* Update LocalModuleConfig from each ModuleConfigProtos.ModuleConfig Oneof
*/
suspend fun setLocalModuleConfig(config: ModuleConfig) {
if (config.hasMqtt()) setMQTTConfig(config.mqtt)
if (config.hasSerial()) setSerialConfig(config.serial)
if (config.hasExternalNotification()) setExternalNotificationConfig(config.externalNotification)
if (config.hasStoreForward()) setStoreForwardConfig(config.storeForward)
if (config.hasRangeTest()) setRangeTestConfig(config.rangeTest)
if (config.hasTelemetry()) setTelemetryConfig(config.telemetry)
if (config.hasCannedMessage()) setCannedMessageConfig(config.cannedMessage)
if (config.hasAudio()) setAudioConfig(config.audio)
}
private suspend fun setMQTTConfig(config: ModuleConfig.MQTTConfig) {
moduleConfigStore.updateData { preference ->
preference.toBuilder().setMqtt(config).build()
}
}
private suspend fun setSerialConfig(config: ModuleConfig.SerialConfig) {
moduleConfigStore.updateData { preference ->
preference.toBuilder().setSerial(config).build()
}
}
private suspend fun setExternalNotificationConfig(config: ModuleConfig.ExternalNotificationConfig) {
moduleConfigStore.updateData { preference ->
preference.toBuilder().setExternalNotification(config).build()
}
}
private suspend fun setStoreForwardConfig(config: ModuleConfig.StoreForwardConfig) {
moduleConfigStore.updateData { preference ->
preference.toBuilder().setStoreForward(config).build()
}
}
private suspend fun setRangeTestConfig(config: ModuleConfig.RangeTestConfig) {
moduleConfigStore.updateData { preference ->
preference.toBuilder().setRangeTest(config).build()
}
}
private suspend fun setTelemetryConfig(config: ModuleConfig.TelemetryConfig) {
moduleConfigStore.updateData { preference ->
preference.toBuilder().setTelemetry(config).build()
}
}
private suspend fun setCannedMessageConfig(config: ModuleConfig.CannedMessageConfig) {
moduleConfigStore.updateData { preference ->
preference.toBuilder().setCannedMessage(config).build()
}
}
private suspend fun setAudioConfig(config: ModuleConfig.AudioConfig) {
moduleConfigStore.updateData { preference ->
preference.toBuilder().setAudio(config).build()
}
}
suspend fun fetchInitialModuleConfig() = moduleConfigStore.data.first()
}

View file

@ -0,0 +1,26 @@
package com.geeksville.mesh.repository.datastore
import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer
import com.geeksville.mesh.LocalOnlyProtos.LocalModuleConfig
import com.google.protobuf.InvalidProtocolBufferException
import java.io.InputStream
import java.io.OutputStream
/**
* Serializer for the [LocalModuleConfig] object defined in localonly.proto.
*/
@Suppress("BlockingMethodInNonBlockingContext")
object ModuleConfigSerializer : Serializer<LocalModuleConfig> {
override val defaultValue: LocalModuleConfig = LocalModuleConfig.getDefaultInstance()
override suspend fun readFrom(input: InputStream): LocalModuleConfig {
try {
return LocalModuleConfig.parseFrom(input)
} catch (exception: InvalidProtocolBufferException) {
throw CorruptionException("Cannot read proto.", exception)
}
}
override suspend fun writeTo(t: LocalModuleConfig, output: OutputStream) = t.writeTo(output)
}