SolarEnergy/central_frontend/src/dialogs/EditDeviceRelaysDialog.tsx

292 lines
9.0 KiB
TypeScript

import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Grid,
Typography,
} from "@mui/material";
import { TimePicker } from "@mui/x-date-pickers";
import React from "react";
import { Device, DeviceRelay } from "../api/DeviceApi";
import { ServerApi } from "../api/ServerApi";
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
import { dayjsToTimeOfDay, timeOfDay } from "../utils/DateUtils";
import { lenValid } from "../utils/StringsUtils";
import { CheckboxInput } from "../widgets/forms/CheckboxInput";
import { TextInput } from "../widgets/forms/TextInput";
import { MultipleSelectInput } from "../widgets/forms/MultipleSelectInput";
export function EditDeviceRelaysDialog(p: {
onClose: () => void;
relay?: DeviceRelay;
device: Device;
onUpdated: () => void;
}): React.ReactElement {
const loadingMessage = useLoadingMessage();
const alert = useAlert();
const snackbar = useSnackbar();
const [relay, setRelay] = React.useState<DeviceRelay>(
p.relay ?? {
id: "",
name: "relay",
enabled: false,
priority: 1,
consumption: 500,
minimal_downtime: 60 * 5,
minimal_uptime: 60 * 5,
depends_on: [],
conflicts_with: [],
}
);
const creating = !p.relay;
const onSubmit = async () => {
try {
loadingMessage.show(
`${creating ? "Creating" : "Updating"} relay information`
);
// TODO
snackbar(
`The relay have been successfully ${creating ? "created" : "updated"}!`
);
p.onUpdated();
} catch (e) {
console.error("Failed to update device relay information!" + e);
alert(`Failed to ${creating ? "create" : "update"} relay! ${e}`);
} finally {
loadingMessage.hide();
}
};
const canSubmit =
lenValid(relay.name, ServerApi.Config.constraints.relay_name_len) &&
relay.priority >= 0;
return (
<Dialog open>
<DialogTitle>Edit relay information</DialogTitle>
<DialogContent>
<DialogFormTitle>General info</DialogFormTitle>
<Grid container spacing={2}>
<Grid item xs={6}>
<TextInput
editable
label="Relay name"
value={relay.name}
onValueChange={(v) =>
setRelay((r) => {
return {
...r,
name: v ?? "",
};
})
}
size={ServerApi.Config.constraints.dev_name_len}
/>
</Grid>
<Grid item xs={6}>
<CheckboxInput
editable
label="Enable relay"
checked={relay.enabled}
onValueChange={(v) =>
setRelay((r) => {
return {
...r,
enabled: v,
};
})
}
/>
</Grid>
<Grid item xs={6}>
<TextInput
editable
label="Priority"
value={relay.priority.toString()}
type="number"
onValueChange={(v) =>
setRelay((r) => {
return {
...r,
priority: Number(v) ?? 0,
};
})
}
size={ServerApi.Config.constraints.relay_priority}
helperText="Relay priority when selecting relays to turn on. 0 = lowest priority"
/>
</Grid>
<Grid item xs={6}>
<TextInput
editable
label="Consumption"
value={relay.consumption.toString()}
type="number"
onValueChange={(v) =>
setRelay((r) => {
return {
...r,
consumption: Number(v) ?? 0,
};
})
}
size={ServerApi.Config.constraints.relay_consumption}
helperText="Estimated consumption of device powered by relay"
/>
</Grid>
<Grid item xs={6}>
<TextInput
editable
label="Minimal uptime"
value={relay.minimal_uptime.toString()}
type="number"
onValueChange={(v) =>
setRelay((r) => {
return {
...r,
minimal_uptime: Number(v) ?? 0,
};
})
}
size={ServerApi.Config.constraints.relay_minimal_uptime}
helperText="Minimal time this relay shall be left on before it can be turned off (in seconds)"
/>
</Grid>
<Grid item xs={6}>
<TextInput
editable
label="Minimal downtime"
value={relay.minimal_downtime.toString()}
type="number"
onValueChange={(v) =>
setRelay((r) => {
return {
...r,
minimal_downtime: Number(v) ?? 0,
};
})
}
size={ServerApi.Config.constraints.relay_minimal_downtime}
helperText="Minimal time this relay shall be left on before it can be turned off (in seconds)"
/>
</Grid>
</Grid>
<DialogFormTitle>Daily runtime</DialogFormTitle>
<Grid container spacing={2}>
<Grid item xs={6}>
<CheckboxInput
editable
label="Enable minimal runtime"
checked={!!relay.daily_runtime}
onValueChange={(v) =>
setRelay((r) => {
return {
...r,
daily_runtime: v
? { reset_time: 0, min_runtime: 3600, catch_up_hours: [] }
: undefined,
};
})
}
/>
</Grid>
{!!relay.daily_runtime && (
<>
<Grid item xs={6}>
<TextInput
editable
label="Minimal daily runtime"
value={relay.daily_runtime!.min_runtime.toString()}
type="number"
onValueChange={(v) =>
setRelay((r) => {
return {
...r,
daily_runtime: {
...r.daily_runtime!,
min_runtime: Number(v),
},
};
})
}
size={
ServerApi.Config.constraints.relay_daily_minimal_runtime
}
helperText="Minimum time, in seconds, that this relay should run each day"
/>
</Grid>
<Grid item xs={6}>
<TimePicker
label="Reset time"
value={timeOfDay(relay.daily_runtime!.reset_time)}
onChange={(d) =>
setRelay((r) => {
return {
...r,
daily_runtime: {
...r.daily_runtime!,
reset_time: d ? dayjsToTimeOfDay(d) : 0,
},
};
})
}
/>
</Grid>
<Grid item xs={6}>
<MultipleSelectInput
label="Catchup hours"
helperText="The hours during which the relay should be turned on to reach expected runtime"
values={Array.apply(null, Array(24)).map((_y, i) => {
return {
label: `${i.toString().padStart(2, "0")}:00`,
value: i,
};
})}
selected={relay.daily_runtime!.catch_up_hours}
onChange={(d) =>
setRelay((r) => {
return {
...r,
daily_runtime: {
...r.daily_runtime!,
catch_up_hours: d,
},
};
})
}
/>
</Grid>
</>
)}
</Grid>
</DialogContent>
<DialogActions>
<Button onClick={p.onClose}>Cancel</Button>
<Button onClick={onSubmit} autoFocus disabled={!canSubmit}>
Submit
</Button>
</DialogActions>
</Dialog>
);
}
function DialogFormTitle(p: React.PropsWithChildren): React.ReactElement {
return (
<>
<span style={{ height: "2px" }}></span>
<Typography variant="h6">{p.children}</Typography>
</>
);
}