diff --git a/app/src/main/java/com/rtbishop/look4sat/data/model/SatPass.kt b/app/src/main/java/com/rtbishop/look4sat/data/model/SatPass.kt index 051a2c06..a79d0214 100644 --- a/app/src/main/java/com/rtbishop/look4sat/data/model/SatPass.kt +++ b/app/src/main/java/com/rtbishop/look4sat/data/model/SatPass.kt @@ -17,12 +17,31 @@ */ package com.rtbishop.look4sat.data.model -import com.github.amsacode.predict4java.Satellite import com.rtbishop.look4sat.utility.PassPredictor +import java.util.* + +data class SatPass( + val catNum: Int, + val name: String, + val isDeepSpace: Boolean, + private val aosTime: Long, + val aosAzimuth: Double, + private val losTime: Long, + val losAzimuth: Double, + private val tcaTime: Long, + val tcaAzimuth: Double, + val altitude: Double, + val maxElevation: Double, + val predictor: PassPredictor +) { + val startDate: Date + get() = Date(aosTime) + + val endDate: Date + get() = Date(losTime) + + val tcaDate: Date + get() = Date(tcaTime) -class SatPass( - val satellite: Satellite, - val predictor: PassPredictor, - val pass: SatPassTime, var progress: Int = 0 -) +} diff --git a/app/src/main/java/com/rtbishop/look4sat/data/model/SatPassTime.kt b/app/src/main/java/com/rtbishop/look4sat/data/model/SatPassTime.kt deleted file mode 100644 index 6f9b5062..00000000 --- a/app/src/main/java/com/rtbishop/look4sat/data/model/SatPassTime.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Look4Sat. Amateur radio satellite tracker and pass predictor. - * Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.rtbishop.look4sat.data.model - -import java.util.* - -class SatPassTime( - private val startTime: Date, - private val endTime: Date, - val aosAzimuth: Int, - val losAzimuth: Int, - val maxEl: Double -) { - - fun getStartTime(): Date { - return Date(startTime.time) - } - - fun getEndTime(): Date { - return Date(endTime.time) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/rtbishop/look4sat/data/repository/PassesRepo.kt b/app/src/main/java/com/rtbishop/look4sat/data/repository/PassesRepo.kt index 98fe2eed..1b71ab83 100644 --- a/app/src/main/java/com/rtbishop/look4sat/data/repository/PassesRepo.kt +++ b/app/src/main/java/com/rtbishop/look4sat/data/repository/PassesRepo.kt @@ -62,8 +62,7 @@ class PassesRepo @Inject constructor( private fun getPasses(satellite: Satellite, refDate: Date): MutableList { val predictor = satellite.getPredictor(prefsRepo.getStationPosition()) val passes = predictor.getPasses(refDate, prefsRepo.getHoursAhead(), true) - val passList = passes.map { SatPass(satellite, predictor, it) } - return passList as MutableList + return passes as MutableList } private fun filterPasses(passes: MutableList, refDate: Date): MutableList { @@ -72,10 +71,10 @@ class PassesRepo @Inject constructor( this.time = refDate this.add(Calendar.HOUR, hoursAhead) }.time - passes.removeAll { it.pass.getStartTime().after(dateFuture) } - passes.removeAll { it.pass.getEndTime().before(refDate) } - passes.removeAll { it.pass.maxEl < prefsRepo.getMinElevation() } - passes.sortBy { it.pass.getStartTime() } + passes.removeAll { it.startDate.after(dateFuture) } + passes.removeAll { it.endDate.before(refDate) } + passes.removeAll { it.maxElevation < prefsRepo.getMinElevation() } + passes.sortBy { it.startDate } return passes } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt index 31bcd977..632789e7 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt @@ -46,7 +46,8 @@ class EntriesViewModel @Inject constructor( private val satDataState = MutableSharedFlow>>(replay = 0) private val satDataFlow = satelliteRepo.getAllSatItems().map { Result.Success(it) } - val satData = flowOf(satDataState, satDataFlow).flattenMerge().asLiveData() + val satData = + flowOf(satDataState, satDataFlow).flattenMerge().asLiveData(viewModelScope.coroutineContext) fun importSatDataFromFile(uri: Uri) { viewModelScope.launch { diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesAdapter.kt b/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesAdapter.kt index 839d2281..411c6d7d 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesAdapter.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesAdapter.kt @@ -44,11 +44,11 @@ class PassesAdapter(private val shouldUseUTC: Boolean = false) : val iterator = satPassList.listIterator() while (iterator.hasNext()) { val satPass = iterator.next() - if (!satPass.satellite.tle.isDeepspace) { + if (!satPass.isDeepSpace) { if (satPass.progress < 100) { - val timeStart = satPass.pass.getStartTime().time + val timeStart = satPass.startDate.time if (timeNow > timeStart) { - val timeEnd = satPass.pass.getEndTime().time + val timeEnd = satPass.endDate.time val index = satPassList.indexOf(satPass) val deltaNow = timeNow.minus(timeStart).toFloat() val deltaTotal = timeEnd.minus(timeStart).toFloat() @@ -69,7 +69,7 @@ class PassesAdapter(private val shouldUseUTC: Boolean = false) : } override fun getItemViewType(position: Int): Int { - return if (satPassList[position].satellite.tle.isDeepspace) 1 + return if (satPassList[position].isDeepSpace) 1 else 0 } @@ -104,20 +104,19 @@ class PassesAdapter(private val shouldUseUTC: Boolean = false) : private val endFormat = SimpleDateFormat(endTimeFormat, Locale.getDefault()) fun bind(satPass: SatPass, position: Int, shouldUseUTC: Boolean) { - val satPos = satPass.predictor.getSatPos(Date()) binding.apply { if (shouldUseUTC) { startFormat.timeZone = timeZoneUTC endFormat.timeZone = timeZoneUTC } - passLeoSatName.text = satPass.satellite.tle.name - passLeoSatId.text = String.format(satIdFormat, satPass.satellite.tle.catnum) - passLeoAosAz.text = String.format(aosAzFormat, satPass.pass.aosAzimuth) - passLeoMaxEl.text = String.format(maxElFormat, satPass.pass.maxEl) - passLeoLosAz.text = String.format(losAzFormat, satPass.pass.losAzimuth) - passLeoStart.text = startFormat.format(satPass.pass.getStartTime()) - passLeoAlt.text = String.format(altFormat, satPos.altitude) - passLeoEnd.text = endFormat.format(satPass.pass.getEndTime()) + passLeoSatName.text = satPass.name + passLeoSatId.text = String.format(satIdFormat, satPass.catNum) + passLeoAosAz.text = String.format(aosAzFormat, satPass.aosAzimuth) + passLeoMaxEl.text = String.format(maxElFormat, satPass.maxElevation) + passLeoLosAz.text = String.format(losAzFormat, satPass.losAzimuth) + passLeoStart.text = startFormat.format(satPass.startDate) + passLeoAlt.text = String.format(altFormat, satPass.altitude) + passLeoEnd.text = endFormat.format(satPass.endDate) passLeoProgress.progress = satPass.progress } @@ -146,13 +145,12 @@ class PassesAdapter(private val shouldUseUTC: Boolean = false) : private val elevFormat = itemView.context.getString(R.string.pat_elevation) fun bind(satPass: SatPass, position: Int) { - val satPos = satPass.predictor.getSatPos(Date()) binding.apply { - passGeoSatName.text = satPass.satellite.tle.name - passGeoSatId.text = String.format(satIdFormat, satPass.satellite.tle.catnum) - passGeoAz.text = String.format(azFormat, Math.toDegrees(satPos.azimuth)) - passGeoAlt.text = String.format(altFormat, satPos.altitude) - passGeoEl.text = String.format(elevFormat, Math.toDegrees(satPos.elevation)) + passGeoSatName.text = satPass.name + passGeoSatId.text = String.format(satIdFormat, satPass.catNum) + passGeoAz.text = String.format(azFormat, satPass.tcaAzimuth) + passGeoAlt.text = String.format(altFormat, satPass.altitude) + passGeoEl.text = String.format(elevFormat, satPass.maxElevation) } itemView.setOnClickListener { diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesFragment.kt index cc34d519..5de59a12 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesFragment.kt @@ -100,12 +100,12 @@ class PassesFragment : Fragment(R.layout.fragment_passes) { private fun tickMainTimer(timeNow: Long) { if (passes.isNotEmpty()) { try { - val nextPass = passes.first { it.pass.getStartTime().time.minus(timeNow) > 0 } - val millisBeforeStart = nextPass.pass.getStartTime().time.minus(timeNow) + val nextPass = passes.first { it.startDate.time.minus(timeNow) > 0 } + val millisBeforeStart = nextPass.startDate.time.minus(timeNow) binding?.passesTimer?.text = millisBeforeStart.formatForTimer() } catch (e: NoSuchElementException) { val lastPass = passes.last() - val millisBeforeEnd = lastPass.pass.getEndTime().time.minus(timeNow) + val millisBeforeEnd = lastPass.endDate.time.minus(timeNow) binding?.passesTimer?.text = millisBeforeEnd.formatForTimer() } } else { diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesViewModel.kt index e11f91e2..ac1918ca 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesViewModel.kt @@ -26,7 +26,6 @@ import com.rtbishop.look4sat.data.repository.PrefsRepo import com.rtbishop.look4sat.data.repository.SatelliteRepo import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import javax.inject.Inject @@ -37,13 +36,11 @@ class PassesViewModel @Inject constructor( private val passesRepo: PassesRepo ) : ViewModel() { - val passes = passesRepo.passes.asLiveData() + val passes = passesRepo.passes.asLiveData(viewModelScope.coroutineContext) init { viewModelScope.launch { - satelliteRepo.getSelectedSatellitesFlow().collect { selectedSatellites -> - passesRepo.calculatePasses(selectedSatellites) - } + passesRepo.calculatePasses(satelliteRepo.getSelectedSatellites()) } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarFragment.kt index 340a8cd3..3e01fd66 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarFragment.kt @@ -99,19 +99,10 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener { binding.frame.addView(polarView) observeTransmitters() }) - -// viewModel.getPasses().observe(viewLifecycleOwner, { result -> -// if (result is Result.Success) { -// satPass = result.data[requireArguments().getInt("index")] -// polarView = PolarView(requireContext()).apply { setPass(satPass) } -// binding.frame.addView(polarView) -// observeTransmitters() -// } -// }) } private fun observeTransmitters() { - viewModel.getTransmittersForSat(satPass.satellite.tle.catnum) + viewModel.getSatTransmitters(satPass.catNum) .observe(viewLifecycleOwner, { list -> transmitterAdapter = TransAdapter(satPass) if (list.isNotEmpty()) { @@ -154,14 +145,14 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener { binding.distance.text = String.format(polarRng, satPos.range) binding.altitude.text = String.format(polarAlt, satPos.altitude) - if (!satPass.satellite.tle.isDeepspace) { - if (dateNow.before(satPass.pass.getStartTime())) { - val millisBeforeStart = satPass.pass.getStartTime().time.minus(timeNow) + if (!satPass.isDeepSpace) { + if (dateNow.before(satPass.startDate)) { + val millisBeforeStart = satPass.startDate.time.minus(timeNow) binding.polarTimer.text = millisBeforeStart.formatForTimer() } else { - val millisBeforeEnd = satPass.pass.getEndTime().time.minus(timeNow) + val millisBeforeEnd = satPass.endDate.time.minus(timeNow) binding.polarTimer.text = millisBeforeEnd.formatForTimer() - if (dateNow.after(satPass.pass.getEndTime())) { + if (dateNow.after(satPass.endDate)) { binding.polarTimer.text = 0L.formatForTimer() findNavController().popBackStack() } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarView.kt b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarView.kt index 925e9f28..22d7a4c2 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarView.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarView.kt @@ -72,7 +72,7 @@ class PolarView(context: Context) : View(context) { canvas.translate(polarCenter, polarCenter) drawRadarView(canvas) drawRadarText(canvas) - if (!satPass.satellite.tle.isDeepspace) drawPassTrajectory(canvas, satPass) + if (!satPass.isDeepSpace) drawPassTrajectory(canvas, satPass) drawSatellite(canvas, satPass) } @@ -92,13 +92,13 @@ class PolarView(context: Context) : View(context) { } private fun drawPassTrajectory(cvs: Canvas, satPass: SatPass) { - val startTime = satPass.pass.getStartTime() - val endTime = satPass.pass.getEndTime() + val startTime = satPass.startDate + val endTime = satPass.endDate while (startTime.before(endTime)) { val satPos = satPass.predictor.getSatPos(startTime) val x = sph2CartX(satPos.azimuth, satPos.elevation, radius.toDouble()) val y = sph2CartY(satPos.azimuth, satPos.elevation, radius.toDouble()) - if (startTime.compareTo(satPass.pass.getStartTime()) == 0) { + if (startTime.compareTo(satPass.startDate) == 0) { path.moveTo(x, -y) } else { path.lineTo(x, -y) diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarViewModel.kt index 04c42fd4..fb119e47 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarViewModel.kt @@ -20,8 +20,8 @@ package com.rtbishop.look4sat.ui.polarScreen import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData import androidx.lifecycle.liveData +import androidx.lifecycle.viewModelScope import com.rtbishop.look4sat.data.model.Result -import com.rtbishop.look4sat.data.model.SatPass import com.rtbishop.look4sat.data.repository.PassesRepo import com.rtbishop.look4sat.data.repository.PrefsRepo import com.rtbishop.look4sat.data.repository.SatelliteRepo @@ -52,8 +52,6 @@ class PolarViewModel @Inject constructor( } } - fun getPasses() = passesRepo.passes.asLiveData() - fun shouldUseCompass(): Boolean { return prefsRepo.shouldUseCompass() } @@ -62,5 +60,6 @@ class PolarViewModel @Inject constructor( return prefsRepo.getMagDeclination() } - fun getTransmittersForSat(satId: Int) = satelliteRepo.getSatTransmitters(satId).asLiveData() + fun getSatTransmitters(satId: Int) = + satelliteRepo.getSatTransmitters(satId).asLiveData(viewModelScope.coroutineContext) } \ No newline at end of file diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/TransAdapter.kt b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/TransAdapter.kt index 8045298b..0969c1b6 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/TransAdapter.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/TransAdapter.kt @@ -25,7 +25,6 @@ import com.rtbishop.look4sat.data.model.SatPass import com.rtbishop.look4sat.data.model.SatTrans import com.rtbishop.look4sat.databinding.ItemTransBinding import com.rtbishop.look4sat.utility.PassPredictor -import com.rtbishop.look4sat.utility.getDopplerFreq import java.util.* class TransAdapter(private val pass: SatPass) : RecyclerView.Adapter() { @@ -38,13 +37,8 @@ class TransAdapter(private val pass: SatPass) : RecyclerView.Adapter { - val passes = mutableListOf() + + fun getPasses(refDate: Date, hoursAhead: Int, windBack: Boolean): List { + val passes = mutableListOf() val endDate = Date(refDate.time + hoursAhead * 60L * 60L * 1000L) var startDate = refDate var shouldWindBack = windBack @@ -68,34 +68,45 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta do { if (count > 0) shouldWindBack = false val pass = nextNearEarthPass(startDate, shouldWindBack) - lastAosDate = pass.getStartTime() + lastAosDate = pass.startDate passes.add(pass) startDate = - Date(pass.getEndTime().time + (oneQuarterOrbitMin * 3) * 60L * 1000L) + Date(pass.endDate.time + (oneQuarterOrbitMin * 3) * 60L * 1000L) count++ } while (lastAosDate < endDate) } } return passes } - - private fun nextDeepSpacePass(refDate: Date): SatPassTime { + + private fun nextDeepSpacePass(refDate: Date): SatPass { val satPos = getSatPos(refDate) - val startDate = Date(refDate.time - 24 * 60L * 60L * 1000L) - val endDate = Date(refDate.time + 24 * 60L * 60L * 1000L) - val azimuth = Math.toDegrees(satPos.azimuth).toInt() - val maxEl = Math.toDegrees(satPos.elevation) - return SatPassTime(startDate, endDate, azimuth, azimuth, maxEl) + val id = satellite.tle.catnum + val name = satellite.tle.name + val isDeep = satellite.tle.isDeepspace + val aos = Date(refDate.time - 24 * 60L * 60L * 1000L).time + val los = Date(refDate.time + 24 * 60L * 60L * 1000L).time + val tca = Date((aos + los) / 2).time + val az = Math.toDegrees(satPos.azimuth) + val elev = Math.toDegrees(satPos.elevation) + val alt = satPos.altitude + return SatPass(id, name, isDeep, aos, az, los, az, tca, az, alt, elev, this) } - - private fun nextNearEarthPass(refDate: Date, windBack: Boolean = false): SatPassTime { + + private fun nextNearEarthPass(refDate: Date, windBack: Boolean = false): SatPass { val calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { clear() timeInMillis = refDate.time } - var maxElevation = 0.0 + val id = satellite.tle.catnum + val name = satellite.tle.name + val isDeep = satellite.tle.isDeepspace + var elevation: Double - + var maxElevation = 0.0 + var alt = 0.0 + var tcaAz = 0.0 + // wind back time 1/4 of an orbit if (windBack) calendar.add(Calendar.MINUTE, -oneQuarterOrbitMin) var satPos = getSatPos(calendar.time) @@ -115,7 +126,11 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta calendar.add(Calendar.SECOND, 60) satPos = getSatPos(calendar.time) elevation = satPos.elevation - if (elevation > maxElevation) maxElevation = elevation + if (elevation > maxElevation) { + maxElevation = elevation + alt = satPos.altitude + tcaAz = Math.toDegrees(satPos.azimuth) + } } while (satPos.elevation < 0.0) // refine to 3 seconds @@ -124,18 +139,26 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta calendar.add(Calendar.SECOND, 3) satPos = getSatPos(calendar.time) elevation = satPos.elevation - if (elevation > maxElevation) maxElevation = elevation + if (elevation > maxElevation) { + maxElevation = elevation + alt = satPos.altitude + tcaAz = Math.toDegrees(satPos.azimuth) + } } while (satPos.elevation < 0.0) - val startDate = satPos.time - val aosAzimuth = Math.toDegrees(satPos.azimuth).toInt() + val aos = satPos.time.time + val aosAz = Math.toDegrees(satPos.azimuth) // find when sat goes below do { calendar.add(Calendar.SECOND, 30) satPos = getSatPos(calendar.time) elevation = satPos.elevation - if (elevation > maxElevation) maxElevation = elevation + if (elevation > maxElevation) { + maxElevation = elevation + alt = satPos.altitude + tcaAz = Math.toDegrees(satPos.azimuth) + } } while (satPos.elevation > 0.0) // refine to 3 seconds @@ -144,12 +167,17 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta calendar.add(Calendar.SECOND, 3) satPos = getSatPos(calendar.time) elevation = satPos.elevation - if (elevation > maxElevation) maxElevation = elevation + if (elevation > maxElevation) { + maxElevation = elevation + alt = satPos.altitude + tcaAz = Math.toDegrees(satPos.azimuth) + } } while (satPos.elevation > 0.0) - val endDate = satPos.time - val losAzimuth = Math.toDegrees(satPos.azimuth).toInt() - val maxEl = Math.toDegrees(maxElevation) - return SatPassTime(startDate, endDate, aosAzimuth, losAzimuth, maxEl) + val los = satPos.time.time + val losAz = Math.toDegrees(satPos.azimuth) + val tca = Date((aos + los) / 2).time + val elev = Math.toDegrees(maxElevation) + return SatPass(id, name, isDeep, aos, aosAz, los, losAz, tca, tcaAz, alt, elev, this) } } diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index ed60406e..c53a9ed5 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -22,9 +22,9 @@ Нет предстоящих пролётов - НПС - %2d° + НПС - %.1f° МаксЭлев: %.1f° - %2d° - КПС + %.1f° - КПС Модуляция: %s Модуляция: нет diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4c6ac071..3604f7b1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -30,9 +30,9 @@ %s Id:%d - AOS - %2d° + AOS - %.1f° MaxEl: %.1f° - %2d° - LOS + %.1f° - LOS HH:mm:ss - EEE EEE - HH:mm:ss