mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
Merge branch 'ft_dashboard' of https://github.com/proddy/EMS-ESP32 into ft_dashboard
This commit is contained in:
@@ -35,7 +35,7 @@
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-icons": "^5.3.0",
|
||||
"react-router-dom": "^6.26.2",
|
||||
"react-router-dom": "^6.27.0",
|
||||
"react-toastify": "^10.0.5",
|
||||
"typesafe-i18n": "^5.26.2",
|
||||
"typescript": "^5.6.3"
|
||||
@@ -49,7 +49,7 @@
|
||||
"@types/formidable": "^3",
|
||||
"@types/node": "^22.7.5",
|
||||
"@types/react": "^18.3.11",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"concurrently": "^9.0.1",
|
||||
"eslint": "^9.12.0",
|
||||
|
||||
@@ -25,7 +25,7 @@ const App = () => {
|
||||
<CustomTheme>
|
||||
<AppRouting />
|
||||
<ToastContainer
|
||||
position="bottom-right"
|
||||
position="bottom-left"
|
||||
autoClose={3000}
|
||||
hideProgressBar={false}
|
||||
newestOnTop={false}
|
||||
|
||||
@@ -88,28 +88,38 @@ const Dashboard = () => {
|
||||
|
||||
const dashboard_theme = useTheme({
|
||||
Table: `
|
||||
--data-table-library_grid-template-columns: minmax(80px, auto) 120px 40px;
|
||||
--data-table-library_grid-template-columns: minmax(80px, auto) 120px 32px;
|
||||
`,
|
||||
BaseRow: `
|
||||
font-size: 14px;
|
||||
.td {
|
||||
height: 32px;
|
||||
height: 28px;
|
||||
}
|
||||
`,
|
||||
Row: `
|
||||
cursor: pointer;
|
||||
background-color: #1e1e1e;
|
||||
.td {
|
||||
height: 22px;
|
||||
// border-top: 1px solid #0000;
|
||||
// border-bottom: 1px solid #0000;
|
||||
}
|
||||
&.tr.tr-body.row-select.row-select-single-selected {
|
||||
background-color: #177ac9;
|
||||
font-weight: normal;
|
||||
}
|
||||
&:hover .td {
|
||||
border-top: 1px solid #177ac9;
|
||||
border-bottom: 1px solid #177ac9;
|
||||
background-color: #177ac9;
|
||||
// border-top: 1px solid #177ac9;
|
||||
// border-bottom: 1px solid #177ac9;
|
||||
}
|
||||
`,
|
||||
BaseCell: `
|
||||
&:nth-of-type(2) {
|
||||
text-align: right;
|
||||
}
|
||||
&:nth-of-type(3) {
|
||||
text-align: right;
|
||||
}
|
||||
`
|
||||
});
|
||||
|
||||
@@ -164,9 +174,9 @@ const Dashboard = () => {
|
||||
case DeviceType.CUSTOM:
|
||||
return LL.CUSTOM_ENTITIES(0);
|
||||
case DeviceType.ANALOGSENSOR:
|
||||
return LL.ANALOG_SENSOR(0);
|
||||
return LL.ANALOG_SENSORS();
|
||||
case DeviceType.TEMPERATURESENSOR:
|
||||
return LL.TEMP_SENSOR();
|
||||
return LL.TEMP_SENSORS();
|
||||
case DeviceType.SCHEDULER:
|
||||
return LL.SCHEDULER();
|
||||
default:
|
||||
@@ -200,8 +210,10 @@ const Dashboard = () => {
|
||||
(parseInt(id.slice(0, 2), 16) & mask) === mask;
|
||||
|
||||
const editDashboardValue = (di: DashboardItem) => {
|
||||
if (me.admin && di.dv?.c) {
|
||||
setSelectedDashboardItem(di);
|
||||
setDeviceValueDialogOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleShowAll = (
|
||||
@@ -276,7 +288,11 @@ const Dashboard = () => {
|
||||
{(tableList: DashboardItem[]) => (
|
||||
<Body>
|
||||
{tableList.map((di: DashboardItem) => (
|
||||
<Row key={di.id} item={di}>
|
||||
<Row
|
||||
key={di.id}
|
||||
item={di}
|
||||
onClick={() => editDashboardValue(di)}
|
||||
>
|
||||
{di.id > 99 ? (
|
||||
<>
|
||||
<Cell>{showName(di)}</Cell>
|
||||
@@ -294,7 +310,7 @@ const Dashboard = () => {
|
||||
</Tooltip>
|
||||
</Cell>
|
||||
|
||||
<Cell stiff pinRight>
|
||||
<Cell>
|
||||
{me.admin &&
|
||||
di.dv?.c &&
|
||||
!hasMask(di.dv.id, DeviceEntityMask.DV_READONLY) && (
|
||||
|
||||
@@ -148,22 +148,23 @@ const Devices = () => {
|
||||
}
|
||||
`,
|
||||
Row: `
|
||||
background-color: #1E1E1E;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
background-color: #1E1E1E;
|
||||
// position: relative;
|
||||
.td {
|
||||
padding: 8px;
|
||||
border-top: 1px solid #565656;
|
||||
border-bottom: 1px solid #565656;
|
||||
// border-top: 1px solid #565656;
|
||||
// border-bottom: 1px solid #565656;
|
||||
}
|
||||
&.tr.tr-body.row-select.row-select-single-selected {
|
||||
background-color: #3d4752;
|
||||
background-color: #177ac9;
|
||||
font-weight: normal;
|
||||
}
|
||||
&:hover .td {
|
||||
border-top: 1px solid #177ac9;
|
||||
border-bottom: 1px solid #177ac9;
|
||||
}
|
||||
// &:hover .td {
|
||||
// background-color: #177ac9;
|
||||
// border-top: 1px solid #177ac9;
|
||||
// border-bottom: 1px solid #177ac9;
|
||||
// }
|
||||
`
|
||||
});
|
||||
|
||||
@@ -174,14 +175,18 @@ const Devices = () => {
|
||||
--data-table-library_grid-template-columns: repeat(1, minmax(0, 1fr)) 130px;
|
||||
`,
|
||||
BaseRow: `
|
||||
.td {
|
||||
height: 42px;
|
||||
}
|
||||
// .td {
|
||||
// height: 42px;
|
||||
// }
|
||||
`,
|
||||
HeaderRow: `
|
||||
.th {
|
||||
padding: 8px;
|
||||
height: 36px;
|
||||
`,
|
||||
Row: `
|
||||
&:hover .td {
|
||||
background-color: #177ac9;
|
||||
`
|
||||
}
|
||||
]);
|
||||
@@ -222,6 +227,11 @@ const Devices = () => {
|
||||
Row: `
|
||||
&:nth-of-type(odd) .td {
|
||||
background-color: #303030;
|
||||
},
|
||||
&:hover .td {
|
||||
background-color: #177ac9;
|
||||
// border-top: 1px solid #177ac9;
|
||||
// border-bottom: 1px solid #177ac9;
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
@@ -1360,10 +1360,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@remix-run/router@npm:1.19.2":
|
||||
version: 1.19.2
|
||||
resolution: "@remix-run/router@npm:1.19.2"
|
||||
checksum: 10c0/ac7fc813350686705f2c29219e70e1e299d9a8e3b301e9e81f7e84f578c40c6462b590cf0d78863bac40dbc325b68c71ae070f4a1465793d1d1971b619618295
|
||||
"@remix-run/router@npm:1.20.0":
|
||||
version: 1.20.0
|
||||
resolution: "@remix-run/router@npm:1.20.0"
|
||||
checksum: 10c0/2e017dea530717a6e93a16d478714c4c9165313a1c48e39172ec609bc20324ca6362e8ee2243602df6343644c9268d82a3f50f154d3bb8a17dddde6c37be6e83
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1699,12 +1699,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react-dom@npm:^18.3.0":
|
||||
version: 18.3.0
|
||||
resolution: "@types/react-dom@npm:18.3.0"
|
||||
"@types/react-dom@npm:^18.3.1":
|
||||
version: 18.3.1
|
||||
resolution: "@types/react-dom@npm:18.3.1"
|
||||
dependencies:
|
||||
"@types/react": "npm:*"
|
||||
checksum: 10c0/6c90d2ed72c5a0e440d2c75d99287e4b5df3e7b011838cdc03ae5cd518ab52164d86990e73246b9d812eaf02ec351d74e3b4f5bd325bf341e13bf980392fd53b
|
||||
checksum: 10c0/8b416551c60bb6bd8ec10e198c957910cfb271bc3922463040b0d57cf4739cdcd24b13224f8d68f10318926e1ec3cd69af0af79f0291b599a992f8c80d47f1eb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1910,7 +1910,7 @@ __metadata:
|
||||
"@types/formidable": "npm:^3"
|
||||
"@types/node": "npm:^22.7.5"
|
||||
"@types/react": "npm:^18.3.11"
|
||||
"@types/react-dom": "npm:^18.3.0"
|
||||
"@types/react-dom": "npm:^18.3.1"
|
||||
"@types/react-router-dom": "npm:^5.3.3"
|
||||
alova: "npm:3.0.20"
|
||||
async-validator: "npm:^4.2.5"
|
||||
@@ -1925,7 +1925,7 @@ __metadata:
|
||||
react: "npm:^18.3.1"
|
||||
react-dom: "npm:^18.3.1"
|
||||
react-icons: "npm:^5.3.0"
|
||||
react-router-dom: "npm:^6.26.2"
|
||||
react-router-dom: "npm:^6.27.0"
|
||||
react-toastify: "npm:^10.0.5"
|
||||
rollup-plugin-visualizer: "npm:^5.12.0"
|
||||
terser: "npm:^5.34.1"
|
||||
@@ -6003,27 +6003,27 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-router-dom@npm:^6.26.2":
|
||||
version: 6.26.2
|
||||
resolution: "react-router-dom@npm:6.26.2"
|
||||
"react-router-dom@npm:^6.27.0":
|
||||
version: 6.27.0
|
||||
resolution: "react-router-dom@npm:6.27.0"
|
||||
dependencies:
|
||||
"@remix-run/router": "npm:1.19.2"
|
||||
react-router: "npm:6.26.2"
|
||||
"@remix-run/router": "npm:1.20.0"
|
||||
react-router: "npm:6.27.0"
|
||||
peerDependencies:
|
||||
react: ">=16.8"
|
||||
react-dom: ">=16.8"
|
||||
checksum: 10c0/7515128a98eef0a6b2bf354ef9dfefad03556a06be00fa9220eda6526aaada8a42f294911083473d7ced6d7128c3088bd193218bbb3d62593f9f4f7053781c23
|
||||
checksum: 10c0/7db48ffd0b387af0eed060ceaf42075d074e63fbd30f4cf60993526b3610883a9ff82615965001165ed69d2bf2f1bce05c594a21c8d0d845e7b9bf203201116e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-router@npm:6.26.2":
|
||||
version: 6.26.2
|
||||
resolution: "react-router@npm:6.26.2"
|
||||
"react-router@npm:6.27.0":
|
||||
version: 6.27.0
|
||||
resolution: "react-router@npm:6.27.0"
|
||||
dependencies:
|
||||
"@remix-run/router": "npm:1.19.2"
|
||||
"@remix-run/router": "npm:1.20.0"
|
||||
peerDependencies:
|
||||
react: ">=16.8"
|
||||
checksum: 10c0/0d15a39b419c99fb5ccad76388bfc4ee2b01323b3b1b694595a9f9ea28e1fbeea25486b5398f5d3d93922f5c6a9aa751b6bb27419488d85279f6ca5ff9e0a6bb
|
||||
checksum: 10c0/440d6ee00890cec92a0c2183164149fbb96363efccf52bb132a964f44e51aec2f4b5a0520c67f6f17faddaa4097090fd76f7efe58263947532fceeb11dd4cdf3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -4351,7 +4351,6 @@ router
|
||||
t: element.t,
|
||||
nodes: getDashboardEntityData(id)
|
||||
};
|
||||
|
||||
// only add to dashboard if we have values
|
||||
if ((dashboard_object.nodes ?? []).length > 0) {
|
||||
dashboard_data.push(dashboard_object);
|
||||
@@ -4374,7 +4373,7 @@ router
|
||||
sensor_data = emsesp_sensordata.ts.map((item, index) => ({
|
||||
id: DeviceTypeUniqueID.TEMPERATURESENSOR_UID * 100 + index,
|
||||
dv: {
|
||||
id: item.n,
|
||||
id: '00' + item.n,
|
||||
v: item.t, // value is called t in ts (temperature)
|
||||
u: item.u
|
||||
}
|
||||
@@ -4395,12 +4394,11 @@ router
|
||||
sensor_data = sensor_data.map((item, index) => ({
|
||||
id: DeviceTypeUniqueID.ANALOGSENSOR_UID * 100 + index,
|
||||
dv: {
|
||||
id: item.n,
|
||||
id: '00' + item.n,
|
||||
v: item.v,
|
||||
u: item.u
|
||||
}
|
||||
}));
|
||||
|
||||
dashboard_object = {
|
||||
id: DeviceTypeUniqueID.ANALOGSENSOR_UID,
|
||||
t: DeviceType.ANALOGSENSOR,
|
||||
@@ -4417,9 +4415,10 @@ router
|
||||
let scheduler_data2 = scheduler_data.map((item, index) => ({
|
||||
id: DeviceTypeUniqueID.SCHEDULER_UID * 100 + index,
|
||||
dv: {
|
||||
id: item.name,
|
||||
v: item.active
|
||||
// u: item.u // don't need uom
|
||||
id: '00' + item.name,
|
||||
v: item.active ? 'on' : 'off',
|
||||
c: item.name,
|
||||
l: ['off', 'on']
|
||||
}
|
||||
}));
|
||||
dashboard_object = {
|
||||
@@ -4431,22 +4430,39 @@ router
|
||||
if ((dashboard_object.nodes ?? []).length > 0) {
|
||||
dashboard_data.push(dashboard_object);
|
||||
}
|
||||
//
|
||||
} else {
|
||||
// for testing
|
||||
// single object
|
||||
const element = emsesp_coredata.devices[3]; // pick the 4th device
|
||||
const id = element.id;
|
||||
// for testing only
|
||||
|
||||
// add the custom entity data
|
||||
dashboard_object = {
|
||||
id: id,
|
||||
n: element.n,
|
||||
t: element.t,
|
||||
nodes: getDashboardEntityData(id)
|
||||
id: DeviceTypeUniqueID.CUSTOM_UID, // unique ID for custom entities
|
||||
t: DeviceType.CUSTOM,
|
||||
nodes: getDashboardEntityData(99)
|
||||
};
|
||||
// only add to dashboard if we have values
|
||||
if ((dashboard_object.nodes ?? []).length > 0) {
|
||||
dashboard_data.push(dashboard_object);
|
||||
}
|
||||
|
||||
let scheduler_data = emsesp_schedule.schedule.filter((item) => item.name);
|
||||
let scheduler_data2 = scheduler_data.map((item, index) => ({
|
||||
id: DeviceTypeUniqueID.SCHEDULER_UID * 100 + index,
|
||||
dv: {
|
||||
id: '00' + item.name,
|
||||
v: item.active ? 'on' : 'off',
|
||||
c: item.name,
|
||||
l: ['off', 'on']
|
||||
}
|
||||
}));
|
||||
dashboard_object = {
|
||||
id: DeviceTypeUniqueID.SCHEDULER_UID,
|
||||
t: DeviceType.SCHEDULER,
|
||||
nodes: scheduler_data2
|
||||
};
|
||||
// only add to dashboard if we have values
|
||||
if ((dashboard_object.nodes ?? []).length > 0) {
|
||||
dashboard_data.push(dashboard_object);
|
||||
}
|
||||
console.log('dashboard_data: ', dashboard_data);
|
||||
}
|
||||
|
||||
// console.log('dashboard_data: ', dashboard_data);
|
||||
@@ -4498,24 +4514,6 @@ router
|
||||
// Scheduler
|
||||
.post(EMSESP_SCHEDULE_ENDPOINT, async (request: any) => {
|
||||
const content = await request.json();
|
||||
// check if we're changing active from the Dashboard
|
||||
if (content.schedule.id === 0) {
|
||||
console.log(
|
||||
"Toggle schedule '" +
|
||||
content.schedule.name +
|
||||
"' to " +
|
||||
content.schedule.active
|
||||
);
|
||||
// find the schedule in emsesp_schedule via the name and toggle the active
|
||||
const objIndex = emsesp_schedule.schedule.findIndex(
|
||||
(obj) => obj.name === content.schedule.name
|
||||
);
|
||||
if (objIndex !== -1) {
|
||||
emsesp_schedule.schedule[objIndex].active = content.schedule.active;
|
||||
}
|
||||
|
||||
return status(200);
|
||||
}
|
||||
emsesp_schedule = content;
|
||||
console.log('schedule saved', emsesp_schedule);
|
||||
return status(200);
|
||||
@@ -4557,6 +4555,10 @@ router
|
||||
const value = content.v;
|
||||
const id = content.id;
|
||||
|
||||
console.log(
|
||||
'write device value, id: ' + id + ' command: ' + command + ' value: ' + value
|
||||
);
|
||||
|
||||
var objIndex;
|
||||
if (id === 1) {
|
||||
objIndex = emsesp_devicedata_1.nodes.findIndex((obj) => obj.c == command);
|
||||
@@ -4598,16 +4600,27 @@ router
|
||||
objIndex = emsesp_devicedata_10.nodes.findIndex((obj) => obj.c == command);
|
||||
emsesp_devicedata_10.nodes[objIndex].v = value;
|
||||
}
|
||||
if (id === 99) {
|
||||
if (id === DeviceTypeUniqueID.CUSTOM_UID) {
|
||||
// custom entities
|
||||
objIndex = emsesp_devicedata_99.nodes.findIndex((obj) => obj.c == command);
|
||||
emsesp_devicedata_99.nodes[objIndex].v = value;
|
||||
}
|
||||
if (id === DeviceTypeUniqueID.SCHEDULER_UID) {
|
||||
// toggle scheduler
|
||||
// find the schedule in emsesp_schedule via the name and toggle the active
|
||||
const objIndex = emsesp_schedule.schedule.findIndex(
|
||||
(obj) => obj.name === command
|
||||
);
|
||||
if (objIndex !== -1) {
|
||||
emsesp_schedule.schedule[objIndex].active = value;
|
||||
console.log("Toggle schedule '" + command + "' to " + value);
|
||||
}
|
||||
}
|
||||
|
||||
// await delay(1000); // wait to show spinner
|
||||
console.log(
|
||||
'Device Value updated. command:' + command + ' value:' + value + ' id:' + id
|
||||
);
|
||||
// console.log(
|
||||
// 'Device Value updated. command:' + command + ' value:' + value + ' id:' + id
|
||||
// );
|
||||
return status(200);
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user