diff --git a/.gitignore b/.gitignore
index 8332b7eb9..a4d5706dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,8 @@
# vscode
.vscode/c_cpp_properties.json
-.vscode/extensions.json
+# .vscode/extensions.json
.vscode/launch.json
-.vscode/settings.json
+# .vscode/settings.json
# c++ compiling
.clang_complete
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 000000000..3afe24493
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,13 @@
+{
+ // See http://go.microsoft.com/fwlink/?LinkId=827846
+ // for the documentation about the extensions.json format
+ "recommendations": [
+ "arcanis.vscode-zipfs",
+ "dbaeumer.vscode-eslint",
+ "esbenp.prettier-vscode",
+ "platformio.platformio-ide"
+ ],
+ "unwantedRecommendations": [
+ "ms-vscode.cpptools-extension-pack"
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..65809f694
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,10 @@
+{
+ "search.exclude": {
+ "**/.yarn": true,
+ "**/.pnp.*": true
+ },
+ "eslint.nodePath": "interface/.yarn/sdks",
+ "prettier.prettierPath": "interface/.yarn/sdks/prettier/index.js",
+ "typescript.tsdk": "interface/.yarn/sdks/typescript/lib",
+ "typescript.enablePromptUseWorkspaceTsdk": true
+}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index c60c56f64..1e14f946b 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -10,7 +10,7 @@
"linux": {
"options": {
"env": {
- // Workaroung for sdl2 `-m32` crash
+ // Workaround for sdl2 `-m32` crash
// https://bugs.launchpad.net/ubuntu/+source/libsdl2/+bug/1775067/comments/7
"DBUS_FATAL_WARNINGS": "0"
}
diff --git a/interface/.yarn/sdks/eslint/package.json b/interface/.yarn/sdks/eslint/package.json
index a29ed491e..1393f7747 100644
--- a/interface/.yarn/sdks/eslint/package.json
+++ b/interface/.yarn/sdks/eslint/package.json
@@ -1,6 +1,6 @@
{
"name": "eslint",
- "version": "8.34.0-sdk",
+ "version": "8.35.0-sdk",
"main": "./lib/api.js",
"type": "commonjs"
}
diff --git a/interface/index.html b/interface/index.html
index 4f115b0e6..602add36a 100644
--- a/interface/index.html
+++ b/interface/index.html
@@ -2,7 +2,7 @@
-
+
EMS-ESP
diff --git a/interface/package.json b/interface/package.json
index 1a9a3caea..9812700bc 100644
--- a/interface/package.json
+++ b/interface/package.json
@@ -27,10 +27,11 @@
"@remix-run/router": "^1.3.3",
"@table-library/react-table-library": "4.0.29",
"@types/lodash-es": "^4.17.6",
- "@types/node": "^18.14.5",
+ "@types/node": "^18.14.6",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/react-router-dom": "^5.3.3",
+ "@yarnpkg/pnpify": "^4.0.0-rc.40",
"async-validator": "^4.2.5",
"axios": "^1.3.4",
"history": "^5.3.0",
@@ -38,8 +39,8 @@
"lodash-es": "^4.17.21",
"mime-types": "^2.1.35",
"notistack": "^2.0.8",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
+ "react": "latest",
+ "react-dom": "latest",
"react-dropzone": "^14.2.3",
"react-icons": "^4.8.0",
"react-router-dom": "^6.8.2",
@@ -49,6 +50,7 @@
},
"devDependencies": {
"@types/mime-types": "^2",
+ "@types/styled-components": "^5",
"@typescript-eslint/eslint-plugin": "^5.54.0",
"@typescript-eslint/parser": "^5.54.0",
"@vitejs/plugin-react-swc": "^3.2.0",
diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts
index 73a54d5b3..c3140937b 100644
--- a/interface/src/i18n/de/index.ts
+++ b/interface/src/i18n/de/index.ts
@@ -311,10 +311,10 @@ const de: Translation = {
LEAVE: 'Verlassen',
SCHEDULER: 'Planer',
SCHEDULER_HELP_1: 'Fügen Sie eigene, geplante Befehle zur Automatisierung hinzu. Vergeben Sie einen Entitätsnamen um die Aktivierung über API/Mqtt zu steuern',
+ SCHEDULER_HELP_2: 'Use 00:00 to trigger on boot', // TODO translate
SCHEDULE: 'Zeitplan',
TIME: 'Zeit',
TIMER: 'Timer',
- WEEKLY: 'Wöchentlich',
SCHEDULE_SAVED: 'Plan gespeichert',
SCHEDULE_TIMER_1: 'beim Start',
SCHEDULE_TIMER_2: 'jede Minute',
diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts
index 6daa59ad8..0cd8899b9 100644
--- a/interface/src/i18n/en/index.ts
+++ b/interface/src/i18n/en/index.ts
@@ -310,11 +310,11 @@ const en: Translation = {
STAY: 'Stay',
LEAVE: 'Leave',
SCHEDULER: 'Scheduler',
- SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt',
+ SCHEDULER_HELP_1: 'Automate commands by adding scheduled events below. Set a unique Name to enable/disable activation via API/MQTT.',
+ SCHEDULER_HELP_2: 'Use 00:00 to trigger once on start-up',
SCHEDULE: 'Schedule',
TIME: 'Time',
TIMER: 'Timer',
- WEEKLY: 'Weekly',
SCHEDULE_SAVED: 'Schedule updated',
SCHEDULE_TIMER_1: 'on startup',
SCHEDULE_TIMER_2: 'every minute',
diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts
index 001b8d880..8a4b9a8a6 100644
--- a/interface/src/i18n/fr/index.ts
+++ b/interface/src/i18n/fr/index.ts
@@ -310,11 +310,11 @@ const fr: Translation = {
STAY: 'Stay', // TODO translate
LEAVE: 'Leave', // TODO translate
SCHEDULER: 'Scheduler', // TODO translate
- SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate
+ SCHEDULER_HELP_1: 'Automate commands by adding scheduled events below. Set a unique Name to enable/disable activation via API/MQTT.', // TODO translate
+ SCHEDULER_HELP_2: 'Use 00:00 to trigger once on start-up', // TODO translate
SCHEDULE: 'Schedule', // TODO translate
TIME: 'Time', // TODO translate
TIMER: 'Timer', // TODO translate
- WEEKLY: 'Weekly', // TODO translate
SCHEDULE_SAVED: 'Schedule updated', // TODO translate
SCHEDULE_TIMER_1: 'on startup', // TODO translate
SCHEDULE_TIMER_2: 'every minute', // TODO translate
diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts
index e24c33c63..e3c46292f 100644
--- a/interface/src/i18n/nl/index.ts
+++ b/interface/src/i18n/nl/index.ts
@@ -310,11 +310,11 @@ const nl: Translation = {
STAY: 'Stay', // TODO translate
LEAVE: 'Leave', // TODO translate
SCHEDULER: 'Scheduler', // TODO translate
- SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate
+ SCHEDULER_HELP_1: 'Automate commands by adding scheduled events below. Set a unique Name to enable/disable activation via API/MQTT.', // TODO translate
+ SCHEDULER_HELP_2: 'Use 00:00 to trigger once on start-up', // TODO translate
SCHEDULE: 'Schedule', // TODO translate
TIME: 'Time', // TODO translate
TIMER: 'Timer', // TODO translate
- WEEKLY: 'Weekly', // TODO translate
SCHEDULE_SAVED: 'Schedule updated', // TODO translate
SCHEDULE_TIMER_1: 'on startup', // TODO translate
SCHEDULE_TIMER_2: 'every minute', // TODO translate
diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts
index aeee08059..ffbc15a9d 100644
--- a/interface/src/i18n/no/index.ts
+++ b/interface/src/i18n/no/index.ts
@@ -310,11 +310,11 @@ const no: Translation = {
STAY: 'Stay', // TODO translate
LEAVE: 'Leave', // TODO translate
SCHEDULER: 'Scheduler', // TODO translate
- SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate
+ SCHEDULER_HELP_1: 'Automate commands by adding scheduled events below. Set a unique Name to enable/disable activation via API/MQTT.', // TODO translate
+ SCHEDULER_HELP_2: 'Use 00:00 to trigger once on start-up', // TODO translate
SCHEDULE: 'Schedule', // TODO translate
TIME: 'Time', // TODO translate
TIMER: 'Timer', // TODO translate
- WEEKLY: 'Weekly', // TODO translate
SCHEDULE_SAVED: 'Schedule updated', // TODO translate
SCHEDULE_TIMER_1: 'on startup', // TODO translate
SCHEDULE_TIMER_2: 'every minute', // TODO translate
diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts
index b963a93ef..fa783c82a 100644
--- a/interface/src/i18n/pl/index.ts
+++ b/interface/src/i18n/pl/index.ts
@@ -310,11 +310,11 @@ const pl: BaseTranslation = {
STAY: 'Stay', // TODO translate
LEAVE: 'Leave', // TODO translate
SCHEDULER: 'Scheduler', // TODO translate
- SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate
- SCHEDULE: 'Schedule', // TODO translate SCHEDULE: 'Schedule', // TODO translate
+ SCHEDULER_HELP_1: 'Automate commands by adding scheduled events below. Set a unique Name to enable/disable activation via API/MQTT.', // TODO translate
+ SCHEDULER_HELP_2: 'Use 00:00 to trigger once on start-up', // TODO translate
+ SCHEDULE: 'Schedule', // TODO translate
TIME: 'Time', // TODO translate
TIMER: 'Timer', // TODO translate
- WEEKLY: 'Weekly', // TODO translate
SCHEDULE_SAVED: 'Schedule updated', // TODO translate
SCHEDULE_TIMER_1: 'on startup', // TODO translate
SCHEDULE_TIMER_2: 'every minute', // TODO translate
diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts
index 23ecddf6c..5fa2ee34e 100644
--- a/interface/src/i18n/sv/index.ts
+++ b/interface/src/i18n/sv/index.ts
@@ -310,11 +310,11 @@ const sv: Translation = {
STAY: 'Stay', // TODO translate
LEAVE: 'Leave', // TODO translate
SCHEDULER: 'Scheduler', // TODO translate
- SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate
+ SCHEDULER_HELP_1: 'Automate commands by adding scheduled events below. Set a unique Name to enable/disable activation via API/MQTT.', // TODO translate
+ SCHEDULER_HELP_2: 'Use 00:00 to trigger once on start-up', // TODO translate
SCHEDULE: 'Schedule', // TODO translate
TIME: 'Time', // TODO translate
TIMER: 'Timer', // TODO translate
- WEEKLY: 'Weekly', // TODO translate
SCHEDULE_SAVED: 'Schedule updated', // TODO translate
SCHEDULE_TIMER_1: 'on startup', // TODO translate
SCHEDULE_TIMER_2: 'every minute', // TODO translate
diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts
index 35ea50a16..6947c2983 100644
--- a/interface/src/i18n/tr/index.ts
+++ b/interface/src/i18n/tr/index.ts
@@ -310,11 +310,11 @@ const tr: Translation = {
STAY: 'Stay', // TODO translate
LEAVE: 'Leave', // TODO translate
SCHEDULER: 'Scheduler', // TODO translate
- SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate
+ SCHEDULER_HELP_1: 'Automate commands by adding scheduled events below. Set a unique Name to enable/disable activation via API/MQTT.', // TODO translate
+ SCHEDULER_HELP_2: 'Use 00:00 to trigger once on start-up', // TODO translate
SCHEDULE: 'Schedule', // TODO translate
TIME: 'Time', // TODO translate
TIMER: 'Timer', // TODO translate
- WEEKLY: 'Weekly', // TODO translate
SCHEDULE_SAVED: 'Schedule updated', // TODO translate
SCHEDULE_TIMER_1: 'on startup', // TODO translate
SCHEDULE_TIMER_2: 'every minute', // TODO translate
diff --git a/interface/src/project/SettingsScheduler.tsx b/interface/src/project/SettingsScheduler.tsx
index ddf0e740c..5be09f33e 100644
--- a/interface/src/project/SettingsScheduler.tsx
+++ b/interface/src/project/SettingsScheduler.tsx
@@ -5,18 +5,17 @@ import {
Button,
Typography,
Box,
+ Stack,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
ToggleButton,
- MenuItem,
ToggleButtonGroup,
Checkbox,
+ Grid,
TextField,
- Radio,
- RadioGroup,
- FormControlLabel
+ Divider
} from '@mui/material';
import { useTheme } from '@table-library/react-table-library/theme';
@@ -25,11 +24,11 @@ import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-li
import { useSnackbar } from 'notistack';
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
-import CheckIcon from '@mui/icons-material/Check';
import WarningIcon from '@mui/icons-material/Warning';
import CancelIcon from '@mui/icons-material/Cancel';
import DoneIcon from '@mui/icons-material/Done';
import AddIcon from '@mui/icons-material/Add';
+import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import {
ValidatedTextField,
@@ -52,6 +51,18 @@ import { useI18nContext } from 'i18n/i18n-react';
import * as EMSESP from './api';
+function makeid() {
+ let result = '';
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+ const charactersLength = characters.length;
+ let counter = 0;
+ while (counter < 4) {
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
+ counter += 1;
+ }
+ return result;
+}
+
const SettingsScheduler: FC = () => {
const { LL, locale } = useI18nContext();
@@ -68,8 +79,8 @@ const SettingsScheduler: FC = () => {
time: '12:00',
cmd: '',
value: '',
- description: '',
- o_id: ''
+ name: '',
+ o_name: ''
};
const [schedule, setSchedule] = useState([emptySchedule]);
const [scheduleItem, setScheduleItem] = useState();
@@ -97,7 +108,7 @@ const SettingsScheduler: FC = () => {
const schedule_theme = useTheme({
Table: `
- --data-table-library_grid-template-columns: 152px 36px 324px 72px 240px repeat(1, minmax(100px, 1fr));
+ --data-table-library_grid-template-columns: 36px 324px 50px 192px repeat(1, minmax(100px, 1fr)) 160px;
`,
BaseRow: `
font-size: 14px;
@@ -106,12 +117,12 @@ const SettingsScheduler: FC = () => {
}
`,
BaseCell: `
- &:nth-of-type(1) {
- padding: 8px;
- }
&:nth-of-type(2) {
text-align: center;
}
+ &:nth-of-type(1) {
+ text-align: center;
+ }
`,
HeaderRow: `
text-transform: uppercase;
@@ -171,7 +182,7 @@ const SettingsScheduler: FC = () => {
o_time: si.time,
o_cmd: si.cmd,
o_value: si.value,
- o_description: si.description
+ o_name: si.name
}))
);
};
@@ -216,7 +227,7 @@ const SettingsScheduler: FC = () => {
function hasScheduleChanged(si: ScheduleItem) {
return (
si.id !== si.o_id ||
- (si?.description || '') !== (si?.o_description || '') ||
+ (si?.name || '') !== (si?.o_name || '') ||
si.active !== si.o_active ||
si.deleted !== si.o_deleted ||
si.flags !== si.o_flags ||
@@ -247,7 +258,7 @@ const SettingsScheduler: FC = () => {
time: condensed_si.time,
cmd: condensed_si.cmd,
value: condensed_si.value,
- description: condensed_si.description
+ name: condensed_si.name
};
})
});
@@ -263,43 +274,54 @@ const SettingsScheduler: FC = () => {
}
};
- function showFlag(si: ScheduleItem, flag: number) {
- let text = '';
+ function getFlagName(flag: number) {
if ((flag & ScheduleFlag.SCHEDULE_MON) === ScheduleFlag.SCHEDULE_MON) {
- text = dow[1];
+ return dow[1];
}
if ((flag & ScheduleFlag.SCHEDULE_TUE) === ScheduleFlag.SCHEDULE_TUE) {
- text = dow[2];
+ return dow[2];
}
if ((flag & ScheduleFlag.SCHEDULE_WED) === ScheduleFlag.SCHEDULE_WED) {
- text = dow[3];
+ return dow[3];
}
if ((flag & ScheduleFlag.SCHEDULE_THU) === ScheduleFlag.SCHEDULE_THU) {
- text = dow[4];
+ return dow[4];
}
if ((flag & ScheduleFlag.SCHEDULE_FRI) === ScheduleFlag.SCHEDULE_FRI) {
- text = dow[5];
+ return dow[5];
}
if ((flag & ScheduleFlag.SCHEDULE_SAT) === ScheduleFlag.SCHEDULE_SAT) {
- text = dow[6];
+ return dow[6];
}
if ((flag & ScheduleFlag.SCHEDULE_SUN) === ScheduleFlag.SCHEDULE_SUN) {
- text = dow[0];
+ return dow[0];
}
if ((flag & ScheduleFlag.SCHEDULE_TIMER) === ScheduleFlag.SCHEDULE_TIMER) {
- text = LL.TIMER();
+ return LL.TIMER();
}
-
- return (
-
- {text}
-
- );
+ return '';
}
+ const dayBox = (si: ScheduleItem, flag: number) => (
+ <>
+
+
+ {getFlagName(flag)}
+
+
+
+ >
+ );
+
+ const showFlag = (si: ScheduleItem, flag: number) => (
+
+ {getFlagName(flag)}
+
+ );
+
const editScheduleItem = (si: ScheduleItem) => {
- if (si.description === undefined) {
- si.description = '';
+ if (si.name === undefined) {
+ si.name = '';
}
setCreating(false);
setScheduleItem(si);
@@ -308,19 +330,21 @@ const SettingsScheduler: FC = () => {
const addScheduleItem = () => {
setCreating(true);
setScheduleItem({
- id: '',
+ id: makeid(),
active: false,
deleted: false,
flags: 0,
time: '12:00',
cmd: '',
value: '',
- description: ''
+ name: ''
});
};
const updateScheduleItem = () => {
- setSchedule([...schedule.filter((si) => creating || si.o_id !== scheduleItem.o_id), scheduleItem]);
+ if (scheduleItem) {
+ setSchedule([...schedule.filter((si) => creating || si.o_id !== scheduleItem.o_id), scheduleItem]);
+ }
setScheduleItem(undefined);
};
@@ -339,56 +363,37 @@ const SettingsScheduler: FC = () => {
<>
- {LL.NAME()}
-
-
-
+
{LL.SCHEDULE()}
{LL.TIME()}
{LL.COMMAND()}
- {LL.VALUE(0)}
+ {LL.VALUE(0)}
+ {LL.NAME(0)}
{tableList.map((si: ScheduleItem) => (
editScheduleItem(si)}>
- | {si.id} |
- {
- si.active = !si.active;
- setFlags(['']); // forces refresh
- }}
- />
+ {si.active && }
|
- {
- si.flags = getFlagNumber(flag);
- if (si.flags & ScheduleFlag.SCHEDULE_TIMER) {
- si.flags = ScheduleFlag.SCHEDULE_TIMER;
- }
- setFlags(['']); // forces refresh
- }}
- >
- {showFlag(si, ScheduleFlag.SCHEDULE_MON)}
- {showFlag(si, ScheduleFlag.SCHEDULE_TUE)}
- {showFlag(si, ScheduleFlag.SCHEDULE_WED)}
- {showFlag(si, ScheduleFlag.SCHEDULE_THU)}
- {showFlag(si, ScheduleFlag.SCHEDULE_FRI)}
- {showFlag(si, ScheduleFlag.SCHEDULE_SAT)}
- {showFlag(si, ScheduleFlag.SCHEDULE_SUN)}
- {showFlag(si, ScheduleFlag.SCHEDULE_TIMER)}
-
+
+
+ {dayBox(si, ScheduleFlag.SCHEDULE_MON)}
+ {dayBox(si, ScheduleFlag.SCHEDULE_TUE)}
+ {dayBox(si, ScheduleFlag.SCHEDULE_WED)}
+ {dayBox(si, ScheduleFlag.SCHEDULE_THU)}
+ {dayBox(si, ScheduleFlag.SCHEDULE_FRI)}
+ {dayBox(si, ScheduleFlag.SCHEDULE_SAT)}
+ {dayBox(si, ScheduleFlag.SCHEDULE_SUN)}
+ {dayBox(si, ScheduleFlag.SCHEDULE_TIMER)}
+
|
{si.time} |
{si.cmd} |
{si.value} |
+ {si.name} |
))}
@@ -408,7 +413,7 @@ const SettingsScheduler: FC = () => {
if (scheduleItem) {
try {
setFieldErrors(undefined);
- await validate(schedulerItemValidation(schedule, scheduleItem.o_id), scheduleItem);
+ await validate(schedulerItemValidation(schedule, scheduleItem), scheduleItem);
updateScheduleItem();
} catch (errors: any) {
setFieldErrors(errors);
@@ -418,89 +423,94 @@ const SettingsScheduler: FC = () => {
const closeDialog = () => {
setScheduleItem(undefined);
- setFieldErrors();
+ setFieldErrors(undefined);
};
const renderEditSchedule = () => {
if (scheduleItem) {
+ const isTimer = scheduleItem.flags === ScheduleFlag.SCHEDULE_TIMER;
return (