mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
313 lines
8.7 KiB
JavaScript
313 lines
8.7 KiB
JavaScript
import { toFixed } from 'common/math';
|
|
import { Fragment } from 'inferno';
|
|
import { useBackend, useLocalState } from '../backend';
|
|
import { Box, Button, LabeledList, Section } from '../components';
|
|
import { getGasLabel, getGasColor } from '../constants';
|
|
import { Window } from '../layouts';
|
|
import { InterfaceLockNoticeBox } from './common/InterfaceLockNoticeBox';
|
|
import { Vent, Scrubber } from './common/AtmosControls';
|
|
|
|
export const AirAlarm = (props, context) => {
|
|
const { act, data } = useBackend(context);
|
|
const locked = data.locked && !data.siliconUser && !data.remoteUser;
|
|
return (
|
|
<Window width={440} height={650} resizable>
|
|
<Window.Content scrollable>
|
|
<InterfaceLockNoticeBox />
|
|
<AirAlarmStatus />
|
|
<AirAlarmUnlockedControl />
|
|
{!locked && <AirAlarmControl />}
|
|
</Window.Content>
|
|
</Window>
|
|
);
|
|
};
|
|
|
|
const AirAlarmStatus = (props, context) => {
|
|
const { data } = useBackend(context);
|
|
const entries = (data.environment_data || []).filter(
|
|
(entry) => entry.value >= 0.01
|
|
);
|
|
const dangerMap = {
|
|
0: {
|
|
color: 'good',
|
|
localStatusText: 'Optimal',
|
|
},
|
|
1: {
|
|
color: 'average',
|
|
localStatusText: 'Caution',
|
|
},
|
|
2: {
|
|
color: 'bad',
|
|
localStatusText: 'Danger (Internals Required)',
|
|
},
|
|
};
|
|
const localStatus = dangerMap[data.danger_level] || dangerMap[0];
|
|
return (
|
|
<Section title="Air Status">
|
|
<LabeledList>
|
|
{(entries.length > 0 && (
|
|
<Fragment>
|
|
{entries.map((entry) => {
|
|
const status = dangerMap[entry.danger_level] || dangerMap[0];
|
|
return (
|
|
<LabeledList.Item
|
|
key={entry.name}
|
|
label={getGasLabel(entry.name)}
|
|
color={status.color}>
|
|
{toFixed(entry.value, 2)}
|
|
{entry.unit}
|
|
</LabeledList.Item>
|
|
);
|
|
})}
|
|
<LabeledList.Item label="Local status" color={localStatus.color}>
|
|
{localStatus.localStatusText}
|
|
</LabeledList.Item>
|
|
<LabeledList.Item
|
|
label="Area status"
|
|
color={data.atmos_alarm || data.fire_alarm ? 'bad' : 'good'}>
|
|
{(data.atmos_alarm && 'Atmosphere Alarm') ||
|
|
(data.fire_alarm && 'Fire Alarm') ||
|
|
'Nominal'}
|
|
</LabeledList.Item>
|
|
</Fragment>
|
|
)) || (
|
|
<LabeledList.Item label="Warning" color="bad">
|
|
Cannot obtain air sample for analysis.
|
|
</LabeledList.Item>
|
|
)}
|
|
{!!data.emagged && (
|
|
<LabeledList.Item label="Warning" color="bad">
|
|
Safety measures offline. Device may exhibit abnormal behavior.
|
|
</LabeledList.Item>
|
|
)}
|
|
</LabeledList>
|
|
</Section>
|
|
);
|
|
};
|
|
|
|
const AirAlarmUnlockedControl = (props, context) => {
|
|
const { act, data } = useBackend(context);
|
|
const { target_temperature, rcon } = data;
|
|
return (
|
|
<Section title="Comfort Settings">
|
|
<LabeledList>
|
|
<LabeledList.Item label="Remote Control">
|
|
<Button
|
|
selected={rcon === 1}
|
|
content="Off"
|
|
onClick={() => act('rcon', { 'rcon': 1 })}
|
|
/>
|
|
<Button
|
|
selected={rcon === 2}
|
|
content="Auto"
|
|
onClick={() => act('rcon', { 'rcon': 2 })}
|
|
/>
|
|
<Button
|
|
selected={rcon === 3}
|
|
content="On"
|
|
onClick={() => act('rcon', { 'rcon': 3 })}
|
|
/>
|
|
</LabeledList.Item>
|
|
<LabeledList.Item label="Thermostat">
|
|
<Button
|
|
content={target_temperature}
|
|
onClick={() => act('temperature')}
|
|
/>
|
|
</LabeledList.Item>
|
|
</LabeledList>
|
|
</Section>
|
|
);
|
|
};
|
|
|
|
const AIR_ALARM_ROUTES = {
|
|
home: {
|
|
title: 'Air Controls',
|
|
component: () => AirAlarmControlHome,
|
|
},
|
|
vents: {
|
|
title: 'Vent Controls',
|
|
component: () => AirAlarmControlVents,
|
|
},
|
|
scrubbers: {
|
|
title: 'Scrubber Controls',
|
|
component: () => AirAlarmControlScrubbers,
|
|
},
|
|
modes: {
|
|
title: 'Operating Mode',
|
|
component: () => AirAlarmControlModes,
|
|
},
|
|
thresholds: {
|
|
title: 'Alarm Thresholds',
|
|
component: () => AirAlarmControlThresholds,
|
|
},
|
|
};
|
|
|
|
const AirAlarmControl = (props, context) => {
|
|
const [screen, setScreen] = useLocalState(context, 'screen');
|
|
const route = AIR_ALARM_ROUTES[screen] || AIR_ALARM_ROUTES.home;
|
|
const Component = route.component();
|
|
return (
|
|
<Section
|
|
title={route.title}
|
|
buttons={
|
|
screen && (
|
|
<Button
|
|
icon="arrow-left"
|
|
content="Back"
|
|
onClick={() => setScreen()}
|
|
/>
|
|
)
|
|
}>
|
|
<Component />
|
|
</Section>
|
|
);
|
|
};
|
|
|
|
// Home screen
|
|
// --------------------------------------------------------
|
|
|
|
const AirAlarmControlHome = (props, context) => {
|
|
const { act, data } = useBackend(context);
|
|
const [screen, setScreen] = useLocalState(context, 'screen');
|
|
const { mode, atmos_alarm } = data;
|
|
return (
|
|
<Fragment>
|
|
<Button
|
|
icon={atmos_alarm ? 'exclamation-triangle' : 'exclamation'}
|
|
color={atmos_alarm && 'caution'}
|
|
content="Area Atmosphere Alarm"
|
|
onClick={() => act(atmos_alarm ? 'reset' : 'alarm')}
|
|
/>
|
|
<Box mt={1} />
|
|
<Button
|
|
icon={mode === 3 ? 'exclamation-triangle' : 'exclamation'}
|
|
color={mode === 3 && 'danger'}
|
|
content="Panic Siphon"
|
|
onClick={() =>
|
|
act('mode', {
|
|
mode: mode === 3 ? 1 : 3,
|
|
})
|
|
}
|
|
/>
|
|
<Box mt={2} />
|
|
<Button
|
|
icon="sign-out-alt"
|
|
content="Vent Controls"
|
|
onClick={() => setScreen('vents')}
|
|
/>
|
|
<Box mt={1} />
|
|
<Button
|
|
icon="filter"
|
|
content="Scrubber Controls"
|
|
onClick={() => setScreen('scrubbers')}
|
|
/>
|
|
<Box mt={1} />
|
|
<Button
|
|
icon="cog"
|
|
content="Operating Mode"
|
|
onClick={() => setScreen('modes')}
|
|
/>
|
|
<Box mt={1} />
|
|
<Button
|
|
icon="chart-bar"
|
|
content="Alarm Thresholds"
|
|
onClick={() => setScreen('thresholds')}
|
|
/>
|
|
</Fragment>
|
|
);
|
|
};
|
|
|
|
// Vents
|
|
// --------------------------------------------------------
|
|
|
|
const AirAlarmControlVents = (props, context) => {
|
|
const { data } = useBackend(context);
|
|
const { vents } = data;
|
|
if (!vents || vents.length === 0) {
|
|
return 'Nothing to show';
|
|
}
|
|
return vents.map((vent) => <Vent key={vent.id_tag} vent={vent} />);
|
|
};
|
|
|
|
// Scrubbers
|
|
// --------------------------------------------------------
|
|
|
|
const AirAlarmControlScrubbers = (props, context) => {
|
|
const { data } = useBackend(context);
|
|
const { scrubbers } = data;
|
|
if (!scrubbers || scrubbers.length === 0) {
|
|
return 'Nothing to show';
|
|
}
|
|
return scrubbers.map((scrubber) => (
|
|
<Scrubber key={scrubber.id_tag} scrubber={scrubber} />
|
|
));
|
|
};
|
|
|
|
// Modes
|
|
// --------------------------------------------------------
|
|
|
|
const AirAlarmControlModes = (props, context) => {
|
|
const { act, data } = useBackend(context);
|
|
const { modes } = data;
|
|
if (!modes || modes.length === 0) {
|
|
return 'Nothing to show';
|
|
}
|
|
return modes.map((mode) => (
|
|
<Fragment key={mode.mode}>
|
|
<Button
|
|
icon={mode.selected ? 'check-square-o' : 'square-o'}
|
|
selected={mode.selected}
|
|
color={mode.selected && mode.danger && 'danger'}
|
|
content={mode.name}
|
|
onClick={() => act('mode', { mode: mode.mode })}
|
|
/>
|
|
<Box mt={1} />
|
|
</Fragment>
|
|
));
|
|
};
|
|
|
|
// Thresholds
|
|
// --------------------------------------------------------
|
|
|
|
const AirAlarmControlThresholds = (props, context) => {
|
|
const { act, data } = useBackend(context);
|
|
const { thresholds } = data;
|
|
return (
|
|
<table className="LabeledList" style={{ width: '100%' }}>
|
|
<thead>
|
|
<tr>
|
|
<td />
|
|
<td className="color-bad">min2</td>
|
|
<td className="color-average">min1</td>
|
|
<td className="color-average">max1</td>
|
|
<td className="color-bad">max2</td>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{thresholds.map((threshold) => (
|
|
<tr key={threshold.name}>
|
|
<td className="LabeledList__label">
|
|
<span className={'color-' + getGasColor(threshold.name)}>
|
|
{getGasLabel(threshold.name)}
|
|
</span>
|
|
</td>
|
|
{threshold.settings.map((setting) => (
|
|
<td key={setting.val}>
|
|
<Button
|
|
content={toFixed(setting.selected, 2)}
|
|
onClick={() =>
|
|
act('threshold', {
|
|
env: setting.env,
|
|
var: setting.val,
|
|
})
|
|
}
|
|
/>
|
|
</td>
|
|
))}
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
);
|
|
};
|