diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 632eeae8a..6af033f66 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Version History =============== +v6.3.0 +------ + +* Add RA, Dec and Rotator parameters to the ATDome component ``_ + v6.2.0 ------ diff --git a/love/src/Utils.js b/love/src/Utils.js index 8c3af25bb..87552bbfb 100644 --- a/love/src/Utils.js +++ b/love/src/Utils.js @@ -1551,6 +1551,37 @@ export function degrees(radians) { return (radians * 180) / Math.PI; } +/** + * Function to transform degress to Right Ascension hour format + * e.g. 180.55 -> 12:02:12 + * @param {number} degrees degrees to be transformed + * @returns {string} Right Ascension hour format + */ +export function degreesToHMS(degrees) { + const h = Math.floor(degrees / 15); + const m = Math.floor((degrees % 15) * 4); + const s = Math.floor(((degrees % 15) * 4 - m) * 60); + return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`; +} + +/** + * Function to transform degress to Declination hour format + * e.g. 180.55 -> +180:02:12 + * @param {number} degrees degrees to be transformed + * @returns {string} Declination hour format + */ +export function degreesToDMS(degrees) { + const d = Math.floor(degrees); + const m = Math.floor((degrees % 1) * 4); + const s = Math.floor(((degrees % 1) * 4 - m) * 60); + const hourFormat = + `${Math.sign(degrees) >= 0 ? '+' : '-'}` + + `${d.toString().padStart(2, '0')}` + + `:${m.toString().padStart(2, '0')}` + + `:${s.toString().padStart(2, '0')}`; + return hourFormat; +} + /** * Function to pase a number or string to float with fixed decimal points * as specified by the points param diff --git a/love/src/components/AuxTel/Dome/Dome.container.jsx b/love/src/components/AuxTel/Dome/Dome.container.jsx index b9ddfc1a0..4203bdd67 100644 --- a/love/src/components/AuxTel/Dome/Dome.container.jsx +++ b/love/src/components/AuxTel/Dome/Dome.container.jsx @@ -19,11 +19,11 @@ this program. If not, see . import React from 'react'; import { connect } from 'react-redux'; -import Dome from './Dome'; -import { getDomeState, getATMCSState } from '../../../redux/selectors'; -import { addGroup, removeGroup } from '../../../redux/actions/ws'; -import SubscriptionTableContainer from '../../GeneralPurpose/SubscriptionTable/SubscriptionTable.container'; +import SubscriptionTableContainer from 'components/GeneralPurpose/SubscriptionTable/SubscriptionTable.container'; +import { getDomeState, getATMCSState, getAuxiliaryTelescopeState } from 'redux/selectors'; +import { addGroup, removeGroup } from 'redux/actions/ws'; import { EUIs } from 'Config'; +import Dome from './Dome'; export const schema = { description: 'Summary view of the ATDome. Contains general information about the dome and mount state', @@ -47,6 +47,12 @@ export const schema = { isPrivate: false, default: EUIs.ATDOME, }, + raDecHourFormat: { + type: 'boolean', + description: 'Whether to display the RA and DEC in hour format', + isPrivate: false, + default: false, + }, }, }; @@ -87,6 +93,10 @@ const DomeContainer = ({ controls, atDomeTracking, targetName, + telescopeRA, + telescopeDec, + telescopeRotator, + raDecHourFormat, ...props }) => { if (props.isRaw) { @@ -130,6 +140,10 @@ const DomeContainer = ({ ATMCSSummaryState={ATMCSSummaryState} atDomeTracking={atDomeTracking} targetName={targetName} + telescopeRA={telescopeRA} + telescopeDec={telescopeDec} + telescopeRotator={telescopeRotator} + raDecHourFormat={raDecHourFormat} /> ); }; @@ -137,19 +151,21 @@ const DomeContainer = ({ const mapStateToProps = (state) => { const domeState = getDomeState(state); const mountState = getATMCSState(state); - return { ...domeState, ...mountState }; + const telescopeState = getAuxiliaryTelescopeState(state); + return { ...domeState, ...mountState, ...telescopeState }; }; const mapDispatchToProps = (dispatch) => { const subscriptions = [ 'telemetry-ATDome-0-position', + 'telemetry-ATMCS-0-mount_AzEl_Encoders', + 'telemetry-ATMCS-0-mount_Nasmyth_Encoders', + 'telemetry-Scheduler-2-observatoryState', 'event-ATDome-0-azimuthState', 'event-ATDome-0-azimuthCommandedState', 'event-ATDome-0-dropoutDoorState', 'event-ATDome-0-mainDoorState', 'event-ATDome-0-allAxesInPosition', - 'telemetry-ATMCS-0-mount_AzEl_Encoders', - 'telemetry-ATMCS-0-mount_Nasmyth_Encoders', 'event-ATMCS-0-atMountState', 'event-ATMCS-0-target', 'event-ATMCS-0-allAxesInPosition', diff --git a/love/src/components/AuxTel/Dome/Dome.jsx b/love/src/components/AuxTel/Dome/Dome.jsx index 82883da63..9dd8005c9 100644 --- a/love/src/components/AuxTel/Dome/Dome.jsx +++ b/love/src/components/AuxTel/Dome/Dome.jsx @@ -18,30 +18,107 @@ this program. If not, see . */ import React, { Component } from 'react'; -// import PropTypes from 'prop-types'; -import ManagerInterface, { fixedFloat, parseCommanderData } from 'Utils'; -// import SkymapGrid from '../Skymap/SkymapGrid'; +import PropTypes from 'prop-types'; +import ManagerInterface, { fixedFloat, parseCommanderData, degreesToHMS, degreesToDMS } from 'Utils'; import PlotContainer from 'components/GeneralPurpose/Plot/Plot.container'; import TimeSeriesControls from 'components/GeneralPurpose/Plot/TimeSeriesControls/TimeSeriesControls'; -import DomeTopView from './DomeTopView'; +import Elevation from 'components/GeneralPurpose/Elevation/Elevation'; +import Azimuth from 'components/GeneralPurpose/Azimuth/Azimuth'; +import WindRose from 'components/icons/WindRose/WindRose'; import DomePointing from './DomePointing'; import DomeShutter from './DomeShutter'; import MountTopView from './MountTopView'; -import Elevation from 'components/GeneralPurpose/Elevation/Elevation'; -import Azimuth from 'components/GeneralPurpose/Azimuth/Azimuth'; - -import WindRose from '../../icons/WindRose/WindRose'; import DomeSummaryTable from './DomeSummaryTable/DomeSummaryTable'; - import styles from './Dome.module.css'; export default class Dome extends Component { static propTypes = { - // raftsDetailedState: PropTypes.string, - // imageReadinessDetailedState: PropTypes.string, - // calibrationDetailedState: PropTypes.string, - // shutterDetailedState: PropTypes.string, - // imageSequence: PropTypes.object, + /** Width for the diferent SVG components */ + width: PropTypes.number, + /** Height for the diferent SVG components */ + height: PropTypes.number, + /** Dropout door opening percentage */ + dropoutDoorOpeningPercentage: PropTypes.number, + /** Main door opening percentage */ + mainDoorOpeningPercentage: PropTypes.number, + /** Azimuth position */ + azimuthPosition: PropTypes.number, + /** Azimuth state */ + azimuthState: PropTypes.string, + /** Azimuth commanded */ + azimuthCommanded: PropTypes.number, + /** Dome in position */ + domeInPosition: PropTypes.bool, + /** Dropout door state */ + dropoutDoorState: PropTypes.string, + /** Main door state */ + mainDoorState: PropTypes.string, + /** AT mount state */ + atMountState: PropTypes.string, + /** Mount in position */ + mountInPosition: PropTypes.bool, + /** Track ID */ + trackID: PropTypes.number, + /** Target azimuth */ + targetAzimuth: PropTypes.number, + /** Target elevation */ + targetElevation: PropTypes.number, + /** Target nasmyth1 */ + targetNasmyth1: PropTypes.number, + /** Target nasmyth2 */ + targetNasmyth2: PropTypes.number, + /** M3 state */ + m3State: PropTypes.string, + /** Min elevation */ + minEl: PropTypes.number, + /** Min azimuth */ + minAz: PropTypes.number, + /** Min nasmyth1 */ + minNas1: PropTypes.number, + /** Min nasmyth2 */ + minNas2: PropTypes.number, + /** Min M3 */ + minM3: PropTypes.number, + /** Max elevation */ + maxEl: PropTypes.number, + /** Max azimuth */ + maxAz: PropTypes.number, + /** Max nasmyth1 */ + maxNas1: PropTypes.number, + /** Max nasmyth2 */ + maxNas2: PropTypes.number, + /** Max M3 */ + maxM3: PropTypes.number, + /** Time azimuth limit */ + timeAzLim: PropTypes.number, + /** Time rotation limit */ + timeRotLim: PropTypes.number, + /** Time unobservable */ + timeUnobservable: PropTypes.number, + /** Time elevation high limit */ + timeElHighLimit: PropTypes.number, + /** Current pointing azimuth */ + currentPointingAz: PropTypes.number, + /** Current pointing elevation */ + currentPointingEl: PropTypes.number, + /** Current pointing nasmyth1 */ + currentPointingNasmyth1: PropTypes.number, + /** Current pointing nasmyth2 */ + currentPointingNasmyth2: PropTypes.number, + /** AT dome summary state */ + atDomeSummaryState: PropTypes.string, + /** ATMCS summary state */ + ATMCSSummaryState: PropTypes.string, + /** AT dome tracking */ + atDomeTracking: PropTypes.bool, + /** Target name */ + targetName: PropTypes.string, + /** Telescope RA */ + telescopeRA: PropTypes.number, + /** Telescope Dec */ + telescopeDec: PropTypes.number, + /** Rotator position */ + telescopeRotator: PropTypes.number, }; static defaultProps = { @@ -196,10 +273,9 @@ export default class Dome extends Component { }; render() { - const width = this.props.width; - const height = this.props.height; - const { + width, + height, dropoutDoorOpeningPercentage, mainDoorOpeningPercentage, azimuthPosition, @@ -216,12 +292,12 @@ export default class Dome extends Component { targetNasmyth1, targetNasmyth2, m3State, - minEl, + // minEl, minAz, minNas1, minNas2, minM3, - maxEl, + // maxEl, maxAz, maxNas1, maxNas2, @@ -238,8 +314,14 @@ export default class Dome extends Component { ATMCSSummaryState, atDomeTracking, targetName, + telescopeRA, + telescopeDec, + telescopeRotator, + raDecHourFormat, } = this.props; + const { timeWindow, isLive, historicalData } = this.state; + const isProjected = true; let azDiff = Math.abs(azimuthPosition - currentPointingAz); if (azDiff > 180) azDiff = azDiff - 360; @@ -257,16 +339,18 @@ export default class Dome extends Component { }; const timeSeriesControlsProps = { - timeWindow: this.state.timeWindow, - isLive: this.state.isLive, - historicalData: this.state.historicalData, + timeWindow: timeWindow, + isLive: isLive, + historicalData: historicalData, }; + const parsedTelescopeRA = raDecHourFormat ? degreesToHMS(telescopeRA) : `${telescopeRA}°`; + const parsedTelescopeDec = raDecHourFormat ? degreesToDMS(telescopeDec) : `${telescopeDec}°`; + return (
- {/* */}
@@ -285,7 +369,6 @@ export default class Dome extends Component { targetValue={targetElevation} />
- Vignetting distance: - {vignettingDistance}º + {vignettingDistance}° +
+
+ Telescope RA: {parsedTelescopeRA} +
+
+ Telescope Dec: {parsedTelescopeDec} +
+
+ Rotator position: {telescopeRotator}° +
+
. align-self: center; flex-wrap: wrap; position: relative; - width: 70%; + width: 100%; max-width: 700px; + container-type: inline-size; } .skymapGridContainer svg { @@ -47,7 +48,7 @@ this program. If not, see . .topRow { display: grid; justify-items: center; - row-gap: 2em; + column-gap: 5em; padding: 1em 0; grid-template-columns: minmax(0, 1fr) minmax(22em, 24em); } @@ -134,7 +135,7 @@ this program. If not, see . .vignettingDistanceContainer { position: absolute; left: 50%; - bottom: 0%; + bottom: calc(var(--content-padding) * -1); transform: translate(-50%, 0); } @@ -142,6 +143,13 @@ this program. If not, see . color: var(--base-font-color); } +.telescopeParametersContainer { + display: flex; + gap: var(--content-padding); + white-space: nowrap; + font-size: var(--font-size-larger); +} + .innerDome { fill: var(--second-tertiary-background-color); fill-opacity: 0.6; @@ -168,3 +176,13 @@ this program. If not, see . .elevationPlot { height: 18em; } + +@container (width < 600px) { + .vignettingDistanceContainer { + bottom: -90px; + } + .telescopeParametersContainer { + flex-direction: column; + gap: 0; + } +} diff --git a/love/src/redux/selectors/selectors.js b/love/src/redux/selectors/selectors.js index 3c9435660..84d8c9dfd 100644 --- a/love/src/redux/selectors/selectors.js +++ b/love/src/redux/selectors/selectors.js @@ -613,6 +613,16 @@ export const getATMCSState = (state) => { }; }; +export const getAuxiliaryTelescopeState = (state) => { + const subscriptions = ['telemetry-Scheduler-2-observatoryState']; + const data = getStreamsData(state, subscriptions); + return { + telescopeRA: data['telemetry-Scheduler-2-observatoryState']?.ra?.value ?? 0, + telescopeDec: data['telemetry-Scheduler-2-observatoryState']?.declination?.value ?? 0, + telescopeRotator: data['telemetry-Scheduler-2-observatoryState']?.telescopeRotator?.value ?? 0, + }; +}; + export const getMountSubscriptions = (index) => { return [ // ATHexapod