mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 16:29:51 +03:00
Merge pull request #1855 from proddy/dev
Implements Feature: message notification #1854
This commit is contained in:
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,29 +1,29 @@
|
||||
---
|
||||
name: Problem Report
|
||||
name: Problem Report/Change Request
|
||||
about: Create a Report to help us improve
|
||||
---
|
||||
|
||||
<!-- Thanks for reporting a problem for this project. READ THIS FIRST:
|
||||
<!-- Thanks for reporting an issue for this project. READ THIS FIRST:
|
||||
|
||||
Please DO NOT OPEN AN ISSUE if your EMS-ESP version is not the latest from the dev branch, please update your device before submitting your issue. Your problem might already be solved. The latest precompiled binaries of EMS-ESP can be downloaded from https://github.com/emsesp/EMS-ESP32/releases/tag/latest
|
||||
Please DO NOT OPEN AN ISSUE if your EMS-ESP version is not the latest from the dev branch, please update your device before submitting your issue. Your issue might already be solved. The latest precompiled binaries of EMS-ESP can be downloaded from https://github.com/emsesp/EMS-ESP32/releases/tag/latest
|
||||
|
||||
Please take a few minutes to complete the requested information below.
|
||||
|
||||
-->
|
||||
|
||||
### PROBLEM DESCRIPTION
|
||||
### DESCRIPTION
|
||||
|
||||
_A clear and concise description of what the problem is._
|
||||
_A clear and concise description of what the problem is or the change requested._
|
||||
|
||||
### REQUESTED INFORMATION
|
||||
|
||||
_Make sure your have performed every step and checked the applicable boxes before submitting your issue. Thank you!_
|
||||
|
||||
- [ ] Searched the problem in [issues](https://github.com/emsesp/EMS-ESP32/issues)
|
||||
- [ ] Searched the problem in [discussions](https://github.com/emsesp/EMS-ESP32/discussions)
|
||||
- [ ] Searched the problem in the [docs](https://emsesp.github.io/docs/Troubleshooting/)
|
||||
- [ ] Searched the problem in the [chat](https://discord.gg/3J3GgnzpyT)
|
||||
- [ ] Provide the output of http://ems-esp.local/api/system :
|
||||
- [ ] Searched the issue in [issues](https://github.com/emsesp/EMS-ESP32/issues)
|
||||
- [ ] Searched the issue in [discussions](https://github.com/emsesp/EMS-ESP32/discussions)
|
||||
- [ ] Searched the issue in the [docs](https://emsesp.github.io/docs/Troubleshooting/)
|
||||
- [ ] Searched the issue in the [chat](https://discord.gg/3J3GgnzpyT)
|
||||
- [ ] Provide the output of <http://ems-esp.local/api/system> :
|
||||
|
||||
```lua
|
||||
System information output here:
|
||||
@@ -41,10 +41,10 @@ _A clear and concise description of what you expected to happen._
|
||||
|
||||
### SCREENSHOTS
|
||||
|
||||
_If applicable, add screenshots to help explain your problem._
|
||||
_If applicable, add screenshots to help explain your issue._
|
||||
|
||||
### ADDITIONAL CONTEXT
|
||||
|
||||
_Add any other context about the problem here._
|
||||
_Add any other context about the issue here._
|
||||
|
||||
**(Please, remember to close the issue when the problem has been addressed)**
|
||||
**(Please, remember to close the issue when it has been addressed)**
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
- new device WATER shows dhw entities from MM100 and SM100 in dhw setting
|
||||
- renamed WWC to DHW, always create DHW nests/topics, remove ww prefix from mqtt names [#1634](https://github.com/emsesp/EMS-ESP32/issues/1634)
|
||||
- change temperaturesensor id to underscore
|
||||
- system/info API command has the word 'Info' removed from the object name for each section (E.g. 'Network Info' is now just 'Network')
|
||||
|
||||
## Added
|
||||
|
||||
@@ -28,6 +29,7 @@
|
||||
- added extra pump characteristics (mode and pressure for EMS+) by @SLTKA [#1802](https://github.com/emsesp/EMS-ESP32/pull/1802)
|
||||
- allow device name to be customized [#1174](https://github.com/emsesp/EMS-ESP32/issues/1174)
|
||||
- Modbus support by @mheyse [#1744](https://github.com/emsesp/EMS-ESP32/issues/1744)
|
||||
- System Message command [#1854](https://github.com/emsesp/EMS-ESP32/issues/1854)
|
||||
|
||||
## Fixed
|
||||
|
||||
|
||||
10218
dump_entities.csv
10218
dump_entities.csv
File diff suppressed because it is too large
Load Diff
@@ -53,6 +53,7 @@ telegram_type_id,name,is_fetched,is_cmd
|
||||
0xA3,RCOutdoorTemp, ,cmd
|
||||
0xA5,IBASettings,fetched,cmd
|
||||
0xA7,RC30Set, ,cmd
|
||||
0xA9,RC30Vacation,fetched,cmd
|
||||
0xAA,MMConfigMessage,fetched,cmd
|
||||
0xAB,MMStatusMessage, ,cmd
|
||||
0xAC,MMSetMessage, ,cmd
|
||||
@@ -91,6 +92,7 @@ telegram_type_id,name,is_fetched,is_cmd
|
||||
0x023E,PVSettings,fetched,cmd
|
||||
0x0240,RC300Settings,fetched,cmd
|
||||
0x0267,RC300Floordry, ,cmd
|
||||
0x0269,RC300Holiday1,fetched,cmd
|
||||
0x0291,HPMode,fetched,cmd
|
||||
0x0292,HPMode,fetched,cmd
|
||||
0x0293,HPMode,fetched,cmd
|
||||
@@ -103,9 +105,9 @@ telegram_type_id,name,is_fetched,is_cmd
|
||||
0x02A0,RC300Curves, ,cmd
|
||||
0x02A1,RC300Curves, ,cmd
|
||||
0x02A2,RC300Curves, ,cmd
|
||||
0x02A5,RC300Monitor, ,cmd
|
||||
0x02A5,CRFMonitor, ,cmd
|
||||
0x02A6,RC300Monitor, ,cmd
|
||||
0x02A7,CRFMonitor, ,cmd
|
||||
0x02A7,RC300Monitor, ,cmd
|
||||
0x02A8,RC300Monitor, ,cmd
|
||||
0x02A9,RC300Monitor, ,cmd
|
||||
0x02AA,RC300Monitor, ,cmd
|
||||
@@ -127,14 +129,14 @@ telegram_type_id,name,is_fetched,is_cmd
|
||||
0x02BE,RC300Set, ,cmd
|
||||
0x02BF,RC300Set, ,cmd
|
||||
0x02C0,RC300Set, ,cmd
|
||||
0x02CC,HPPressure,fetched,cmd
|
||||
0x02CD,MMPLUSSetMessage_HC,fetched,cmd
|
||||
0x02CC,RC300Set2, ,cmd
|
||||
0x02CD,MMPLUSConfigMessage,fetched,cmd
|
||||
0x02CE,RC300Set2, ,cmd
|
||||
0x02D0,RC300Set2, ,cmd
|
||||
0x02D2,RC300Set2, ,cmd
|
||||
0x02D5,MMPLUSSetMessage_HC,fetched,cmd
|
||||
0x02D7,MMPLUSStatusMessage_HC, ,cmd
|
||||
0x02DF,MMPLUSStatusMessage_HC, ,cmd
|
||||
0x02D5,MMPLUSConfigMessage,fetched,cmd
|
||||
0x02D7,MMPLUSStatusMessage, ,cmd
|
||||
0x02DF,MMPLUSStatusMessage, ,cmd
|
||||
0x02F5,RC300WWmode,fetched,cmd
|
||||
0x02F6,RC300WW2mode,fetched,cmd
|
||||
0x031B,RC300WWtemp,fetched,cmd
|
||||
|
||||
|
@@ -16,7 +16,7 @@ export default tseslint.config(
|
||||
}
|
||||
},
|
||||
{
|
||||
ignores: ['dist/*', '*.js', '**/*.cjs', '**/unpack.ts', 'i18*.ts']
|
||||
ignores: ['dist/*', '*.js', '**/*.cjs', '**/unpack.ts', 'i18n*.*']
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
|
||||
@@ -26,15 +26,15 @@
|
||||
"@alova/scene-react": "^1.6.1",
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.5",
|
||||
"@mui/icons-material": "^5.16.0",
|
||||
"@mui/material": "^5.16.0",
|
||||
"@mui/icons-material": "^5.16.1",
|
||||
"@mui/material": "^5.16.1",
|
||||
"@table-library/react-table-library": "4.1.7",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^20.14.10",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"alova": "^2.21.3",
|
||||
"alova": "^2.21.4",
|
||||
"async-validator": "^4.2.5",
|
||||
"history": "^5.3.0",
|
||||
"jwt-decode": "^4.0.0",
|
||||
@@ -50,19 +50,19 @@
|
||||
"typescript": "^5.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.7",
|
||||
"@eslint/js": "^9.6.0",
|
||||
"@babel/core": "^7.24.8",
|
||||
"@eslint/js": "^9.7.0",
|
||||
"@preact/compat": "^17.1.2",
|
||||
"@preact/preset-vite": "^2.8.3",
|
||||
"@preact/preset-vite": "^2.9.0",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@types/babel__core": "^7",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^9.6.0",
|
||||
"eslint": "^9.7.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"preact": "^10.22.1",
|
||||
"prettier": "^3.3.2",
|
||||
"prettier": "^3.3.3",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"terser": "^5.31.1",
|
||||
"terser": "^5.31.2",
|
||||
"typescript-eslint": "8.0.0-alpha.10",
|
||||
"vite": "^5.3.3",
|
||||
"vite-plugin-imagemin": "^0.6.1",
|
||||
|
||||
@@ -54,6 +54,8 @@ const levelLabel = (level: LogLevel) => {
|
||||
return 'NOTICE';
|
||||
case LogLevel.INFO:
|
||||
return 'INFO';
|
||||
case LogLevel.DEBUG:
|
||||
return 'DEBUG';
|
||||
case LogLevel.TRACE:
|
||||
return 'TRACE';
|
||||
default:
|
||||
@@ -175,7 +177,7 @@ const SystemLog: FC = () => {
|
||||
justifyContent="flex-start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Grid item xs={2}>
|
||||
<Grid item xs={4}>
|
||||
<TextField
|
||||
name="level"
|
||||
label={LL.LOG_LEVEL()}
|
||||
@@ -194,7 +196,7 @@ const SystemLog: FC = () => {
|
||||
<MenuItem value={9}>ALL</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={2}>
|
||||
<Grid item xs={4}>
|
||||
<TextField
|
||||
name="max_messages"
|
||||
label={LL.BUFFER_SIZE()}
|
||||
@@ -211,7 +213,7 @@ const SystemLog: FC = () => {
|
||||
<MenuItem value={100}>100</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Grid item xs={2}>
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
@@ -226,8 +228,7 @@ const SystemLog: FC = () => {
|
||||
<Box
|
||||
sx={{
|
||||
'& button, & a, & .MuiCard-root': {
|
||||
mt: 3,
|
||||
mx: 0.6
|
||||
ml: 3
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -266,8 +267,7 @@ const SystemLog: FC = () => {
|
||||
{logEntries.map((e) => (
|
||||
<LogEntryLine key={e.i}>
|
||||
<span>{e.t}</span>
|
||||
{data.compact && <span>{paddedLevelLabel(e.l)} </span>}
|
||||
{!data.compact && <span>{paddedLevelLabel(e.l)} </span>}
|
||||
<span>{paddedLevelLabel(e.l)} </span>
|
||||
<span>{paddedIDLabel(e.i)} </span>
|
||||
<span>{paddedNameLabel(e.n)} </span>
|
||||
<span>{e.m}</span>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { type FC, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||
import { Box, Button, Link, Typography } from '@mui/material';
|
||||
import { Box, Button, Divider, Link, Typography } from '@mui/material';
|
||||
|
||||
import * as SystemApi from 'api/system';
|
||||
|
||||
@@ -195,6 +195,8 @@ const UploadDownload: FC = () => {
|
||||
<Box p={2} border="2px solid grey" borderRadius={2}>
|
||||
{LL.VERSION_ON() + ' '}
|
||||
<b>{data.emsesp_version}</b> ({data.esp_platform})
|
||||
{data.model.length > 0 && <p>Gateway Hardware: {data.model}</p>}
|
||||
<Divider />
|
||||
{latestVersion && (
|
||||
<Box mt={2}>
|
||||
{LL.THE_LATEST()} {LL.OFFICIAL()} {LL.RELEASE_IS()}
|
||||
|
||||
@@ -244,7 +244,7 @@ const Scheduler: FC = () => {
|
||||
data={{
|
||||
nodes: schedule
|
||||
.filter((si) => !si.deleted)
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.sort((a, b) => a.flags - b.flags)
|
||||
}}
|
||||
theme={schedule_theme}
|
||||
layout={{ custom: true }}
|
||||
|
||||
@@ -344,7 +344,7 @@ const SchedulerDialog = ({
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors}
|
||||
name="name"
|
||||
label={LL.NAME(0)}
|
||||
label={LL.NAME(0) + ' (' + LL.OPTIONAL() + ')'}
|
||||
value={editItem.name}
|
||||
fullWidth
|
||||
margin="normal"
|
||||
|
||||
@@ -287,6 +287,7 @@ export const uniqueNameValidator = (schedule: ScheduleItem[], o_name?: string) =
|
||||
callback: (error?: string) => void
|
||||
) {
|
||||
if (
|
||||
name !== '' &&
|
||||
(o_name === undefined || o_name !== name) &&
|
||||
schedule.find((si) => si.name === name)
|
||||
) {
|
||||
@@ -303,10 +304,9 @@ export const schedulerItemValidation = (
|
||||
) =>
|
||||
new Schema({
|
||||
name: [
|
||||
{ required: true, message: 'Name is required' },
|
||||
{
|
||||
type: 'string',
|
||||
pattern: /^[a-zA-Z0-9_\\.]{1,15}$/,
|
||||
pattern: /^[a-zA-Z0-9_\\.]{0,15}$/,
|
||||
message: "Must be <15 characters: alpha numeric, '_' or '.'"
|
||||
},
|
||||
...[uniqueNameValidator(schedule, scheduleItem.o_name)]
|
||||
@@ -392,8 +392,8 @@ export const temperatureSensorItemValidation = () =>
|
||||
n: [
|
||||
{
|
||||
type: 'string',
|
||||
pattern: /^[a-zA-Z0-9_\\.]{0,15}$/,
|
||||
message: "Must be <15 characters: alpha numeric, '_' or '.'"
|
||||
pattern: /^[a-zA-Z0-9_\\.]{0,17}$/,
|
||||
message: "Must be <18 characters: alpha numeric, '_' or '.'"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@@ -24,6 +24,7 @@ export interface ESPSystemStatus {
|
||||
psram_size?: number;
|
||||
free_psram?: number;
|
||||
has_loader: boolean;
|
||||
model: string;
|
||||
}
|
||||
|
||||
export interface SystemStatus {
|
||||
|
||||
@@ -56,10 +56,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/compat-data@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/compat-data@npm:7.24.7"
|
||||
checksum: 10c0/dcd93a5632b04536498fbe2be5af1057f635fd7f7090483d8e797878559037e5130b26862ceb359acbae93ed27e076d395ddb4663db6b28a665756ffd02d324f
|
||||
"@babel/compat-data@npm:^7.24.8":
|
||||
version: 7.24.8
|
||||
resolution: "@babel/compat-data@npm:7.24.8"
|
||||
checksum: 10c0/7f465e9d8e44c5b516eeb3001362a3cd9a6df51dd90d3ac9868e1e7fa631ac57fc781cec6700110d4f555ba37fe59c4a71927b445106fe0062e79e79ffe11091
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -86,26 +86,26 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/core@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/core@npm:7.24.7"
|
||||
"@babel/core@npm:^7.24.8":
|
||||
version: 7.24.8
|
||||
resolution: "@babel/core@npm:7.24.8"
|
||||
dependencies:
|
||||
"@ampproject/remapping": "npm:^2.2.0"
|
||||
"@babel/code-frame": "npm:^7.24.7"
|
||||
"@babel/generator": "npm:^7.24.7"
|
||||
"@babel/helper-compilation-targets": "npm:^7.24.7"
|
||||
"@babel/helper-module-transforms": "npm:^7.24.7"
|
||||
"@babel/helpers": "npm:^7.24.7"
|
||||
"@babel/parser": "npm:^7.24.7"
|
||||
"@babel/generator": "npm:^7.24.8"
|
||||
"@babel/helper-compilation-targets": "npm:^7.24.8"
|
||||
"@babel/helper-module-transforms": "npm:^7.24.8"
|
||||
"@babel/helpers": "npm:^7.24.8"
|
||||
"@babel/parser": "npm:^7.24.8"
|
||||
"@babel/template": "npm:^7.24.7"
|
||||
"@babel/traverse": "npm:^7.24.7"
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
"@babel/traverse": "npm:^7.24.8"
|
||||
"@babel/types": "npm:^7.24.8"
|
||||
convert-source-map: "npm:^2.0.0"
|
||||
debug: "npm:^4.1.0"
|
||||
gensync: "npm:^1.0.0-beta.2"
|
||||
json5: "npm:^2.2.3"
|
||||
semver: "npm:^6.3.1"
|
||||
checksum: 10c0/4004ba454d3c20a46ea66264e06c15b82e9f6bdc35f88819907d24620da70dbf896abac1cb4cc4b6bb8642969e45f4d808497c9054a1388a386cf8c12e9b9e0d
|
||||
checksum: 10c0/5e21b40cc69746deda3fe3d6540351d9cb0d1ad5aea055b7c319db26071ff5789fd9580d1aa47b114f07631e8e2109f4e71696ca11d7c7e60d157767022c1bd2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -144,6 +144,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/generator@npm:^7.24.8":
|
||||
version: 7.24.8
|
||||
resolution: "@babel/generator@npm:7.24.8"
|
||||
dependencies:
|
||||
"@babel/types": "npm:^7.24.8"
|
||||
"@jridgewell/gen-mapping": "npm:^0.3.5"
|
||||
"@jridgewell/trace-mapping": "npm:^0.3.25"
|
||||
jsesc: "npm:^2.5.1"
|
||||
checksum: 10c0/e8a278e75a895f13a7b17dd79abe1e894fe82a5ed3abb127c33c14c66773d69993762521c094c6c364723f8f7375683b0d4a96097781175a29407baedf67b769
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-annotate-as-pure@npm:^7.22.5":
|
||||
version: 7.22.5
|
||||
resolution: "@babel/helper-annotate-as-pure@npm:7.22.5"
|
||||
@@ -166,16 +178,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-compilation-targets@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-compilation-targets@npm:7.24.7"
|
||||
"@babel/helper-compilation-targets@npm:^7.24.8":
|
||||
version: 7.24.8
|
||||
resolution: "@babel/helper-compilation-targets@npm:7.24.8"
|
||||
dependencies:
|
||||
"@babel/compat-data": "npm:^7.24.7"
|
||||
"@babel/helper-validator-option": "npm:^7.24.7"
|
||||
browserslist: "npm:^4.22.2"
|
||||
"@babel/compat-data": "npm:^7.24.8"
|
||||
"@babel/helper-validator-option": "npm:^7.24.8"
|
||||
browserslist: "npm:^4.23.1"
|
||||
lru-cache: "npm:^5.1.1"
|
||||
semver: "npm:^6.3.1"
|
||||
checksum: 10c0/1d580a9bcacefe65e6bf02ba1dafd7ab278269fef45b5e281d8354d95c53031e019890464e7f9351898c01502dd2e633184eb0bcda49ed2ecd538675ce310f51
|
||||
checksum: 10c0/2885c44ef6aaf82b7e4352b30089bb09fbe08ed5ec24eb452c2bdc3c021e2a65ab412f74b3d67ec1398da0356c730b33a2ceca1d67d34c85080d31ca6efa9aec
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -267,9 +279,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-module-transforms@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-module-transforms@npm:7.24.7"
|
||||
"@babel/helper-module-transforms@npm:^7.24.8":
|
||||
version: 7.24.8
|
||||
resolution: "@babel/helper-module-transforms@npm:7.24.8"
|
||||
dependencies:
|
||||
"@babel/helper-environment-visitor": "npm:^7.24.7"
|
||||
"@babel/helper-module-imports": "npm:^7.24.7"
|
||||
@@ -278,7 +290,7 @@ __metadata:
|
||||
"@babel/helper-validator-identifier": "npm:^7.24.7"
|
||||
peerDependencies:
|
||||
"@babel/core": ^7.0.0
|
||||
checksum: 10c0/4f311755fcc3b4cbdb689386309cdb349cf0575a938f0b9ab5d678e1a81bbb265aa34ad93174838245f2ac7ff6d5ddbd0104638a75e4e961958ed514355687b6
|
||||
checksum: 10c0/b76496d5045af55be9de60e59e65e56a43033f01ccc746b26b7af911c358668c206b688ce70a23ab31ec04f9728f3a38e8d01073c85244115ab62f271a7fa3d1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -340,6 +352,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-string-parser@npm:^7.24.8":
|
||||
version: 7.24.8
|
||||
resolution: "@babel/helper-string-parser@npm:7.24.8"
|
||||
checksum: 10c0/6361f72076c17fabf305e252bf6d580106429014b3ab3c1f5c4eb3e6d465536ea6b670cc0e9a637a77a9ad40454d3e41361a2909e70e305116a23d68ce094c08
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-validator-identifier@npm:^7.16.7, @babel/helper-validator-identifier@npm:^7.24.5":
|
||||
version: 7.24.5
|
||||
resolution: "@babel/helper-validator-identifier@npm:7.24.5"
|
||||
@@ -361,10 +380,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-validator-option@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-validator-option@npm:7.24.7"
|
||||
checksum: 10c0/21aea2b7bc5cc8ddfb828741d5c8116a84cbc35b4a3184ec53124f08e09746f1f67a6f9217850188995ca86059a7942e36d8965a6730784901def777b7e8a436
|
||||
"@babel/helper-validator-option@npm:^7.24.8":
|
||||
version: 7.24.8
|
||||
resolution: "@babel/helper-validator-option@npm:7.24.8"
|
||||
checksum: 10c0/73db93a34ae89201351288bee7623eed81a54000779462a986105b54ffe82069e764afd15171a428b82e7c7a9b5fec10b5d5603b216317a414062edf5c67a21f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -379,13 +398,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helpers@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helpers@npm:7.24.7"
|
||||
"@babel/helpers@npm:^7.24.8":
|
||||
version: 7.24.8
|
||||
resolution: "@babel/helpers@npm:7.24.8"
|
||||
dependencies:
|
||||
"@babel/template": "npm:^7.24.7"
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
checksum: 10c0/aa8e230f6668773e17e141dbcab63e935c514b4b0bf1fed04d2eaefda17df68e16b61a56573f7f1d4d1e605ce6cc162b5f7e9fdf159fde1fd9b77c920ae47d27
|
||||
"@babel/types": "npm:^7.24.8"
|
||||
checksum: 10c0/42b8939b0a0bf72d6df9721973eb0fd7cd48f42641c5c9c740916397faa586255c06d36c6e6a7e091860723096281c620f6ffaee0011a3bb254a6f5475d89a12
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -431,6 +450,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/parser@npm:^7.24.8":
|
||||
version: 7.24.8
|
||||
resolution: "@babel/parser@npm:7.24.8"
|
||||
bin:
|
||||
parser: ./bin/babel-parser.js
|
||||
checksum: 10c0/ce69671de8fa6f649abf849be262707ac700b573b8b1ce1893c66cc6cd76aeb1294a19e8c290b0eadeb2f47d3f413a2e57a281804ffbe76bfb9fa50194cf3c52
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/plugin-syntax-jsx@npm:^7.23.3":
|
||||
version: 7.24.1
|
||||
resolution: "@babel/plugin-syntax-jsx@npm:7.24.1"
|
||||
@@ -553,6 +581,24 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/traverse@npm:^7.24.8":
|
||||
version: 7.24.8
|
||||
resolution: "@babel/traverse@npm:7.24.8"
|
||||
dependencies:
|
||||
"@babel/code-frame": "npm:^7.24.7"
|
||||
"@babel/generator": "npm:^7.24.8"
|
||||
"@babel/helper-environment-visitor": "npm:^7.24.7"
|
||||
"@babel/helper-function-name": "npm:^7.24.7"
|
||||
"@babel/helper-hoist-variables": "npm:^7.24.7"
|
||||
"@babel/helper-split-export-declaration": "npm:^7.24.7"
|
||||
"@babel/parser": "npm:^7.24.8"
|
||||
"@babel/types": "npm:^7.24.8"
|
||||
debug: "npm:^4.3.1"
|
||||
globals: "npm:^11.1.0"
|
||||
checksum: 10c0/67a5cc35824455cdb54fb9e196a44b3186283e29018a9c2331f51763921e18e891b3c60c283615a27540ec8eb4c8b89f41c237b91f732a7aa518b2eb7a0d434d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/types@npm:7.17.0":
|
||||
version: 7.17.0
|
||||
resolution: "@babel/types@npm:7.17.0"
|
||||
@@ -585,6 +631,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/types@npm:^7.24.8":
|
||||
version: 7.24.8
|
||||
resolution: "@babel/types@npm:7.24.8"
|
||||
dependencies:
|
||||
"@babel/helper-string-parser": "npm:^7.24.8"
|
||||
"@babel/helper-validator-identifier": "npm:^7.24.7"
|
||||
to-fast-properties: "npm:^2.0.0"
|
||||
checksum: 10c0/2d7bf561ae993e794cb052c5a81d3a6d1877da13e1e2eb2a59ae75a8fb1c965b618fb3e4abd42548f5f9a4587d3a149185a32d6c4c4ea82195da7dd86f2da0f1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@emotion/babel-plugin@npm:^11.11.0":
|
||||
version: 11.11.0
|
||||
resolution: "@emotion/babel-plugin@npm:11.11.0"
|
||||
@@ -910,13 +967,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.6.1":
|
||||
"@eslint-community/regexpp@npm:^4.10.0":
|
||||
version: 4.10.0
|
||||
resolution: "@eslint-community/regexpp@npm:4.10.0"
|
||||
checksum: 10c0/c5f60ef1f1ea7649fa7af0e80a5a79f64b55a8a8fa5086de4727eb4c86c652aedee407a9c143b8995d2c0b2d75c1222bec9ba5d73dbfc1f314550554f0979ef4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@eslint-community/regexpp@npm:^4.11.0":
|
||||
version: 4.11.0
|
||||
resolution: "@eslint-community/regexpp@npm:4.11.0"
|
||||
checksum: 10c0/0f6328869b2741e2794da4ad80beac55cba7de2d3b44f796a60955b0586212ec75e6b0253291fd4aad2100ad471d1480d8895f2b54f1605439ba4c875e05e523
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@eslint/config-array@npm:^0.17.0":
|
||||
version: 0.17.0
|
||||
resolution: "@eslint/config-array@npm:0.17.0"
|
||||
@@ -945,10 +1009,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@eslint/js@npm:9.6.0, @eslint/js@npm:^9.6.0":
|
||||
version: 9.6.0
|
||||
resolution: "@eslint/js@npm:9.6.0"
|
||||
checksum: 10c0/83967a7e59f2e958c9bbb3acd0929cad00d59d927ad786ed8e0d30b07f983c6bea3af6f4ad32da32145db40b7a741a816ba339bdd8960fc7fc8231716d943b7f
|
||||
"@eslint/js@npm:9.7.0, @eslint/js@npm:^9.7.0":
|
||||
version: 9.7.0
|
||||
resolution: "@eslint/js@npm:9.7.0"
|
||||
checksum: 10c0/73fc10666f6f4aed6f58e407e09f42ceb0d42fa60c52701c64ea9f59a81a6a8ad5caecdfd423d03088481515fe7ec17eb461acb4ef1ad70b649b6eae465b3164
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1099,16 +1163,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mui/core-downloads-tracker@npm:^5.16.0":
|
||||
version: 5.16.0
|
||||
resolution: "@mui/core-downloads-tracker@npm:5.16.0"
|
||||
checksum: 10c0/ed2c7e4e87637435d138026837436527934cd9c4c340721859f2f24d21d63e922231beb3b916070d549e2e6133310b2d3cca5b1d8bc1b8f88a10e6de913a363d
|
||||
"@mui/core-downloads-tracker@npm:^5.16.1":
|
||||
version: 5.16.1
|
||||
resolution: "@mui/core-downloads-tracker@npm:5.16.1"
|
||||
checksum: 10c0/2bdad71c53d65e59eba4889e6d3270b964200dddae448ae7d095de7130a4ec82e7fccdf8668488996e22993b653b91544195c10eeb996dc1c3a6c7a34c88c9c4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mui/icons-material@npm:^5.16.0":
|
||||
version: 5.16.0
|
||||
resolution: "@mui/icons-material@npm:5.16.0"
|
||||
"@mui/icons-material@npm:^5.16.1":
|
||||
version: 5.16.1
|
||||
resolution: "@mui/icons-material@npm:5.16.1"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.23.9"
|
||||
peerDependencies:
|
||||
@@ -1118,25 +1182,25 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/c4aa6ea2941efe6bf50f477657234a946579f0ee0592cacec03a6e2bacefef04af2073e43c06cb69b1372f1ffb89ff4e4fc75f909ed4c54a04974176562f52f0
|
||||
checksum: 10c0/90c235ee065a18e07e2c3059dcfe15ef880c5f936cde538c41ba3dfab83bbb963093a28603852647e0ef05e0a233e50ea4cd932d9ae58dcf803dadc16dd603af
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mui/material@npm:^5.16.0":
|
||||
version: 5.16.0
|
||||
resolution: "@mui/material@npm:5.16.0"
|
||||
"@mui/material@npm:^5.16.1":
|
||||
version: 5.16.1
|
||||
resolution: "@mui/material@npm:5.16.1"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.23.9"
|
||||
"@mui/base": "npm:5.0.0-beta.40"
|
||||
"@mui/core-downloads-tracker": "npm:^5.16.0"
|
||||
"@mui/system": "npm:^5.16.0"
|
||||
"@mui/types": "npm:^7.2.14"
|
||||
"@mui/utils": "npm:^5.16.0"
|
||||
"@mui/core-downloads-tracker": "npm:^5.16.1"
|
||||
"@mui/system": "npm:^5.16.1"
|
||||
"@mui/types": "npm:^7.2.15"
|
||||
"@mui/utils": "npm:^5.16.1"
|
||||
"@types/react-transition-group": "npm:^4.4.10"
|
||||
clsx: "npm:^2.1.0"
|
||||
csstype: "npm:^3.1.3"
|
||||
prop-types: "npm:^15.8.1"
|
||||
react-is: "npm:^18.2.0"
|
||||
react-is: "npm:^18.3.1"
|
||||
react-transition-group: "npm:^4.4.5"
|
||||
peerDependencies:
|
||||
"@emotion/react": ^11.5.0
|
||||
@@ -1151,16 +1215,16 @@ __metadata:
|
||||
optional: true
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/59a302ad3168a9768980f9bc8b18044876194ecebc51fd166ff002ad86df9c73f43409ed451916ed8cbbeb86447ec27b234c469f654d9d0313e36ef2d487a55a
|
||||
checksum: 10c0/13baf645c276a97fade56ccce83ceaea95ee71cff56fea407cce576ff96b81115dacc5dd3d30a250047fc104e5ce63c28bdc095351e567407f9944af9d9daa83
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mui/private-theming@npm:^5.16.0":
|
||||
version: 5.16.0
|
||||
resolution: "@mui/private-theming@npm:5.16.0"
|
||||
"@mui/private-theming@npm:^5.16.1":
|
||||
version: 5.16.1
|
||||
resolution: "@mui/private-theming@npm:5.16.1"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.23.9"
|
||||
"@mui/utils": "npm:^5.16.0"
|
||||
"@mui/utils": "npm:^5.16.1"
|
||||
prop-types: "npm:^15.8.1"
|
||||
peerDependencies:
|
||||
"@types/react": ^17.0.0 || ^18.0.0
|
||||
@@ -1168,13 +1232,13 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/cd7c1888f45da3db701806a1d127010514815bb4acf502c3cf711e63d2307b18387bdc7a9f3815031210814b6a1fd977722e5cef2133e077e9bc2ac0bdb5504f
|
||||
checksum: 10c0/8a95c7d59be1fd3ba8e49addb76870d5efe675a8f61ecb1558306053f0c71abad22f08d551e55fc48d5c012b0d1f1aefe924e0d3395485451ad1fe92a47adab2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mui/styled-engine@npm:^5.15.14":
|
||||
version: 5.15.14
|
||||
resolution: "@mui/styled-engine@npm:5.15.14"
|
||||
"@mui/styled-engine@npm:^5.16.1":
|
||||
version: 5.16.1
|
||||
resolution: "@mui/styled-engine@npm:5.16.1"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.23.9"
|
||||
"@emotion/cache": "npm:^11.11.0"
|
||||
@@ -1189,19 +1253,19 @@ __metadata:
|
||||
optional: true
|
||||
"@emotion/styled":
|
||||
optional: true
|
||||
checksum: 10c0/0d262ea0b3c117f865af1cd52b992592c24432e491b35e712159bb49adfd776ee9a532abbc4ab08889f308e75d30082a0fee809119d5d61a82b3277212655319
|
||||
checksum: 10c0/fc011390c64ff970ad095e0a9e18f5ad777491fd49974233137b673fa9698d178c6b5f6346a28c1d8a1718dd453879ded4198bbc73e73dfcc8d5a90ea17760f6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mui/system@npm:^5.16.0":
|
||||
version: 5.16.0
|
||||
resolution: "@mui/system@npm:5.16.0"
|
||||
"@mui/system@npm:^5.16.1":
|
||||
version: 5.16.1
|
||||
resolution: "@mui/system@npm:5.16.1"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.23.9"
|
||||
"@mui/private-theming": "npm:^5.16.0"
|
||||
"@mui/styled-engine": "npm:^5.15.14"
|
||||
"@mui/types": "npm:^7.2.14"
|
||||
"@mui/utils": "npm:^5.16.0"
|
||||
"@mui/private-theming": "npm:^5.16.1"
|
||||
"@mui/styled-engine": "npm:^5.16.1"
|
||||
"@mui/types": "npm:^7.2.15"
|
||||
"@mui/utils": "npm:^5.16.1"
|
||||
clsx: "npm:^2.1.0"
|
||||
csstype: "npm:^3.1.3"
|
||||
prop-types: "npm:^15.8.1"
|
||||
@@ -1217,7 +1281,7 @@ __metadata:
|
||||
optional: true
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/b5db097ba432653eba723424264204d3037ab1cdb30acc63b2d2fbcb98bae8999cbfd7ffff54173593dc2a4771558177602f01377da6f4134e7017f93a3624bf
|
||||
checksum: 10c0/17b76d32d4ee1800910993d7309c36a8ea1982890ee952d1a301e5125a8ebe7bcdf3d8930fb385dd79712c4e3ea9e9e9547fac23b79dc874b60b33b0dbdffa8a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1233,6 +1297,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mui/types@npm:^7.2.15":
|
||||
version: 7.2.15
|
||||
resolution: "@mui/types@npm:7.2.15"
|
||||
peerDependencies:
|
||||
"@types/react": ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/26c39674fe6f653a4c7406890b081b772e62efbd5b2754ab28bb8346819265d7c6496db8a8923230a84252ffd890e3d0b41642c151b78fdf8505336c92d78e14
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mui/utils@npm:^5.15.14":
|
||||
version: 5.15.14
|
||||
resolution: "@mui/utils@npm:5.15.14"
|
||||
@@ -1251,21 +1327,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mui/utils@npm:^5.16.0":
|
||||
version: 5.16.0
|
||||
resolution: "@mui/utils@npm:5.16.0"
|
||||
"@mui/utils@npm:^5.16.1":
|
||||
version: 5.16.1
|
||||
resolution: "@mui/utils@npm:5.16.1"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.23.9"
|
||||
"@types/prop-types": "npm:^15.7.11"
|
||||
"@types/prop-types": "npm:^15.7.12"
|
||||
prop-types: "npm:^15.8.1"
|
||||
react-is: "npm:^18.2.0"
|
||||
react-is: "npm:^18.3.1"
|
||||
peerDependencies:
|
||||
"@types/react": ^17.0.0 || ^18.0.0
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/0b56f9265a8ea686b50195448f1dea41c637d504c30da44c5f3f315bc81d24598f3b2acb281dd24d15831f7756dcaab285b7b891883bbec5809c54ef24affb49
|
||||
checksum: 10c0/9a64bbfcd84474c9d18a79f3e236c4145d43983c3b1810cbcb6cf9d37d36f1bfeeb5a4f9ebf907050364b0a991caba28c481d2e6b2818e4e1c22729eeed24505
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1341,9 +1417,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@preact/preset-vite@npm:^2.8.3":
|
||||
version: 2.8.3
|
||||
resolution: "@preact/preset-vite@npm:2.8.3"
|
||||
"@preact/preset-vite@npm:^2.9.0":
|
||||
version: 2.9.0
|
||||
resolution: "@preact/preset-vite@npm:2.9.0"
|
||||
dependencies:
|
||||
"@babel/code-frame": "npm:^7.22.13"
|
||||
"@babel/plugin-transform-react-jsx": "npm:^7.22.15"
|
||||
@@ -1361,7 +1437,7 @@ __metadata:
|
||||
peerDependencies:
|
||||
"@babel/core": 7.x
|
||||
vite: 2.x || 3.x || 4.x || 5.x
|
||||
checksum: 10c0/984b47d24491d20ea9f0787adbef3515c3bd4cdfd77154cdb84e9038fabb5db09a0c76237557aff88b3da26cff6146ac616c2375579143fc511afcf7baf63927
|
||||
checksum: 10c0/658e3dc048d1f1d8ad7cb1fef4a3db0f933be4e00d3d6cdfbd29fe7ec02341b3a26747520a5b261992923b3d3f49800c23a4d77da849e708a5c1ad9a920343b2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1784,7 +1860,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/prop-types@npm:*, @types/prop-types@npm:^15.7.11":
|
||||
"@types/prop-types@npm:*, @types/prop-types@npm:^15.7.11, @types/prop-types@npm:^15.7.12":
|
||||
version: 15.7.12
|
||||
resolution: "@types/prop-types@npm:15.7.12"
|
||||
checksum: 10c0/1babcc7db6a1177779f8fde0ccc78d64d459906e6ef69a4ed4dd6339c920c2e05b074ee5a92120fe4e9d9f1a01c952f843ebd550bee2332fc2ef81d1706878f8
|
||||
@@ -2002,14 +2078,14 @@ __metadata:
|
||||
dependencies:
|
||||
"@alova/adapter-xhr": "npm:^1.0.6"
|
||||
"@alova/scene-react": "npm:^1.6.1"
|
||||
"@babel/core": "npm:^7.24.7"
|
||||
"@babel/core": "npm:^7.24.8"
|
||||
"@emotion/react": "npm:^11.11.4"
|
||||
"@emotion/styled": "npm:^11.11.5"
|
||||
"@eslint/js": "npm:^9.6.0"
|
||||
"@mui/icons-material": "npm:^5.16.0"
|
||||
"@mui/material": "npm:^5.16.0"
|
||||
"@eslint/js": "npm:^9.7.0"
|
||||
"@mui/icons-material": "npm:^5.16.1"
|
||||
"@mui/material": "npm:^5.16.1"
|
||||
"@preact/compat": "npm:^17.1.2"
|
||||
"@preact/preset-vite": "npm:^2.8.3"
|
||||
"@preact/preset-vite": "npm:^2.9.0"
|
||||
"@table-library/react-table-library": "npm:4.1.7"
|
||||
"@trivago/prettier-plugin-sort-imports": "npm:^4.3.0"
|
||||
"@types/babel__core": "npm:^7"
|
||||
@@ -2018,17 +2094,17 @@ __metadata:
|
||||
"@types/react": "npm:^18.3.3"
|
||||
"@types/react-dom": "npm:^18.3.0"
|
||||
"@types/react-router-dom": "npm:^5.3.3"
|
||||
alova: "npm:^2.21.3"
|
||||
alova: "npm:^2.21.4"
|
||||
async-validator: "npm:^4.2.5"
|
||||
concurrently: "npm:^8.2.2"
|
||||
eslint: "npm:^9.6.0"
|
||||
eslint: "npm:^9.7.0"
|
||||
eslint-config-prettier: "npm:^9.1.0"
|
||||
history: "npm:^5.3.0"
|
||||
jwt-decode: "npm:^4.0.0"
|
||||
lodash-es: "npm:^4.17.21"
|
||||
mime-types: "npm:^2.1.35"
|
||||
preact: "npm:^10.22.1"
|
||||
prettier: "npm:^3.3.2"
|
||||
prettier: "npm:^3.3.3"
|
||||
react: "npm:latest"
|
||||
react-dom: "npm:latest"
|
||||
react-dropzone: "npm:^14.2.3"
|
||||
@@ -2036,7 +2112,7 @@ __metadata:
|
||||
react-router-dom: "npm:^6.24.1"
|
||||
react-toastify: "npm:^10.0.5"
|
||||
rollup-plugin-visualizer: "npm:^5.12.0"
|
||||
terser: "npm:^5.31.1"
|
||||
terser: "npm:^5.31.2"
|
||||
typesafe-i18n: "npm:^5.26.2"
|
||||
typescript: "npm:^5.5.3"
|
||||
typescript-eslint: "npm:8.0.0-alpha.10"
|
||||
@@ -2111,10 +2187,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"alova@npm:^2.21.3":
|
||||
version: 2.21.3
|
||||
resolution: "alova@npm:2.21.3"
|
||||
checksum: 10c0/ce03ced33660f15ec667e24df5c7fbeff223dace95a7d50d657dd038f21dc865d8a9290914edbc5a980c8573daa4354ac714f97ae58650ea5b8fefd8fc2d313c
|
||||
"alova@npm:^2.21.4":
|
||||
version: 2.21.4
|
||||
resolution: "alova@npm:2.21.4"
|
||||
checksum: 10c0/6600826747eecc85f750904cd5a9f75361bd5b542615b027fae072cafe72cb27b9f7b260a834063c0734a9b41a7aa8b15396a190f8ce9a46713d01b073296a50
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2373,6 +2449,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browserslist@npm:^4.23.1":
|
||||
version: 4.23.2
|
||||
resolution: "browserslist@npm:4.23.2"
|
||||
dependencies:
|
||||
caniuse-lite: "npm:^1.0.30001640"
|
||||
electron-to-chromium: "npm:^1.4.820"
|
||||
node-releases: "npm:^2.0.14"
|
||||
update-browserslist-db: "npm:^1.1.0"
|
||||
bin:
|
||||
browserslist: cli.js
|
||||
checksum: 10c0/0217d23c69ed61cdd2530c7019bf7c822cd74c51f8baab18dd62457fed3129f52499f8d3a6f809ae1fb7bb3050aa70caa9a529cc36c7478427966dbf429723a5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"buffer-alloc-unsafe@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "buffer-alloc-unsafe@npm:1.1.0"
|
||||
@@ -2487,6 +2577,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"caniuse-lite@npm:^1.0.30001640":
|
||||
version: 1.0.30001641
|
||||
resolution: "caniuse-lite@npm:1.0.30001641"
|
||||
checksum: 10c0/a065b641cfcc84b36955ee909bfd7313ad103d6a299f0fd261e0e4160e8f1cec79d685c5a9f11097a77687cf47154eddb8133163f2a34bcb8d73c45033a014d2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"caw@npm:^2.0.0, caw@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "caw@npm:2.0.1"
|
||||
@@ -3098,6 +3195,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"electron-to-chromium@npm:^1.4.820":
|
||||
version: 1.4.827
|
||||
resolution: "electron-to-chromium@npm:1.4.827"
|
||||
checksum: 10c0/e37719d8f13da78eb2bc68184cdf73d167ecf413abc28afef2b0a5c55866293752fda980d83a5f42b5780781bde418b24c12e1c38f2662d25ed1c2f71880bc24
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"emoji-regex@npm:^8.0.0":
|
||||
version: 8.0.0
|
||||
resolution: "emoji-regex@npm:8.0.0"
|
||||
@@ -3493,13 +3597,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-scope@npm:^8.0.1":
|
||||
version: 8.0.1
|
||||
resolution: "eslint-scope@npm:8.0.1"
|
||||
"eslint-scope@npm:^8.0.2":
|
||||
version: 8.0.2
|
||||
resolution: "eslint-scope@npm:8.0.2"
|
||||
dependencies:
|
||||
esrecurse: "npm:^4.3.0"
|
||||
estraverse: "npm:^5.2.0"
|
||||
checksum: 10c0/0ec40ab284e58ac7ef064ecd23c127e03d339fa57173c96852336c73afc70ce5631da21dc1c772415a37a421291845538dd69db83c68d611044c0fde1d1fa269
|
||||
checksum: 10c0/477f820647c8755229da913025b4567347fd1f0bf7cbdf3a256efff26a7e2e130433df052bd9e3d014025423dc00489bea47eb341002b15553673379c1a7dc36
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -3517,15 +3621,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint@npm:^9.6.0":
|
||||
version: 9.6.0
|
||||
resolution: "eslint@npm:9.6.0"
|
||||
"eslint@npm:^9.7.0":
|
||||
version: 9.7.0
|
||||
resolution: "eslint@npm:9.7.0"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": "npm:^4.2.0"
|
||||
"@eslint-community/regexpp": "npm:^4.6.1"
|
||||
"@eslint-community/regexpp": "npm:^4.11.0"
|
||||
"@eslint/config-array": "npm:^0.17.0"
|
||||
"@eslint/eslintrc": "npm:^3.1.0"
|
||||
"@eslint/js": "npm:9.6.0"
|
||||
"@eslint/js": "npm:9.7.0"
|
||||
"@humanwhocodes/module-importer": "npm:^1.0.1"
|
||||
"@humanwhocodes/retry": "npm:^0.3.0"
|
||||
"@nodelib/fs.walk": "npm:^1.2.8"
|
||||
@@ -3534,7 +3638,7 @@ __metadata:
|
||||
cross-spawn: "npm:^7.0.2"
|
||||
debug: "npm:^4.3.2"
|
||||
escape-string-regexp: "npm:^4.0.0"
|
||||
eslint-scope: "npm:^8.0.1"
|
||||
eslint-scope: "npm:^8.0.2"
|
||||
eslint-visitor-keys: "npm:^4.0.0"
|
||||
espree: "npm:^10.1.0"
|
||||
esquery: "npm:^1.5.0"
|
||||
@@ -3557,7 +3661,7 @@ __metadata:
|
||||
text-table: "npm:^0.2.0"
|
||||
bin:
|
||||
eslint: bin/eslint.js
|
||||
checksum: 10c0/82ea5ad3f28aaef89e2a98f4e6df0eae9d4e16ccd6d667c69977042e0b103fa5df98bf16d3df72d1ae77edd8c1dccfdf4afa2a55309aa8081a1bc54af6229826
|
||||
checksum: 10c0/e2369a9534404f62f37ee5560e56fb84e0776a9c8f084550170017992772e7034d73571bdf4060e2fe9b836f136d45b07d50407d4b9361de720ee77794259274
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5999,12 +6103,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"prettier@npm:^3.3.2":
|
||||
version: 3.3.2
|
||||
resolution: "prettier@npm:3.3.2"
|
||||
"prettier@npm:^3.3.3":
|
||||
version: 3.3.3
|
||||
resolution: "prettier@npm:3.3.3"
|
||||
bin:
|
||||
prettier: bin/prettier.cjs
|
||||
checksum: 10c0/39ed27d17f0238da6dd6571d63026566bd790d3d0edac57c285fbab525982060c8f1e01955fe38134ab10f0951a6076da37f015db8173c02f14bc7f0803a384c
|
||||
checksum: 10c0/b85828b08e7505716324e4245549b9205c0cacb25342a030ba8885aba2039a115dbcf75a0b7ca3b37bc9d101ee61fab8113fc69ca3359f2a226f1ecc07ad2e26
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6140,7 +6244,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-is@npm:^18.2.0":
|
||||
"react-is@npm:^18.2.0, react-is@npm:^18.3.1":
|
||||
version: 18.3.1
|
||||
resolution: "react-is@npm:18.3.1"
|
||||
checksum: 10c0/f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072
|
||||
@@ -7035,9 +7139,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"terser@npm:^5.31.1":
|
||||
version: 5.31.1
|
||||
resolution: "terser@npm:5.31.1"
|
||||
"terser@npm:^5.31.2":
|
||||
version: 5.31.2
|
||||
resolution: "terser@npm:5.31.2"
|
||||
dependencies:
|
||||
"@jridgewell/source-map": "npm:^0.3.3"
|
||||
acorn: "npm:^8.8.2"
|
||||
@@ -7045,7 +7149,7 @@ __metadata:
|
||||
source-map-support: "npm:~0.5.20"
|
||||
bin:
|
||||
terser: bin/terser
|
||||
checksum: 10c0/4d49a58f64c11f3742e779a0a03aff69972ca5739decb361d909d22c8f3f7d8e2ec982a928d987d56737ad50229e8ab3f62d8ba993e4b5f360a53ed487d3c06c
|
||||
checksum: 10c0/5b72f58421f69267f67cb60cf4398282afcdec697e9b6f1909035cdf52d9960226fc1df5968e27ba96736b7a7ba76609d0b7b060ee5da7769553940726059b63
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -7274,6 +7378,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"update-browserslist-db@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "update-browserslist-db@npm:1.1.0"
|
||||
dependencies:
|
||||
escalade: "npm:^3.1.2"
|
||||
picocolors: "npm:^1.0.1"
|
||||
peerDependencies:
|
||||
browserslist: ">= 4.21.0"
|
||||
bin:
|
||||
update-browserslist-db: cli.js
|
||||
checksum: 10c0/a7452de47785842736fb71547651c5bbe5b4dc1e3722ccf48a704b7b34e4dcf633991eaa8e4a6a517ffb738b3252eede3773bef673ef9021baa26b056d63a5b9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"uri-js@npm:^4.2.2":
|
||||
version: 4.4.1
|
||||
resolution: "uri-js@npm:4.4.1"
|
||||
|
||||
@@ -13,80 +13,83 @@ the LICENSE file.
|
||||
namespace espMqttClientInternals {
|
||||
|
||||
ClientPosix::ClientPosix()
|
||||
: _sockfd(-1)
|
||||
, _host() {
|
||||
// empty
|
||||
: _sockfd(-1)
|
||||
, _host() {
|
||||
// empty
|
||||
}
|
||||
|
||||
ClientPosix::~ClientPosix() {
|
||||
ClientPosix::stop();
|
||||
ClientPosix::stop();
|
||||
}
|
||||
|
||||
bool ClientPosix::connect(IPAddress ip, uint16_t port) {
|
||||
if (connected()) stop();
|
||||
if (connected())
|
||||
stop();
|
||||
|
||||
_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (_sockfd < 0) {
|
||||
emc_log_e("Error %d opening socket", errno);
|
||||
}
|
||||
_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (_sockfd < 0) {
|
||||
emc_log_e("Error %d opening socket", errno);
|
||||
}
|
||||
|
||||
int flag = 1;
|
||||
if (setsockopt(_sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)) < 0) {
|
||||
emc_log_e("Error %d disabling nagle", errno);
|
||||
}
|
||||
int flag = 1;
|
||||
if (setsockopt(_sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)) < 0) {
|
||||
emc_log_e("Error %d disabling nagle", errno);
|
||||
}
|
||||
|
||||
memset(&_host, 0, sizeof(_host));
|
||||
_host.sin_family = AF_INET;
|
||||
_host.sin_addr.s_addr = htonl(uint32_t(ip));
|
||||
_host.sin_port = ::htons(port);
|
||||
memset(&_host, 0, sizeof(_host));
|
||||
_host.sin_family = AF_INET;
|
||||
_host.sin_addr.s_addr = htonl(uint32_t(ip));
|
||||
#ifndef __APPLE__
|
||||
_host.sin_port = ::htons(port);
|
||||
#endif
|
||||
|
||||
int ret = ::connect(_sockfd, reinterpret_cast<sockaddr*>(&_host), sizeof(_host));
|
||||
int ret = ::connect(_sockfd, reinterpret_cast<sockaddr *>(&_host), sizeof(_host));
|
||||
|
||||
if (ret < 0) {
|
||||
emc_log_e("Error connecting: %d - (%d) %s", ret, errno, strerror(errno));
|
||||
if (ret < 0) {
|
||||
emc_log_e("Error connecting: %d - (%d) %s", ret, errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
emc_log_i("Connected");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientPosix::connect(const char * host, uint16_t port) {
|
||||
// tbi
|
||||
(void)host;
|
||||
(void)port;
|
||||
return false;
|
||||
}
|
||||
|
||||
emc_log_i("Connected");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientPosix::connect(const char* host, uint16_t port) {
|
||||
// tbi
|
||||
(void) host;
|
||||
(void) port;
|
||||
return false;
|
||||
size_t ClientPosix::write(const uint8_t * buf, size_t size) {
|
||||
return ::send(_sockfd, buf, size, 0);
|
||||
}
|
||||
|
||||
size_t ClientPosix::write(const uint8_t* buf, size_t size) {
|
||||
return ::send(_sockfd, buf, size, 0);
|
||||
}
|
||||
|
||||
int ClientPosix::read(uint8_t* buf, size_t size) {
|
||||
int ret = ::recv(_sockfd, buf, size, MSG_DONTWAIT);
|
||||
/*
|
||||
int ClientPosix::read(uint8_t * buf, size_t size) {
|
||||
int ret = ::recv(_sockfd, buf, size, MSG_DONTWAIT);
|
||||
/*
|
||||
if (ret < 0) {
|
||||
emc_log_e("Error reading: %s", strerror(errno));
|
||||
}
|
||||
*/
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ClientPosix::stop() {
|
||||
if (_sockfd >= 0) {
|
||||
::close(_sockfd);
|
||||
_sockfd = -1;
|
||||
}
|
||||
if (_sockfd >= 0) {
|
||||
::close(_sockfd);
|
||||
_sockfd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientPosix::connected() {
|
||||
return _sockfd >= 0;
|
||||
return _sockfd >= 0;
|
||||
}
|
||||
|
||||
bool ClientPosix::disconnected() {
|
||||
return _sockfd < 0;
|
||||
return _sockfd < 0;
|
||||
}
|
||||
|
||||
} // namespace espMqttClientInternals
|
||||
} // namespace espMqttClientInternals
|
||||
|
||||
#endif
|
||||
|
||||
@@ -269,7 +269,7 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
|
||||
newSettings.publish_time_solar = static_cast<uint16_t>(root["publish_time_solar"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||
newSettings.publish_time_mixer = static_cast<uint16_t>(root["publish_time_mixer"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||
newSettings.publish_time_water = static_cast<uint16_t>(root["publish_time_water"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||
newSettings.publish_time_other = static_cast<uint16_t>(root["publish_time_other"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||
newSettings.publish_time_other = static_cast<uint16_t>(root["publish_time_other"] | EMSESP_DEFAULT_PUBLISH_TIME_OTHER);
|
||||
newSettings.publish_time_sensor = static_cast<uint16_t>(root["publish_time_sensor"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||
newSettings.publish_time_heartbeat = static_cast<uint16_t>(root["publish_time_heartbeat"] | EMSESP_DEFAULT_PUBLISH_HEARTBEAT);
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ Commands::Execution Commands::execute_command(Shell & shell, CommandLine && comm
|
||||
result.error = nullptr;
|
||||
|
||||
if (commands.exact.empty()) {
|
||||
result.error = "Command not found";
|
||||
result.error = "Command not found. Try 'help' for a list of commands.";
|
||||
} else if (commands.exact.count(longest->first) == 1) {
|
||||
auto & command = longest->second;
|
||||
std::vector<std::string> arguments;
|
||||
@@ -130,7 +130,7 @@ Commands::Execution Commands::execute_command(Shell & shell, CommandLine && comm
|
||||
command_line.reset();
|
||||
|
||||
if (commands.partial.upper_bound(longest->first) != commands.partial.end() && !arguments.empty()) {
|
||||
result.error = "Command not found";
|
||||
result.error = "Command not found. Try 'help' for a list of commands.";
|
||||
} else if (arguments.size() < command->minimum_arguments()) {
|
||||
result.error = "Not enough arguments for command";
|
||||
} else if (arguments.size() > command->maximum_arguments()) {
|
||||
|
||||
@@ -47,7 +47,7 @@ rest_server.get(ES_LOG_ENDPOINT, (_req, res) => {
|
||||
const interval = setInterval(() => {
|
||||
const data = {
|
||||
t: new Date().toISOString(),
|
||||
l: 3, // error
|
||||
l: 7, // debug
|
||||
i: count,
|
||||
n: 'system',
|
||||
m: 'message #' + count++
|
||||
|
||||
@@ -350,23 +350,26 @@ const GENERATE_TOKEN_ENDPOINT = REST_ENDPOINT_ROOT + 'generateToken';
|
||||
const ESPsystem_status = {
|
||||
emsesp_version: '3.7-demo',
|
||||
esp_platform: 'ESP32',
|
||||
max_alloc_heap: 89,
|
||||
cpu_type: 'ESP32-S3',
|
||||
cpu_rev: '0',
|
||||
cpu_cores: 2,
|
||||
max_alloc_heap: 89,
|
||||
psram_size: 0,
|
||||
free_psram: 0,
|
||||
cpu_freq_mhz: 240,
|
||||
free_heap: 143,
|
||||
arduino_version: 'ESP32 Arduino v2.0.14',
|
||||
sdk_version: 'v4.4.2',
|
||||
partition: 'app0',
|
||||
flash_chip_size: 4096,
|
||||
flash_chip_speed: 40000000,
|
||||
fs_used: 40,
|
||||
fs_free: 24,
|
||||
partition: 'app0',
|
||||
app_used: 1863,
|
||||
app_free: 121,
|
||||
arduino_version: 'ESP32 Arduino v2.0.14'
|
||||
fs_used: 40,
|
||||
fs_free: 24,
|
||||
free_mem: 100,
|
||||
psram_size: 0,
|
||||
free_psram: 0,
|
||||
has_loader: true,
|
||||
model: 'BBQKees Gateway Model E32V2 vE32V2.0P3/2024011'
|
||||
};
|
||||
|
||||
const system_status = {
|
||||
|
||||
@@ -213,14 +213,15 @@ build_unflags = ${common.unbuild_flags}
|
||||
; to build and run: pio run -e native -t exec
|
||||
[env:native]
|
||||
platform = native
|
||||
extra_scripts = pre:scripts/rename_prog.py
|
||||
build_flags =
|
||||
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
|
||||
-DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_TEST
|
||||
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.0-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
||||
-std=gnu++14 -Og -ggdb
|
||||
-std=gnu++14 -Og -ggdb -D__linux__
|
||||
build_src_flags =
|
||||
-Wall -Wextra -Werror
|
||||
-Wno-unused-parameter -Wno-sign-compare
|
||||
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
|
||||
-I./lib_standalone
|
||||
-I./lib/uuid-common/src
|
||||
-I./lib/uuid-console/src
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
# creates an CSV file called "dump_telegrams.cvs" with all devices and their telegrams
|
||||
# run from top folder like `sh ./scripts/dump_telegrams.sh`
|
||||
rm -f dump_telegrams.csv
|
||||
# make clean
|
||||
# make
|
||||
make clean
|
||||
make ARGS=-DEMSESP_STANDALONE
|
||||
echo "test telegram_dump" | ./emsesp | python3 ./scripts/strip_csv.py > dump_telegrams.csv
|
||||
cat dump_telegrams.csv
|
||||
@@ -3,9 +3,11 @@
|
||||
# This script generates c++ code for the modbus parameter definitions.
|
||||
#
|
||||
# Usage:
|
||||
# - first, dump all entities to csv by running 'scripts/dump_entities.sh'
|
||||
# - first, dump all entities to csv by running 'sh ./scripts/dump_entities.sh'
|
||||
# - then run 'cat ../dump_entities.csv | python3 update_modbus_registers.py > ../src/modbus_entity_parameters.hpp'
|
||||
# from the "scripts" folder
|
||||
# OR
|
||||
# run `sh ./scripts/update_modbus_registers.sh` from the root folder
|
||||
|
||||
import fileinput
|
||||
import csv
|
||||
@@ -114,6 +116,12 @@ device_type_names = [
|
||||
cpp_file_template = Template('''#include "modbus.h"
|
||||
#include "emsdevice.h"
|
||||
|
||||
/*
|
||||
* This file is auto-generated by the update_modbus_registers.sh script. Do not modify.
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
using dt = EMSdevice::DeviceType;
|
||||
@@ -125,7 +133,10 @@ using dt = EMSdevice::DeviceType;
|
||||
const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_mappings = {
|
||||
$entries};
|
||||
|
||||
} // namespace emsesp''')
|
||||
} // namespace emsesp
|
||||
|
||||
// clang-format off
|
||||
''')
|
||||
# cpp_entry_template = Template(
|
||||
# ' {std::make_tuple($devtype, $tagtype, std::string(\"$shortname\")), {$registeroffset, $registercount}},\n')
|
||||
cpp_entry_template = Template(
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Update modbus parameters from entity definitions.
|
||||
# This script generates c++ code for the modbus parameter definitions.
|
||||
#
|
||||
# Run this script from the EMS-ESP32 root directory with the command `scripts/update_modbus_registers.sh`.
|
||||
# Run this script from the EMS-ESP32 root directory with the command `sh ./scripts/update_modbus_registers.sh`.
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
@@ -35,6 +35,12 @@ if [ "$RESET" = "YES" ]; then
|
||||
#include "modbus.h"
|
||||
#include "emsdevice.h"
|
||||
|
||||
/*
|
||||
* This file is auto-generated by the update_modbus_registers.sh script. Do not modify.
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
using dt = EMSdevice::DeviceType;
|
||||
@@ -46,6 +52,9 @@ using dt = EMSdevice::DeviceType;
|
||||
const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_mappings = {};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
// clang-format on
|
||||
|
||||
EOL
|
||||
fi
|
||||
|
||||
@@ -53,3 +62,4 @@ make clean
|
||||
make ARGS=-DEMSESP_STANDALONE
|
||||
echo "test entity_dump" | ./emsesp | python3 ./scripts/strip_csv.py | python3 ./scripts/update_modbus_registers.py > ./src/modbus_entity_parameters.hpp
|
||||
echo "Modbus entity parameters written to ./src/modbus_entity_parameters.hpp."
|
||||
|
||||
|
||||
@@ -643,7 +643,7 @@ void AnalogSensor::publish_values(const bool force) {
|
||||
// called from emsesp.cpp for commands
|
||||
// searches sensor by name
|
||||
bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int8_t id) {
|
||||
// check of it a 'commmands' command
|
||||
// check of it a 'commands' command
|
||||
if (Helpers::toLower(cmd) == F_(commands)) {
|
||||
return Command::list(EMSdevice::DeviceType::ANALOGSENSOR, output);
|
||||
}
|
||||
@@ -700,22 +700,18 @@ bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int
|
||||
// if we're filtering on an attribute, go find it
|
||||
if (attribute_s) {
|
||||
if (output.containsKey(attribute_s)) {
|
||||
String data = output[attribute_s].as<String>();
|
||||
std::string data = output[attribute_s].as<std::string>();
|
||||
output.clear();
|
||||
output["api_data"] = data;
|
||||
output["api_data"] = data; // always as a string
|
||||
return true;
|
||||
} else {
|
||||
char error[100];
|
||||
snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, sensor_name);
|
||||
output.clear();
|
||||
output["message"] = error;
|
||||
return false;
|
||||
}
|
||||
return EMSESP::return_not_found(output, "attribute", sensor_name); // not found
|
||||
}
|
||||
return true; // found a match, exit
|
||||
}
|
||||
}
|
||||
return false; // not found
|
||||
|
||||
return EMSESP::return_not_found(output, "analog sensor", cmd); // not found
|
||||
}
|
||||
|
||||
void AnalogSensor::addSensorJson(JsonObject output, const Sensor & sensor) {
|
||||
|
||||
@@ -79,7 +79,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
|
||||
uint8_t device_type = EMSdevice::device_name_2_device_type(device_s);
|
||||
if (!device_has_commands(device_type)) {
|
||||
LOG_DEBUG("Command failed: unknown device '%s'", device_s);
|
||||
return message(CommandRet::ERROR, "unknown device", output);
|
||||
return message(CommandRet::NOT_FOUND, "unknown device", output);
|
||||
}
|
||||
|
||||
// the next value on the path should be the command or entity name
|
||||
@@ -161,21 +161,25 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
|
||||
if (data_p == nullptr) {
|
||||
return CommandRet::INVALID;
|
||||
}
|
||||
|
||||
char data_s[COMMAND_MAX_LENGTH];
|
||||
strlcpy(data_s, Helpers::toLower(data_p).c_str(), 30);
|
||||
if (strstr(data_s, "/value") == nullptr) {
|
||||
strcat(data_s, "/value");
|
||||
}
|
||||
|
||||
uint8_t device_type = EMSdevice::device_name_2_device_type(device_p);
|
||||
if (CommandRet::OK != Command::call(device_type, data_s, "", true, id_d, output)) {
|
||||
return CommandRet::INVALID;
|
||||
}
|
||||
if (!output.containsKey("api_data")) {
|
||||
return CommandRet::INVALID;
|
||||
|
||||
const char * api_data = output["api_data"];
|
||||
if (api_data) {
|
||||
output.clear();
|
||||
return Command::call(device_type, command_p, api_data, is_admin, id_n, output);
|
||||
}
|
||||
String dat = output["api_data"].as<String>();
|
||||
output.clear();
|
||||
return Command::call(device_type, command_p, dat.c_str(), is_admin, id_n, output);
|
||||
|
||||
return CommandRet::INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -296,11 +300,23 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
|
||||
if (cmd == nullptr) {
|
||||
return CommandRet::NOT_FOUND;
|
||||
}
|
||||
uint8_t return_code = CommandRet::OK;
|
||||
|
||||
auto dname = EMSdevice::device_type_2_device_name(device_type);
|
||||
auto dname = EMSdevice::device_type_2_device_name(device_type); // device name, not translated
|
||||
|
||||
// check first if there is only a command being called without a value
|
||||
// it could be an endpoint like a device's entity or attribute e.g. api/boiler/nrgheat or /api/boiler/nrgheat/value
|
||||
// or a special command like 'info', 'values', 'commands', 'entities' etc
|
||||
bool single_command = (!value || !strlen(value));
|
||||
if (single_command) {
|
||||
if (EMSESP::get_device_value_info(output, cmd, id, device_type)) { // entity = cmd
|
||||
LOG_DEBUG("Fetched device entity/attributes for %s/%s", dname, cmd);
|
||||
return CommandRet::OK;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t device_id = EMSESP::device_id_from_cmd(device_type, cmd, id);
|
||||
|
||||
// determine flags based on id (which is the tag)
|
||||
uint8_t flag = CommandFlag::CMD_FLAG_DEFAULT;
|
||||
int8_t tag = id;
|
||||
if (tag >= DeviceValueTAG::TAG_HC1 && tag <= DeviceValueTAG::TAG_HC8) {
|
||||
@@ -312,31 +328,19 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
|
||||
} else if (tag >= DeviceValueTAG::TAG_AHS1 && tag <= DeviceValueTAG::TAG_AHS1) {
|
||||
flag = CommandFlag::CMD_FLAG_AHS;
|
||||
}
|
||||
// see if there is a command registered
|
||||
|
||||
// first see if there is a command registered and it's valid
|
||||
auto cf = find_command(device_type, device_id, cmd, flag);
|
||||
|
||||
// check if its a call to an end-point of a device
|
||||
// this is used to fetch the attributes of the device entity, or call a command directly
|
||||
// for example info, values, commands, etc
|
||||
bool single_command = (!value || !strlen(value));
|
||||
if (single_command) {
|
||||
// exception: boiler coldshot command
|
||||
bool get_attributes = (!cf || !cf->cmdfunction_json_) && (strcmp(cmd, F_(coldshot)) != 0);
|
||||
|
||||
if (get_attributes) {
|
||||
LOG_DEBUG("Calling %s command '%s' to retrieve attributes", dname, cmd);
|
||||
return EMSESP::get_device_value_info(output, cmd, id, device_type) ? CommandRet::OK : CommandRet::ERROR; // entity = cmd
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have a matching command
|
||||
if (!cf) {
|
||||
// we didn't find the command, report error
|
||||
LOG_WARNING("Command failed: invalid command '%s'", cmd ? cmd : "");
|
||||
return message(CommandRet::NOT_FOUND, "invalid command", output);
|
||||
// if we don't alread have a message set, set it to invalid command
|
||||
if (!output["message"]) {
|
||||
output["message"] = "invalid command";
|
||||
}
|
||||
return CommandRet::ERROR;
|
||||
}
|
||||
|
||||
// check permissions and abort if not authorized
|
||||
// before calling the command, check permissions and abort if not authorized
|
||||
if (cf->has_flags(CommandFlag::ADMIN_ONLY) && !is_admin) {
|
||||
LOG_WARNING("Command failed: authentication failed");
|
||||
output["message"] = "authentication failed";
|
||||
@@ -353,7 +357,8 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
|
||||
} else {
|
||||
snprintf(info_s, sizeof(info_s), "'%s/%s'", dname, cmd);
|
||||
}
|
||||
if ((value == nullptr) || (strlen(value) == 0)) {
|
||||
|
||||
if (single_command) {
|
||||
LOG_DEBUG(("%sCalling command %s"), ro.c_str(), info_s);
|
||||
} else {
|
||||
if (id > 0) {
|
||||
@@ -364,6 +369,7 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
|
||||
}
|
||||
|
||||
// call the function based on type, either with a json package or no parameters
|
||||
uint8_t return_code = CommandRet::OK;
|
||||
if (cf->cmdfunction_json_) {
|
||||
// JSON
|
||||
return_code = ((cf->cmdfunction_json_)(value, id, output)) ? CommandRet::OK : CommandRet::ERROR;
|
||||
@@ -378,7 +384,7 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
|
||||
|
||||
// report back. If not OK show output from error, other return the HTTP code
|
||||
if (return_code != CommandRet::OK) {
|
||||
if ((value == nullptr) || (strlen(value) == 0)) {
|
||||
if (single_command) {
|
||||
LOG_ERROR("Command '%s' failed with error '%s'", cmd, FL_(cmdRet)[return_code]);
|
||||
} else {
|
||||
LOG_ERROR("Command '%s: %s' failed with error '%s'", cmd, value, FL_(cmdRet)[return_code]);
|
||||
@@ -543,7 +549,7 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo
|
||||
// verbose mode
|
||||
shell.printfln("\n%s%s %s:%s", COLOR_BOLD_ON, COLOR_YELLOW, EMSdevice::device_type_2_device_name(device_type), COLOR_RESET);
|
||||
|
||||
// we hard code 'info' and 'commmands' commands so print them first
|
||||
// we hard code 'info' and 'commands' commands so print them first
|
||||
if (show_info) {
|
||||
shell.printf(" info:\t\t\t\t%slists all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN);
|
||||
shell.println(COLOR_RESET);
|
||||
@@ -641,7 +647,7 @@ void Command::show_devices(uuid::console::Shell & shell) {
|
||||
shell.println();
|
||||
}
|
||||
|
||||
// 'show commmands' : output list of all commands to console
|
||||
// 'show commands' : output list of all commands to console
|
||||
// calls show with verbose mode set
|
||||
void Command::show_all(uuid::console::Shell & shell) {
|
||||
shell.printfln("Showing all available commands (%s*%s=authentication not required):", COLOR_BRIGHT_GREEN, COLOR_RESET);
|
||||
|
||||
@@ -563,15 +563,21 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
|
||||
}
|
||||
}
|
||||
|
||||
if (return_code == CommandRet::OK && json.size()) {
|
||||
if (json.containsKey("api_data")) {
|
||||
String data = json["api_data"].as<String>();
|
||||
shell.println(data.c_str());
|
||||
if (return_code == CommandRet::OK) {
|
||||
if (json.size()) {
|
||||
if (json.containsKey("api_data")) {
|
||||
String data = json["api_data"].as<String>();
|
||||
shell.println(data.c_str());
|
||||
return;
|
||||
}
|
||||
serializeJsonPretty(doc, shell);
|
||||
shell.println();
|
||||
return;
|
||||
} else {
|
||||
// show message if no data returned (e.g. for analogsensor, temperaturesensor, custom)
|
||||
shell.println("No data.");
|
||||
return;
|
||||
}
|
||||
serializeJsonPretty(doc, shell);
|
||||
shell.println();
|
||||
return;
|
||||
}
|
||||
|
||||
if (return_code == CommandRet::NOT_FOUND) {
|
||||
@@ -637,7 +643,11 @@ void EMSESPShell::stopped() {
|
||||
void EMSESPShell::display_banner() {
|
||||
println();
|
||||
printfln("┌───────────────────────────────────────┐");
|
||||
#ifndef EMSESP_DEBUG
|
||||
printfln("│ %sEMS-ESP version %-20s%s │", COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_BOLD_OFF);
|
||||
#else
|
||||
printfln("│ %sEMS-ESP version %s%-8s%s │", COLOR_BOLD_ON, EMSESP_APP_VERSION, " (D)", COLOR_BOLD_OFF);
|
||||
#endif
|
||||
printfln("│ │");
|
||||
printfln("│ %shelp%s to show available commands │", COLOR_UNDERLINE, COLOR_RESET);
|
||||
printfln("│ %ssu%s to access admin commands │", COLOR_UNDERLINE, COLOR_RESET);
|
||||
@@ -685,6 +695,9 @@ void EMSESPShell::end_of_transmission() {
|
||||
}
|
||||
|
||||
void EMSESPShell::main_help_function(Shell & shell, const std::vector<std::string> & arguments) {
|
||||
shell.println();
|
||||
shell.printfln("%s%sEMS-ESP version %s%s", COLOR_BRIGHT_GREEN, COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_RESET);
|
||||
shell.println();
|
||||
shell.print_all_available_commands();
|
||||
}
|
||||
|
||||
|
||||
@@ -189,6 +189,11 @@
|
||||
#define EMSESP_DEFAULT_PUBLISH_TIME 10
|
||||
#endif
|
||||
|
||||
// default for scheduler etc
|
||||
#ifndef EMSESP_DEFAULT_PUBLISH_TIME_OTHER
|
||||
#define EMSESP_DEFAULT_PUBLISH_TIME_OTHER 60
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_PUBLISH_HEARTBEAT
|
||||
#define EMSESP_DEFAULT_PUBLISH_HEARTBEAT 60
|
||||
#endif
|
||||
|
||||
@@ -100,7 +100,7 @@ const char * EMSdevice::brand_to_char() {
|
||||
}
|
||||
}
|
||||
|
||||
// returns the short name of the device, used in MQTT and console commands, all lowercase
|
||||
// returns the short name of the device, used in MQTT and console commands, all lowercase, no translated
|
||||
const char * EMSdevice::device_type_2_device_name(const uint8_t device_type) {
|
||||
switch (device_type) {
|
||||
case DeviceType::SYSTEM:
|
||||
@@ -1425,7 +1425,7 @@ void EMSdevice::dump_telegram_info(std::vector<TelegramFunctionDump> & telegram_
|
||||
}
|
||||
#endif
|
||||
|
||||
// builds json for a specific device value / entity
|
||||
// builds json for a specific EMS device value / entity
|
||||
// cmd is the endpoint or name of the device entity
|
||||
// returns false if failed, otherwise true
|
||||
bool EMSdevice::get_value_info(JsonObject output, const char * cmd, const int8_t tag) {
|
||||
@@ -1582,6 +1582,9 @@ bool EMSdevice::get_value_info(JsonObject output, const char * cmd, const int8_t
|
||||
json["writeable"] = dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY);
|
||||
json["visible"] = !dv.has_state(DeviceValueState::DV_WEB_EXCLUDE);
|
||||
|
||||
// TODO refactor to remove containsKey as it's costly and not advisable to use it
|
||||
// https://arduinojson.org/v7/api/jsonobject/containskey/#avoid
|
||||
|
||||
// if there is no value, mention it
|
||||
if (!json.containsKey(value)) {
|
||||
json[value] = "not set";
|
||||
@@ -1590,30 +1593,22 @@ bool EMSdevice::get_value_info(JsonObject output, const char * cmd, const int8_t
|
||||
// if we're filtering on an attribute, go find it
|
||||
if (attribute_s) {
|
||||
#if defined(EMSESP_DEBUG)
|
||||
EMSESP::logger().debug("Attribute '%s'", attribute_s);
|
||||
EMSESP::logger().debug("[DEBUG] fetching single attribute '%s'", attribute_s);
|
||||
#endif
|
||||
if (json.containsKey(attribute_s)) {
|
||||
String data = json[attribute_s].as<String>();
|
||||
std::string data = json[attribute_s].as<std::string>();
|
||||
output.clear();
|
||||
output["api_data"] = data;
|
||||
output["api_data"] = data; // always as string
|
||||
return true;
|
||||
} else {
|
||||
char error[100];
|
||||
snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, command_s);
|
||||
output.clear();
|
||||
output["message"] = error;
|
||||
return false;
|
||||
}
|
||||
return EMSESP::return_not_found(output, "attribute", command_s); // not found
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
char error[100];
|
||||
snprintf(error, sizeof(error), "cannot find values for entity '%s'", cmd);
|
||||
json["message"] = error;
|
||||
return false;
|
||||
return false; // not found, but don't return a message error yet
|
||||
}
|
||||
|
||||
// mqtt publish all single values from one device (used for time schedule)
|
||||
@@ -1941,7 +1936,7 @@ std::string EMSdevice::name() {
|
||||
// returns true on success.
|
||||
int EMSdevice::get_modbus_value(uint8_t tag, const std::string & shortname, std::vector<uint16_t> & result) {
|
||||
// find device value by shortname
|
||||
// TODO linear search is inefficient
|
||||
// TODO replace linear search which is inefficient
|
||||
const auto & it = std::find_if(devicevalues_.begin(), devicevalues_.end(), [&](const DeviceValue & x) { return x.tag == tag && x.short_name == shortname; });
|
||||
if (it == devicevalues_.end())
|
||||
return -1;
|
||||
|
||||
@@ -563,6 +563,7 @@ void EMSESP::publish_all(bool force) {
|
||||
publish_device_values(EMSdevice::DeviceType::WATER);
|
||||
publish_other_values(); // switch and heat pump, ...
|
||||
publish_sensor_values(true); // includes temperature and analog sensors
|
||||
|
||||
system_.send_heartbeat();
|
||||
}
|
||||
}
|
||||
@@ -683,10 +684,11 @@ void EMSESP::publish_other_values() {
|
||||
publish_device_values(EMSdevice::DeviceType::EXTENSION);
|
||||
publish_device_values(EMSdevice::DeviceType::ALERT);
|
||||
publish_device_values(EMSdevice::DeviceType::POOL);
|
||||
// other devices without values yet
|
||||
// other EMS devices without values yet
|
||||
// publish_device_values(EMSdevice::DeviceType::GATEWAY);
|
||||
// publish_device_values(EMSdevice::DeviceType::CONNECT);
|
||||
// publish_device_values(EMSdevice::DeviceType::GENERIC);
|
||||
|
||||
webSchedulerService.publish();
|
||||
webCustomEntityService.publish();
|
||||
}
|
||||
@@ -740,19 +742,19 @@ void EMSESP::publish_response(std::shared_ptr<const Telegram> telegram) {
|
||||
buffer = nullptr;
|
||||
}
|
||||
|
||||
// builds json with the detail of each value, for an EMS device
|
||||
// builds json with the detail of each value, for a given EMS device
|
||||
// for other types like sensors, scheduler, custom entities it will process single commands like 'info', 'values', 'commands'...
|
||||
bool EMSESP::get_device_value_info(JsonObject root, const char * cmd, const int8_t id, const uint8_t devicetype) {
|
||||
// check first for EMS devices
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice->device_type() == devicetype) {
|
||||
if (emsdevice->get_value_info(root, cmd, id)) {
|
||||
return true;
|
||||
}
|
||||
return emsdevice->get_value_info(root, cmd, id);
|
||||
}
|
||||
}
|
||||
|
||||
// temperaturesensor
|
||||
// check for other devices...
|
||||
|
||||
// temperature sensor
|
||||
if (devicetype == DeviceType::TEMPERATURESENSOR) {
|
||||
return temperaturesensor_.get_value_info(root, cmd, id);
|
||||
}
|
||||
@@ -772,14 +774,20 @@ bool EMSESP::get_device_value_info(JsonObject root, const char * cmd, const int8
|
||||
return webCustomEntityService.get_value_info(root, cmd);
|
||||
}
|
||||
|
||||
// system
|
||||
if (devicetype == DeviceType::SYSTEM) {
|
||||
return system_.get_value_info(root, cmd);
|
||||
}
|
||||
|
||||
char error[100];
|
||||
snprintf(error, sizeof(error), "cannot find values for entity '%s'", cmd);
|
||||
root["message"] = error;
|
||||
return false; // not found
|
||||
}
|
||||
|
||||
// sends JSON error message, used with API calls
|
||||
bool EMSESP::return_not_found(JsonObject output, const char * msg, const char * cmd) {
|
||||
output.clear();
|
||||
char error[100];
|
||||
snprintf(error, sizeof(error), "cannot find %s in '%s'", msg, cmd);
|
||||
output["message"] = error;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1617,6 +1625,8 @@ void EMSESP::start() {
|
||||
if (!nvs_.begin("ems-esp", false, "nvs1")) { // try bigger nvs partition on 16M flash first
|
||||
nvs_.begin("ems-esp", false, "nvs"); // fallback to small nvs
|
||||
}
|
||||
LOG_DEBUG("NVS device information: %s", system_.getBBQKeesGatewayDetails().c_str());
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
LOG_INFO("Starting EMS-ESP version %s from %s partition", EMSESP_APP_VERSION, esp_ota_get_running_partition()->label); // welcome message
|
||||
#else
|
||||
@@ -1631,6 +1641,8 @@ void EMSESP::start() {
|
||||
system_.system_restart();
|
||||
};
|
||||
|
||||
|
||||
|
||||
webSettingsService.begin(); // load EMS-ESP Application settings...
|
||||
|
||||
// do any system upgrades
|
||||
|
||||
@@ -213,6 +213,8 @@ class EMSESP {
|
||||
static void scan_devices();
|
||||
static void clear_all_devices();
|
||||
|
||||
static bool return_not_found(JsonObject output, const char * msg, const char * cmd);
|
||||
|
||||
static std::vector<std::unique_ptr<EMSdevice>> emsdevices;
|
||||
|
||||
// services
|
||||
|
||||
@@ -67,6 +67,7 @@ MAKE_WORD(publish)
|
||||
MAKE_WORD(board_profile)
|
||||
MAKE_WORD(setvalue)
|
||||
MAKE_WORD(service)
|
||||
MAKE_WORD(message)
|
||||
|
||||
// for commands
|
||||
MAKE_WORD(call)
|
||||
|
||||
@@ -75,6 +75,7 @@ MAKE_WORD_TRANSLATION(entity_cmd, "set custom value on ems", "Sende eigene Entit
|
||||
MAKE_WORD_TRANSLATION(commands_response, "get response", "Hole Antwort", "Verzoek om antwoord", "", "uzyskaj odpowiedź", "", "", "gelen cevap", "", "získať odpoveď") // TODO translate
|
||||
MAKE_WORD_TRANSLATION(coldshot_cmd, "send a cold shot of water", "", "", "", "uruchom tryśnięcie zimnej wody", "", "", "soğuk su gönder", "", "pošlite studenú dávku vody") // TODO translate
|
||||
MAKE_WORD_TRANSLATION(allvalues_cmd, "output all values", "", "", "", "wyświetl wszystkie wartości", "", "", "", "", "vypísať všetky hodnoty") // TODO translate
|
||||
MAKE_WORD_TRANSLATION(message_cmd, "send a message", "", "", "", "", "", "", "", "", "") // TODO translate
|
||||
|
||||
// tags
|
||||
MAKE_WORD_TRANSLATION(tag_hc1, "hc1", "HK1", "hc1", "VK1", "OG1", "hc1", "hc1", "ID1", "hc1", "hc1")
|
||||
|
||||
@@ -68,7 +68,7 @@ bool Modbus::check_parameter_order() {
|
||||
} else if (prev == nullptr) {
|
||||
LOG_ERROR("Error checking modbus parameters %s.", mi.short_name);
|
||||
return false;
|
||||
} else if(!prev->isLessThan(mi)) {
|
||||
} else if (!prev->isLessThan(mi)) {
|
||||
LOG_ERROR("Error in modbus parameters: %s must be listed before %s.", mi.short_name, prev->short_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
#include "modbus.h"
|
||||
#include "emsdevice.h"
|
||||
|
||||
/*
|
||||
* This file is auto-generated by the update_modbus_registers.sh script. Do not modify.
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
using dt = EMSdevice::DeviceType;
|
||||
@@ -513,3 +519,6 @@ const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_ma
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
// clang-format off
|
||||
|
||||
|
||||
132
src/system.cpp
132
src/system.cpp
@@ -226,6 +226,18 @@ bool System::command_syslog_level(const char * value, const int8_t id) {
|
||||
}
|
||||
*/
|
||||
|
||||
// send message - to log and MQTT
|
||||
bool System::command_message(const char * value, const int8_t id) {
|
||||
if (value == nullptr || value[0] == '\0') {
|
||||
return false; // must have a string value
|
||||
}
|
||||
|
||||
LOG_INFO("Message: %s", value);
|
||||
Mqtt::queue_publish(F_(message), value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// watch
|
||||
bool System::command_watch(const char * value, const int8_t id) {
|
||||
uint8_t w = 0xff;
|
||||
@@ -831,10 +843,10 @@ void System::commands_init() {
|
||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send, FL_(send_cmd), CommandFlag::ADMIN_ONLY);
|
||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch, FL_(fetch_cmd), CommandFlag::ADMIN_ONLY);
|
||||
|
||||
// restart and watch (and test) are also exposed as Console commands
|
||||
// restart, watch, message (and test) are also exposed as Console commands
|
||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, FL_(restart_cmd), CommandFlag::ADMIN_ONLY);
|
||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, FL_(watch_cmd));
|
||||
|
||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(message), System::command_message, FL_(message_cmd));
|
||||
#if defined(EMSESP_TEST)
|
||||
Command::add(EMSdevice::DeviceType::SYSTEM, ("test"), System::command_test, FL_(test_cmd));
|
||||
#endif
|
||||
@@ -1107,7 +1119,7 @@ bool System::check_restore() {
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
// see if we have a temp file, if so try and read it
|
||||
// TODO find a nicer way to see if a file exists without reporting an error
|
||||
// TODO find a nicer way to see if a file exists without reporting an error, like using lfs_stat. exists() uses open so same problem.
|
||||
File new_file = LittleFS.open(TEMP_FILENAME_PATH);
|
||||
if (new_file) {
|
||||
JsonDocument jsonDocument;
|
||||
@@ -1288,52 +1300,61 @@ bool System::get_value_info(JsonObject root, const char * command) {
|
||||
LOG_ERROR("empty system command");
|
||||
return false;
|
||||
}
|
||||
|
||||
char cmd[COMMAND_MAX_LENGTH];
|
||||
strlcpy(cmd, command, sizeof(cmd));
|
||||
char * val = strstr(cmd, "/value");
|
||||
if (val) {
|
||||
val[0] = '\0';
|
||||
}
|
||||
char * dash = strchr(cmd, '/');
|
||||
if (dash) {
|
||||
*dash = '\0';
|
||||
dash++;
|
||||
|
||||
char * slash = strchr(cmd, '/');
|
||||
if (slash) {
|
||||
*slash = '\0';
|
||||
slash++;
|
||||
}
|
||||
if (command_info("", 0, root)) {
|
||||
std::string s;
|
||||
// Loop through all the key-value pairs in root to find the key case independent
|
||||
if (dash) { // search the nest first
|
||||
for (JsonPair p : root) {
|
||||
if (p.value().is<JsonObject>() && Helpers::toLower(p.key().c_str()) == cmd) {
|
||||
for (JsonPair p1 : p.value().as<JsonObject>()) {
|
||||
if (Helpers::toLower(p1.key().c_str()) == dash && !p1.value().is<JsonObject>()) {
|
||||
s = p1.value().as<std::string>();
|
||||
break;
|
||||
}
|
||||
|
||||
// fetch all the data from the system
|
||||
(void)command_info("", 0, root);
|
||||
|
||||
// check for hardcoded "info"
|
||||
if (Helpers::toLower(cmd) == F_(info)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string s;
|
||||
// Loop through all the key-value pairs in root to find the key, case independent
|
||||
if (slash) { // search the top level first
|
||||
for (JsonPair p : root) {
|
||||
if (p.value().is<JsonObject>() && Helpers::toLower(p.key().c_str()) == cmd) {
|
||||
for (JsonPair p1 : p.value().as<JsonObject>()) {
|
||||
if (Helpers::toLower(p1.key().c_str()) == slash && !p1.value().is<JsonObject>()) {
|
||||
s = p1.value().as<std::string>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (JsonPair p : root) {
|
||||
if (Helpers::toLower(p.key().c_str()) == cmd && !p.value().is<JsonObject>()) {
|
||||
s = p.value().as<std::string>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!s.empty()) {
|
||||
root.clear();
|
||||
if (val) {
|
||||
root["api_data"] = s;
|
||||
} else {
|
||||
root["value"] = s;
|
||||
} else {
|
||||
for (JsonPair p : root) {
|
||||
if (Helpers::toLower(p.key().c_str()) == cmd && !p.value().is<JsonObject>()) {
|
||||
s = p.value().as<std::string>();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
root.clear();
|
||||
LOG_ERROR("system command '%s' not found", command);
|
||||
return false;
|
||||
|
||||
if (!s.empty()) {
|
||||
root.clear();
|
||||
if (val) {
|
||||
root["api_data"] = s;
|
||||
} else {
|
||||
root["value"] = s;
|
||||
}
|
||||
return true; // found
|
||||
}
|
||||
|
||||
return EMSESP::return_not_found(root, "data", command); // not found
|
||||
}
|
||||
|
||||
// export status information including the device information
|
||||
@@ -1342,7 +1363,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
JsonObject node;
|
||||
|
||||
// System
|
||||
node = output["System Info"].to<JsonObject>();
|
||||
node = output["System"].to<JsonObject>();
|
||||
node["version"] = EMSESP_APP_VERSION;
|
||||
node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3);
|
||||
node["uptime (seconds)"] = uuid::get_uptime_sec();
|
||||
@@ -1359,9 +1380,9 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
#endif
|
||||
node["reset reason"] = EMSESP::system_.reset_reason(0) + " / " + EMSESP::system_.reset_reason(1);
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
// Network Status
|
||||
node = output["Network Info"].to<JsonObject>();
|
||||
node = output["Network"].to<JsonObject>();
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (EMSESP::system_.ethernet_connected()) {
|
||||
node["network"] = "Ethernet";
|
||||
node["hostname"] = ETH.getHostname();
|
||||
@@ -1384,10 +1405,15 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
// node["IPv6 address"] = uuid::printable_to_string(WiFi.localIPv6());
|
||||
// }
|
||||
}
|
||||
#else
|
||||
// for testing
|
||||
node["network"] = "WiFi";
|
||||
node["hostname"] = "ems-esp";
|
||||
node["RSSI"] = -23;
|
||||
#endif
|
||||
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & settings) {
|
||||
if (WiFi.status() == WL_CONNECTED && !settings.bssid.isEmpty()) {
|
||||
node["BSSID"] = "set";
|
||||
node["BSSID"] = "set"; // TODO why is this not the actual value?
|
||||
}
|
||||
node["TxPower setting"] = settings.tx_power;
|
||||
node["static ip config"] = settings.staticIPConfig;
|
||||
@@ -1409,7 +1435,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
#endif
|
||||
|
||||
// NTP status
|
||||
node = output["NTP Info"].to<JsonObject>();
|
||||
node = output["NTP"].to<JsonObject>();
|
||||
#ifndef EMSESP_STANDALONE
|
||||
node["NTP status"] = EMSESP::system_.ntp_connected() ? "connected" : "disconnected";
|
||||
EMSESP::esp8266React.getNTPSettingsService()->read([&](NTPSettings & settings) {
|
||||
@@ -1421,7 +1447,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
#endif
|
||||
|
||||
// MQTT Status
|
||||
node = output["MQTT Info"].to<JsonObject>();
|
||||
node = output["MQTT"].to<JsonObject>();
|
||||
node["MQTT status"] = Mqtt::connected() ? F_(connected) : F_(disconnected);
|
||||
if (Mqtt::enabled()) {
|
||||
node["MQTT publishes"] = Mqtt::publish_count();
|
||||
@@ -1456,7 +1482,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
});
|
||||
|
||||
// Syslog Status
|
||||
node = output["Syslog Info"].to<JsonObject>();
|
||||
node = output["Syslog"].to<JsonObject>();
|
||||
node["enabled"] = EMSESP::system_.syslog_enabled_;
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (EMSESP::system_.syslog_enabled_) {
|
||||
@@ -1468,7 +1494,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
#endif
|
||||
|
||||
// Sensor Status
|
||||
node = output["Sensor Info"].to<JsonObject>();
|
||||
node = output["Sensor"].to<JsonObject>();
|
||||
if (EMSESP::sensor_enabled()) {
|
||||
node["temperature sensors"] = EMSESP::temperaturesensor_.no_sensors();
|
||||
node["temperature sensor reads"] = EMSESP::temperaturesensor_.reads();
|
||||
@@ -1481,12 +1507,12 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
}
|
||||
|
||||
// API Status
|
||||
node = output["API Info"].to<JsonObject>();
|
||||
node = output["API"].to<JsonObject>();
|
||||
node["API calls"] = WebAPIService::api_count();
|
||||
node["API fails"] = WebAPIService::api_fails();
|
||||
|
||||
// EMS Bus Status
|
||||
node = output["Bus Info"].to<JsonObject>();
|
||||
node = output["Bus"].to<JsonObject>();
|
||||
switch (EMSESP::bus_status()) {
|
||||
case EMSESP::BUS_STATUS_OFFLINE:
|
||||
node["bus status"] = "disconnected";
|
||||
@@ -1589,7 +1615,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return true; // this function always returns true!
|
||||
}
|
||||
|
||||
#if defined(EMSESP_TEST)
|
||||
@@ -1728,4 +1754,18 @@ bool System::ntp_connected() {
|
||||
return ntp_connected_;
|
||||
}
|
||||
|
||||
String System::getBBQKeesGatewayDetails() {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (!EMSESP::nvs_.isKey("mfg")) {
|
||||
return "";
|
||||
}
|
||||
if (EMSESP::nvs_.getString("mfg") != "BBQKees") {
|
||||
return "";
|
||||
}
|
||||
return "BBQKees Gateway Model " + EMSESP::nvs_.getString("model") + " v" + EMSESP::nvs_.getString("hwrevision") + "/" + EMSESP::nvs_.getString("batch");
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -57,6 +57,7 @@ class System {
|
||||
static bool command_restart(const char * value, const int8_t id);
|
||||
static bool command_syslog_level(const char * value, const int8_t id);
|
||||
static bool command_watch(const char * value, const int8_t id);
|
||||
static bool command_message(const char * value, const int8_t id);
|
||||
static bool command_info(const char * value, const int8_t id, JsonObject output);
|
||||
static bool command_commands(const char * value, const int8_t id, JsonObject output);
|
||||
static bool command_response(const char * value, const int8_t id, JsonObject output);
|
||||
@@ -97,6 +98,8 @@ class System {
|
||||
}
|
||||
#endif
|
||||
|
||||
String getBBQKeesGatewayDetails();
|
||||
|
||||
void led_init(bool refresh);
|
||||
void network_init(bool refresh);
|
||||
void button_init(bool refresh);
|
||||
|
||||
@@ -343,13 +343,14 @@ bool TemperatureSensor::updated_values() {
|
||||
|
||||
// called from emsesp.cpp for commands
|
||||
bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, const int8_t id) {
|
||||
// check of it a 'commmands' command
|
||||
// check of it a 'commands' command
|
||||
if (Helpers::toLower(cmd) == F_(commands)) {
|
||||
return Command::list(EMSdevice::DeviceType::TEMPERATURESENSOR, output);
|
||||
}
|
||||
|
||||
// return empty json if there are no sensors
|
||||
if (sensors_.empty()) {
|
||||
return true; // no sensors, return true
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t show_all = 0;
|
||||
@@ -391,28 +392,23 @@ bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, cons
|
||||
for (const auto & sensor : sensors_) {
|
||||
// match custom name or sensor ID
|
||||
if (sensor_name == Helpers::toLower(sensor.name()) || sensor_name == Helpers::toLower(sensor.id())) {
|
||||
// add values
|
||||
// add all the data elements
|
||||
addSensorJson(output, sensor);
|
||||
// if we're filtering on an attribute, go find it
|
||||
if (attribute_s) {
|
||||
if (output.containsKey(attribute_s)) {
|
||||
String data = output[attribute_s].as<String>();
|
||||
std::string data = output[attribute_s].as<std::string>();
|
||||
output.clear();
|
||||
output["api_data"] = data;
|
||||
output["api_data"] = data; // always as string
|
||||
return true;
|
||||
} else {
|
||||
char error[100];
|
||||
snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, sensor_name);
|
||||
output.clear();
|
||||
output["message"] = error;
|
||||
return false;
|
||||
}
|
||||
return EMSESP::return_not_found(output, "attribute", sensor_name); // not found
|
||||
}
|
||||
return true; // found a match, exit
|
||||
}
|
||||
}
|
||||
|
||||
return false; // not found
|
||||
return EMSESP::return_not_found(output, "temperature sensor", cmd); // not found
|
||||
}
|
||||
|
||||
void TemperatureSensor::addSensorJson(JsonObject output, const Sensor & sensor) {
|
||||
@@ -629,15 +625,15 @@ void TemperatureSensor::test() {
|
||||
uint8_t addr[ADDR_LEN] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
sensors_.emplace_back(addr);
|
||||
sensors_.back().apply_customization();
|
||||
sensors_.back().temperature_c = 123;
|
||||
sensors_.back().temperature_c = 123; // 12.3
|
||||
sensors_.back().read = true;
|
||||
publish_sensor(sensors_.back()); // call publish single
|
||||
|
||||
// Sensor ID: 0B-0C0D-0E0F-1011
|
||||
// Sensor ID: 0B_0C0D_0E0F_1011
|
||||
uint8_t addr2[ADDR_LEN] = {11, 12, 13, 14, 15, 16, 17, 18};
|
||||
sensors_.emplace_back(addr2);
|
||||
sensors_.back().apply_customization();
|
||||
sensors_.back().temperature_c = 456;
|
||||
sensors_.back().temperature_c = 456; // 45.6
|
||||
sensors_.back().read = true;
|
||||
publish_sensor(sensors_.back()); // call publish single
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class TemperatureSensor {
|
||||
bool apply_customization();
|
||||
|
||||
// initial values
|
||||
int16_t temperature_c = EMS_VALUE_INT16_NOTSET;
|
||||
int16_t temperature_c = EMS_VALUE_INT16_NOTSET; // value is *10
|
||||
bool read = false;
|
||||
bool ha_registered = false;
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
shell.printfln("Testing adding a boiler, thermostat, all sensors, scheduler and custom entities...");
|
||||
|
||||
// setup fake data
|
||||
EMSESP::webCustomizationService.test(); // set customizations - this will overwrite any settings in the file
|
||||
EMSESP::webCustomizationService.test(); // set customizations - this will overwrite any settings in the FS
|
||||
|
||||
// add devices
|
||||
test("general");
|
||||
@@ -324,7 +324,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
EMSESP::webSchedulerService.test(); // add scheduler items
|
||||
EMSESP::webCustomEntityService.test(); // add custom entities
|
||||
|
||||
shell.invoke_command("show devices");
|
||||
// shell.invoke_command("show devices");
|
||||
// shell.invoke_command("show values");
|
||||
// shell.invoke_command("call system allvalues");
|
||||
// shell.invoke_command("call system publish");
|
||||
@@ -944,37 +944,149 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (command == "api_values") {
|
||||
shell.printfln("Testing API getting values");
|
||||
Mqtt::ha_enabled(false);
|
||||
Mqtt::nested_format(1);
|
||||
// Mqtt::send_response(false);
|
||||
// EMSESP::bool_format(BOOL_FORMAT_10); // BOOL_FORMAT_10_STR
|
||||
if (command == "api3") {
|
||||
shell.printfln("Testing API getting values from system");
|
||||
EMSESP::system_.bool_format(BOOL_FORMAT_TRUEFALSE); // BOOL_FORMAT_TRUEFALSE_STR
|
||||
|
||||
test("boiler");
|
||||
test("thermostat");
|
||||
ok = true;
|
||||
|
||||
bool single;
|
||||
|
||||
// single = true;
|
||||
single = false;
|
||||
|
||||
AsyncWebServerRequest request;
|
||||
JsonDocument doc;
|
||||
JsonVariant json;
|
||||
request.method(HTTP_GET);
|
||||
|
||||
request.url("/api/boiler/values");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/dhw/circ");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/dhw/circ/fullname");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/selburnpow/value");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/dhw/chargetype/writeable");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/flamecurr/value");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/flamecurr/bad");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
ok = true;
|
||||
// load devices
|
||||
test("boiler");
|
||||
// test("thermostat");
|
||||
|
||||
if (single) {
|
||||
// run dedicated tests only
|
||||
EMSESP::webCustomEntityService.test(); // custom entities
|
||||
EMSESP::webCustomizationService.test(); // set customizations - this will overwrite any settings in the FS
|
||||
EMSESP::temperaturesensor_.test(); // add temperature sensors
|
||||
EMSESP::webSchedulerService.test(); // run scheduler tests, and conditions
|
||||
|
||||
// request.url("/api/analogsensor/test_analog10/bad");
|
||||
// EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
} else {
|
||||
EMSESP::webCustomEntityService.test(); // custom entities
|
||||
EMSESP::webCustomizationService.test(); // set customizations - this will overwrite any settings in the FS
|
||||
EMSESP::temperaturesensor_.test(); // add temperature sensors
|
||||
EMSESP::webSchedulerService.test(); // run scheduler tests, and conditions
|
||||
|
||||
// boiler
|
||||
request.url("/api/boiler");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/commands");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/values");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/info");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/entities");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/comfort");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/comfort/value");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/comfort/fullname");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/outdoortemp");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/dhw/chargetype/writeable");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/flamecurr/value");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
// custom
|
||||
request.url("/api/custom");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/custom/seltemp");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
// system
|
||||
request.url("/api/system");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/system/settings/locale");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
// scheduler
|
||||
request.url("/api/scheduler/info");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/scheduler/test_scheduler");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
// temperaturesensor
|
||||
request.url("/api/temperaturesensor/test_sensor2");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/temperaturesensor/0B_0C0D_0E0F_1011");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/temperaturesensor/test_sensor2/value");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
// analogsensor
|
||||
request.url("/api/analogsensor");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/analogsensor/test_analog1");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/analogsensor/test_analog1/offset");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
//
|
||||
// This next batch should all fail
|
||||
//
|
||||
|
||||
Serial.printf("%s**** Testing bad urls ****\n%s", COLOR_RED, COLOR_RESET);
|
||||
Serial.println();
|
||||
|
||||
// boiler
|
||||
request.url("/api/boiler/bad");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/bad/value");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler2/bad");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/bad");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/bad/value");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/boiler/comfort/valu");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
// system
|
||||
request.url("/api/system/settings/locale2");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
// scheduler
|
||||
request.url("/api/scheduler/test_scheduler2");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
// custom
|
||||
request.url("/api/custom/seltemp2");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
// temperaturesensor
|
||||
request.url("/api/temperaturesensor/test_sensor20");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/temperaturesensor/0B_0C0D_0E0F_XXXX");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/temperaturesensor/test_sensor2/bad");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
|
||||
// analogsensor
|
||||
request.url("/api/analogsensor/test_analog1/bad");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/analogsensor/test_analog10");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
request.url("/api/analogsensor/test_analog10/bad");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
}
|
||||
}
|
||||
|
||||
if (command == "mqtt_post") {
|
||||
|
||||
@@ -41,13 +41,13 @@ namespace emsesp {
|
||||
// #define EMSESP_DEBUG_DEFAULT "310"
|
||||
// #define EMSESP_DEBUG_DEFAULT "render"
|
||||
// #define EMSESP_DEBUG_DEFAULT "api"
|
||||
#define EMSESP_DEBUG_DEFAULT "api3"
|
||||
// #define EMSESP_DEBUG_DEFAULT "crash"
|
||||
// #define EMSESP_DEBUG_DEFAULT "dv"
|
||||
// #define EMSESP_DEBUG_DEFAULT "lastcode"
|
||||
// #define EMSESP_DEBUG_DEFAULT "2thermostats"
|
||||
// #define EMSESP_DEBUG_DEFAULT "temperature"
|
||||
// #define EMSESP_DEBUG_DEFAULT "analog"
|
||||
// #define EMSESP_DEBUG_DEFAULT "api_values"
|
||||
// #define EMSESP_DEBUG_DEFAULT "mqtt_post"
|
||||
// #define EMSESP_DEBUG_DEFAULT "api_wwmode"
|
||||
// #define EMSESP_DEBUG_DEFAULT "customization"
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.7.0-dev.23"
|
||||
#define EMSESP_APP_VERSION "3.7.0-dev.25"
|
||||
|
||||
@@ -128,9 +128,9 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject input) {
|
||||
if (return_code != CommandRet::OK) {
|
||||
char error[100];
|
||||
if (output.size()) {
|
||||
snprintf(error, sizeof(error), "API failed with error %s (%s)", (const char *)output["message"], Command::return_code_string(return_code).c_str());
|
||||
snprintf(error, sizeof(error), "API call failed. %s (%s)", (const char *)output["message"], Command::return_code_string(return_code).c_str());
|
||||
} else {
|
||||
snprintf(error, sizeof(error), "API failed with error %s", Command::return_code_string(return_code).c_str());
|
||||
snprintf(error, sizeof(error), "API call failed (%s)", Command::return_code_string(return_code).c_str());
|
||||
}
|
||||
emsesp::EMSESP::logger().err(error);
|
||||
api_fails_++;
|
||||
@@ -138,17 +138,27 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject input) {
|
||||
|
||||
// if we're returning single values, just sent as plain text
|
||||
// https://github.com/emsesp/EMS-ESP32/issues/462#issuecomment-1093877210
|
||||
if (output.containsKey("api_data")) {
|
||||
String data = output["api_data"].as<String>();
|
||||
request->send(200, "text/plain; charset=utf-8", data);
|
||||
const char * api_data = output["api_data"];
|
||||
if (api_data) {
|
||||
request->send(200, "text/plain; charset=utf-8", api_data);
|
||||
#if defined(EMSESP_STANDALONE)
|
||||
Serial.printf("%sweb output: %s[%s] %s(200)%s ", COLOR_WHITE, COLOR_BRIGHT_CYAN, request->url().c_str(), COLOR_BRIGHT_GREEN, COLOR_MAGENTA);
|
||||
serializeJson(output, Serial);
|
||||
Serial.println(COLOR_RESET);
|
||||
Serial.println();
|
||||
#endif
|
||||
api_count_++;
|
||||
delete response;
|
||||
return;
|
||||
}
|
||||
|
||||
// send the json that came back from the command call
|
||||
// FAIL, OK, NOT_FOUND, ERROR, NOT_ALLOWED = 400 (bad request), 200 (OK), 400 (not found), 400 (bad request), 401 (unauthorized)
|
||||
int ret_codes[6] = {400, 200, 400, 400, 401, 400};
|
||||
// sequence is FAIL, OK, NOT_FOUND, ERROR, NOT_ALLOWED, INVALID
|
||||
// 400 (bad request)
|
||||
// 200 (OK)
|
||||
// 404 (not found)
|
||||
// 401 (unauthorized)
|
||||
int ret_codes[6] = {400, 200, 404, 400, 401, 400};
|
||||
response->setCode(ret_codes[return_code]);
|
||||
response->setLength();
|
||||
response->setContentType("application/json; charset=utf-8");
|
||||
@@ -156,15 +166,11 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject input) {
|
||||
api_count_++;
|
||||
|
||||
#if defined(EMSESP_STANDALONE)
|
||||
Serial.print(COLOR_YELLOW);
|
||||
Serial.print("data: ");
|
||||
if (output.size()) {
|
||||
serializeJson(output, Serial);
|
||||
}
|
||||
Serial.print(" (response code ");
|
||||
Serial.print(ret_codes[return_code]);
|
||||
Serial.println(")");
|
||||
Serial.print(COLOR_RESET);
|
||||
Serial.printf("%sweb output: %s[%s]", COLOR_WHITE, COLOR_BRIGHT_CYAN, request->url().c_str());
|
||||
Serial.printf(" %s(%d)%s ", ret_codes[return_code] == 200 ? COLOR_BRIGHT_GREEN : COLOR_BRIGHT_RED, ret_codes[return_code], COLOR_YELLOW);
|
||||
serializeJson(output, Serial);
|
||||
Serial.println(COLOR_RESET);
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -237,13 +237,12 @@ void WebCustomEntityService::render_value(JsonObject output, CustomEntityItem en
|
||||
}
|
||||
break;
|
||||
case DeviceValueType::STRING:
|
||||
default:
|
||||
// if no type treat it as a string
|
||||
if (entity.data.length() > 0) {
|
||||
output[name] = entity.data;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// EMSESP::logger().warning("unknown value type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +268,8 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
|
||||
return true;
|
||||
}
|
||||
|
||||
// if no entries, return empty json
|
||||
// if no custom entries, return empty json
|
||||
// even if we're looking for a specific entity
|
||||
// https://github.com/emsesp/EMS-ESP32/issues/1297
|
||||
if (customEntityItems_->size() == 0) {
|
||||
return true;
|
||||
@@ -287,6 +287,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
|
||||
char command_s[COMMAND_MAX_LENGTH];
|
||||
strlcpy(command_s, Helpers::toLower(cmd).c_str(), sizeof(command_s));
|
||||
char * attribute_s = nullptr;
|
||||
|
||||
// check specific attribute to fetch instead of the complete record
|
||||
char * breakp = strchr(command_s, '/');
|
||||
if (breakp) {
|
||||
@@ -315,21 +316,16 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
|
||||
output["bytes"] = (uint8_t)entity.factor;
|
||||
}
|
||||
}
|
||||
render_value(output, entity, true);
|
||||
render_value(output, entity, true); // create the "value" field
|
||||
|
||||
if (attribute_s) {
|
||||
if (output.containsKey(attribute_s)) {
|
||||
String data = output[attribute_s].as<String>();
|
||||
std::string data = output[attribute_s].as<std::string>();
|
||||
output.clear();
|
||||
output["api_data"] = data;
|
||||
output["api_data"] = data; // always as string
|
||||
return true;
|
||||
} else {
|
||||
char error[100];
|
||||
snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, command_s);
|
||||
output.clear();
|
||||
output["message"] = error;
|
||||
return false;
|
||||
}
|
||||
return EMSESP::return_not_found(output, "attribute", command_s); // not found
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,8 +334,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
|
||||
}
|
||||
}
|
||||
|
||||
output["message"] = "unknown command";
|
||||
return false;
|
||||
return EMSESP::return_not_found(output, "custom entity", cmd); // not found
|
||||
}
|
||||
|
||||
// publish single value
|
||||
@@ -641,8 +636,10 @@ bool WebCustomEntityService::get_value(std::shared_ptr<const Telegram> telegram)
|
||||
void WebCustomEntityService::test() {
|
||||
update([&](WebCustomEntity & webCustomEntity) {
|
||||
webCustomEntity.customEntityItems.clear();
|
||||
auto entityItem = CustomEntityItem();
|
||||
|
||||
// test 1
|
||||
auto entityItem = CustomEntityItem();
|
||||
entityItem.id = 1;
|
||||
entityItem.ram = 0;
|
||||
entityItem.device_id = 8;
|
||||
entityItem.type_id = 24;
|
||||
@@ -656,6 +653,7 @@ void WebCustomEntityService::test() {
|
||||
webCustomEntity.customEntityItems.push_back(entityItem);
|
||||
|
||||
// test 2
|
||||
entityItem.id = 2;
|
||||
entityItem.ram = 0;
|
||||
entityItem.device_id = 24;
|
||||
entityItem.type_id = 677;
|
||||
@@ -668,7 +666,8 @@ void WebCustomEntityService::test() {
|
||||
entityItem.data = "48";
|
||||
webCustomEntity.customEntityItems.push_back(entityItem);
|
||||
|
||||
// test 2
|
||||
// test 3
|
||||
entityItem.id = 3;
|
||||
entityItem.ram = 1;
|
||||
entityItem.device_id = 0;
|
||||
entityItem.type_id = 0;
|
||||
@@ -681,6 +680,21 @@ void WebCustomEntityService::test() {
|
||||
entityItem.data = "14";
|
||||
webCustomEntity.customEntityItems.push_back(entityItem);
|
||||
|
||||
// test 4
|
||||
entityItem.id = 4;
|
||||
entityItem.ram = 1;
|
||||
entityItem.device_id = 0;
|
||||
entityItem.type_id = 0;
|
||||
entityItem.offset = 0;
|
||||
entityItem.factor = 1;
|
||||
entityItem.name = "seltemp";
|
||||
entityItem.uom = 0;
|
||||
entityItem.value_type = 8;
|
||||
entityItem.writeable = true;
|
||||
entityItem.data = "14";
|
||||
entityItem.value = 12;
|
||||
webCustomEntity.customEntityItems.push_back(entityItem);
|
||||
|
||||
return StateUpdateResult::CHANGED; // persist the changes
|
||||
});
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ void WebCustomizationService::reset_customization(AsyncWebServerRequest * reques
|
||||
EMSESP::system_.restart_requested(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// failed
|
||||
AsyncWebServerResponse * response = request->beginResponse(400); // bad request
|
||||
request->send(response);
|
||||
|
||||
@@ -212,7 +212,7 @@ void WebDataService::device_data(AsyncWebServerRequest * request) {
|
||||
}
|
||||
|
||||
// invalid
|
||||
AsyncWebServerResponse * response = request->beginResponse(400);
|
||||
AsyncWebServerResponse * response = request->beginResponse(400); // bad request
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ bool WebSchedulerService::command_setvalue(const char * value, const int8_t id,
|
||||
|
||||
// process json output for info/commands and value_info
|
||||
bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
||||
// check of it a 'commmands' command
|
||||
// check of it a 'commands' command
|
||||
if (Helpers::toLower(cmd) == F_(commands)) {
|
||||
output[F_(info)] = Helpers::translated_word(FL_(info_cmd));
|
||||
output[F_(commands)] = Helpers::translated_word(FL_(commands_cmd));
|
||||
@@ -161,7 +161,11 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
return (output.size() > 0);
|
||||
if (output.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return EMSESP::return_not_found(output, "schedule", cmd); // not found
|
||||
}
|
||||
|
||||
char command_s[COMMAND_MAX_LENGTH];
|
||||
@@ -196,17 +200,17 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
||||
}
|
||||
|
||||
if (attribute_s && output.containsKey(attribute_s)) {
|
||||
String data = output[attribute_s].as<String>();
|
||||
std::string data = output[attribute_s].as<std::string>();
|
||||
output.clear();
|
||||
output["api_data"] = data;
|
||||
output["api_data"] = data; // always as a string
|
||||
return true;
|
||||
}
|
||||
|
||||
if (output.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
output["message"] = "unknown command";
|
||||
return false;
|
||||
return EMSESP::return_not_found(output, "schedule", cmd); // not found
|
||||
}
|
||||
|
||||
// publish single value
|
||||
@@ -304,8 +308,10 @@ void WebSchedulerService::publish(const bool force) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ha_registered_ = ha_created;
|
||||
if (doc.size() > 0) {
|
||||
|
||||
if (!doc.isNull()) {
|
||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||
snprintf(topic, sizeof(topic), "%s_data", F_(scheduler));
|
||||
Mqtt::queue_publish(topic, doc.as<JsonObject>());
|
||||
@@ -340,6 +346,7 @@ bool WebSchedulerService::command(const char * cmd, const char * data) {
|
||||
// prefix "api/" to command string
|
||||
char command_str[COMMAND_MAX_LENGTH];
|
||||
snprintf(command_str, sizeof(command_str), "/api/%s", cmd);
|
||||
|
||||
uint8_t return_code = Command::process(command_str, true, input, output); // admin set
|
||||
|
||||
if (return_code == CommandRet::OK) {
|
||||
@@ -471,23 +478,69 @@ void WebSchedulerService::loop() {
|
||||
// hard coded tests
|
||||
#if defined(EMSESP_TEST)
|
||||
void WebSchedulerService::test() {
|
||||
update([&](WebScheduler & webScheduler) {
|
||||
webScheduler.scheduleItems.clear();
|
||||
// test 1
|
||||
auto si = ScheduleItem();
|
||||
si.active = true;
|
||||
si.flags = 1;
|
||||
si.time = "12:00";
|
||||
si.cmd = "system/fetch";
|
||||
si.value = "10";
|
||||
si.name = "test_scheduler";
|
||||
si.elapsed_min = 0;
|
||||
si.retry_cnt = 0xFF; // no startup retries
|
||||
static bool already_added = false;
|
||||
if (!already_added) {
|
||||
update([&](WebScheduler & webScheduler) {
|
||||
// webScheduler.scheduleItems.clear();
|
||||
// test 1
|
||||
auto si = ScheduleItem();
|
||||
si.active = true;
|
||||
si.flags = 1;
|
||||
si.time = "12:00";
|
||||
si.cmd = "system/fetch";
|
||||
si.value = "10";
|
||||
si.name = "test_scheduler";
|
||||
si.elapsed_min = 0;
|
||||
si.retry_cnt = 0xFF; // no startup retries
|
||||
|
||||
webScheduler.scheduleItems.push_back(si);
|
||||
webScheduler.scheduleItems.push_back(si);
|
||||
already_added = true;
|
||||
|
||||
return StateUpdateResult::CHANGED; // persist the changes
|
||||
});
|
||||
return StateUpdateResult::CHANGED; // persist the changes
|
||||
});
|
||||
}
|
||||
|
||||
// test shunting yard
|
||||
std::string test_cmd = "system/message";
|
||||
std::string test_value;
|
||||
|
||||
// should output 'locale is en'
|
||||
test_value = "\"locale is \"system/settings/locale";
|
||||
command(test_cmd.c_str(), compute(test_value).c_str());
|
||||
|
||||
// test with negative value
|
||||
// should output 'rssi is -23'
|
||||
test_value = "\"rssi is \"0+system/network/rssi";
|
||||
command(test_cmd.c_str(), compute(test_value).c_str());
|
||||
|
||||
// should output 'rssi is -23 dbm'
|
||||
test_value = "\"rssi is \"(system/network/rssi)\" dBm\"";
|
||||
command(test_cmd.c_str(), compute(test_value).c_str());
|
||||
|
||||
test_value = "(custom/seltemp/value)";
|
||||
command(test_cmd.c_str(), compute(test_value).c_str());
|
||||
|
||||
test_value = "\"seltemp=\"(custom/seltemp/value)";
|
||||
command(test_cmd.c_str(), compute(test_value).c_str());
|
||||
|
||||
test_value = "(custom/seltemp)";
|
||||
command(test_cmd.c_str(), compute(test_value).c_str());
|
||||
|
||||
test_value = "(boiler/outdoortemp)";
|
||||
command(test_cmd.c_str(), compute(test_value).c_str());
|
||||
|
||||
test_value = "boiler/flowtempoffset";
|
||||
command(test_cmd.c_str(), compute(test_value).c_str());
|
||||
|
||||
test_value = "(boiler/flowtempoffset/value)";
|
||||
command(test_cmd.c_str(), compute(test_value).c_str());
|
||||
|
||||
test_value = "(boiler/storagetemp1/value)";
|
||||
command(test_cmd.c_str(), compute(test_value).c_str());
|
||||
|
||||
// (14 - 40) * 2.8 + 5 = -67.8
|
||||
test_value = "(custom/seltemp - boiler/flowtempoffset) * 2.8 + 5";
|
||||
command(test_cmd.c_str(), compute(test_value).c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -136,6 +136,9 @@ void WebStatusService::ESPsystemStatus(AsyncWebServerRequest * request) {
|
||||
root["has_loader"] = (buffer != 0xFFFFFFFFFFFFFFFF && running->size != partition->size);
|
||||
}
|
||||
}
|
||||
|
||||
root["model"] = EMSESP::system_.getBBQKeesGatewayDetails();
|
||||
|
||||
#endif
|
||||
|
||||
response->setLength();
|
||||
|
||||
@@ -386,9 +386,8 @@ std::string to_string(double d) {
|
||||
// RPN calculator
|
||||
std::string calculate(const std::string & expr) {
|
||||
auto expr_new = emsesp::Helpers::toLower(expr);
|
||||
// emsesp::EMSESP::logger().info("calculate: %s", expr_new.c_str());
|
||||
commands(expr_new);
|
||||
// emsesp::EMSESP::logger().info("calculate: %s", expr_new.c_str());
|
||||
|
||||
const auto tokens = exprToTokens(expr_new);
|
||||
if (tokens.empty()) {
|
||||
return "";
|
||||
@@ -397,6 +396,16 @@ std::string calculate(const std::string & expr) {
|
||||
if (queue.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
// debug only print tokens
|
||||
#ifdef EMSESP_STANDALONE
|
||||
for (const auto & t : queue) {
|
||||
emsesp::EMSESP::logger().debug("shunt token: %s(%d)", t.str.c_str(), t.type);
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
std::vector<std::string> stack;
|
||||
|
||||
while (!queue.empty()) {
|
||||
@@ -556,7 +565,16 @@ std::string calculate(const std::string & expr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return stack.back();
|
||||
|
||||
// concatenate all elements in stack to a single string, separated by spaces and return
|
||||
// experimental - for MDvP to check
|
||||
std::string result = "";
|
||||
for (const auto & s : stack) {
|
||||
result += s;
|
||||
}
|
||||
return result;
|
||||
|
||||
// return stack.back();
|
||||
}
|
||||
|
||||
// check for multiple instances of <cond> ? <expr1> : <expr2>
|
||||
@@ -586,5 +604,6 @@ std::string compute(const std::string & expr) {
|
||||
}
|
||||
q = expr_new.find_first_of("?"); // search next instance
|
||||
}
|
||||
|
||||
return calculate(expr_new);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user