From dd76dcfc98d67144a9c0f5f944c090a0ff5c62dd Mon Sep 17 00:00:00 2001
From: Andrew <ajohns1288@gmail.com>
Date: Fri, 18 Mar 2022 14:35:14 -0400
Subject: [PATCH] Bluetooth added

---
 app/src/main/AndroidManifest.xml              |   4 +
 .../look4sat/framework/SettingsManager.kt     |  35 +++++
 .../rtbishop/look4sat/injection/BaseModule.kt |   5 +
 .../presentation/radarScreen/BTReporter.kt    | 134 ++++++++++++++++++
 .../radarScreen/RadarViewModel.kt             |  25 ++++
 .../settingsScreen/SettingsFragment.kt        |  36 ++++-
 .../settingsScreen/SettingsViewModel.kt       |  16 +++
 app/src/main/res/layout/card_btremote.xml     |  74 ++++++++++
 app/src/main/res/layout/fragment_settings.xml |  12 +-
 app/src/main/res/values/strings.xml           |   5 +
 .../look4sat/domain/ISettingsManager.kt       |  16 +++
 11 files changed, 359 insertions(+), 3 deletions(-)
 create mode 100644 app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/BTReporter.kt
 create mode 100644 app/src/main/res/layout/card_btremote.xml

diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 998bbbdc..71c49a71 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,10 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"  />
     <uses-permission android:name="android.permission.INTERNET" />
 
+    <uses-permission android:name="android.permission.BLUETOOTH"
+        android:maxSdkVersion="30" />
+    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+
     <application
         android:name=".presentation.MainApplication"
         android:icon="@mipmap/ic_launcher"
diff --git a/app/src/main/java/com/rtbishop/look4sat/framework/SettingsManager.kt b/app/src/main/java/com/rtbishop/look4sat/framework/SettingsManager.kt
index d353c008..2eb4ae18 100644
--- a/app/src/main/java/com/rtbishop/look4sat/framework/SettingsManager.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/framework/SettingsManager.kt
@@ -38,6 +38,10 @@ class SettingsManager @Inject constructor(private val prefs: SharedPreferences)
         const val keyRotator = "isRotatorEnabled"
         const val keyRotatorAddress = "rotatorAddress"
         const val keyRotatorPort = "rotatorPort"
+        const val keyBTEnabled = "isBTEnabled"
+        const val keyBTDeviceName = "BTDevice"
+        const val keyBTDeviceAddr = "BTDevice"
+        const val keyBTFormat = "BTFormat"
         const val keyLatitude = "stationLat"
         const val keyLongitude = "stationLon"
         const val keyLocator = "stationQTH"
@@ -148,6 +152,37 @@ class SettingsManager @Inject constructor(private val prefs: SharedPreferences)
         prefs.edit { putString(keyRotatorPort, value) }
     }
 
+    override fun getBTEnabled(): Boolean {
+        return prefs.getBoolean(keyBTEnabled, true)
+    }
+
+    override fun setBTEnabled(value: Boolean) {
+        prefs.edit { putBoolean(keyBTEnabled, value) }
+    }
+
+    override fun getBTDeviceAddr(): String {
+        return prefs.getString(keyBTDeviceAddr, null) ?: "00:0C:BF:13:80:5D"
+    }
+
+    override fun setBTDeviceAddr(value: String) {
+        prefs.edit { putString(keyBTDeviceAddr, value) }
+    }
+    override fun getBTDeviceName(): String {
+        return prefs.getString(keyBTDeviceName, null) ?: "Default"
+    }
+
+    override fun setBTDeviceName(value: String) {
+        prefs.edit { putString(keyBTDeviceName, value) }
+    }
+
+    override fun getBTFormat(): String {
+        return prefs.getString(keyBTFormat, null) ?: "W\$AZ \$EL"
+    }
+
+    override fun setBTFormat(value: String) {
+        prefs.edit { putString(keyBTFormat, value) }
+    }
+
     override fun loadDataSources(): List<String> {
         val sourcesList = prefs.getStringSet(keyDataSources, null)?.toList()
         return if (sourcesList.isNullOrEmpty()) defaultSources else sourcesList.sortedDescending()
diff --git a/app/src/main/java/com/rtbishop/look4sat/injection/BaseModule.kt b/app/src/main/java/com/rtbishop/look4sat/injection/BaseModule.kt
index 266b9cab..dadb4d59 100644
--- a/app/src/main/java/com/rtbishop/look4sat/injection/BaseModule.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/injection/BaseModule.kt
@@ -28,6 +28,7 @@ import com.rtbishop.look4sat.domain.predict.SatelliteManager
 import com.rtbishop.look4sat.framework.LocationManager
 import com.rtbishop.look4sat.framework.SettingsManager
 import com.rtbishop.look4sat.framework.data.*
+import com.rtbishop.look4sat.presentation.radarScreen.BTReporter
 import com.rtbishop.look4sat.utility.DataParser
 import com.rtbishop.look4sat.utility.DataReporter
 import dagger.Module
@@ -62,6 +63,10 @@ object BaseModule {
     @Singleton
     fun provideDataReporter(): DataReporter = DataReporter(CoroutineScope(Dispatchers.IO))
 
+    @Provides
+    @Singleton
+    fun provideBTReporter(): BTReporter = BTReporter(CoroutineScope(Dispatchers.IO))
+
     @Provides
     @Singleton
     fun provideLocationManager(manager: LocationManager): ILocationManager = manager
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/BTReporter.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/BTReporter.kt
new file mode 100644
index 00000000..e4f0acac
--- /dev/null
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/BTReporter.kt
@@ -0,0 +1,134 @@
+package com.rtbishop.look4sat.presentation.radarScreen
+
+import android.Manifest
+import android.content.Context
+import android.util.Log
+import android.widget.Toast
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.launch
+import java.net.InetSocketAddress
+import java.nio.ByteBuffer
+import java.nio.channels.SocketChannel
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothManager
+import android.bluetooth.BluetoothSocket
+import android.content.pm.PackageManager
+import androidx.core.app.ActivityCompat
+import java.io.OutputStream
+import java.util.*
+
+class BTReporter(private val reporterScope: CoroutineScope) {
+
+    private var rotationConnectBTJob: Job? = null
+    private var rotationReportingBT: Job? = null
+    private var satVisible=false
+    private var CRchar:Char = '\r'
+    private var NLchar:Char = '\n'
+    private var TBchar:Char = '\t'
+    private val bluetoothAdapter: BluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
+    private lateinit var mmOutStream: OutputStream
+    private val SPPID: UUID=UUID.fromString("00001101-0000-1000-8000-00805f9b34fb")
+    private var connected = false
+    private var connectInProgress = false
+
+    fun connectBTDevice(dev: String) {
+        if (!connected) {
+
+            rotationConnectBTJob = reporterScope.launch {
+                runCatching {
+                    connectInProgress = true
+                    val rotationBTDevice = bluetoothAdapter.getRemoteDevice(dev)
+                    val sock = rotationBTDevice.createInsecureRfcommSocketToServiceRecord(SPPID)
+                    sock.connect()
+                    mmOutStream = sock.outputStream
+                    connected = true
+
+                    connectInProgress = false
+                    Log.i("look4satBT", "Connected!")
+                }.onFailure { error: Throwable ->
+                    Log.e("BT Error", "${error.message}")
+                }
+            }
+        }
+
+    }
+
+
+    fun isBTConnected():Boolean
+    {
+        return connected
+    }
+
+    fun connectInProg():Boolean
+    {
+        return connectInProgress
+    }
+
+
+    fun reportRotationBT(dev: String, fmt: String, AZ: Int, EL: Int) {
+
+        runCatching {
+            var azStr:String
+            var elStr:String
+            satVisible=(EL>1)
+
+            //Need to add leading zeros to string to ensure always 3 digits.
+            //Ideally this could be done via the format string but this will do for now.
+            if(AZ<100){
+                if(AZ<10){
+                    azStr="00"
+                }
+                else
+                {
+                    azStr="0"
+                }
+                azStr=azStr.plus(AZ.toString())
+            }
+            else
+            {
+                azStr=AZ.toString()
+            }
+
+            if(EL<100){
+                if(EL<10){
+                    elStr="00"
+                }
+                else
+                {
+                    elStr="0"
+                }
+                if(satVisible) {
+                    elStr = elStr.plus(EL.toString())
+                }
+                else {
+                    elStr="000"
+                }
+
+            }
+            else
+            {
+                elStr=EL.toString()
+            }
+
+            var buffer = fmt.replace("\$AZ",azStr)
+            buffer = buffer.replace("\$EL",elStr)
+            buffer = buffer.replace("\\r",CRchar.toString())
+            buffer = buffer.replace("\\n",NLchar.toString())
+            buffer = buffer.replace("\\t",TBchar.toString())
+            Log.i("Output is", buffer)
+            if(connected) {
+                Log.i("Sending BT", buffer)
+                this.mmOutStream.write(buffer.toByteArray())
+                Log.i("Sent", buffer)
+            }
+        }.onFailure { error: Throwable ->
+            Log.e("BT Error","${error.message}")
+            connected=false
+        }
+    }
+}
+
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt
index 2cf6af1b..501d0d4e 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt
@@ -18,6 +18,7 @@
 package com.rtbishop.look4sat.presentation.radarScreen
 
 import android.hardware.GeomagneticField
+import android.util.Log
 import androidx.lifecycle.*
 import com.rtbishop.look4sat.domain.IDataRepository
 import com.rtbishop.look4sat.domain.ISatelliteManager
@@ -41,6 +42,7 @@ import javax.inject.Inject
 class RadarViewModel @Inject constructor(
     private val orientationManager: OrientationManager,
     private val reporter: DataReporter,
+    private val BTreporter: BTReporter,
     private val satelliteManager: ISatelliteManager,
     private val repository: IDataRepository,
     private val settings: ISettingsManager
@@ -60,6 +62,7 @@ class RadarViewModel @Inject constructor(
             pass?.let { satPass ->
                 emit(satPass)
                 sendPassData(satPass)
+                sendPassDataBT(satPass)
                 processTransmitters(satPass)
             }
         }
@@ -110,6 +113,28 @@ class RadarViewModel @Inject constructor(
         }
     }
 
+    private fun sendPassDataBT(satPass: SatPass) {
+        viewModelScope.launch {
+            while (isActive) {
+                val satPos = satelliteManager.getPosition(satPass.satellite, stationPos, Date().time)
+                if (settings.getBTEnabled()) {
+                    val server = settings.getBTDeviceAddr()
+                    if(BTreporter.isBTConnected()) {
+                        val port = settings.getBTFormat()
+                        val azimuth = satPos.azimuth.toDegrees().round(0).toInt()
+                        val elevation = satPos.elevation.toDegrees().round(0).toInt()
+                        BTreporter.reportRotationBT(server, port, azimuth, elevation)
+                    }
+                    else if(!BTreporter.connectInProg()) {
+                        Log.i("look4satBT", "Attempting to connect...")
+                        BTreporter.connectBTDevice(server)
+                    }
+                }
+                delay(2000)
+            }
+        }
+    }
+
     private fun processTransmitters(pass: SatPass) {
         viewModelScope.launch {
             delay(125)
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt
index 85be5278..350e7ada 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt
@@ -17,12 +17,15 @@
  */
 package com.rtbishop.look4sat.presentation.settingsScreen
 
+//import com.rtbishop.look4sat.BuildConfig
 import android.Manifest
+import android.bluetooth.BluetoothAdapter
 import android.content.Intent
 import android.net.Uri
 import android.os.Bundle
 import android.text.method.LinkMovementMethod
 import android.view.View
+import android.widget.ArrayAdapter
 import android.widget.Toast
 import androidx.activity.result.contract.ActivityResultContracts
 import androidx.core.widget.NestedScrollView
@@ -31,7 +34,6 @@ import androidx.fragment.app.Fragment
 import androidx.fragment.app.viewModels
 import androidx.lifecycle.asLiveData
 import androidx.navigation.fragment.findNavController
-import com.rtbishop.look4sat.BuildConfig
 import com.rtbishop.look4sat.R
 import com.rtbishop.look4sat.databinding.FragmentSettingsBinding
 import com.rtbishop.look4sat.domain.model.DataState
@@ -42,6 +44,7 @@ import com.rtbishop.look4sat.utility.isValidIPv4
 import com.rtbishop.look4sat.utility.isValidPort
 import dagger.hilt.android.AndroidEntryPoint
 
+
 @AndroidEntryPoint
 class SettingsFragment : Fragment(R.layout.fragment_settings) {
 
@@ -70,7 +73,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
                 if (y > newY) settingsFab.hide() else settingsFab.show()
             })
             settingsAbout.aboutVersion.text =
-                String.format(getString(R.string.app_version), BuildConfig.VERSION_NAME)
+                String.format(getString(R.string.app_version), 0)
             settingsBtnGithub.clickWithDebounce {
                 gotoUrl("https://github.com/rt-bishop/Look4Sat/")
             }
@@ -81,9 +84,12 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
                 gotoUrl("https://f-droid.org/en/packages/com.rtbishop.look4sat/")
             }
         }
+
+
         setupLocationCard()
         setupDataCard()
         setupRemoteCard()
+        setupBTCard()
         setupOtherCard()
         setupOutroCard()
         viewModel.stationPosition.asLiveData().observe(viewLifecycleOwner) { stationPos ->
@@ -162,6 +168,32 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
         }
     }
 
+    private fun setupBTCard() {
+
+        binding.run {
+            settingsBtremote.BTremoteSwitch.apply {
+                isChecked = viewModel.getBTEnabled()
+                settingsBtremote.BTremoteAddress.isEnabled = isChecked
+                settingsBtremote.BTremoteFormat.isEnabled = isChecked
+                settingsBtremote.BTAddressEdit.setText(viewModel.getBTDeviceAddr())
+                settingsBtremote.BTFormatEdit.setText(viewModel.getBTFormat())
+                setOnCheckedChangeListener { _, isChecked ->
+                    viewModel.setBTEnabled(isChecked)
+                    settingsBtremote.BTremoteAddress.isEnabled = isChecked
+                    settingsBtremote.BTremoteFormat.isEnabled = isChecked
+                }
+            }
+
+            settingsBtremote.BTAddressEdit.doOnTextChanged { text, _, _, _ ->
+                viewModel.setBTDeviceAddr(text.toString())
+            }
+
+            settingsBtremote.BTFormatEdit.doOnTextChanged { text, _, _, _ ->
+                viewModel.setBTFormat(text.toString())
+            }
+        }
+    }
+
     private fun setupOtherCard() {
         binding.run {
             settingsOther.otherSwitchUtc.apply {
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsViewModel.kt
index ac78f754..4d69f906 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsViewModel.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsViewModel.kt
@@ -75,6 +75,22 @@ class SettingsViewModel @Inject constructor(
 
     fun setRotatorPort(value: String) = settings.setRotatorPort(value)
 
+    fun getBTEnabled(): Boolean = settings.getBTEnabled()
+
+    fun setBTEnabled(value: Boolean) = settings.setBTEnabled(value)
+
+    fun getBTFormat(): String = settings.getBTFormat()
+
+    fun setBTFormat(value: String) = settings.setBTFormat(value)
+
+    fun getBTDeviceName(): String = settings.getBTDeviceName()
+
+    fun setBTDeviceName(value: String) = settings.setBTDeviceName(value)
+
+    fun getBTDeviceAddr(): String = settings.getBTDeviceAddr()
+
+    fun setBTDeviceAddr(value: String) = settings.setBTDeviceAddr(value)
+
     fun getUpdateState() = repository.updateState
 
     fun setUpdateHandled() = repository.setUpdateStateHandled()
diff --git a/app/src/main/res/layout/card_btremote.xml b/app/src/main/res/layout/card_btremote.xml
new file mode 100644
index 00000000..ca72fc19
--- /dev/null
+++ b/app/src/main/res/layout/card_btremote.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    style="@style/SurfaceCard">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <TextView
+            android:id="@+id/BTremote_title"
+            style="@style/SettingsTitle"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="12dp"
+            android:layout_marginTop="10dp"
+            android:layout_marginEnd="12dp"
+            android:text="@string/BTremote_title"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <com.google.android.material.switchmaterial.SwitchMaterial
+            android:id="@+id/BTremote_switch"
+            style="@style/SettingsText"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:minHeight="42dp"
+            android:text="@string/BTremote_switch"
+            app:layout_constraintEnd_toEndOf="@+id/BTremote_title"
+            app:layout_constraintStart_toStartOf="@+id/BTremote_title"
+            app:layout_constraintTop_toBottomOf="@+id/BTremote_title"
+            app:trackTint="@color/textDisabled" />
+
+
+        <com.google.android.material.textfield.TextInputLayout
+            android:id="@+id/BTremote_address"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            app:layout_constraintTop_toBottomOf="@id/BTremote_switch"
+            app:layout_constraintEnd_toEndOf="@+id/BTremote_title"
+            app:layout_constraintStart_toStartOf="@+id/BTremote_title"
+            tools:layout_editor_absoluteY="70dp">
+
+        <com.google.android.material.textfield.TextInputEditText
+            android:id="@+id/BT_address_edit"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:hint="@string/BTremote_device_hint"
+            android:textColorHint="@color/textMain" />
+        </com.google.android.material.textfield.TextInputLayout>
+
+        <com.google.android.material.textfield.TextInputLayout
+            android:id="@+id/BTremote_format"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            app:layout_constraintTop_toBottomOf="@id/BTremote_address"
+            app:layout_constraintEnd_toEndOf="@+id/BTremote_title"
+            app:layout_constraintStart_toStartOf="@+id/BTremote_title"
+            tools:layout_editor_absoluteY="70dp">
+
+            <com.google.android.material.textfield.TextInputEditText
+                android:id="@+id/BT_format_edit"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:hint="@string/BTremote_output_hint"
+                android:textColorHint="@color/textMain" />
+
+        </com.google.android.material.textfield.TextInputLayout>
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</androidx.cardview.widget.CardView>
diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml
index 3cfa5139..d3604d78 100644
--- a/app/src/main/res/layout/fragment_settings.xml
+++ b/app/src/main/res/layout/fragment_settings.xml
@@ -82,6 +82,16 @@
                     app:layout_constraintStart_toStartOf="parent"
                     app:layout_constraintTop_toBottomOf="@+id/settings_data" />
 
+                <include
+                    android:id="@+id/settings_btremote"
+                    layout="@layout/card_btremote"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/view_default_margin"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toBottomOf="@+id/settings_remote" />
+
                 <include
                     android:id="@+id/settings_other"
                     layout="@layout/card_other"
@@ -90,7 +100,7 @@
                     android:layout_marginTop="@dimen/view_default_margin"
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toBottomOf="@+id/settings_remote" />
+                    app:layout_constraintTop_toBottomOf="@+id/settings_btremote" />
 
                 <include
                     android:id="@+id/settings_outro"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7c419165..d20ef091 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -139,6 +139,11 @@
     <string name="remote_ip_hint">IP address</string>
     <string name="remote_port_hint">Port</string>
 
+    <string name="BTremote_title">Bluetooth Output</string>
+    <string name="BTremote_switch">Enable Bluetooth</string>
+    <string name="BTremote_device_hint">Device</string>
+    <string name="BTremote_output_hint">Output format</string>
+
     <string name="other_title">Other preferences</string>
     <string name="other_switch_utc">Show pass time in UTC</string>
     <string name="other_switch_sweep">Enable radar sweep animation</string>
diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/ISettingsManager.kt b/base/src/main/java/com/rtbishop/look4sat/domain/ISettingsManager.kt
index 17ec4b63..1bc0a946 100644
--- a/base/src/main/java/com/rtbishop/look4sat/domain/ISettingsManager.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/domain/ISettingsManager.kt
@@ -77,6 +77,22 @@ interface ISettingsManager {
 
     fun setRotatorPort(value: String)
 
+    fun getBTEnabled(): Boolean
+
+    fun setBTEnabled(value: Boolean)
+
+    fun getBTDeviceAddr(): String
+
+    fun setBTDeviceAddr(value: String)
+
+    fun getBTDeviceName(): String
+
+    fun setBTDeviceName(value: String)
+
+    fun getBTFormat(): String
+
+    fun setBTFormat(value: String)
+
     fun loadDataSources(): List<String>
 
     fun saveDataSources(sources: List<String>)