| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- import { useEffect, useState } from "react";
- import { Button, Collapse, Drawer, Icon, Steps, Typography } from "tiny-ui";
- import WLED from "./WLED.js";
- import { useLocalStorage } from "lib/state";
- import { isBlank } from "lib/utils";
- const { Step } = Steps;
- const { Panel } = Collapse;
- const { Heading, Paragraph, Text } = Typography;
- const Client = ({ name, client, connection, ...rest }) => {
- const normalize = (v) => JSON.stringify(v, null, 2);
- return (
- <Panel header={name} {...rest}>
- <p>IP address: {client}</p>
- <div style={{ overflowY: "scroll", height: 200 }}>
- {Object.keys(connection?.state)?.map((o, i) => {
- return (
- <div>
- <strong>{o}:</strong> {normalize(connection?.state?.[o])}
- </div>
- );
- })}
- </div>
- </Panel>
- );
- };
- const WLEDClient = WLED(Client);
- const Automation = ({
- automation,
- presets,
- clients,
- names,
- onPreset,
- onSync,
- onPower,
- connections,
- ...props
- }) => {
- const [current, setCurrent] = useLocalStorage("preset", -1, 3600);
- const [total, setTotal] = useState();
- const [help, setHelp] = useState(false);
- const [info, setInfo] = useState(false);
- const getTitle = (indx) => presets?.[indx]?.name || indx;
- const getName = (v) => {
- let indx = clients?.findIndex((o) => o === v);
- return indx > -1 ? names?.[indx] : v;
- };
- const getDescription = (indx) => {
- return (
- (automation?.[indx] &&
- Object.keys(automation?.[indx])
- ?.map((o) => getName(o))
- ?.join(", ")) ||
- null
- );
- };
- const handleChange = (indx) => {
- let keys = Object.keys(automation?.[indx]);
- let preset = { clients: keys || [], value: indx };
- let power = { on: [], off: [] };
- let sync = { enable: [], disable: [] };
- // loop the keys and determine what to do
- for (let key of keys) {
- if (automation?.[indx]?.[key]?.on === true) power.on.push(key);
- else power.off.push(key);
- if (automation?.[indx]?.[key]?.sync === true) sync.enable.push(key);
- else sync.disable.push(key);
- }
- if (!isBlank(sync?.enable))
- onSync({ clients: sync?.enable, value: "enable" }); // enable sync
- if (!isBlank(sync?.disable))
- onSync({ clients: sync?.disable, value: "disable" }); // disable sync
- setTimeout(() => {
- onPreset(preset); // apply the preset
- }, 100);
- setTimeout(() => {
- if (!isBlank(power?.on)) onPower({ clients: power?.on, value: "on" }); // power on
- if (!isBlank(power?.off)) onPower({ clients: power?.off, value: "off" }); // power off
- }, 200);
- };
- const handlePower = (value) => {
- let keys = Object.keys(automation?.[1]);
- onPower({ clients: keys, value: value });
- };
- useEffect(() => {
- setTotal((automation && Object.keys(automation)?.length) || 0);
- }, []);
- useEffect(() => {
- if (current > -1 && current < total) {
- handleChange(current + 1);
- }
- }, [current]);
- let steps = Object.keys(automation).map((o, i) => {
- return (
- <Step
- key={i}
- title={
- <div style={{ display: "flex", flexDirection: "row" }}>
- <div>{getTitle(o)}</div>
- {current === o - 1 ? (
- <div style={{ marginLeft: "3rem" }}>
- <Button
- title="Reapply"
- round
- icon={<Icon name="loader-circle" />}
- onClick={() => {
- handleChange(o);
- }}
- />
- </div>
- ) : null}
- </div>
- }
- description={getDescription(o)}
- ></Step>
- );
- });
- return (
- <>
- <div style={{ position: "sticky", top: "60px", marginBottom: "2rem" }}>
- <Button.Group size="md" round>
- <Button
- title="Previous"
- icon={<Icon name="arrow-left" />}
- onClick={() => {
- let next = current - 1;
- if (next < 0) next = 0;
- setCurrent(next);
- }}
- />
- <Button
- title="Reapply"
- icon={<Icon name="loader-circle" />}
- onClick={() => {
- handleChange(current + 1);
- }}
- />
- <Button
- title="Next"
- icon={<Icon name="arrow-right" />}
- onClick={() => {
- let next = current + 1;
- if (next > total) next = 0;
- setCurrent(next);
- }}
- />
- </Button.Group>
- <Button.Group size="md" round>
- <Button
- title="Power on"
- onClick={() => {
- handlePower("on");
- }}
- >
- On
- </Button>
- <Button
- title="Power off"
- onClick={() => {
- handlePower("off");
- }}
- >
- Off
- </Button>
- </Button.Group>
- <Button.Group size="md" round>
- <Button
- title="Help"
- icon={<Icon name="question-fill" />}
- onClick={() => {
- setHelp(true);
- }}
- />
- </Button.Group>
- <Button.Group size="md" round>
- <Button
- title="Information"
- icon={<Icon name="info" />}
- onClick={() => {
- setInfo(true);
- }}
- />
- </Button.Group>
- </div>
- <Steps
- current={current}
- direction="vertical"
- onChange={(v) => setCurrent(v)}
- >
- {steps}
- </Steps>
- <Drawer
- header="Client connections"
- placement="right"
- size={480}
- onClose={() => setInfo(false)}
- visible={info}
- >
- <Collapse accordion bordered={false}>
- {connections?.map((o, i) => (
- <WLEDClient
- key={i}
- itemKey={i}
- connection={o}
- client={clients[i]}
- name={names[i]}
- />
- ))}
- </Collapse>
- </Drawer>
- <Drawer
- header="Help"
- placement="right"
- size={480}
- onClose={() => setHelp(false)}
- visible={help}
- >
- <>
- <Paragraph>
- Select one of the presets from the left to start applying preset
- automation.
- </Paragraph>
- <Paragraph>
- You can use the navigation buttons above to advance forward{" "}
- <Icon name="arrow-right" size={16} /> and backward{" "}
- <Icon name="arrow-left" size={16} /> through the preset list.
- </Paragraph>
- <Paragraph>
- If a preset fails to apply to all of the intended WLED instances
- then use the Reapply button <Icon name="loader-circle" size={16} />{" "}
- within the navigation menu bar or within the target step.
- </Paragraph>
- </>
- </Drawer>
- </>
- );
- };
- export default Automation;
|