diff --git a/dashboard/__init__.py b/dashboard/__init__.py index b4e7df8..5231690 100644 --- a/dashboard/__init__.py +++ b/dashboard/__init__.py @@ -47,34 +47,31 @@ GENERATED_DATA_DIR = os.path.join(os.path.dirname(__file__), '..', 'generated') W1M_GENERATED_DATA = { - 'blue': 'dashboard-BLUE.json', 'blue/thumb': 'dashboard-BLUE-thumb.jpg', 'blue/clip': 'dashboard-BLUE-clip.jpg', - 'red': 'dashboard-RED.json', 'red/thumb': 'dashboard-RED-thumb.jpg', 'red/clip': 'dashboard-RED-clip.jpg', } CLASP_GENERATED_DATA = { - 'cam1': 'dashboard-CAM1.json', 'cam1/thumb': 'dashboard-CAM1-thumb.jpg', 'cam1/clip': 'dashboard-CAM1-clip.jpg', - 'cam2': 'dashboard-CAM2.json', 'cam2/thumb': 'dashboard-CAM2-thumb.jpg', 'cam2/clip': 'dashboard-CAM2-clip.jpg', } +HALFMETRE_GENERATED_DATA = { + 'thumb': 'dashboard-HALFMETRE-thumb.jpg', + 'clip': 'ddashboard-HALFMETRE-clip.jpg', +} + SUPERWASP_GENERATED_DATA = { - 'cam1': 'dashboard-1.json', 'cam1/thumb': 'dashboard-1-thumb.jpg', 'cam1/clip': 'dashboard-1-clip.jpg', - 'cam2': 'dashboard-2.json', 'cam2/thumb': 'dashboard-2-thumb.jpg', 'cam2/clip': 'dashboard-2-clip.jpg', - 'cam3': 'dashboard-3.json', 'cam3/thumb': 'dashboard-3-thumb.jpg', 'cam3/clip': 'dashboard-3-clip.jpg', - 'cam4': 'dashboard-4.json', 'cam4/thumb': 'dashboard-4-thumb.jpg', 'cam4/clip': 'dashboard-4-clip.jpg', } @@ -151,7 +148,7 @@ def get_user_account(): # https://github.com/orgs/warwick-one-metre/teams/observers if is_github_team_member(user, 2128810): - permissions.update(['w1m', 'infrastructure_log', 'satellites']) + permissions.update(['w1m', 'halfmetre', 'infrastructure_log', 'satellites']) # https://github.com/orgs/GOTO-OBS/teams/ops-team/ if is_github_team_member(user, 2308649): @@ -263,6 +260,23 @@ def superwasp_generated_data(path): abort(404) +@app.route('/halfmetre/') +def halfmetre_dashboard(): + account = get_user_account() + if 'halfmetre' not in account['permissions']: + return redirect(url_for('site_overview')) + + return render_template('halfmetre.html', user_account=get_user_account()) + + +@app.route('/data/halfmetre/') +def halfmetre_generated_data(path): + account = get_user_account() + if 'halfmetre' in account['permissions'] and path in HALFMETRE_GENERATED_DATA: + print(HALFMETRE_GENERATED_DATA[path]) + return send_from_directory(GENERATED_DATA_DIR, HALFMETRE_GENERATED_DATA[path]) + abort(404) + @app.route('/goto1/') def goto1_dashboard(): account = get_user_account() @@ -314,6 +328,7 @@ def site_overview(): authorised_goto = user_account is not None and 'goto' in user_account['permissions'] authorised_satellites = user_account is not None and 'satellites' in user_account['permissions'] authorised_onemetre = user_account is not None and 'w1m' in user_account['permissions'] + authorised_halfmetre = user_account is not None and 'halfmetre' in user_account['permissions'] authorised_extcams = authorised_goto or authorised_satellites authorised = len(user_account['permissions']) > 0 @@ -334,7 +349,7 @@ def site_overview(): internal_cameras = [ SiteCamera('goto1', 'GOTO 1', authorised=authorised_goto, video=True, audio=True, light=True, infrared=True), SiteCamera('goto2', 'GOTO 2', authorised=authorised_goto, video=True, audio=True, light=True, infrared=True), - SiteCamera('halfmetre', 'Half Metre', authorised=authorised_satellites, video=True, audio=True, light=True, infrared=True), + SiteCamera('halfmetre', 'Half Metre', authorised=authorised_halfmetre, video=True, audio=True, light=True, infrared=True), SiteCamera('w1m', 'W1m', authorised=authorised_onemetre, video=True, audio=True, light=True, infrared=True), SiteCamera('superwasp', 'SuperWASP', authorised=authorised_satellites, video=True, audio=True, light=True, infrared=True), SiteCamera('clasp', 'CLASP', authorised=authorised_satellites, video=True, audio=True, light=True, infrared=True) @@ -477,7 +492,7 @@ def clasp_log(): @app.route('/data/halfmetre/log') def halfmetre_log(): account = get_user_account() - if 'satellites' not in account['permissions']: + if 'halfmetre' not in account['permissions']: abort(404) return fetch_log_messages({ @@ -488,6 +503,7 @@ def halfmetre_log(): 'pipelined@halfmetre': 'pipeline', 'qhy_camd@halfmetre': 'cam', 'diskspaced@halfmetre': 'diskspace', + 'focusd@halfmetre': 'focus' }) @@ -741,55 +757,16 @@ def superwasp_dashboard_data(): @app.route('/data/halfmetre/') def halfmetre_dashboard_data(): - data = json.load(open(GENERATED_DATA_DIR + '/halfmetre-public.json')) + account = get_user_account() + if 'halfmetre' not in account['permissions']: + abort(404) - # Some private data is needed for the public info + data = json.load(open(GENERATED_DATA_DIR + '/halfmetre-public.json')) private = json.load(open(GENERATED_DATA_DIR + '/halfmetre-private.json')) + data.update(private) - account = get_user_account() - if 'satellites' in account['permissions']: - data.update(private) - - # Extract safe public info from private daemons - private_ops = private.get('superwasp_ops', {}) - private_telescope = private.get('superwasp_telescope', {}) - private_roof = private.get('superwasp_roof', {}) - - # Tel status: - # 0: error - # 1: offline - # 2: online - tel_status = 0 - if 'state' in private_telescope: - tel_status = 1 if private_telescope['state'] == 0 else 2 - - # Roof status: - # 0: error - # 1: closed - # 2: open - roof_status = 0 - if 'status' in private_roof and 'heartbeat_status' in private_roof: - if private_roof['heartbeat_status'] != 2: - roof_status = 1 if private_roof['status'] == 1 else 2 - - roof_mode = 0 - if 'dome' in private_ops and 'mode' in private_ops['dome']: - roof_mode = private_ops['dome']['mode'] - - tel_mode = 0 - if 'telescope' in private_ops and 'mode' in private_ops['telescope']: - tel_mode = private_ops['telescope']['mode'] - - env = {} - if 'environment' in private_ops: - env = private_ops['environment'] - - data['wasp_status'] = { - 'tel': tel_status, - 'roof': roof_status, - 'tel_mode': tel_mode, - 'roof_mode': roof_mode, - 'environment': env + data['previews'] = { + 'halfmetre': json.load(open(GENERATED_DATA_DIR + '/dashboard-HALFMETRE.json')) } response = jsonify(**data) diff --git a/dashboard/templates/halfmetre.html b/dashboard/templates/halfmetre.html new file mode 100644 index 0000000..cba7fec --- /dev/null +++ b/dashboard/templates/halfmetre.html @@ -0,0 +1,122 @@ +{% extends "layout.html" %} +{% set title = '0.5m » Dashboard' -%} +{% set active_page = 'halfmetre-dashboard' -%} +{% block body %} +
+
+
+ Environment + Tel. Rm. Temp. + Tel. Rm. Humidity + Tel. Rm. Aircon + Comp Room Temp. +
+
+
+
+ UPS 1 + UPS 2 + ATS + Comp. Rm. Light + Tel. Rm. Light +
+
+
+
+ Mount + RA / Dec + Alt / Az + Sun / Moon Sep. + Mirrors Temp. +
+
+
+ Loading... +
+ Roof + Heartbeat + Roof Charger + Roof Battery +
+
+
+
+
+
+
+
+ Action Queue +
+
+
+
+
+
+
+
+ Dome Open +
+
+
+
+ Dome Close +
+
+
+
+
+
+ Camera + Exposure + Temperature + Filter + Disk Space + Focus +
+
+
+
+
+
+ +
+
+
+
+
+
+ Preview + Exposure started + Exposure length + Type + Overheads + Saved as +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + +{% endblock %} diff --git a/dashboard/templates/halfmetre/dashboard.html b/dashboard/templates/halfmetre/dashboard.html deleted file mode 100644 index 4a08c31..0000000 --- a/dashboard/templates/halfmetre/dashboard.html +++ /dev/null @@ -1,193 +0,0 @@ -{% extends "layout.html" %} -{% set title = 'Half Metre » Dashboard' -%} -{% set active_page = 'halfmetre-dashboard' -%} -{% block body %} -
-
-

{{ title|safe }}

-
Loading...
-
-
- -
-
-
- Roof Control - Roof Status -
-
-
-
- Tel. Control - Tel. Status -
-
-
-
- Environment -
-
-
- -
-
-
- UPS 1 - UPS 2 - Comp. Rm. Light - Comp. Rm. Aircon - Comp. Rm. Temp. - Comp. Rm. Hum. -
-
-
-
- Cam. Rm. Light - Cam. Rm. Aircon - Cam. Rm. Temp. - Cam. Rm. Hum. - Cam. Rack Temp. - Sky Clarity. -
-
-
-
- Ext. Humidity - Ext. Temp. - T > Dew Pt. - Peak Wind - Median Wind - Dust (TNG) -
-
-
-
- Rain Detectors - Sun Altitude - Moon Illumination - Moon Altitude - Seeing (TNG) - Brightness (TNG) -
-
-
-{% if user_account != None and 'satellites' in user_account['permissions'] %} -
-
-
-
Mount
- State - RA / Dec - Alt / Az - Sun / Moon Sep. - Mount - Lens Heaters -
-
-
-
-
Roof
- State - Heartbeat - Sched. Open - Sched. Close - Roof Charger - Roof Battery -
-
-
-
-
Cameras
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Status
Exposure
Temperature
Cooling
Lens Temp.
Disk Space
-
-
-
-
-
-
-
Ops / Pipeline
- Action - Status - Object - Prefix -
-
-
-
-
System Log
-
- -
-
-
-
-
-{% else %} -
-
-
-
Authentication Required
- Observation details are restricted to logged in observers. -
-
-
-{% endif %} - - - - - -{% endblock %} diff --git a/dashboard/templates/layout.html b/dashboard/templates/layout.html index 0b35bdb..aa73a4b 100644 --- a/dashboard/templates/layout.html +++ b/dashboard/templates/layout.html @@ -2,6 +2,7 @@ ('goto1-dashboard', url_for('goto1_dashboard'), 'goto', 'GOTO1'), ('goto2-dashboard', url_for('goto2_dashboard'), 'goto', 'GOTO2'), ('w1m-dashboard', url_for('w1m_dashboard'), 'w1m', 'W1m'), + ('halfmetre-dashboard', url_for('halfmetre_dashboard'), 'halfmetre', '0.5m'), ('clasp-dashboard', url_for('clasp_dashboard'), 'satellites', 'CLASP'), ('superwasp-dashboard', url_for('superwasp_dashboard'), 'satellites', 'SuperWASP'), ] %} diff --git a/static/halfmetre-dashboard.js b/static/halfmetre-dashboard.js deleted file mode 100644 index 4565519..0000000 --- a/static/halfmetre-dashboard.js +++ /dev/null @@ -1,278 +0,0 @@ -function roofBattery(row, cell, data) { - if (data != null) { - var display = data.toFixed(2); - var units = row.data('units'); - if (units) - display += units; - cell.html(display); - } else { - cell.html('NO DATA'); - cell.addClass('text-danger'); - } -} - -function powerInstrAircon(row, cell, data) { - status = 'ERROR'; - style = 'text-danger'; - - if (data && 'enabled' in data) { - if (data['enabled']) { - status = 'AUTO'; - style = 'text-success'; - } - else { - status = 'DISABLED'; - style = 'text-warning'; - } - } - - cell.html(status); - cell.addClass(style); -} - -function powerCompAircon(row, cell, data) { - status = 'ERROR'; - style = 'text-danger'; - - if (data && 'active' in data) { - if (data['active'] == 1) { - status = 'ACTIVE'; - style = 'text-success'; - } - else { - status = 'INACTIVE'; - style = 'text-warning'; - } - } - - cell.html(status); - cell.addClass(style); -} - -function telState(row, cell, data) { - var state = [ - ['DISABLED', 'text-danger'], - ['STOPPED', 'text-danger'], - ['HUNTING', 'text-warning'], - ['TRACKING', 'text-success'], - ['SLEWING', 'text-warning'], - ['HOMING', 'text-warning'], - ['LIMITING', 'text-warning'], - ]; - if (data && 'state' in data) { - if ('axes_homed' in data && !data['axes_homed']) { - cell.html('NOT HOMED'); - cell.addClass('text-danger'); - } else { - cell.html(state[data['state']][0]); - cell.addClass(state[data['state']][1]); - } - } else { - cell.html('ERROR'); - cell.addClass('text-danger'); - } -} - -function telRADec(row, cell, data) { - if (data && (('state' in data && (data['state'] < 1 || data['state'] > 3)) || ('axes_homed' in data && !data['axes_homed']))) - cell.html('N/A') - else if (!data || !('ra' in data) || !('dec' in data)) { - cell.html('ERROR'); - cell.addClass('text-danger'); - } else - cell.html(sexagesimal(data['ra'] / 15) + ' / ' + sexagesimal(data['dec'])); -} - -function telAltAz(row, cell, data) { - if (data && (('state' in data && (data['state'] < 1 || data['state'] > 3)) || ('axes_homed' in data && !data['axes_homed']))) - cell.html('N/A') - else if (!data || !('alt' in data) || !('az' in data)) { - cell.html('ERROR'); - cell.addClass('text-danger'); - } else - cell.html((data['alt']).toFixed(1) + '° / ' + (data['az']).toFixed(1) + '°'); -} - -function telSunMoon(row, cell, data) { - if (data && (('state' in data && (data['state'] < 1 || data['state'] > 3)) || ('axes_homed' in data && !data['axes_homed']))) - cell.html('N/A') - else if (!data || !('sun_separation' in data) || !('moon_separation' in data)) { - cell.html('ERROR'); - cell.addClass('text-danger'); - } else - cell.html((data['sun_separation']).toFixed(1) + '° / ' + (data['moon_separation']).toFixed(1) + '°'); -} - -function roofState(row, cell, data) { - var state = [ - ['PARTIALLY OPEN', 'text-info'], - ['CLOSED', 'text-danger'], - ['OPEN', 'text-success'], - ['CLOSING', 'text-warning'], - ['OPENING', 'text-warning'], - ]; - - if (data >= 0 && data < state.length) { - cell.html(state[data][0]); - cell.addClass(state[data][1]); - } else { - cell.html('ERROR'); - cell.addClass('text-danger'); - } -} - -function roofHeartbeat(row, cell, data) { - var state = [ - ['DISABLED', 'text-warning'], - ['ENABLED', 'text-success'], - ['TRIPPED', 'text-danger'], - ]; - - status = 'ERROR'; - style = 'text-danger'; - - if ('heartbeat_status' in data && 'heartbeat_remaining' in data) { - if (data['heartbeat_status'] == 1) { - status = data['heartbeat_remaining'] + 's remaining'; - if (data['heartbeat_remaining'] < 10) - style = 'text-danger' - else if (data['heartbeat_remaining'] < 30) - style = 'text-warning'; - else - style = 'text-success'; - } else { - status = state[data['heartbeat_status']][0]; - style = state[data['heartbeat_status']][1]; - } - } - - cell.html(status); - cell.addClass(style); -} - -function camStatus(row, cell, data) { - const cam = row.data('cam'); - const cam_state = getData(data, ["superwasp_cam_" + cam, "state"]); - const cam_power = getData(data, ["superwasp_power", "cam" + cam]); - const state = [ - ['OFFLINE', 'text-danger'], - ['INITIALIZING', 'text-danger'], - ['IDLE'], - ['WAITING', 'text-warning'], - ['EXPOSING', 'text-success'], - ['READING', 'text-warning'], - ['ABORTING', 'text-danger'], - ]; - - let label, style; - if (cam_state === undefined || cam_power === undefined) { - label = 'ERROR'; - style = 'text-danger'; - } else if (cam_power == 0) { - label = 'POWER OFF'; - style = 'text-danger'; - } else { - label = state[cam_state][0]; - style = state[cam_state][1]; - } - - cell.html(label); - cell.addClass(style); -} - -function camExposure(row, cell, data) { - const cam = row.data('cam'); - const cam_state = getData(data, ["superwasp_cam_" + cam, "state"]); - const cam_exposure = getData(data, ["superwasp_cam_" + cam, "exposure_time"]); - let label, style; - if (cam_state === 0) { - label = 'N/A'; - style = ''; - } else if (cam_exposure === undefined) { - label = 'ERROR'; - style = 'text-danger'; - } else { - label = cam_exposure.toFixed(3) + ' s'; - style = ''; - } - - cell.html(label); - cell.addClass(style); -} - -function camTemp(row, cell, data) { - const cam = row.data('cam'); - const cam_state = getData(data, ["superwasp_cam_" + cam, "state"]); - const cam_temperature = getData(data, ["superwasp_cam_" + cam, "cooler_temperature"]); - const cam_temperature_locked = getData(data, ["superwasp_cam_" + cam, "temperature_locked"]); - - let label, style; - if (cam_state === 0) { - label = 'N/A'; - style = ''; - } else if (cam_temperature === undefined || cam_temperature_locked === undefined) { - label = 'ERROR'; - style = 'text-danger'; - } else { - label = cam_temperature.toFixed(0) + ' °C'; - style = cam_temperature_locked ? 'text-success' : 'text-danger'; - } - - cell.html(label); - cell.addClass(style); -} - -function camCool(row, cell, data) { - const state = [ - ['UNKNOWN', 'text-danger'], - ['WARM', 'text-danger'], - ['WARMING', 'text-warning'], - ['COOLING', 'text-info'], - ['LOCKING', 'text-warning'], - ['LOCKED', 'text-success'], - ]; - - const cam = row.data('cam'); - const cam_state = getData(data, ["superwasp_cam_" + cam, "state"]); - const cam_cooler_power = getData(data, ["superwasp_cam_" + cam, "cooler_pwm"]); - const cam_cooler_mode = getData(data, ["superwasp_cam_" + cam, "cooler_mode"]); - - let label, style; - if (cam_state === 0) { - label = 'N/A'; - style = ''; - } else if (cam_cooler_power === undefined || cam_cooler_mode === undefined) { - label = 'ERROR'; - style = 'text-danger'; - } else { - label = state[cam_cooler_mode][0] - if (cam_cooler_mode !== 1) - label += ' (' + cam_cooler_power.toFixed(0) + '%)'; - - style = state[cam_cooler_mode][1]; - } - - cell.html(label); - cell.addClass(style); -} - -function camLensTemp(row, cell, data) { - var cam_number = row.data('cam'); - lens_temperature = getData(data, ["superwasp_lensheater", "temp_" + cam_number]); - if (lens_temperature === undefined) { - status = 'ERROR'; - style = 'text-danger'; - } else { - status = lens_temperature.toFixed(0) + ' °C'; - style = ''; - } - - cell.html(status); - cell.addClass(style); -} - -function camDiskSpace(row, cell, data){ - const cam = row.data('cam'); - const diskspace = getData(data, ["superwasp_diskspace_cam" + cam, "data_fs_available_bytes"]); - diskSpaceGB(row, cell, diskspace); -} diff --git a/static/rockit-dashboard.js b/static/rockit-dashboard.js index 811a11b..93998de 100644 --- a/static/rockit-dashboard.js +++ b/static/rockit-dashboard.js @@ -1,3 +1,5 @@ +// noinspection JSUnusedGlobalSymbols + function diskSpaceGB(row, cell, data) { if (data && 'latest' in data) { let display = +(data['latest'] / 1073741824).toFixed(1); @@ -9,66 +11,6 @@ function diskSpaceGB(row, cell, data) { } } -// Header generators -function opsHeaderTel(row, cell, data) { - let label = 'ERROR'; - let style = 'text-danger'; - let row_style = 'list-group-item-danger'; - - if (data === 1) { - label = 'OFFLINE'; - } else if (data === 2) { - label = 'ONLINE'; - style = 'text-success'; - row_style = 'list-group-item-success'; - } - - cell.html(label); - cell.addClass(style); - row.addClass(row_style); -} - -function opsHeaderDome(row, cell, data) { - let label = 'ERROR'; - let style = 'text-danger'; - let row_style = 'list-group-item-danger'; - - if (data === 1) { - label = 'CLOSED'; - } else if (data === 2) { - label = 'OPEN'; - style = 'text-success'; - row_style = 'list-group-item-success'; - } - - cell.html(label); - cell.addClass(style); - row.addClass(row_style); -} - -function opsHeaderMode(row, cell, data) { - const modes = [ - ['ERROR', 'list-group-item-danger'], - ['AUTO', 'list-group-item-success'], - ['MANUAL', 'list-group-item-warning'], - ]; - - const mode = data in modes ? modes[data] : mode[0]; - cell.html(mode[0]); - row.addClass(mode[1]); -} - -function opsHeaderDehumidifier(row, cell, data) { - const modes = [ - ['MANUAL', 'list-group-item-warning'], - ['AUTO', 'list-group-item-success'], - ]; - - const mode = data in modes ? modes[data] : modes[0]; - cell.html(mode[0]); - row.addClass(mode[1]); -} - function opsConditions(row, cell, data) { if ('safe' in data && 'conditions' in data) { cell.html(data['safe'] ? 'SAFE' : 'NOT SAFE'); @@ -524,6 +466,21 @@ function qhyTemperature(row, cell, data) { cell.addClass(style); } +function qhyFilter(row, cell, data) { + const state = getData(data, ["state"]); + let label = getData(data, ["filter"]); + let style = ''; + if (state === 0) { + label = 'N/A'; + } else if (label === undefined) { + label = 'ERROR'; + style = 'text-danger'; + } + + cell.html(label); + cell.addClass(style); +} + function swirState(row, cell, data) { // SWIR uses the same state dictionary as QHY qhyState(row, cell, data); @@ -666,6 +623,122 @@ function lensTemperature(row, cell, data) { } } +function roofBattery(row, cell, data) { + if (data != null) { + let display = data.toFixed(2); + const units = row.data('units'); + if (units) + display += units; + cell.html(display); + } else { + cell.html('NO DATA'); + cell.addClass('text-danger'); + } +} + +function roofState(row, cell, data) { + const state = [ + ['PARTIALLY OPEN', 'text-info'], + ['CLOSED', 'text-danger'], + ['OPEN', 'text-success'], + ['CLOSING', 'text-warning'], + ['OPENING', 'text-warning'], + ]; + + if (data >= 0 && data < state.length) { + cell.html(state[data][0]); + cell.addClass(state[data][1]); + } else { + cell.html('ERROR'); + cell.addClass('text-danger'); + } +} + +function roofHeartbeat(row, cell, data) { + const state = [ + ['DISABLED', 'text-warning'], + ['ENABLED', 'text-success'], + ['TRIPPED', 'text-danger'], + ]; + + let status = 'ERROR'; + let style = 'text-danger'; + + if ('heartbeat_status' in data && 'heartbeat_remaining' in data) { + if (data['heartbeat_status'] === 1) { + status = data['heartbeat_remaining'] + 's remaining'; + if (data['heartbeat_remaining'] < 10) + style = 'text-danger' + else if (data['heartbeat_remaining'] < 30) + style = 'text-warning'; + else + style = 'text-success'; + } else { + status = state[data['heartbeat_status']][0]; + style = state[data['heartbeat_status']][1]; + } + } + + cell.html(status); + cell.addClass(style); +} + +function powerInstrAircon(row, cell, data) { + let status = 'ERROR'; + let style = 'text-danger'; + + if (data && 'enabled' in data) { + if (data['enabled']) { + status = 'AUTO'; + style = 'text-success'; + } + else { + status = 'DISABLED'; + style = 'text-warning'; + } + } + + cell.html(status); + cell.addClass(style); +} + +function powerCompAircon(row, cell, data) { + let status = 'ERROR'; + let style = 'text-danger'; + + if (data && 'active' in data) { + if (data['active'] === 1) { + status = 'ACTIVE'; + style = 'text-success'; + } + else { + status = 'INACTIVE'; + style = 'text-warning'; + } + } + + cell.html(status); + cell.addClass(style); +} + +function halfmetreMirrorTemperature(row, cell, data) { + const focuser_data = getData(data, row.data('focuser-index')); + const powered = getData(data, row.data('power-index')); + const status = getData(focuser_data, ['status']); + const pri_temp = getData(focuser_data, ['temperature', 'primary_mirror']); + const sec_temp = getData(focuser_data, ['temperature', 'secondary_mirror']); + + let label, style; + if (powered === 0 || status === 0) { + cell.html('N/A'); + } else if (pri_temp !== undefined && sec_temp !== undefined) { + cell.html(pri_temp.toFixed(1) + ' °C / ' + sec_temp.toFixed(1)+ ' °C'); + } else { + cell.html('ERROR'); + cell.addClass('text-danger'); + } +} + function onemetreState(row, cell, data) { const state = [ ['DISABLED', 'text-danger'], @@ -808,6 +881,8 @@ function previewOverheads(row, cell, data) { cell.addClass('text-danger'); } else { cell.html(time.toFixed(1) + ' s (' + steps.join(', ') + ')'); + cell.addClass('d-inline-block text-truncate'); + cell.css('max-width', '230px'); } } diff --git a/update-dashboard-data b/update-dashboard-data index 0554379..d87dfd8 100644 --- a/update-dashboard-data +++ b/update-dashboard-data @@ -361,6 +361,7 @@ generate_json(BASE_OUTPUT_DIR + '/halfmetre-private.json', [ (daemons.halfmetre_roof, 'halfmetre_roof', lambda d: d.status()), (daemons.halfmetre_pipeline, 'halfmetre_pipeline', lambda d: d.report_status()), (daemons.halfmetre_cam, 'halfmetre_cam', lambda d: d.report_status()), + (daemons.halfmetre_focuser, 'halfmetre_focus', lambda d: d.report_status()), ]) # Raw data for GOTO operations