Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagohm committed May 20, 2024
2 parents 01b0dde + 4678033 commit c063c37
Show file tree
Hide file tree
Showing 73 changed files with 1,363 additions and 267 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import nebulosa.indi.device.filterwheel.FilterWheel
import nebulosa.indi.device.focuser.Focuser
import nebulosa.indi.device.guide.GuideOutput
import nebulosa.indi.device.mount.Mount
import nebulosa.indi.device.rotator.Rotator
import org.springframework.core.MethodParameter
import org.springframework.stereotype.Component
import org.springframework.web.bind.support.WebDataBinderFactory
Expand All @@ -35,6 +36,7 @@ class DeviceOrEntityParamMethodArgumentResolver(
Mount::class.java to { connectionService.mount(it) },
Focuser::class.java to { connectionService.focuser(it) },
FilterWheel::class.java to { connectionService.wheel(it) },
Rotator::class.java to { connectionService.rotator(it) },
GuideOutput::class.java to { connectionService.guideOutput(it) },
)

Expand Down
5 changes: 3 additions & 2 deletions api/src/main/kotlin/nebulosa/api/cameras/CameraController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.filterwheel.FilterWheel
import nebulosa.indi.device.focuser.Focuser
import nebulosa.indi.device.mount.Mount
import nebulosa.indi.device.rotator.Rotator
import org.hibernate.validator.constraints.Range
import org.springframework.web.bind.annotation.*

Expand Down Expand Up @@ -39,8 +40,8 @@ class CameraController(
@PutMapping("{camera}/snoop")
fun snoop(
camera: Camera,
mount: Mount?, wheel: FilterWheel?, focuser: Focuser?,
) = cameraService.snoop(camera, mount, wheel, focuser)
mount: Mount?, wheel: FilterWheel?, focuser: Focuser?, rotator: Rotator?
) = cameraService.snoop(camera, mount, wheel, focuser, rotator)

@PutMapping("{camera}/cooler")
fun cooler(
Expand Down
32 changes: 25 additions & 7 deletions api/src/main/kotlin/nebulosa/api/connection/ConnectionService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import nebulosa.indi.device.focuser.Focuser
import nebulosa.indi.device.gps.GPS
import nebulosa.indi.device.guide.GuideOutput
import nebulosa.indi.device.mount.Mount
import nebulosa.indi.device.rotator.Rotator
import nebulosa.indi.device.thermometer.Thermometer
import nebulosa.log.error
import nebulosa.log.loggerFor
Expand Down Expand Up @@ -106,31 +107,35 @@ class ConnectionService(
disconnectAll()
}

fun cameras(id: String): List<Camera> {
fun cameras(id: String): Collection<Camera> {
return providers[id]?.cameras() ?: emptyList()
}

fun mounts(id: String): List<Mount> {
fun mounts(id: String): Collection<Mount> {
return providers[id]?.mounts() ?: emptyList()
}

fun focusers(id: String): List<Focuser> {
fun focusers(id: String): Collection<Focuser> {
return providers[id]?.focusers() ?: emptyList()
}

fun wheels(id: String): List<FilterWheel> {
fun wheels(id: String): Collection<FilterWheel> {
return providers[id]?.wheels() ?: emptyList()
}

fun gpss(id: String): List<GPS> {
fun rotators(id: String): Collection<Rotator> {
return providers[id]?.rotators() ?: emptyList()
}

fun gpss(id: String): Collection<GPS> {
return providers[id]?.gps() ?: emptyList()
}

fun guideOutputs(id: String): List<GuideOutput> {
fun guideOutputs(id: String): Collection<GuideOutput> {
return providers[id]?.guideOutputs() ?: emptyList()
}

fun thermometers(id: String): List<Thermometer> {
fun thermometers(id: String): Collection<Thermometer> {
return providers[id]?.thermometers() ?: emptyList()
}

Expand All @@ -150,6 +155,10 @@ class ConnectionService(
return providers.values.flatMap { it.wheels() }
}

fun rotators(): List<Rotator> {
return providers.values.flatMap { it.rotators() }
}

fun gpss(): List<GPS> {
return providers.values.flatMap { it.gps() }
}
Expand Down Expand Up @@ -178,6 +187,10 @@ class ConnectionService(
return providers[id]?.wheel(name)
}

fun rotator(id: String, name: String): Rotator? {
return providers[id]?.rotator(name)
}

fun gps(id: String, name: String): GPS? {
return providers[id]?.gps(name)
}
Expand Down Expand Up @@ -206,6 +219,10 @@ class ConnectionService(
return providers.firstNotNullOfOrNull { it.value.wheel(name) }
}

fun rotator(name: String): Rotator? {
return providers.firstNotNullOfOrNull { it.value.rotator(name) }
}

fun gps(name: String): GPS? {
return providers.firstNotNullOfOrNull { it.value.gps(name) }
}
Expand All @@ -223,6 +240,7 @@ class ConnectionService(
?: mount(name)
?: focuser(name)
?: wheel(name)
?: rotator(name)
?: guideOutput(name)
?: gps(name)
?: thermometer(name)
Expand Down
3 changes: 2 additions & 1 deletion api/src/main/kotlin/nebulosa/api/image/ImageController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ class ImageController(
@RequestParam(required = false, defaultValue = "true") starsAndDSOs: Boolean,
@RequestParam(required = false, defaultValue = "false") minorPlanets: Boolean,
@RequestParam(required = false, defaultValue = "12.0") minorPlanetMagLimit: Double,
@RequestParam(required = false, defaultValue = "false") useSimbad: Boolean,
@LocationParam location: Location? = null,
) = imageService.annotations(path, starsAndDSOs, minorPlanets, minorPlanetMagLimit, location)
) = imageService.annotations(path, starsAndDSOs, minorPlanets, minorPlanetMagLimit, useSimbad, location)

@GetMapping("coordinate-interpolation")
fun coordinateInterpolation(@RequestParam path: Path): CoordinateInterpolation? {
Expand Down
27 changes: 14 additions & 13 deletions api/src/main/kotlin/nebulosa/api/image/ImageService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ import nebulosa.image.algorithms.computation.Statistics
import nebulosa.image.algorithms.transformation.*
import nebulosa.image.format.ImageModifier
import nebulosa.indi.device.camera.Camera
import nebulosa.log.debug
import nebulosa.log.loggerFor
import nebulosa.math.*
import nebulosa.nova.astrometry.VSOP87E
import nebulosa.nova.position.Barycentric
import nebulosa.sbd.SmallBodyDatabaseService
import nebulosa.simbad.SimbadSearch
import nebulosa.simbad.SimbadService
import nebulosa.skycatalog.ClassificationType
import nebulosa.skycatalog.SkyObjectType
import nebulosa.star.detection.ImageStar
Expand Down Expand Up @@ -50,6 +51,7 @@ class ImageService(
private val calibrationFrameService: CalibrationFrameService,
private val smallBodyDatabaseService: SmallBodyDatabaseService,
private val simbadEntityRepository: SimbadEntityRepository,
private val simbadService: SimbadService,
private val imageBucket: ImageBucket,
private val threadPoolTaskExecutor: ThreadPoolTaskExecutor,
private val connectionService: ConnectionService,
Expand Down Expand Up @@ -168,7 +170,7 @@ class ImageService(
fun annotations(
path: Path,
starsAndDSOs: Boolean, minorPlanets: Boolean,
minorPlanetMagLimit: Double = 12.0,
minorPlanetMagLimit: Double = 12.0, useSimbad: Boolean = false,
location: Location? = null,
): List<ImageAnnotation> {
val (image, calibration) = imageBucket[path] ?: return emptyList()
Expand Down Expand Up @@ -229,27 +231,26 @@ class ImageService(

if (starsAndDSOs) {
threadPoolTaskExecutor.submitCompletable {
val barycentric = VSOP87E.EARTH.at<Barycentric>(UTC(TimeYMDHMS(dateTime)))
LOG.info("finding star/DSO annotations. dateTime={}, useSimbad={}, calibration={}", dateTime, useSimbad, calibration)

LOG.info("finding star/DSO annotations. dateTime={}, calibration={}", dateTime, calibration)
val rightAscension = calibration.rightAscension
val declination = calibration.declination
val radius = calibration.radius

val catalog = simbadEntityRepository.find(null, null, calibration.rightAscension, calibration.declination, calibration.radius)
val catalog = if (useSimbad) {
simbadService.search(SimbadSearch.Builder().region(rightAscension, declination, radius).build())
} else {
simbadEntityRepository.find(null, null, rightAscension, declination, radius)
}

var count = 0
val barycentric = VSOP87E.EARTH.at<Barycentric>(UTC(TimeYMDHMS(dateTime)))

for (entry in catalog) {
if (entry.type == SkyObjectType.EXTRA_SOLAR_PLANET) continue

val astrometric = barycentric.observe(entry).equatorial()

LOG.debug {
"%s: %s %s -> %s %s".format(
entry.name,
entry.rightAscensionJ2000.formatHMS(), entry.declinationJ2000.formatSignedDMS(),
astrometric.longitude.normalized.formatHMS(), astrometric.latitude.formatSignedDMS(),
)
}

val (x, y) = wcs.skyToPix(astrometric.longitude.normalized, astrometric.latitude)
val annotation = if (entry.type.classification == ClassificationType.STAR) ImageAnnotation(x, y, star = StarDSO(entry))
else ImageAnnotation(x, y, dso = StarDSO(entry))
Expand Down
69 changes: 69 additions & 0 deletions api/src/main/kotlin/nebulosa/api/rotators/RotatorController.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package nebulosa.api.rotators

import jakarta.validation.Valid
import nebulosa.api.connection.ConnectionService
import nebulosa.indi.device.rotator.Rotator
import org.hibernate.validator.constraints.Range
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("rotators")
class RotatorController(
private val connectionService: ConnectionService,
private val rotatorService: RotatorService,
) {

@GetMapping
fun rotators(): List<Rotator> {
return connectionService.rotators().sorted()
}

@GetMapping("{rotator}")
fun rotator(rotator: Rotator): Rotator {
return rotator
}

@PutMapping("{rotator}/connect")
fun connect(rotator: Rotator) {
rotatorService.connect(rotator)
}

@PutMapping("{rotator}/disconnect")
fun disconnect(rotator: Rotator) {
rotatorService.disconnect(rotator)
}

@PutMapping("{rotator}/reverse")
fun reverse(
rotator: Rotator,
@RequestParam enabled: Boolean,
) {
rotatorService.reverse(rotator, enabled)
}

@PutMapping("{rotator}/move")
fun move(
rotator: Rotator,
@RequestParam @Valid @Range(min = 0, max = 360) angle: Double,
) {
rotatorService.move(rotator, angle)
}

@PutMapping("{rotator}/abort")
fun abort(rotator: Rotator) {
rotatorService.abort(rotator)
}

@PutMapping("{rotator}/home")
fun home(rotator: Rotator) {
rotatorService.home(rotator)
}

@PutMapping("{rotator}/sync")
fun sync(
rotator: Rotator,
@RequestParam @Valid @Range(min = 0, max = 360) angle: Double,
) {
rotatorService.sync(rotator, angle)
}
}
16 changes: 16 additions & 0 deletions api/src/main/kotlin/nebulosa/api/rotators/RotatorDeserializer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package nebulosa.api.rotators

import nebulosa.api.beans.converters.device.DeviceDeserializer
import nebulosa.api.connection.ConnectionService
import nebulosa.indi.device.rotator.Rotator
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Lazy
import org.springframework.stereotype.Component

@Component
class RotatorDeserializer : DeviceDeserializer<Rotator>(Rotator::class.java) {

@Autowired @Lazy private lateinit var connectionService: ConnectionService

override fun deviceFor(name: String) = connectionService.rotator(name)
}
59 changes: 59 additions & 0 deletions api/src/main/kotlin/nebulosa/api/rotators/RotatorEventHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package nebulosa.api.rotators

import io.reactivex.rxjava3.subjects.PublishSubject
import nebulosa.api.beans.annotations.Subscriber
import nebulosa.api.messages.MessageService
import nebulosa.indi.device.PropertyChangedEvent
import nebulosa.indi.device.rotator.Rotator
import nebulosa.indi.device.rotator.RotatorAttached
import nebulosa.indi.device.rotator.RotatorDetached
import nebulosa.indi.device.rotator.RotatorEvent
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.springframework.stereotype.Component
import java.io.Closeable
import java.util.concurrent.TimeUnit

@Component
@Subscriber
class RotatorEventHandler(
private val messageService: MessageService,
) : Closeable {

private val throttler = PublishSubject.create<RotatorEvent>()

init {
throttler
.throttleLast(1000, TimeUnit.MILLISECONDS)
.subscribe { sendUpdate(it.device!!) }
}

@Subscribe(threadMode = ThreadMode.ASYNC)
fun onRotatorEvent(event: RotatorEvent) {
when (event) {
is PropertyChangedEvent -> throttler.onNext(event)
is RotatorAttached -> sendMessage(ROTATOR_ATTACHED, event.device)
is RotatorDetached -> sendMessage(ROTATOR_DETACHED, event.device)
}
}

@Suppress("NOTHING_TO_INLINE")
private inline fun sendMessage(eventName: String, device: Rotator) {
messageService.sendMessage(RotatorMessageEvent(eventName, device))
}

fun sendUpdate(device: Rotator) {
sendMessage(ROTATOR_UPDATED, device)
}

override fun close() {
throttler.onComplete()
}

companion object {

const val ROTATOR_UPDATED = "ROTATOR.UPDATED"
const val ROTATOR_ATTACHED = "ROTATOR.ATTACHED"
const val ROTATOR_DETACHED = "ROTATOR.DETACHED"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package nebulosa.api.rotators

import nebulosa.api.messages.DeviceMessageEvent
import nebulosa.indi.device.rotator.Rotator

data class RotatorMessageEvent(
override val eventName: String,
override val device: Rotator,
) : DeviceMessageEvent<Rotator>
30 changes: 30 additions & 0 deletions api/src/main/kotlin/nebulosa/api/rotators/RotatorSerializer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package nebulosa.api.rotators

import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.ser.std.StdSerializer
import nebulosa.indi.device.rotator.Rotator
import org.springframework.stereotype.Component

@Component
class RotatorSerializer : StdSerializer<Rotator>(Rotator::class.java) {

override fun serialize(value: Rotator, gen: JsonGenerator, provider: SerializerProvider) {
gen.writeStartObject()
gen.writeStringField("sender", value.sender.id)
gen.writeStringField("id", value.id)
gen.writeStringField("name", value.name)
gen.writeBooleanField("connected", value.connected)
gen.writeBooleanField("moving", value.moving)
gen.writeNumberField("angle", value.angle)
gen.writeBooleanField("canAbort", value.canAbort)
gen.writeBooleanField("canReverse", value.canReverse)
gen.writeBooleanField("reversed", value.reversed)
gen.writeBooleanField("canHome", value.canHome)
gen.writeBooleanField("canSync", value.canSync)
gen.writeBooleanField("hasBacklashCompensation", value.hasBacklashCompensation)
gen.writeNumberField("maxAngle", value.maxAngle)
gen.writeNumberField("minAngle", value.minAngle)
gen.writeEndObject()
}
}
Loading

0 comments on commit c063c37

Please sign in to comment.