|
@@ -1,46 +1,24 @@
|
|
|
import { useEffect, useState } from "react";
|
|
import { useEffect, useState } from "react";
|
|
|
-import { Button, Collapse, Drawer, Icon, Steps, Typography } from "tiny-ui";
|
|
|
|
|
-import WLED from "./WLED.js";
|
|
|
|
|
|
|
+import { Button, Icon, Steps, Typography } from "tiny-ui";
|
|
|
|
|
|
|
|
import { useLocalStorage } from "lib/state";
|
|
import { useLocalStorage } from "lib/state";
|
|
|
-import { isBlank } from "lib/utils";
|
|
|
|
|
|
|
|
|
|
const { Step } = Steps;
|
|
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) => (
|
|
|
|
|
- <div key={i}>
|
|
|
|
|
- <strong>{o}:</strong> {normalize(connection?.state?.[o])}
|
|
|
|
|
- </div>
|
|
|
|
|
- ))}
|
|
|
|
|
- </div>
|
|
|
|
|
- </Panel>
|
|
|
|
|
- );
|
|
|
|
|
-};
|
|
|
|
|
-const WLEDClient = WLED(Client);
|
|
|
|
|
|
|
+const { Paragraph } = Typography;
|
|
|
|
|
|
|
|
const Automation = ({
|
|
const Automation = ({
|
|
|
- automation,
|
|
|
|
|
- presets,
|
|
|
|
|
clients,
|
|
clients,
|
|
|
names,
|
|
names,
|
|
|
- onPreset,
|
|
|
|
|
- onSync,
|
|
|
|
|
|
|
+ presets,
|
|
|
|
|
+ automation,
|
|
|
|
|
+ onAutomation,
|
|
|
onPower,
|
|
onPower,
|
|
|
- connections,
|
|
|
|
|
|
|
+ busy,
|
|
|
...props
|
|
...props
|
|
|
}) => {
|
|
}) => {
|
|
|
const [current, setCurrent] = useLocalStorage("preset", -1, 3600);
|
|
const [current, setCurrent] = useLocalStorage("preset", -1, 3600);
|
|
|
const [total, setTotal] = useState();
|
|
const [total, setTotal] = useState();
|
|
|
const [help, setHelp] = useState(false);
|
|
const [help, setHelp] = useState(false);
|
|
|
- const [info, setInfo] = useState(false);
|
|
|
|
|
|
|
|
|
|
const getTitle = (indx) => presets?.[indx]?.name || indx;
|
|
const getTitle = (indx) => presets?.[indx]?.name || indx;
|
|
|
const getName = (v) => {
|
|
const getName = (v) => {
|
|
@@ -57,45 +35,15 @@ const Automation = ({
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- 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(() => {
|
|
useEffect(() => {
|
|
|
setTotal((automation && Object.keys(automation)?.length) || 0);
|
|
setTotal((automation && Object.keys(automation)?.length) || 0);
|
|
|
- }, []);
|
|
|
|
|
|
|
+ }, [automation]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
if (current > -1 && current < total) {
|
|
if (current > -1 && current < total) {
|
|
|
- handleChange(current + 1);
|
|
|
|
|
|
|
+ onAutomation(current + 1);
|
|
|
}
|
|
}
|
|
|
- }, [current]);
|
|
|
|
|
|
|
+ }, [current, total]);
|
|
|
|
|
|
|
|
let steps = Object.keys(automation).map((o, i) => {
|
|
let steps = Object.keys(automation).map((o, i) => {
|
|
|
return (
|
|
return (
|
|
@@ -111,7 +59,7 @@ const Automation = ({
|
|
|
round
|
|
round
|
|
|
icon={<Icon name="loader-circle" />}
|
|
icon={<Icon name="loader-circle" />}
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
|
- handleChange(o);
|
|
|
|
|
|
|
+ onAutomation(o);
|
|
|
}}
|
|
}}
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
@@ -140,7 +88,7 @@ const Automation = ({
|
|
|
title="Reapply"
|
|
title="Reapply"
|
|
|
icon={<Icon name="loader-circle" />}
|
|
icon={<Icon name="loader-circle" />}
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
|
- handleChange(current + 1);
|
|
|
|
|
|
|
+ onAutomation(current + 1);
|
|
|
}}
|
|
}}
|
|
|
/>
|
|
/>
|
|
|
<Button
|
|
<Button
|
|
@@ -157,7 +105,7 @@ const Automation = ({
|
|
|
<Button
|
|
<Button
|
|
|
title="Power on"
|
|
title="Power on"
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
|
- handlePower("on");
|
|
|
|
|
|
|
+ onPower("on");
|
|
|
}}
|
|
}}
|
|
|
>
|
|
>
|
|
|
On
|
|
On
|
|
@@ -165,7 +113,7 @@ const Automation = ({
|
|
|
<Button
|
|
<Button
|
|
|
title="Power off"
|
|
title="Power off"
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
|
- handlePower("off");
|
|
|
|
|
|
|
+ onPower("off");
|
|
|
}}
|
|
}}
|
|
|
>
|
|
>
|
|
|
Off
|
|
Off
|
|
@@ -180,15 +128,12 @@ const Automation = ({
|
|
|
}}
|
|
}}
|
|
|
/>
|
|
/>
|
|
|
</Button.Group>
|
|
</Button.Group>
|
|
|
- <Button.Group size="md" round>
|
|
|
|
|
- <Button
|
|
|
|
|
- title="Information"
|
|
|
|
|
- icon={<Icon name="info" />}
|
|
|
|
|
- onClick={() => {
|
|
|
|
|
- setInfo(true);
|
|
|
|
|
- }}
|
|
|
|
|
- />
|
|
|
|
|
- </Button.Group>
|
|
|
|
|
|
|
+ {(busy && (
|
|
|
|
|
+ <Button.Group size="md" round>
|
|
|
|
|
+ <Button title="Busy" icon={<Icon spin name="loader-3quarter" />} />
|
|
|
|
|
+ </Button.Group>
|
|
|
|
|
+ )) ||
|
|
|
|
|
+ null}
|
|
|
</div>
|
|
</div>
|
|
|
<Steps
|
|
<Steps
|
|
|
current={current}
|
|
current={current}
|
|
@@ -197,49 +142,6 @@ const Automation = ({
|
|
|
>
|
|
>
|
|
|
{steps}
|
|
{steps}
|
|
|
</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>
|
|
|
|
|
</>
|
|
</>
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|