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 @@
+
+
+
{
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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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" />
+
+
+ app:layout_constraintTop_toBottomOf="@+id/settings_btremote" />
IP address
Port
+ Bluetooth Output
+ Enable Bluetooth
+ Device
+ Output format
+
Other preferences
Show pass time in UTC
Enable radar sweep animation
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
fun saveDataSources(sources: List)