mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-03-21 17:16:34 +03:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22312812bb | ||
|
|
a54edcaf5b | ||
|
|
e446954844 | ||
|
|
4a2d0d6787 | ||
|
|
9725314135 | ||
|
|
40f371d23b | ||
|
|
817b791e59 | ||
|
|
25a7aac360 | ||
|
|
37115a174d | ||
|
|
1397f81fd0 | ||
|
|
56365cb403 | ||
|
|
dfd245ee7b | ||
|
|
9c81e4b34d | ||
|
|
67676df131 | ||
|
|
a73b129596 | ||
|
|
4600d886b5 | ||
|
|
0fe45a2405 | ||
|
|
db87213242 | ||
|
|
5c3c010d5a | ||
|
|
c804cedd7a | ||
|
|
aa30ca99bf | ||
|
|
c0ca9d1069 | ||
|
|
5e79e1d57f | ||
|
|
8c732f9f1e | ||
|
|
5e94c2f636 | ||
|
|
64e5d29996 | ||
|
|
b320d8ded2 | ||
|
|
0be1b20996 | ||
|
|
6c55460622 | ||
|
|
d627404dc2 | ||
|
|
f317123c26 | ||
|
|
e4df1887b0 | ||
|
|
34142c3e85 | ||
|
|
6e7f8bdf02 | ||
|
|
3dd9fcfb58 | ||
|
|
35e2954b8b | ||
|
|
59aa63db0f | ||
|
|
7a41a190f8 | ||
|
|
6741232450 |
@@ -12,6 +12,7 @@ For more details go to [emsesp.org](https://emsesp.org/).
|
||||
- prometheus metrics for temperature/analog/scheduler/custom [#2962](https://github.com/emsesp/EMS-ESP32/issues/2962)
|
||||
- boiler pumpkick [#2965](https://github.com/emsesp/EMS-ESP32/discussions/2965)
|
||||
- heatpump reset [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
|
||||
- e-mail notification using ReadyMail Client
|
||||
|
||||
## Fixed
|
||||
|
||||
@@ -27,3 +28,5 @@ For more details go to [emsesp.org](https://emsesp.org/).
|
||||
- support `minflowtemp` and `baseflowtemp` [#2969](https://github.com/emsesp/EMS-ESP32/discussions/2969)
|
||||
- update version if it is 00.00 in first read [#2981](https://github.com/emsesp/EMS-ESP32/issues/2981)
|
||||
- device class for % values [#2980](https://github.com/emsesp/EMS-ESP32/issues/2980)
|
||||
- use tasmota core 2026.03.30
|
||||
- secure mqtt uses ESP_SSLClient
|
||||
|
||||
7
Makefile
7
Makefile
@@ -63,8 +63,9 @@ CXX_STANDARD := -std=gnu++17
|
||||
#----------------------------------------------------------------------
|
||||
# Defined Symbols
|
||||
#----------------------------------------------------------------------
|
||||
DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
|
||||
DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
|
||||
DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500
|
||||
DEFINES += -DNO_TLS_SUPPORT
|
||||
DEFINES += $(ARGS)
|
||||
|
||||
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\"
|
||||
@@ -79,6 +80,10 @@ SYMBOLS := $(CURDIR)/$(BUILD)/$(TARGET).out
|
||||
CSOURCES := $(shell find $(SOURCES) -name "*.c" 2>/dev/null)
|
||||
CXXSOURCES := $(shell find $(SOURCES) -name "*.cpp" 2>/dev/null)
|
||||
|
||||
# Exclude files not needed for standalone build, if they exist
|
||||
CSOURCES := $(filter-out src/core/ModuleLibrary.c,$(CSOURCES))
|
||||
CXXSOURCES := $(filter-out src/core/ModuleLibrary.cpp,$(CXXSOURCES))
|
||||
|
||||
OBJS := $(patsubst %,$(BUILD)/%.o,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))
|
||||
DEPS := $(patsubst %,$(BUILD)/%.d,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DTASMOTA_SDK",
|
||||
"-DNO_TLS_SUPPORT",
|
||||
"-DARDUINO_LOLIN_C3_MINI",
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DTASMOTA_SDK",
|
||||
"-DNO_TLS_SUPPORT",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=0"
|
||||
],
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "Espressif ESP32-S3 32M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS",
|
||||
"name": "Tasmota ESP32-S3 32M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS",
|
||||
"upload": {
|
||||
"flash_size": "32MB",
|
||||
"maximum_ram_size": 327680,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"build": {
|
||||
"core": "esp32",
|
||||
"extra_flags": "-DTASMOTA_SDK",
|
||||
"extra_flags": "-DNO_TLS_SUPPORT",
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "40000000L",
|
||||
"flash_mode": "dio",
|
||||
@@ -19,7 +19,7 @@
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "Espressif ESP32 16M Flash, 4608KB Code/OTA, 2MB FS",
|
||||
"name": "Tasmota ESP32 16M Flash, 4608KB Code/OTA, 2MB FS",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "Espressif ESP32 16M Flash DIO PSRAM, 4608KB Code/OTA, 2MB FS",
|
||||
"name": "Tasmota ESP32 16M Flash DIO PSRAM, 4608KB Code/OTA, 2MB FS",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"build": {
|
||||
"core": "esp32",
|
||||
"extra_flags": "-DTASMOTA_SDK",
|
||||
"extra_flags": "-DNO_TLS_SUPPORT",
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "40000000L",
|
||||
"flash_mode": "dio",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"vite.config.ts",
|
||||
"lib/esp32-psram/**",
|
||||
"test/test_api/test_api.h",
|
||||
"lib_standalone/**"
|
||||
"lib_standalone/**",
|
||||
"lib/mbedtls_ssl/**"
|
||||
]
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
"@mui/material": "^7.3.9",
|
||||
"@preact/compat": "^18.3.2",
|
||||
"@table-library/react-table-library": "4.1.15",
|
||||
"alova": "3.5.1",
|
||||
"alova": "^3.5.1",
|
||||
"async-validator": "^4.2.5",
|
||||
"etag": "^1.8.1",
|
||||
"formidable": "^3.5.4",
|
||||
@@ -49,23 +49,22 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.29.0",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@preact/compat": "^18.3.2",
|
||||
"@preact/preset-vite": "^2.10.3",
|
||||
"@preact/compat": "^18.3.1",
|
||||
"@preact/preset-vite": "^2.10.4",
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||
"@types/node": "^25.5.0",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"axe-core": "^4.11.1",
|
||||
"concurrently": "^9.2.1",
|
||||
"eslint": "^10.0.3",
|
||||
"eslint": "^10.1.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"prettier": "^3.8.1",
|
||||
"rollup-plugin-visualizer": "^7.0.1",
|
||||
"terser": "^5.46.0",
|
||||
"typescript-eslint": "^8.57.0",
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-imagemin": "^0.6.1",
|
||||
"vite-tsconfig-paths": "^6.1.1"
|
||||
"terser": "^5.46.1",
|
||||
"typescript-eslint": "^8.57.1",
|
||||
"vite": "^8.0.1",
|
||||
"vite-plugin-imagemin": "^0.6.1"
|
||||
},
|
||||
"packageManager": "pnpm@10.32.1"
|
||||
"packageManager": "pnpm@10.32.1+sha512.a706938f0e89ac1456b6563eab4edf1d1faf3368d1191fc5c59790e96dc918e4456ab2e67d613de1043d2e8c81f87303e6b40d4ffeca9df15ef1ad567348f2be"
|
||||
}
|
||||
|
||||
573
interface/pnpm-lock.yaml
generated
573
interface/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -263,7 +263,17 @@ const Dashboard = memo(() => {
|
||||
return (
|
||||
<>
|
||||
{!data.connected && (
|
||||
<MessageBox level="error" message={LL.EMS_BUS_WARNING()} />
|
||||
<MessageBox level="error" message={LL.EMS_BUS_WARNING() + '.'}>
|
||||
(
|
||||
<Link
|
||||
target="_blank"
|
||||
to="https://docs.emsesp.org/Troubleshooting#ems-bus-is-not-connecting"
|
||||
style={{ color: 'white' }}
|
||||
>
|
||||
{LL.ONLINE_HELP()}
|
||||
</Link>
|
||||
)
|
||||
</MessageBox>
|
||||
)}
|
||||
|
||||
{data.connected && data.nodes.length > 0 && !hasFavEntities && (
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
useState
|
||||
} from 'react';
|
||||
import { IconContext } from 'react-icons';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { Link, useNavigate } from 'react-router';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
|
||||
@@ -534,7 +534,17 @@ const Devices = memo(() => {
|
||||
const renderCoreData = () => (
|
||||
<>
|
||||
{!coreData.connected ? (
|
||||
<MessageBox level="error" message={LL.EMS_BUS_WARNING()} />
|
||||
<MessageBox level="error" message={LL.EMS_BUS_WARNING() + '.'}>
|
||||
(
|
||||
<Link
|
||||
target="_blank"
|
||||
to="https://docs.emsesp.org/Troubleshooting#ems-bus-is-not-connecting"
|
||||
style={{ color: 'white' }}
|
||||
>
|
||||
{LL.ONLINE_HELP()}
|
||||
</Link>
|
||||
)
|
||||
</MessageBox>
|
||||
) : (
|
||||
<Box justifyContent="center" flexDirection="column">
|
||||
<IconContext.Provider
|
||||
|
||||
@@ -43,6 +43,16 @@ export interface Settings {
|
||||
modbus_port: number;
|
||||
modbus_max_clients: number;
|
||||
modbus_timeout: number;
|
||||
email_enabled: boolean;
|
||||
email_ssl?: boolean;
|
||||
email_starttls?: boolean;
|
||||
email_server: string;
|
||||
email_port: number;
|
||||
email_login: string;
|
||||
email_pass: string;
|
||||
email_sender: string;
|
||||
email_recp: string;
|
||||
email_subject: string;
|
||||
developer_mode: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
FormLoader,
|
||||
MessageBox,
|
||||
SectionContent,
|
||||
ValidatedPasswordField,
|
||||
ValidatedTextField,
|
||||
useLayoutTitle
|
||||
} from 'components';
|
||||
@@ -351,6 +352,156 @@ const ApplicationSettings = () => {
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
<Typography color="secondary">eMail</Typography>
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.email_enabled}
|
||||
onChange={updateFormValue}
|
||||
name="email_enabled"
|
||||
disabled={!hardwareData.psram}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Typography color={!hardwareData.psram ? 'grey' : 'default'}>
|
||||
Enable eMail notification
|
||||
{!hardwareData.psram && (
|
||||
<Typography variant="caption">
|
||||
({LL.IS_REQUIRED('PSRAM')})
|
||||
</Typography>
|
||||
)}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
{data.email_enabled && (
|
||||
<>
|
||||
<Grid
|
||||
container
|
||||
spacing={2}
|
||||
direction="row"
|
||||
justifyContent="flex-start"
|
||||
alignItems="flex-start"
|
||||
>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_server"
|
||||
label="SMTP Server"
|
||||
variant="outlined"
|
||||
value={data.email_server}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
sx={{ width: '12ch' }}
|
||||
name="email_port"
|
||||
variant="outlined"
|
||||
label="Port"
|
||||
value={numberValue(data.email_port)}
|
||||
type="number"
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={4} mt={!data.email_ssl && !data.email_starttls ? 0 : 3}>
|
||||
{!data.email_starttls && (
|
||||
<BlockFormControlLabel
|
||||
sx={{ width: '12ch' }}
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.email_ssl}
|
||||
onChange={updateFormValue}
|
||||
name="email_ssl"
|
||||
disabled={
|
||||
data.email_starttls || data.email_ssl === undefined
|
||||
}
|
||||
/>
|
||||
}
|
||||
label="SSL/TLS"
|
||||
/>
|
||||
)}
|
||||
{!data.email_ssl && (
|
||||
<BlockFormControlLabel
|
||||
sx={{ width: '12ch' }}
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.email_starttls}
|
||||
onChange={updateFormValue}
|
||||
name="email_starttls"
|
||||
disabled={
|
||||
data.email_ssl || data.email_starttls === undefined
|
||||
}
|
||||
/>
|
||||
}
|
||||
label="STARTTLS"
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={2} rowSpacing={0}>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_login"
|
||||
label="Login"
|
||||
variant="outlined"
|
||||
value={data.email_login}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<ValidatedPasswordField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_pass"
|
||||
label="Password"
|
||||
variant="outlined"
|
||||
value={data.email_pass}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={2} rowSpacing={0}>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_sender"
|
||||
label="From"
|
||||
variant="outlined"
|
||||
value={data.email_sender}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_recp"
|
||||
label="To"
|
||||
variant="outlined"
|
||||
value={data.email_recp}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_subject"
|
||||
label="Subject"
|
||||
variant="outlined"
|
||||
value={data.email_subject}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
<Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary">
|
||||
{LL.SENSORS()}
|
||||
</Typography>
|
||||
|
||||
@@ -20,7 +20,6 @@ import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { saveFile } from 'utils';
|
||||
|
||||
interface DownloadButton {
|
||||
key: string;
|
||||
type: string;
|
||||
label: string | number;
|
||||
isGridButton: boolean;
|
||||
@@ -66,31 +65,31 @@ const DownloadUpload = () => {
|
||||
const downloadButtons: DownloadButton[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
key: 'settings',
|
||||
type: 'settings',
|
||||
label: LL.SETTINGS_OF(LL.APPLICATION()),
|
||||
isGridButton: true
|
||||
},
|
||||
{
|
||||
key: 'customizations',
|
||||
type: 'customizations',
|
||||
label: LL.CUSTOMIZATIONS(),
|
||||
isGridButton: true
|
||||
},
|
||||
{
|
||||
key: 'entities',
|
||||
type: 'entities',
|
||||
label: LL.CUSTOM_ENTITIES(0),
|
||||
isGridButton: true
|
||||
},
|
||||
{
|
||||
key: 'schedule',
|
||||
type: 'schedule',
|
||||
label: LL.SCHEDULE(0),
|
||||
isGridButton: true
|
||||
},
|
||||
{
|
||||
key: 'allvalues',
|
||||
type: 'systembackup',
|
||||
label: LL.DOWNLOAD_SYSTEM_BACKUP(),
|
||||
isGridButton: true
|
||||
},
|
||||
{
|
||||
type: 'allvalues',
|
||||
label: LL.ALLVALUES(),
|
||||
isGridButton: false
|
||||
@@ -133,7 +132,7 @@ const DownloadUpload = () => {
|
||||
|
||||
<Grid container spacing={2}>
|
||||
{gridButtons.map((button) => (
|
||||
<Grid key={button.key}>
|
||||
<Grid key={button.type}>
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
|
||||
@@ -60,18 +60,16 @@ const SystemMonitor = () => {
|
||||
const { statusMessage, isUploading, progressValue } = useMemo(() => {
|
||||
const status = data?.status;
|
||||
|
||||
let message = '';
|
||||
if (status && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING) {
|
||||
message = LL.WAIT_FIRMWARE();
|
||||
} else if (status === SystemStatusCodes.SYSTEM_STATUS_PENDING_RESTART) {
|
||||
message = LL.APPLICATION_RESTARTING();
|
||||
} else if (status === SystemStatusCodes.SYSTEM_STATUS_NORMAL) {
|
||||
message = LL.RESTARTING_PRE();
|
||||
} else if (status === SystemStatusCodes.SYSTEM_STATUS_ERROR_UPLOAD) {
|
||||
message = 'Upload Failed';
|
||||
} else {
|
||||
message = LL.RESTARTING_POST();
|
||||
}
|
||||
const message =
|
||||
status && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING
|
||||
? LL.WAIT_FIRMWARE()
|
||||
: status === SystemStatusCodes.SYSTEM_STATUS_PENDING_RESTART
|
||||
? LL.APPLICATION_RESTARTING()
|
||||
: status === SystemStatusCodes.SYSTEM_STATUS_NORMAL
|
||||
? LL.RESTARTING_PRE()
|
||||
: status === SystemStatusCodes.SYSTEM_STATUS_ERROR_UPLOAD
|
||||
? 'Upload Failed'
|
||||
: LL.RESTARTING_POST();
|
||||
|
||||
const uploading =
|
||||
status !== undefined && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING;
|
||||
|
||||
@@ -274,7 +274,6 @@ const InstallDialog = memo(
|
||||
fetchDevVersion,
|
||||
latestVersion,
|
||||
latestDevVersion,
|
||||
downloadOnly,
|
||||
platform,
|
||||
LL,
|
||||
onClose,
|
||||
@@ -284,7 +283,6 @@ const InstallDialog = memo(
|
||||
fetchDevVersion: boolean;
|
||||
latestVersion?: VersionInfo;
|
||||
latestDevVersion?: VersionInfo;
|
||||
downloadOnly: boolean;
|
||||
platform: string;
|
||||
LL: TranslationFunctions;
|
||||
onClose: () => void;
|
||||
@@ -309,7 +307,7 @@ const InstallDialog = memo(
|
||||
<DialogContent dividers>
|
||||
<Typography mb={2}>
|
||||
{LL.INSTALL_VERSION(
|
||||
downloadOnly ? LL.DOWNLOAD(1) : LL.INSTALL(),
|
||||
LL.INSTALL(),
|
||||
fetchDevVersion ? latestDevVersion?.name : latestVersion?.name
|
||||
)}
|
||||
</Typography>
|
||||
@@ -333,16 +331,14 @@ const InstallDialog = memo(
|
||||
{LL.DOWNLOAD(0)}
|
||||
</Link>
|
||||
</Button>
|
||||
{!downloadOnly && (
|
||||
<Button
|
||||
startIcon={<WarningIcon color="warning" />}
|
||||
variant="outlined"
|
||||
onClick={() => onInstall(binURL)}
|
||||
color="primary"
|
||||
>
|
||||
{LL.INSTALL()}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
startIcon={<WarningIcon color="warning" />}
|
||||
variant="outlined"
|
||||
onClick={() => onInstall(binURL)}
|
||||
color="primary"
|
||||
>
|
||||
{LL.INSTALL()}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
@@ -423,7 +419,6 @@ const Version = () => {
|
||||
const [stableUpgradeAvailable, setStableUpgradeAvailable] =
|
||||
useState<boolean>(false);
|
||||
const [internetLive, setInternetLive] = useState<boolean>(false);
|
||||
const [downloadOnly, setDownloadOnly] = useState<boolean>(false);
|
||||
const [showVersionInfo, setShowVersionInfo] = useState<number>(0); // 1 = stable, 2 = dev, 3 = partition
|
||||
const [firmwareSize, setFirmwareSize] = useState<number>(0);
|
||||
|
||||
@@ -449,9 +444,6 @@ const Version = () => {
|
||||
error
|
||||
} = useRequest(SystemApi.readSystemStatus).onSuccess((event) => {
|
||||
const systemData = event.data as VersionData;
|
||||
if (systemData.arduino_version.startsWith('Tasmota')) {
|
||||
setDownloadOnly(true);
|
||||
}
|
||||
setUsingDevVersion(systemData.emsesp_version.includes('dev'));
|
||||
});
|
||||
|
||||
@@ -815,7 +807,6 @@ const Version = () => {
|
||||
fetchDevVersion={fetchDevVersion}
|
||||
latestVersion={latestVersion}
|
||||
latestDevVersion={latestDevVersion}
|
||||
downloadOnly={downloadOnly}
|
||||
platform={platform}
|
||||
LL={LL}
|
||||
onClose={closeInstallDialog}
|
||||
@@ -851,7 +842,6 @@ const Version = () => {
|
||||
locale,
|
||||
openInstallDialog,
|
||||
fetchDevVersion,
|
||||
downloadOnly,
|
||||
me.admin,
|
||||
showButtons,
|
||||
handleVersionInfoClose,
|
||||
|
||||
@@ -186,7 +186,8 @@ const cz: Translation = {
|
||||
BUFFER_SIZE: 'Maximální velikost vyrovnávací paměti',
|
||||
COMPACT: 'Kompaktní',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Vytvořte zálohu svého nastavení a konfigurace',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportovat všechna data',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportovat všechny hodnoty',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha',
|
||||
UPLOAD_TEXT: 'Nahrajte nový soubor firmwaru (.bin) nebo záložní soubor (.json)',
|
||||
UPLOAD_DROP_TEXT: 'Přetáhněte soubor sem nebo klikněte pro výběr',
|
||||
ERROR: 'Neočekávaná chyba, zkuste to prosím znovu',
|
||||
@@ -357,7 +358,8 @@ const cz: Translation = {
|
||||
FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru',
|
||||
NO_DATA: 'Žádná data',
|
||||
USER_PROFILE: 'Uživatelský profil',
|
||||
STORED_VERSIONS: 'Uložené verze'
|
||||
STORED_VERSIONS: 'Uložené verze',
|
||||
ONLINE_HELP: 'online nápověda'
|
||||
};
|
||||
|
||||
export default cz;
|
||||
|
||||
@@ -186,7 +186,8 @@ const de: Translation = {
|
||||
BUFFER_SIZE: 'Max. Puffergröße',
|
||||
COMPACT: 'Kompakte Darstellung',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Erstellen Sie eine Sicherung Ihrer Konfigurationen und Einstellungen',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Daten',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Werte',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'System Sicherung',
|
||||
UPLOAD_TEXT: 'Laden Sie eine neue Firmware-Datei (.bin) oder eine Sicherungsdatei (.json) hoch',
|
||||
UPLOAD_DROP_TEXT: 'Legen Sie eine Firmware-Datei (.bin) ab oder klicken Sie hier',
|
||||
ERROR: 'Unerwarteter Fehler, bitte versuchen Sie es erneut.',
|
||||
@@ -357,7 +358,8 @@ const de: Translation = {
|
||||
FIRMWARE_VERSION_INFO: 'Firmware-Versionsinformation',
|
||||
NO_DATA: 'Keine Daten',
|
||||
USER_PROFILE: 'Benutzerprofil',
|
||||
STORED_VERSIONS: 'Gespeicherte Versionen'
|
||||
STORED_VERSIONS: 'Gespeicherte Versionen',
|
||||
ONLINE_HELP: 'Online-Hilfe'
|
||||
};
|
||||
|
||||
export default de;
|
||||
|
||||
@@ -186,7 +186,8 @@ const en: Translation = {
|
||||
BUFFER_SIZE: 'Max Buffer Size',
|
||||
COMPACT: 'Compact',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Export all data',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Export all values',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'System Backup',
|
||||
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
|
||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
|
||||
ERROR: 'Unexpected Error, please try again',
|
||||
@@ -357,7 +358,8 @@ const en: Translation = {
|
||||
FIRMWARE_VERSION_INFO: 'Firmware Version Information',
|
||||
NO_DATA: 'No data',
|
||||
USER_PROFILE: 'User Profile',
|
||||
STORED_VERSIONS: 'Stored Versions'
|
||||
STORED_VERSIONS: 'Stored Versions',
|
||||
ONLINE_HELP: 'online help'
|
||||
};
|
||||
|
||||
export default en;
|
||||
|
||||
@@ -186,7 +186,8 @@ const fr: Translation = {
|
||||
BUFFER_SIZE: 'Max taille du buffer',
|
||||
COMPACT: 'Compact',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Créer une sauvegarde de vos paramètres et configurations',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exporter toutes les données',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exporter toutes les valeurs',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'Sauvegarde système',
|
||||
UPLOAD_TEXT: 'Télécharger un nouveau fichier firmware (.bin) ou une sauvegarde (.json)',
|
||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
|
||||
ERROR: 'Erreur inattendue, veuillez réessayer',
|
||||
@@ -357,7 +358,8 @@ const fr: Translation = {
|
||||
FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware',
|
||||
NO_DATA: 'Aucune donnée',
|
||||
USER_PROFILE: 'Profil utilisateur',
|
||||
STORED_VERSIONS: 'Versions stockées'
|
||||
STORED_VERSIONS: 'Versions stockées',
|
||||
ONLINE_HELP: 'aide en ligne'
|
||||
};
|
||||
|
||||
export default fr;
|
||||
|
||||
@@ -186,7 +186,8 @@ const it: Translation = {
|
||||
BUFFER_SIZE: 'Max Buffer Size',
|
||||
COMPACT: 'Compatto',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Esporta tutti i dati',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Esporta tutti i valori',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'Backup sistema',
|
||||
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
|
||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
|
||||
ERROR: 'Errore Inaspettato, prego tenta ancora',
|
||||
@@ -357,7 +358,8 @@ const it: Translation = {
|
||||
FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware',
|
||||
NO_DATA: 'Nessun dato',
|
||||
USER_PROFILE: 'Profilo utente',
|
||||
STORED_VERSIONS: 'Versioni memorizzate'
|
||||
STORED_VERSIONS: 'Versioni memorizzate',
|
||||
ONLINE_HELP: 'aiuto online'
|
||||
};
|
||||
|
||||
export default it;
|
||||
|
||||
@@ -186,7 +186,8 @@ const nl: Translation = {
|
||||
BUFFER_SIZE: 'Max buffer grootte',
|
||||
COMPACT: 'Compact',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Maak een back-up van uw configuratie en instellingen',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exporteer alle data',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exporteer alle waarden',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'Systeem Backup',
|
||||
UPLOAD_TEXT: 'Upload een nieuw firmwarebestand (.bin) of een back-upbestand (.json)',
|
||||
UPLOAD_DROP_TEXT: 'Sleep en firmware .bin bestand hierheen of klik hier',
|
||||
ERROR: 'Onverwachte fout, probeer opnieuw',
|
||||
@@ -357,7 +358,8 @@ const nl: Translation = {
|
||||
FIRMWARE_VERSION_INFO: 'Informatie over firmwareversie',
|
||||
NO_DATA: 'Geen data',
|
||||
USER_PROFILE: 'Gebruikersprofiel',
|
||||
STORED_VERSIONS: 'Opgeslagen versies'
|
||||
STORED_VERSIONS: 'Opgeslagen versies',
|
||||
ONLINE_HELP: 'online help'
|
||||
};
|
||||
|
||||
export default nl;
|
||||
|
||||
@@ -186,7 +186,8 @@ const no: Translation = {
|
||||
BUFFER_SIZE: 'Max Buffer Størrelse',
|
||||
COMPACT: 'Komprimere',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Lag en sikkerhetskopi av dine konfigurasjon og innstillinger',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Eksporter alle data',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Eksporter alle verdier',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'System Sikkerhetskopi',
|
||||
UPLOAD_TEXT: 'Last opp en ny firmware fil (.bin) eller en sikkerhetskopi fil (.json)',
|
||||
UPLOAD_DROP_TEXT: 'Dropp en firmware fil (.bin) eller klikk her',
|
||||
ERROR: 'Ukjent feil, prøv igjen',
|
||||
@@ -357,7 +358,8 @@ const no: Translation = {
|
||||
FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon',
|
||||
NO_DATA: 'Ingen data',
|
||||
USER_PROFILE: 'Brukerprofil',
|
||||
STORED_VERSIONS: 'Lagret versjoner'
|
||||
STORED_VERSIONS: 'Lagret versjoner',
|
||||
ONLINE_HELP: 'online hjelp'
|
||||
};
|
||||
|
||||
export default no;
|
||||
|
||||
@@ -186,7 +186,8 @@ const pl: BaseTranslation = {
|
||||
BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)',
|
||||
COMPACT: 'Kompaktowy',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Utwórz kopię swoich ustawień i konfiguracji',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Eksportuj wszystkie dane',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Eksportuj wszystkie wartości',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'Kopia zapasowa systemu',
|
||||
UPLOAD_TEXT: 'Wgraj nowy plik firmware (.bin) lub kopię ustawień (.json)',
|
||||
UPLOAD_DROP_TEXT: 'Upuść plik firmware .bin lub kliknij tutaj',
|
||||
ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!',
|
||||
@@ -357,7 +358,8 @@ const pl: BaseTranslation = {
|
||||
FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware',
|
||||
NO_DATA: 'Brak danych',
|
||||
USER_PROFILE: 'Profil użytkownika',
|
||||
STORED_VERSIONS: 'Zapisane wersje'
|
||||
STORED_VERSIONS: 'Zapisane wersje',
|
||||
ONLINE_HELP: 'pomoc online'
|
||||
};
|
||||
|
||||
export default pl;
|
||||
|
||||
@@ -186,7 +186,8 @@ const sk: Translation = {
|
||||
BUFFER_SIZE: 'Buffer-max. veľkosť',
|
||||
COMPACT: 'Kompaktné',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Vytvorte zálohu svojej konfigurácie a nastavení',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportovať všetky dáta',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportovať všetky hodnoty',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha',
|
||||
UPLOAD_TEXT: 'Nahrajte nový súbor firmvéru (.bin) alebo súbor zálohy (.json)',
|
||||
UPLOAD_DROP_TEXT: 'Presuňte súbor .bin firmvéru alebo kliknite sem',
|
||||
ERROR: 'Neočakávaná chyba, prosím skúste to znova',
|
||||
@@ -357,7 +358,8 @@ const sk: Translation = {
|
||||
FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware',
|
||||
NO_DATA: 'Žiadne dáta',
|
||||
USER_PROFILE: 'Profil používateľa',
|
||||
STORED_VERSIONS: 'Uložené verzie'
|
||||
STORED_VERSIONS: 'Uložené verzie',
|
||||
ONLINE_HELP: 'online pomoc'
|
||||
};
|
||||
|
||||
export default sk;
|
||||
|
||||
@@ -186,7 +186,8 @@ const sv: Translation = {
|
||||
BUFFER_SIZE: 'Max bufferstorlek',
|
||||
COMPACT: 'Komprimerad',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Skapa en säkerhetskopia av din konfiguration och inställningar',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportera alla data',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportera alla värden',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'System säkerhetskopia',
|
||||
UPLOAD_TEXT: 'Ladda upp en ny firmwarefil (.bin) eller en säkerhetskopiafil (.json)',
|
||||
UPLOAD_DROP_TEXT: 'Droppa en firmware .bin fil eller klicka här',
|
||||
ERROR: 'Okänt fel, var god försök igen',
|
||||
@@ -357,7 +358,8 @@ const sv: Translation = {
|
||||
FIRMWARE_VERSION_INFO: 'Information om firmwareversion',
|
||||
NO_DATA: 'Ingen data',
|
||||
USER_PROFILE: 'Användarprofil',
|
||||
STORED_VERSIONS: 'Lagrad versioner'
|
||||
STORED_VERSIONS: 'Lagrad versioner',
|
||||
ONLINE_HELP: 'online hjälp'
|
||||
};
|
||||
|
||||
export default sv;
|
||||
|
||||
@@ -186,7 +186,8 @@ const tr: Translation = {
|
||||
BUFFER_SIZE: 'En fazla bellek boyutu',
|
||||
COMPACT: 'Sıkışık',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Yapılandırma ve ayarlarınızın yedekleme yapın',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Tüm verileri dışarı al',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Tüm değerleri dışarı al',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'Sistem yedekleme',
|
||||
UPLOAD_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle',
|
||||
UPLOAD_DROP_TEXT: 'Bir firmware .bin dosyası veya buraya tıklayın',
|
||||
ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.',
|
||||
@@ -357,7 +358,8 @@ const tr: Translation = {
|
||||
FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi',
|
||||
NO_DATA: 'Hiçbir veri yok',
|
||||
USER_PROFILE: 'Kullanıcı Profili',
|
||||
STORED_VERSIONS: 'Kaydedilmiş Sürümler'
|
||||
STORED_VERSIONS: 'Kaydedilmiş Sürümler',
|
||||
ONLINE_HELP: 'online yardım'
|
||||
};
|
||||
|
||||
export default tr;
|
||||
|
||||
@@ -23,6 +23,8 @@ export const saveFile = (
|
||||
}, 100);
|
||||
} catch (error) {
|
||||
console.error('Failed to save file:', error);
|
||||
throw new Error(`Unable to save file: ${filename}${extension}`);
|
||||
throw new Error(`Unable to save file: ${filename}${extension}`, {
|
||||
cause: error
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,9 +2,8 @@ import preact from '@preact/preset-vite';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { visualizer } from 'rollup-plugin-visualizer';
|
||||
import { Plugin, defineConfig } from 'vite';
|
||||
import { Plugin, PluginOption, defineConfig } from 'vite';
|
||||
import viteImagemin from 'vite-plugin-imagemin';
|
||||
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
||||
import zlib from 'zlib';
|
||||
|
||||
// @ts-expect-error - mock server doesn't have type declarations
|
||||
@@ -99,16 +98,31 @@ const createPreactPlugin = (devToolsEnabled: boolean) =>
|
||||
prefreshEnabled: false
|
||||
});
|
||||
|
||||
// Patch preact/compat to export stub React 19 APIs (use, useOptimistic) so that
|
||||
// react-router v7 doesn't trigger IMPORT_IS_UNDEFINED warnings from Rolldown.
|
||||
const preactCompatPatchPlugin = (): Plugin => ({
|
||||
name: 'preact-compat-react19-patch',
|
||||
transform(code, id) {
|
||||
if (id.includes('preact') && id.includes('compat.module.js')) {
|
||||
return {
|
||||
code:
|
||||
code +
|
||||
'\nexport var use = undefined;\nexport var useOptimistic = undefined;\n',
|
||||
map: null
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
// Common base plugins
|
||||
const createBasePlugins = (
|
||||
devToolsEnabled: boolean,
|
||||
includeBundleReporter = true
|
||||
) => {
|
||||
const plugins = [
|
||||
): PluginOption[] => {
|
||||
const plugins: PluginOption[] = [
|
||||
createPreactPlugin(devToolsEnabled),
|
||||
viteTsconfigPaths({
|
||||
projects: ['./tsconfig.json']
|
||||
})
|
||||
preactCompatPatchPlugin()
|
||||
];
|
||||
if (includeBundleReporter) {
|
||||
plugins.push(bundleSizeReporter());
|
||||
@@ -234,7 +248,8 @@ export default defineConfig(
|
||||
plugins: [...createBasePlugins(true, true), mockServer()],
|
||||
resolve: {
|
||||
alias: RESOLVE_ALIASES,
|
||||
extensions: RESOLVE_EXTENSIONS
|
||||
extensions: RESOLVE_EXTENSIONS,
|
||||
tsconfigPaths: true
|
||||
},
|
||||
server: {
|
||||
open: true,
|
||||
@@ -263,7 +278,8 @@ export default defineConfig(
|
||||
plugins: createBasePlugins(false, true),
|
||||
resolve: {
|
||||
alias: RESOLVE_ALIASES,
|
||||
extensions: RESOLVE_EXTENSIONS
|
||||
extensions: RESOLVE_EXTENSIONS,
|
||||
tsconfigPaths: true
|
||||
},
|
||||
build: {
|
||||
...createBaseBuildConfig(),
|
||||
@@ -297,7 +313,8 @@ export default defineConfig(
|
||||
],
|
||||
resolve: {
|
||||
alias: RESOLVE_ALIASES,
|
||||
extensions: RESOLVE_EXTENSIONS
|
||||
extensions: RESOLVE_EXTENSIONS,
|
||||
tsconfigPaths: true
|
||||
},
|
||||
build: {
|
||||
...createBaseBuildConfig(),
|
||||
@@ -306,8 +323,7 @@ export default defineConfig(
|
||||
rollupOptions: {
|
||||
treeshake: {
|
||||
moduleSideEffects: false,
|
||||
propertyReadSideEffects: false,
|
||||
tryCatchDeoptimization: false,
|
||||
propertyReadSideEffects: false as const,
|
||||
unknownGlobalSideEffects: false
|
||||
},
|
||||
output: {
|
||||
|
||||
@@ -148,9 +148,7 @@
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#include <driver/rtc_io.h>
|
||||
#include <soc/gpio_struct.h>
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
#include "soc/gpio_periph.h"
|
||||
#endif // ESP_IDF_VERSION_MAJOR >= 5
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
// Include all library components
|
||||
#include "esp32-psram/AllocatorPSRAM.h" // PSRAM-backed vector
|
||||
#include "esp32-psram/VectorPSRAM.h" // PSRAM-backed vector
|
||||
#include "esp32-psram/VectorHIMEM.h" // HIMEM-backed vector
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32-psram/VectorHIMEM.h" // HIMEM-backed vector (ESP32 only)
|
||||
#endif
|
||||
// #include "esp32-psram/InMemoryFile.h" // File interface using vectors
|
||||
// #include "esp32-psram/PSRAM.h" // PSRAM file system
|
||||
// #include "esp32-psram/HIMEM.h" // HIMEM file system
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// HIMEM is only available on original ESP32
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
@@ -360,3 +363,5 @@ class HimemBlock {
|
||||
};
|
||||
|
||||
} // namespace esp32_psram
|
||||
|
||||
#endif // CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
@@ -238,7 +238,9 @@ using RingBufferStreamPSRAM = RingBufferStream<VectorPSRAM<uint8_t>>;
|
||||
/**
|
||||
* @brief Type alias for a RingBufferStream that uses HIMEM-backed vector storage
|
||||
*/
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
using RingBufferStreamHIMEM = RingBufferStream<VectorHIMEM<uint8_t>>;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Type alias for a RingBufferStream that uses std::vector storage
|
||||
|
||||
@@ -209,8 +209,10 @@ using TypedRingBufferRAM = TypedRingBuffer<T, std::vector<T>>;
|
||||
/**
|
||||
* @brief Type alias for a typed ring buffer that uses HIMEM-backed vector storage
|
||||
*/
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
template<typename T>
|
||||
using TypedRingBufferHIMEM = TypedRingBuffer<T, VectorHIMEM<T>>;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Type alias for a typed ring buffer that uses PSRAM-backed vector storage
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// HIMEM is only available on original ESP32
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
#include "HimemBlock.h"
|
||||
|
||||
namespace esp32_psram {
|
||||
@@ -526,4 +529,6 @@ void swap(VectorHIMEM<T>& lhs, VectorHIMEM<T>& rhs) noexcept {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace esp32_psram
|
||||
} // namespace esp32_psram
|
||||
|
||||
#endif // CONFIG_IDF_TARGET_ESP32
|
||||
@@ -49,6 +49,10 @@ the LICENSE file.
|
||||
#define EMC_CLIENTID_LENGTH 23 + 1
|
||||
#endif
|
||||
|
||||
#ifdef EMSESP_MQTT_STACKSIZE
|
||||
#define EMC_TASK_STACK_SIZE EMSESP_MQTT_STACKSIZE
|
||||
#endif
|
||||
|
||||
#ifndef EMC_TASK_STACK_SIZE
|
||||
#define EMC_TASK_STACK_SIZE 5120
|
||||
#endif
|
||||
@@ -66,14 +70,10 @@ the LICENSE file.
|
||||
#endif
|
||||
|
||||
#if EMC_USE_MEMPOOL
|
||||
#ifndef EMC_NUM_POOL_ELEMENTS
|
||||
#define EMC_NUM_POOL_ELEMENTS 32
|
||||
#endif
|
||||
#ifndef EMC_SIZE_POOL_ELEMENTS
|
||||
#define EMC_SIZE_POOL_ELEMENTS 128
|
||||
#endif
|
||||
#ifndef EMC_NUM_POOL_ELEMENTS
|
||||
#define EMC_NUM_POOL_ELEMENTS 32
|
||||
#endif
|
||||
#ifndef EMC_SIZE_POOL_ELEMENTS
|
||||
#define EMC_SIZE_POOL_ELEMENTS 128
|
||||
#endif
|
||||
|
||||
#ifndef TASMOTA_SDK
|
||||
#define EMC_CLIENT_SECURE
|
||||
#endif
|
||||
|
||||
@@ -62,7 +62,11 @@ MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint
|
||||
_xSemaphore = xSemaphoreCreateMutex();
|
||||
EMC_SEMAPHORE_GIVE(); // release before first use
|
||||
if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) {
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle, core);
|
||||
if (core > 1) {
|
||||
xTaskCreate((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle);
|
||||
} else {
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle, core);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void) useInternalTask;
|
||||
@@ -70,6 +74,7 @@ MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint
|
||||
(void) core;
|
||||
#endif
|
||||
_clientId = _generatedClientId;
|
||||
_core = core;
|
||||
}
|
||||
|
||||
MqttClient::~MqttClient() {
|
||||
|
||||
@@ -69,7 +69,17 @@ class MqttClient {
|
||||
const char* getClientId() const;
|
||||
size_t queueSize(); // No const because of mutex
|
||||
void loop();
|
||||
|
||||
uint32_t stack() {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
return uxTaskGetStackHighWaterMark(_taskHandle);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
uint8_t core() {
|
||||
return _core;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1);
|
||||
espMqttClientTypes::UseInternalTask _useInternalTask;
|
||||
@@ -98,6 +108,7 @@ class MqttClient {
|
||||
uint8_t _willQos;
|
||||
bool _willRetain;
|
||||
uint32_t _timeout;
|
||||
uint8_t _core;
|
||||
|
||||
// state is protected to allow state changes by the transport system, defined in child classes
|
||||
// eg. to allow AsyncTCP
|
||||
|
||||
@@ -6,66 +6,65 @@ For a copy, see <https://opensource.org/licenses/MIT> or
|
||||
the LICENSE file.
|
||||
*/
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
|
||||
#include "ClientSecureSync.h"
|
||||
#include <lwip/sockets.h> // socket options
|
||||
#include <lwip/sockets.h>
|
||||
#include "../Config.h"
|
||||
|
||||
namespace espMqttClientInternals {
|
||||
|
||||
ClientSecureSync::ClientSecureSync()
|
||||
: client() {
|
||||
// empty
|
||||
: client() {
|
||||
client.setClient(&basic_client, true);
|
||||
client.setBufferSizes(EMC_RX_BUFFER_SIZE, EMC_TX_BUFFER_SIZE);
|
||||
client.setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds)
|
||||
}
|
||||
|
||||
ClientSecureSync::~ClientSecureSync() {
|
||||
stop();
|
||||
}
|
||||
|
||||
bool ClientSecureSync::connect(IPAddress ip, uint16_t port) {
|
||||
bool ret = client.connect(ip, port); // implicit conversion of return code int --> bool
|
||||
if (ret) {
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
client.setNoDelay(true);
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
|
||||
int val = true;
|
||||
client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
bool ret = client.connect(ip, port); // implicit conversion of return code int --> bool
|
||||
if (ret) {
|
||||
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
|
||||
int val = true;
|
||||
basic_client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ClientSecureSync::connect(const char* host, uint16_t port) {
|
||||
bool ret = client.connect(host, port); // implicit conversion of return code int --> bool
|
||||
if (ret) {
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
client.setNoDelay(true);
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
|
||||
int val = true;
|
||||
client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
bool ClientSecureSync::connect(const char * host, uint16_t port) {
|
||||
bool ret = client.connect(host, port); // implicit conversion of return code int --> bool
|
||||
if (ret) {
|
||||
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
|
||||
int val = true;
|
||||
basic_client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t ClientSecureSync::write(const uint8_t* buf, size_t size) {
|
||||
return client.write(buf, size);
|
||||
size_t ClientSecureSync::write(const uint8_t * buf, size_t size) {
|
||||
return client.write(buf, size);
|
||||
}
|
||||
|
||||
int ClientSecureSync::read(uint8_t* buf, size_t size) {
|
||||
return client.read(buf, size);
|
||||
int ClientSecureSync::read(uint8_t * buf, size_t size) {
|
||||
return client.read(buf, size);
|
||||
}
|
||||
|
||||
void ClientSecureSync::stop() {
|
||||
client.stop();
|
||||
client.stop();
|
||||
}
|
||||
|
||||
bool ClientSecureSync::connected() {
|
||||
return client.connected();
|
||||
return client.connected();
|
||||
}
|
||||
|
||||
bool ClientSecureSync::disconnected() {
|
||||
return !client.connected();
|
||||
return !client.connected();
|
||||
}
|
||||
|
||||
} // namespace espMqttClientInternals
|
||||
} // namespace espMqttClientInternals
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -8,15 +8,11 @@ the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
|
||||
// Added for EMS-ESP
|
||||
#include "../Config.h"
|
||||
#if defined(EMC_CLIENT_SECURE)
|
||||
#include <WiFiClientSecure.h> // includes IPAddress
|
||||
#else
|
||||
// #include "esp_tls.h"
|
||||
#include <WiFiClient.h>
|
||||
#endif
|
||||
#include <ESP_SSLClient.h>
|
||||
#include "Transport.h"
|
||||
|
||||
namespace espMqttClientInternals {
|
||||
@@ -24,6 +20,7 @@ namespace espMqttClientInternals {
|
||||
class ClientSecureSync : public Transport {
|
||||
public:
|
||||
ClientSecureSync();
|
||||
~ClientSecureSync();
|
||||
bool connect(IPAddress ip, uint16_t port) override;
|
||||
bool connect(const char * host, uint16_t port) override;
|
||||
size_t write(const uint8_t * buf, size_t size) override;
|
||||
@@ -31,14 +28,11 @@ class ClientSecureSync : public Transport {
|
||||
void stop() override;
|
||||
bool connected() override;
|
||||
bool disconnected() override;
|
||||
// added for EMS-ESP
|
||||
#if defined(EMC_CLIENT_SECURE)
|
||||
WiFiClientSecure client;
|
||||
#else
|
||||
WiFiClient client;
|
||||
#endif
|
||||
|
||||
WiFiClient basic_client;
|
||||
ESP_SSLClient client;
|
||||
};
|
||||
|
||||
} // namespace espMqttClientInternals
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -8,50 +8,6 @@ the LICENSE file.
|
||||
|
||||
#include "espMqttClient.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
espMqttClient::espMqttClient()
|
||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO)
|
||||
, _client() {
|
||||
_transport = &_client;
|
||||
}
|
||||
|
||||
espMqttClientSecure::espMqttClientSecure()
|
||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO)
|
||||
, _client() {
|
||||
_transport = &_client;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setInsecure() {
|
||||
_client.client.setInsecure();
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setFingerprint(const uint8_t fingerprint[20]) {
|
||||
_client.client.setFingerprint(fingerprint);
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setTrustAnchors(const X509List * ta) {
|
||||
_client.client.setTrustAnchors(ta);
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setClientRSACert(const X509List * cert, const PrivateKey * sk) {
|
||||
_client.client.setClientRSACert(cert, sk);
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setClientECCert(const X509List * cert, const PrivateKey * sk, unsigned allowed_usages, unsigned cert_issuer_key_type) {
|
||||
_client.client.setClientECCert(cert, sk, allowed_usages, cert_issuer_key_type);
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setCertStore(CertStoreBase * certStore) {
|
||||
_client.client.setCertStore(certStore);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
espMqttClient::espMqttClient(espMqttClientTypes::UseInternalTask useInternalTask)
|
||||
: MqttClientSetup(useInternalTask)
|
||||
@@ -78,36 +34,35 @@ espMqttClientSecure::espMqttClientSecure(uint8_t priority, uint8_t core)
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setInsecure() {
|
||||
#if defined(EMC_CLIENT_SECURE)
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
_client.client.setInsecure();
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setCACert(const char * rootCA) {
|
||||
#if defined(EMC_CLIENT_SECURE)
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
_client.client.setCACert(rootCA);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setCertificate(const char * clientCa) {
|
||||
#if defined(EMC_CLIENT_SECURE)
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
_client.client.setCertificate(clientCa);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setPrivateKey(const char * privateKey) {
|
||||
#if defined(EMC_CLIENT_SECURE)
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
_client.client.setPrivateKey(privateKey);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setPreSharedKey(const char * pskIdent, const char * psKey) {
|
||||
#if defined(EMC_CLIENT_SECURE)
|
||||
_client.client.setPreSharedKey(pskIdent, psKey);
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
@@ -120,9 +75,4 @@ espMqttClient::espMqttClient()
|
||||
, _client() {
|
||||
_transport = &_client;
|
||||
}
|
||||
#elif defined(_WIN32) || defined(__APPLE__)
|
||||
// Windows
|
||||
espMqttClient::espMqttClient()
|
||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO) {
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -65,10 +65,16 @@ class espMqttClientSecure : public MqttClientSetup<espMqttClientSecure> {
|
||||
espMqttClientSecure & setPreSharedKey(const char * pskIdent, const char * psKey);
|
||||
|
||||
protected:
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
espMqttClientInternals::ClientSecureSync _client;
|
||||
#else
|
||||
espMqttClientInternals::ClientSync _client;
|
||||
#endif
|
||||
};
|
||||
|
||||
#elif defined(__linux__)
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
class espMqttClient : public MqttClientSetup<espMqttClient> {
|
||||
public:
|
||||
espMqttClient();
|
||||
@@ -76,10 +82,4 @@ class espMqttClient : public MqttClientSetup<espMqttClient> {
|
||||
protected:
|
||||
espMqttClientInternals::ClientPosix _client;
|
||||
};
|
||||
#elif defined(_WIN32) || defined(__APPLE__)
|
||||
class espMqttClient : public MqttClientSetup<espMqttClient> {
|
||||
public:
|
||||
espMqttClient();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -145,6 +145,7 @@ double ledcSetup(uint8_t chan, double freq, uint8_t bit_num) {
|
||||
return 0;
|
||||
};
|
||||
void ledcAttachPin(uint8_t pin, uint8_t chan) {};
|
||||
void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num) {};
|
||||
void ledcWrite(uint8_t chan, uint32_t duty) {};
|
||||
void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {};
|
||||
void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {};
|
||||
|
||||
@@ -72,6 +72,7 @@ void analogSetAttenuation(adc_attenuation_t attenuation);
|
||||
void dacWrite(uint8_t pin, uint8_t value);
|
||||
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num);
|
||||
void ledcAttachPin(uint8_t pin, uint8_t chan);
|
||||
void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num);
|
||||
void ledcWrite(uint8_t chan, uint32_t duty);
|
||||
void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val);
|
||||
void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val);
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
"@msgpack/msgpack": "^3.1.3",
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||
"formidable": "^3.5.4",
|
||||
"itty-router": "^5.0.22",
|
||||
"itty-router": "^5.0.23",
|
||||
"prettier": "^3.8.1"
|
||||
},
|
||||
"packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264"
|
||||
"packageManager": "pnpm@10.32.1+sha512.a706938f0e89ac1456b6563eab4edf1d1faf3368d1191fc5c59790e96dc918e4456ab2e67d613de1043d2e8c81f87303e6b40d4ffeca9df15ef1ad567348f2be"
|
||||
}
|
||||
|
||||
42
mock-api/pnpm-lock.yaml
generated
42
mock-api/pnpm-lock.yaml
generated
@@ -18,8 +18,8 @@ importers:
|
||||
specifier: ^3.5.4
|
||||
version: 3.5.4
|
||||
itty-router:
|
||||
specifier: ^5.0.22
|
||||
version: 5.0.22
|
||||
specifier: ^5.0.23
|
||||
version: 5.0.23
|
||||
prettier:
|
||||
specifier: ^3.8.1
|
||||
version: 3.8.1
|
||||
@@ -30,8 +30,8 @@ packages:
|
||||
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/generator@7.29.0':
|
||||
resolution: {integrity: sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==}
|
||||
'@babel/generator@7.29.1':
|
||||
resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-globals@7.28.0':
|
||||
@@ -46,8 +46,8 @@ packages:
|
||||
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/parser@7.29.0':
|
||||
resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==}
|
||||
'@babel/parser@7.29.2':
|
||||
resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -131,8 +131,8 @@ packages:
|
||||
resolution: {integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
itty-router@5.0.22:
|
||||
resolution: {integrity: sha512-9hmdGErWdYDOurGYxSbqLhy4EFReIwk71hMZTJ5b+zfa2zjMNV1ftFno2b8VjAQvX615gNB8Qxbl9JMRqHnIVA==}
|
||||
itty-router@5.0.23:
|
||||
resolution: {integrity: sha512-i49WU+SNPrwOZA4Z61En1RYd5h2Lcqa+5IvCpMrNi4dxymzJK15ozUUnRrWIUAv95Zamd4eJPAot2UvHRrQg7w==}
|
||||
|
||||
javascript-natural-sort@0.7.1:
|
||||
resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==}
|
||||
@@ -148,8 +148,8 @@ packages:
|
||||
lodash-es@4.17.23:
|
||||
resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==}
|
||||
|
||||
minimatch@9.0.5:
|
||||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||
minimatch@9.0.9:
|
||||
resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
ms@2.1.3:
|
||||
@@ -183,9 +183,9 @@ snapshots:
|
||||
js-tokens: 4.0.0
|
||||
picocolors: 1.1.1
|
||||
|
||||
'@babel/generator@7.29.0':
|
||||
'@babel/generator@7.29.1':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.0
|
||||
'@babel/parser': 7.29.2
|
||||
'@babel/types': 7.29.0
|
||||
'@jridgewell/gen-mapping': 0.3.13
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
@@ -197,22 +197,22 @@ snapshots:
|
||||
|
||||
'@babel/helper-validator-identifier@7.28.5': {}
|
||||
|
||||
'@babel/parser@7.29.0':
|
||||
'@babel/parser@7.29.2':
|
||||
dependencies:
|
||||
'@babel/types': 7.29.0
|
||||
|
||||
'@babel/template@7.28.6':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.29.0
|
||||
'@babel/parser': 7.29.0
|
||||
'@babel/parser': 7.29.2
|
||||
'@babel/types': 7.29.0
|
||||
|
||||
'@babel/traverse@7.29.0':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.29.0
|
||||
'@babel/generator': 7.29.0
|
||||
'@babel/generator': 7.29.1
|
||||
'@babel/helper-globals': 7.28.0
|
||||
'@babel/parser': 7.29.0
|
||||
'@babel/parser': 7.29.2
|
||||
'@babel/template': 7.28.6
|
||||
'@babel/types': 7.29.0
|
||||
debug: 4.4.3
|
||||
@@ -248,13 +248,13 @@ snapshots:
|
||||
|
||||
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.1)':
|
||||
dependencies:
|
||||
'@babel/generator': 7.29.0
|
||||
'@babel/parser': 7.29.0
|
||||
'@babel/generator': 7.29.1
|
||||
'@babel/parser': 7.29.2
|
||||
'@babel/traverse': 7.29.0
|
||||
'@babel/types': 7.29.0
|
||||
javascript-natural-sort: 0.7.1
|
||||
lodash-es: 4.17.23
|
||||
minimatch: 9.0.5
|
||||
minimatch: 9.0.9
|
||||
parse-imports-exports: 0.2.4
|
||||
prettier: 3.8.1
|
||||
transitivePeerDependencies:
|
||||
@@ -283,7 +283,7 @@ snapshots:
|
||||
dezalgo: 1.0.4
|
||||
once: 1.4.0
|
||||
|
||||
itty-router@5.0.22: {}
|
||||
itty-router@5.0.23: {}
|
||||
|
||||
javascript-natural-sort@0.7.1: {}
|
||||
|
||||
@@ -293,7 +293,7 @@ snapshots:
|
||||
|
||||
lodash-es@4.17.23: {}
|
||||
|
||||
minimatch@9.0.5:
|
||||
minimatch@9.0.9:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.2
|
||||
|
||||
|
||||
@@ -302,10 +302,10 @@ function updateMask(entity: any, de: any, dd: any) {
|
||||
const old_custom_name = dd.nodes[dd_objIndex].cn;
|
||||
console.log(
|
||||
'comparing names, old (' +
|
||||
old_custom_name +
|
||||
') with new (' +
|
||||
new_custom_name +
|
||||
')'
|
||||
old_custom_name +
|
||||
') with new (' +
|
||||
new_custom_name +
|
||||
')'
|
||||
);
|
||||
if (old_custom_name !== new_custom_name) {
|
||||
changed = true;
|
||||
@@ -363,6 +363,8 @@ function export_data(type: string) {
|
||||
return emsesp_modules;
|
||||
case 'allvalues':
|
||||
return emsesp_allvalues;
|
||||
case 'systembackup':
|
||||
return emsesp_systembackup;
|
||||
default:
|
||||
return status(404);
|
||||
}
|
||||
@@ -401,15 +403,15 @@ function check_upgrade(version: string) {
|
||||
|
||||
console.log(
|
||||
'Upgrade this version (' +
|
||||
THIS_VERSION +
|
||||
') to dev (' +
|
||||
dev_version +
|
||||
') is ' +
|
||||
(DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') +
|
||||
' and to stable (' +
|
||||
stable_version +
|
||||
') is ' +
|
||||
(STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO')
|
||||
THIS_VERSION +
|
||||
') to dev (' +
|
||||
dev_version +
|
||||
') is ' +
|
||||
(DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') +
|
||||
' and to stable (' +
|
||||
stable_version +
|
||||
') is ' +
|
||||
(STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO')
|
||||
);
|
||||
data = {
|
||||
emsesp_version: THIS_VERSION,
|
||||
@@ -732,6 +734,8 @@ const emsesp_info = {
|
||||
]
|
||||
};
|
||||
|
||||
const emsesp_systembackup = {};
|
||||
|
||||
const emsesp_allvalues = {
|
||||
'Boiler Nefit Trendline HRC30 (DeviceID:0x08, ProductID:123, Version:06.01)': {
|
||||
'force heating off': 'off',
|
||||
@@ -4564,7 +4568,7 @@ router
|
||||
let sorted_devices = [...emsesp_coredata.devices].sort((a, b) => a.t - b.t);
|
||||
// append emsesp_coredata to sorted_devices so Custom is always at the end of the list
|
||||
sorted_devices.push(emsesp_coredata_custom);
|
||||
// sorted_devices = []; // uncomment if simulating no devices...
|
||||
// return { connected: false, devices: [] }; // uncomment if simulating no devices...
|
||||
return { connected: true, devices: sorted_devices };
|
||||
})
|
||||
.get(EMSESP_SENSOR_DATA_ENDPOINT, () => {
|
||||
|
||||
@@ -15,15 +15,14 @@ description = EMS-ESP Firmware for the ESP32
|
||||
src_dir = src
|
||||
lib_dir = lib
|
||||
boards_dir = boards
|
||||
; build_cache_dir = .pio/build_cache
|
||||
|
||||
extra_configs =
|
||||
factory_settings.ini
|
||||
pio_local.ini
|
||||
|
||||
[common]
|
||||
core_build_flags = -std=c++17 -std=gnu++17 -O3 -flto=auto -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format
|
||||
core_unbuild_flags = -std=gnu++11 -fno-lto
|
||||
core_build_flags = -std=c++17 -std=gnu++17 -O3 -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format -Wno-missing-field-initializers
|
||||
core_unbuild_flags = -std=gnu++11
|
||||
|
||||
my_build_flags =
|
||||
|
||||
@@ -54,13 +53,21 @@ build_flags =
|
||||
unbuild_flags =
|
||||
${common.core_unbuild_flags}
|
||||
|
||||
; 4MB Flash variants
|
||||
[espressif32_base_4M]
|
||||
framework = arduino
|
||||
board_build.partitions = partitions/esp32_partition_4M.csv
|
||||
board_upload.flash_size = 4MB
|
||||
board_build.app_partition_name = app0
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.03.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.7 based on IDF 5.5.3.260313
|
||||
|
||||
; 16MB Flash variants
|
||||
[espressif32_base_16M]
|
||||
framework = arduino
|
||||
board_build.partitions = partitions/esp32_partition_16M.csv
|
||||
board_upload.flash_size = 16MB
|
||||
board_build.app_partition_name = app0
|
||||
platform = espressif32@6.12.0 ; Arduino Core 2.0.17 / IDF 4.4.7
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.03.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.7 based on IDF 5.5.3.260313
|
||||
|
||||
; 32MB Flash variants
|
||||
[espressif32_base_32M]
|
||||
@@ -68,29 +75,7 @@ framework = arduino
|
||||
board_build.partitions = partitions/esp32_partition_32M.csv
|
||||
board_upload.flash_size = 32MB
|
||||
board_build.app_partition_name = app0
|
||||
platform = espressif32@6.12.0 ; Arduino Core 2.0.17 / IDF 4.4.7
|
||||
|
||||
; use Tasmota's library for 4MB Flash variants.
|
||||
; Removes libs (like mbedtsl, so no WiFi_secure.h) to increase available heap
|
||||
[espressif32_base_T_4M]
|
||||
framework = arduino
|
||||
board_build.partitions = partitions/esp32_partition_4M.csv
|
||||
board_upload.flash_size = 4MB
|
||||
board_build.app_partition_name = app0
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ; Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
|
||||
; Tasmota Arduino Core 3.1.3.250302 based on IDF 5.3.2.250228
|
||||
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2025.03.30/platform-espressif32.zip
|
||||
|
||||
; use Tasmota's library for 16MB Flash variants.
|
||||
; Removes libs (like mbedtsl, so no WiFi_secure.h) to increase available heap
|
||||
[espressif32_base_T_16M]
|
||||
framework = arduino
|
||||
board_build.partitions = partitions/esp32_partition_16M.csv
|
||||
board_upload.flash_size = 16MB
|
||||
board_build.app_partition_name = app0
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ; Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
|
||||
; Tasmota Arduino Core 3.1.3.250302 based on IDF 5.3.2.250228
|
||||
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2025.03.30/platform-espressif32.zip
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.03.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.7 based on IDF 5.5.3.260313
|
||||
|
||||
[env]
|
||||
build_flags =
|
||||
@@ -106,9 +91,10 @@ board_build.filesystem = littlefs
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson @ 7.4.2
|
||||
ESP32Async/AsyncTCP @ 3.4.10
|
||||
ESP32Async/ESPAsyncWebServer @ 3.10.1
|
||||
https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
|
||||
|
||||
ESP32Async/ESPAsyncWebServer @ 3.10.3
|
||||
https://github.com/mobizt/ReadyMail.git @ 0.3.8
|
||||
https://github.com/mobizt/ESP_SSLClient.git @ 3.1.3
|
||||
; https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
|
||||
|
||||
; builds the web interface only, not the firmware
|
||||
[env:build_webUI]
|
||||
@@ -120,18 +106,17 @@ build_src_filter = -<*>
|
||||
|
||||
;
|
||||
; Builds for different board types
|
||||
; We use Tasmota for boards without PSRAM as this framework has mbedtls removed to save memory.
|
||||
; If you're building for a single target environment, we recommend creating a pio_local.ini (see example file)
|
||||
;
|
||||
|
||||
[env:s_4M]
|
||||
; 4MB ESP32 - no SSL, no PSRAM - like a BBQKees older S32 and E32 models - uses Tasmota
|
||||
extends = espressif32_base_T_4M
|
||||
; 4MB ESP32 - no SSL, no PSRAM - like a BBQKees older S32 and E32 models
|
||||
extends = espressif32_base_4M
|
||||
board = s_4M
|
||||
|
||||
[env:s_16M]
|
||||
; 16MB ESP32 - no PSRAM - like a BBQKees later S32 V2 models - uses Tasmota
|
||||
extends = espressif32_base_T_16M
|
||||
; 16MB ESP32 - no PSRAM - like a BBQKees later S32 V2 models
|
||||
extends = espressif32_base_16M
|
||||
board = s_16M
|
||||
|
||||
[env:s_16M_P]
|
||||
@@ -150,19 +135,19 @@ extends = espressif32_base_32M
|
||||
board = s3_32M_P
|
||||
|
||||
[env:s2_4M_P]
|
||||
; based on lolin_s2_mini 4MB with 2MB PSRAM - uses Tasmota
|
||||
extends = espressif32_base_T_4M
|
||||
; based on lolin_s2_mini 4MB with 2MB PSRAM
|
||||
extends = espressif32_base_4M
|
||||
board = s2_4M_P
|
||||
|
||||
[env:c3_mini_4M]
|
||||
; based on lolin_c3_mini 4MB, no PSRAM - uses Tasmota
|
||||
extends = espressif32_base_T_4M
|
||||
; based on lolin_c3_mini 4MB, no PSRAM
|
||||
extends = espressif32_base_4M
|
||||
board = c3_mini_4M
|
||||
|
||||
; lolin C3 mini v1 needs special wifi initialization
|
||||
; https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
||||
[env:c3_miniv1_4M]
|
||||
extends = espressif32_base_T_4M
|
||||
extends = espressif32_base_4M
|
||||
board = c3_mini_4M
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
@@ -174,8 +159,7 @@ framework = arduino
|
||||
board_build.partitions = partitions/esp32_partition_4M.csv
|
||||
board_upload.flash_size = 4MB
|
||||
board_build.app_partition_name = app0
|
||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.21-2/platform-espressif32.zip ; Arduino Release v3.2.1 based on ESP-IDF v5.4.2
|
||||
; platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip ; Arduino Release v3.3.0 based on ESP-IDF v5.5.0
|
||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip ; Arduino Release v3.3.0 based on ESP-IDF v5.5.0
|
||||
board = seeed_xiao_esp32c6
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
@@ -190,6 +174,7 @@ build_flags =
|
||||
build_src_flags =
|
||||
-DEMSESP_STANDALONE -DEMSESP_TEST
|
||||
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
|
||||
-DNO_TLS_SUPPORT
|
||||
-std=gnu++17 -Og -ggdb
|
||||
-Wall -Wextra
|
||||
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
|
||||
@@ -212,6 +197,8 @@ build_src_filter =
|
||||
-<../lib/uuid-syslog>
|
||||
-<../lib/eModbus>
|
||||
-<../lib/OneWire>
|
||||
-<../lib/mbedtls_ssl/src>
|
||||
-<../src/core/ModuleLibrary.cpp>
|
||||
lib_ldf_mode = off
|
||||
lib_deps =
|
||||
|
||||
@@ -228,6 +215,7 @@ build_src_flags =
|
||||
-DEMSESP_STANDALONE -DEMSESP_TEST
|
||||
-DEMSESP_UNITY
|
||||
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
|
||||
-DNO_TLS_SUPPORT
|
||||
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
||||
-std=gnu++17 -Og -ggdb
|
||||
-Wall -Wextra
|
||||
@@ -254,6 +242,8 @@ build_src_filter =
|
||||
-<../lib/uuid-syslog>
|
||||
-<../lib/eModbus>
|
||||
-<../lib/OneWire>
|
||||
-<../lib/mbedtls_ssl/src>
|
||||
-<../src/core/ModuleLibrary.cpp>
|
||||
lib_ldf_mode = off
|
||||
lib_deps = Unity
|
||||
test_testing_command =
|
||||
|
||||
@@ -6,6 +6,9 @@ abluftqualität
|
||||
abluftqualitätsfühler
|
||||
abrt
|
||||
absburnpow
|
||||
ACAC
|
||||
ACAH
|
||||
ACAO
|
||||
accomodate
|
||||
aceotrope
|
||||
activehigh
|
||||
@@ -64,7 +67,6 @@ asyncwebsocket
|
||||
asyncwebsynchronization
|
||||
atoint
|
||||
ausreichend
|
||||
außenluft
|
||||
authmode
|
||||
autodst
|
||||
automode
|
||||
@@ -82,6 +84,7 @@ auxheatmix
|
||||
auxheatrmode
|
||||
auxlimitstart
|
||||
auxmaxlimit
|
||||
außenluft
|
||||
avty
|
||||
awsc
|
||||
azubuike
|
||||
@@ -137,7 +140,6 @@ calinttemp
|
||||
catagory
|
||||
cbuf
|
||||
cerapur
|
||||
česky
|
||||
cfamily
|
||||
changeloglevel
|
||||
chargeduration
|
||||
@@ -192,6 +194,7 @@ controlmode
|
||||
coolingcircuit
|
||||
coolingon
|
||||
coolingstarts
|
||||
coolingtype
|
||||
cooloffdelay
|
||||
coolondelay
|
||||
coolstart
|
||||
@@ -669,12 +672,12 @@ lowpressure
|
||||
lowtopic
|
||||
lufqualität
|
||||
luft
|
||||
lüfterstufe
|
||||
luftfeuchte
|
||||
luftfeuchtefühler
|
||||
luftqualfühl
|
||||
lüftungsfrostschutz
|
||||
lukás
|
||||
lüfterstufe
|
||||
lüftungsfrostschutz
|
||||
maintenancedate
|
||||
maintenancemessage
|
||||
maintenancetime
|
||||
@@ -827,7 +830,6 @@ nwcl
|
||||
nystrom
|
||||
odata
|
||||
oddparity
|
||||
öffnen
|
||||
offsettemp
|
||||
offtemp
|
||||
oilpreheat
|
||||
@@ -942,6 +944,9 @@ rawstr
|
||||
rcplus
|
||||
readback
|
||||
readelf
|
||||
READYCLIENT
|
||||
readymail
|
||||
recp
|
||||
recved
|
||||
redtemp
|
||||
redthreshold
|
||||
@@ -1090,17 +1095,18 @@ staipassigned
|
||||
startshp
|
||||
starttemp
|
||||
starttemperature
|
||||
starttls
|
||||
startvalue
|
||||
statusbyte
|
||||
stickbreaker
|
||||
stoffregen
|
||||
stoptime
|
||||
storagetemp
|
||||
störung
|
||||
stringarray
|
||||
stringize
|
||||
studt
|
||||
studt's
|
||||
störung
|
||||
suback
|
||||
substract
|
||||
summermode
|
||||
@@ -1126,6 +1132,7 @@ switchtimeww
|
||||
sycle
|
||||
syspress
|
||||
sysrettemp
|
||||
systembackup
|
||||
systemstatus
|
||||
tado
|
||||
tapactivated
|
||||
@@ -1182,7 +1189,6 @@ trocken
|
||||
truefalse
|
||||
tsens
|
||||
tseslint
|
||||
türk
|
||||
turnoffdiff
|
||||
turnondiff
|
||||
txen
|
||||
@@ -1200,6 +1206,7 @@ typehh
|
||||
typeids
|
||||
typel
|
||||
typesafe
|
||||
türk
|
||||
uart
|
||||
ubauptime
|
||||
ucrt
|
||||
@@ -1252,7 +1259,6 @@ vorheizreg
|
||||
vpcooling
|
||||
vrey
|
||||
vybm
|
||||
wärmetauscher
|
||||
washingmachine
|
||||
watchid
|
||||
wayon
|
||||
@@ -1301,6 +1307,7 @@ wwtemp
|
||||
wwtemplow
|
||||
wwvacations
|
||||
wwwhenmodeoff
|
||||
wärmetauscher
|
||||
xclnt
|
||||
xiao
|
||||
xrtu
|
||||
@@ -1311,7 +1318,6 @@ yerger's
|
||||
yubox
|
||||
zadig
|
||||
zivanovic
|
||||
živanović
|
||||
zlcn
|
||||
zolder
|
||||
zqhi
|
||||
@@ -1321,6 +1327,6 @@ zuluftebläse
|
||||
zuluftgebläse
|
||||
zulufttemp
|
||||
zyxwvutsrqponmlkjihgfedcba
|
||||
ACAO
|
||||
ACAH
|
||||
ACAC
|
||||
öffnen
|
||||
česky
|
||||
živanović
|
||||
|
||||
@@ -10,7 +10,6 @@ APSettingsService::APSettingsService(AsyncWebServer * server, FS * fs, SecurityM
|
||||
, _reconfigureAp(false)
|
||||
, _connected(0) {
|
||||
addUpdateHandler([this] { reconfigureAP(); }, false);
|
||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||
}
|
||||
|
||||
void APSettingsService::begin() {
|
||||
@@ -19,39 +18,27 @@ void APSettingsService::begin() {
|
||||
// reconfigureAP();
|
||||
}
|
||||
|
||||
// wait 10 sec on STA disconnect before starting AP
|
||||
void APSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||
const uint8_t was_connected = _connected;
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
_connected &= ~1U;
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
_connected &= ~2U;
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||
_connected |= 1U;
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP6:
|
||||
_connected |= 2U;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
// wait 10 sec before starting AP
|
||||
if (was_connected && !_connected) {
|
||||
_lastManaged = uuid::get_uptime();
|
||||
}
|
||||
}
|
||||
|
||||
void APSettingsService::reconfigureAP() {
|
||||
_lastManaged = uuid::get_uptime() - MANAGE_NETWORK_DELAY;
|
||||
_reconfigureAp = true;
|
||||
}
|
||||
|
||||
void APSettingsService::loop() {
|
||||
const uint8_t was_connected = _connected;
|
||||
if (WiFi.isConnected()) {
|
||||
_connected |= 1U;
|
||||
} else {
|
||||
_connected &= ~1U;
|
||||
}
|
||||
if (ETH.connected()) {
|
||||
_connected |= 2U;
|
||||
} else {
|
||||
_connected &= ~2U;
|
||||
}
|
||||
// wait 10 sec before starting AP
|
||||
if (was_connected && !_connected) {
|
||||
_lastManaged = uuid::get_uptime();
|
||||
}
|
||||
const unsigned long currentMillis = uuid::get_uptime();
|
||||
if ((currentMillis - _lastManaged) >= MANAGE_NETWORK_DELAY) {
|
||||
_lastManaged = currentMillis;
|
||||
@@ -76,11 +63,7 @@ void APSettingsService::manageAP() {
|
||||
}
|
||||
|
||||
void APSettingsService::startAP() {
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
WiFi.softAPenableIpV6(); // force IPV6, same as for WiFi - fixes https://github.com/emsesp/EMS-ESP32/issues/1922
|
||||
#else
|
||||
WiFi.softAPenableIPv6(); // force IPV6, same as for WiFi - fixes https://github.com/emsesp/EMS-ESP32/issues/1922
|
||||
#endif
|
||||
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
|
||||
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_AP), WIFI_BW_HT20);
|
||||
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients);
|
||||
|
||||
@@ -70,9 +70,9 @@ class APSettings {
|
||||
IPAddress subnetMask;
|
||||
|
||||
bool operator==(const APSettings & settings) const {
|
||||
return provisionMode == settings.provisionMode && channel == settings.channel && ssidHidden == settings.ssidHidden
|
||||
&& maxClients == settings.maxClients && localIP == settings.localIP && gatewayIP == settings.gatewayIP
|
||||
&& subnetMask == settings.subnetMask && ssid == settings.ssid && password == settings.password;
|
||||
return provisionMode == settings.provisionMode && channel == settings.channel && ssidHidden == settings.ssidHidden && maxClients == settings.maxClients
|
||||
&& localIP == settings.localIP && gatewayIP == settings.gatewayIP && subnetMask == settings.subnetMask && ssid == settings.ssid
|
||||
&& password == settings.password;
|
||||
}
|
||||
|
||||
static void read(const APSettings & settings, JsonObject root);
|
||||
@@ -104,7 +104,6 @@ class APSettingsService : public StatefulService<APSettings> {
|
||||
void startAP();
|
||||
void stopAP();
|
||||
void handleDNS();
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -66,21 +66,16 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument & jsonDocument) {
|
||||
}
|
||||
|
||||
/*
|
||||
* ESP32 uses mbedtls, with decent HMAC implementations supporting sha256, as well as others.
|
||||
* No need to pull in additional crypto libraries - lets use what we already have.
|
||||
* HMAC-SHA256 using mbedtls
|
||||
*/
|
||||
String ArduinoJsonJWT::sign(String & payload) {
|
||||
std::array<unsigned char, 32> hmacResult{};
|
||||
{
|
||||
mbedtls_md_context_t ctx;
|
||||
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
||||
mbedtls_md_init(&ctx);
|
||||
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
|
||||
mbedtls_md_hmac_starts(&ctx, reinterpret_cast<const unsigned char *>(_secret.c_str()), _secret.length());
|
||||
mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char *>(payload.c_str()), payload.length());
|
||||
mbedtls_md_hmac_finish(&ctx, hmacResult.data());
|
||||
mbedtls_md_free(&ctx);
|
||||
}
|
||||
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
|
||||
reinterpret_cast<const unsigned char *>(_secret.c_str()),
|
||||
_secret.length(),
|
||||
reinterpret_cast<const unsigned char *>(payload.c_str()),
|
||||
payload.length(),
|
||||
hmacResult.data());
|
||||
return encode(reinterpret_cast<const char *>(hmacResult.data()), hmacResult.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -84,4 +84,5 @@ void ESP32React::loop() {
|
||||
_networkSettingsService.loop();
|
||||
_apSettingsService.loop();
|
||||
_mqttSettingsService.loop();
|
||||
_ntpSettingsService.loop();
|
||||
}
|
||||
@@ -9,7 +9,6 @@ MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, Secur
|
||||
, _disconnectedAt(0)
|
||||
, _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED)
|
||||
, _mqttClient(nullptr) {
|
||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||
addUpdateHandler([this] { onConfigUpdated(); }, false);
|
||||
}
|
||||
|
||||
@@ -29,6 +28,7 @@ MqttSettingsService::~MqttSettingsService() {
|
||||
void MqttSettingsService::begin() {
|
||||
_fsPersistence.readFromFS();
|
||||
startClient();
|
||||
_reconfigureMqtt = true;
|
||||
}
|
||||
|
||||
void MqttSettingsService::startClient() {
|
||||
@@ -41,7 +41,7 @@ void MqttSettingsService::startClient() {
|
||||
delete _mqttClient;
|
||||
_mqttClient = nullptr;
|
||||
}
|
||||
#ifndef TASMOTA_SDK
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
if (_state.enableTLS) {
|
||||
isSecure = true;
|
||||
if (emsesp::EMSESP::system_.PSram() == 0) {
|
||||
@@ -79,6 +79,10 @@ void MqttSettingsService::startClient() {
|
||||
}
|
||||
|
||||
void MqttSettingsService::loop() {
|
||||
if (_state.enabled && _mqttClient && _mqttClient->connected() && !emsesp::EMSESP::system_.network_connected()) {
|
||||
// emsesp::EMSESP::logger().info("Network connection dropped, stopping MQTT client");
|
||||
_mqttClient->disconnect(true);
|
||||
}
|
||||
if (_reconfigureMqtt || (_disconnectedAt && static_cast<uint32_t>(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
|
||||
// reconfigure MQTT client
|
||||
_disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime();
|
||||
@@ -142,28 +146,6 @@ void MqttSettingsService::onConfigUpdated() {
|
||||
emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings
|
||||
}
|
||||
|
||||
void MqttSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP6:
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||
if (_state.enabled && !_mqttClient->connected()) {
|
||||
onConfigUpdated();
|
||||
}
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
if (_state.enabled) {
|
||||
_mqttClient->disconnect(true);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MqttSettingsService::configureMqtt() {
|
||||
// disconnect if already connected
|
||||
if (_mqttClient->connected()) {
|
||||
@@ -182,7 +164,7 @@ bool MqttSettingsService::configureMqtt() {
|
||||
}
|
||||
|
||||
_reconfigureMqtt = false;
|
||||
#ifndef TASMOTA_SDK
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
if (_state.enableTLS) {
|
||||
if (_state.rootCA == "insecure") {
|
||||
emsesp::EMSESP::logger().debug("Start insecure MQTT");
|
||||
@@ -219,7 +201,7 @@ bool MqttSettingsService::configureMqtt() {
|
||||
}
|
||||
|
||||
void MqttSettings::read(MqttSettings & settings, JsonObject root) {
|
||||
#ifndef TASMOTA_SDK
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
root["enableTLS"] = settings.enableTLS;
|
||||
root["rootCA"] = settings.rootCA;
|
||||
#endif
|
||||
@@ -256,9 +238,9 @@ void MqttSettings::read(MqttSettings & settings, JsonObject root) {
|
||||
|
||||
StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings) {
|
||||
MqttSettings newSettings;
|
||||
bool changed = false;
|
||||
bool changed = false;
|
||||
|
||||
#ifndef TASMOTA_SDK
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
newSettings.enableTLS = root["enableTLS"];
|
||||
newSettings.rootCA = root["rootCA"] | "";
|
||||
#else
|
||||
@@ -389,7 +371,7 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
|
||||
emsesp::EMSESP::mqtt_.set_publish_time_heartbeat(newSettings.publish_time_heartbeat);
|
||||
}
|
||||
|
||||
#ifndef TASMOTA_SDK
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
// strip down to certificate only
|
||||
newSettings.rootCA.replace("\r", "");
|
||||
newSettings.rootCA.replace("\n", "");
|
||||
|
||||
@@ -134,7 +134,6 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
|
||||
// the MQTT client instance
|
||||
MqttClient * _mqttClient;
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
void onMqttConnect(bool sessionPresent);
|
||||
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
|
||||
void
|
||||
|
||||
@@ -11,7 +11,6 @@ NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, Securit
|
||||
configureTime(request, json);
|
||||
});
|
||||
|
||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||
addUpdateHandler([this] { configureNTP(); }, false);
|
||||
}
|
||||
|
||||
@@ -20,27 +19,10 @@ void NTPSettingsService::begin() {
|
||||
configureNTP();
|
||||
}
|
||||
|
||||
// handles both WiFI and Ethernet
|
||||
void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
if (_connected && emsesp::EMSESP::system_.ntp_connected()) {
|
||||
emsesp::EMSESP::logger().info("WiFi connection dropped, stopping NTP");
|
||||
_connected = false;
|
||||
configureNTP();
|
||||
}
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
// emsesp::EMSESP::logger().info("Got IP address, starting NTP synchronization");
|
||||
_connected = true;
|
||||
void NTPSettingsService::loop() {
|
||||
if (_connected != emsesp::EMSESP::system_.network_connected()) {
|
||||
_connected = emsesp::EMSESP::system_.network_connected();
|
||||
configureNTP();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +37,9 @@ void NTPSettingsService::configureNTP() {
|
||||
} else {
|
||||
setenv("TZ", _state.tzFormat.c_str(), 1);
|
||||
tzset();
|
||||
esp_sntp_stop();
|
||||
if (esp_sntp_enabled()) {
|
||||
esp_sntp_stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
|
||||
NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
|
||||
|
||||
void begin();
|
||||
void loop();
|
||||
static void ntp_received(struct timeval * tv);
|
||||
|
||||
private:
|
||||
@@ -51,7 +52,6 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
|
||||
FSPersistence<NTPSettings> _fsPersistence;
|
||||
volatile bool _connected;
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
void configureNTP();
|
||||
void configureTime(AsyncWebServerRequest * request, JsonVariant json);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs,
|
||||
, _stopping(false) {
|
||||
addUpdateHandler([this] { reconfigureWiFiConnection(); }, false);
|
||||
// Eth is also bound to the WifiGeneric event handler
|
||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event, info); });
|
||||
// Network.onEvent([this](arduino_event_id_t event, arduino_event_info_t info) { WiFiEvent(event, info); });
|
||||
}
|
||||
|
||||
static bool formatBssid(const String & bssid, uint8_t (&mac)[6]) {
|
||||
@@ -62,24 +62,118 @@ void NetworkSettingsService::loop() {
|
||||
_lastConnectionAttempt = currentMillis;
|
||||
manageSTA();
|
||||
}
|
||||
static uint8_t connect = 0;
|
||||
enum uint8_t {
|
||||
CONNECT_IDLE = 0,
|
||||
CONNECT_WAIT_ETH,
|
||||
CONNECT_WAIT_IP4,
|
||||
CONNECT_WAIT_ETH_IP4,
|
||||
CONNECT_WAIT_IP6,
|
||||
CONNECT_WAIT_ETH_IP6,
|
||||
CONNECT_ETH_ACTIVE,
|
||||
CONNECT_WIFI_ACTIVE
|
||||
};
|
||||
switch (connect) {
|
||||
default:
|
||||
connect = CONNECT_IDLE;
|
||||
break;
|
||||
case CONNECT_IDLE:
|
||||
if (ETH.started() && _state.ssid.length() == 0) {
|
||||
emsesp::EMSESP::logger().info("ETH started");
|
||||
ETH.enableIPv6(true);
|
||||
if (_state.staticIPConfig) {
|
||||
ETH.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2);
|
||||
}
|
||||
ETH.setHostname(emsesp::EMSESP::system_.hostname().c_str());
|
||||
connect = CONNECT_WAIT_ETH;
|
||||
}
|
||||
if (WiFi.isConnected()) {
|
||||
emsesp::EMSESP::logger().info("Wifi connected");
|
||||
if (_state.tx_power == 0) {
|
||||
setWiFiPowerOnRSSI();
|
||||
}
|
||||
mDNS_start();
|
||||
emsesp::EMSESP::system_.has_ipv6(true);
|
||||
connect = CONNECT_WAIT_IP4;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WAIT_ETH:
|
||||
if (ETH.connected()) {
|
||||
emsesp::EMSESP::logger().info("ETH connected");
|
||||
emsesp::EMSESP::system_.ethernet_connected(true);
|
||||
mDNS_start();
|
||||
emsesp::EMSESP::system_.has_ipv6(true);
|
||||
connect = CONNECT_WAIT_ETH_IP4;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WAIT_ETH_IP4:
|
||||
if (ETH.hasIP()) {
|
||||
emsesp::EMSESP::logger().info("Eth IPv4: %s", ETH.localIP().toString().c_str());
|
||||
connect = CONNECT_WAIT_ETH_IP6;
|
||||
}
|
||||
if (!ETH.connected()) {
|
||||
connect = CONNECT_ETH_ACTIVE;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WAIT_ETH_IP6:
|
||||
if (ETH.hasLinkLocalIPv6() && ETH.hasGlobalIPv6()) {
|
||||
emsesp::EMSESP::system_.has_ipv6(true);
|
||||
connect = CONNECT_ETH_ACTIVE;
|
||||
}
|
||||
if (!ETH.connected()) {
|
||||
connect = CONNECT_ETH_ACTIVE;
|
||||
}
|
||||
break;
|
||||
case CONNECT_ETH_ACTIVE:
|
||||
if (!ETH.connected()) {
|
||||
emsesp::EMSESP::logger().info("ETH disconnected");
|
||||
emsesp::EMSESP::system_.ethernet_connected(false);
|
||||
emsesp::EMSESP::system_.has_ipv6(false);
|
||||
connect = CONNECT_IDLE;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WAIT_IP4:
|
||||
if (!WiFi.localIP().toString().isEmpty()) {
|
||||
emsesp::EMSESP::logger().info("Wifi IPv4: %s", WiFi.localIP().toString().c_str());
|
||||
connect = CONNECT_WAIT_IP6;
|
||||
}
|
||||
if (!WiFi.isConnected()) {
|
||||
connect = CONNECT_ETH_ACTIVE;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WAIT_IP6:
|
||||
if (WiFi.linkLocalIPv6().toString() != "::" && WiFi.globalIPv6().toString() != "::") {
|
||||
emsesp::EMSESP::logger().info("Wifi IPv6: %s, %s", WiFi.linkLocalIPv6().toString().c_str(), WiFi.globalIPv6().toString().c_str());
|
||||
emsesp::EMSESP::system_.has_ipv6(true);
|
||||
connect = CONNECT_WIFI_ACTIVE;
|
||||
}
|
||||
if (!WiFi.isConnected()) {
|
||||
connect = CONNECT_WIFI_ACTIVE;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WIFI_ACTIVE:
|
||||
if (!WiFi.isConnected()) {
|
||||
emsesp::EMSESP::logger().info("WiFi disconnected");
|
||||
if (_stopping) {
|
||||
_lastConnectionAttempt = 0;
|
||||
_stopping = false;
|
||||
}
|
||||
emsesp::EMSESP::system_.has_ipv6(false);
|
||||
connect = CONNECT_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkSettingsService::manageSTA() {
|
||||
// Abort if already connected, or if we have no SSID
|
||||
if (WiFi.isConnected() || _state.ssid.length() == 0) {
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
if (_state.ssid.length() == 0) {
|
||||
ETH.enableIPv6(true);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// Connect or reconnect as required
|
||||
if ((WiFi.getMode() & WIFI_STA) == 0) {
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
WiFi.enableIPv6(true);
|
||||
#endif
|
||||
if (_state.staticIPConfig) {
|
||||
WiFi.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2); // configure for static IP
|
||||
}
|
||||
@@ -293,7 +387,7 @@ const char * NetworkSettingsService::disconnectReason(uint8_t code) {
|
||||
}
|
||||
|
||||
// handles both WiFI and Ethernet
|
||||
void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
void NetworkSettingsService::WiFiEvent(arduino_event_id_t event, arduino_event_info_t info) {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
|
||||
switch (event) {
|
||||
@@ -305,7 +399,7 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
connectcount_++; // count the number of WiFi reconnects
|
||||
connectcount_ = connectcount_ + 1; // count the number of WiFi reconnects
|
||||
emsesp::EMSESP::logger().warning("WiFi disconnected (#%d). Reason: %s (%d)",
|
||||
connectcount_,
|
||||
disconnectReason(info.wifi_sta_disconnected.reason),
|
||||
@@ -360,25 +454,15 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
|
||||
if (_state.tx_power == 0) {
|
||||
setWiFiPowerOnRSSI();
|
||||
}
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
WiFi.enableIpV6(); // force ipv6
|
||||
#endif
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
ETH.enableIpV6(); // force ipv6
|
||||
#endif
|
||||
break;
|
||||
|
||||
// IPv6 specific - WiFi/Eth
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP6: {
|
||||
#if !TASMOTA_SDK && ESP_IDF_VERSION_MAJOR < 5
|
||||
auto ip6 = IPv6Address((uint8_t *)info.got_ip6.ip6_info.ip.addr).toString();
|
||||
#else
|
||||
auto ip6 = IPAddress(IPv6, (uint8_t *)info.got_ip6.ip6_info.ip.addr, 0).toString();
|
||||
#endif
|
||||
auto ip6 = IPAddress(IPv6, (uint8_t *)info.got_ip6.ip6_info.ip.addr, 0).toString();
|
||||
const char * link = event == ARDUINO_EVENT_ETH_GOT_IP6 ? "Eth" : "WiFi";
|
||||
if (ip6.startsWith("fe80")) {
|
||||
emsesp::EMSESP::logger().info("IPv6 (%s) local: %s", link, ip6.c_str());
|
||||
|
||||
@@ -107,7 +107,7 @@ class NetworkSettingsService : public StatefulService<NetworkSettings> {
|
||||
|
||||
volatile uint16_t connectcount_ = 0; // number of wifi reconnects
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
void WiFiEvent(arduino_event_id_t event, arduino_event_info_t info);
|
||||
void mDNS_start() const;
|
||||
const char * disconnectReason(uint8_t code);
|
||||
void reconfigureWiFiConnection();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <emsesp.h>
|
||||
|
||||
#ifdef TASMOTA_SDK
|
||||
#ifdef NO_TLS_SUPPORT
|
||||
#include "lwip/dns.h"
|
||||
#endif
|
||||
|
||||
@@ -31,22 +31,13 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
||||
// for both connections show ethernet
|
||||
if (ethernet_connected) {
|
||||
// Ethernet
|
||||
root["local_ip"] = ETH.localIP().toString();
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
root["local_ipv6"] = ETH.localIPv6().toString();
|
||||
#else
|
||||
root["local_ipv6"] = ETH.linkLocalIPv6().toString();
|
||||
#endif
|
||||
root["local_ip"] = ETH.localIP().toString();
|
||||
root["local_ipv6"] = ETH.linkLocalIPv6().toString();
|
||||
root["mac_address"] = ETH.macAddress();
|
||||
root["subnet_mask"] = ETH.subnetMask().toString();
|
||||
root["gateway_ip"] = ETH.gatewayIP().toString();
|
||||
#ifdef TASMOTA_SDK
|
||||
IPAddress dnsIP1 = IPAddress(dns_getserver(0));
|
||||
IPAddress dnsIP2 = IPAddress(dns_getserver(1));
|
||||
#else
|
||||
IPAddress dnsIP1 = ETH.dnsIP(0);
|
||||
IPAddress dnsIP2 = ETH.dnsIP(1);
|
||||
#endif
|
||||
IPAddress dnsIP1 = ETH.dnsIP(0);
|
||||
IPAddress dnsIP2 = ETH.dnsIP(1);
|
||||
if (IPUtils::isSet(dnsIP1)) {
|
||||
root["dns_ip_1"] = dnsIP1.toString();
|
||||
}
|
||||
@@ -54,12 +45,8 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
||||
root["dns_ip_2"] = dnsIP2.toString();
|
||||
}
|
||||
} else if (wifi_status == WL_CONNECTED) {
|
||||
root["local_ip"] = WiFi.localIP().toString();
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
root["local_ipv6"] = WiFi.localIPv6().toString();
|
||||
#else
|
||||
root["local_ipv6"] = WiFi.linkLocalIPv6().toString();
|
||||
#endif
|
||||
root["local_ip"] = WiFi.localIP().toString();
|
||||
root["local_ipv6"] = WiFi.linkLocalIPv6().toString();
|
||||
root["mac_address"] = WiFi.macAddress();
|
||||
root["rssi"] = WiFi.RSSI();
|
||||
root["ssid"] = WiFi.SSID();
|
||||
@@ -71,14 +58,8 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
||||
if (WiFi.gatewayIP() != INADDR_NONE) {
|
||||
root["gateway_ip"] = WiFi.gatewayIP().toString();
|
||||
}
|
||||
|
||||
#ifdef TASMOTA_SDK
|
||||
IPAddress dnsIP1 = IPAddress(dns_getserver(0));
|
||||
IPAddress dnsIP2 = IPAddress(dns_getserver(1));
|
||||
#else
|
||||
IPAddress dnsIP1 = WiFi.dnsIP(0);
|
||||
IPAddress dnsIP2 = WiFi.dnsIP(1);
|
||||
#endif
|
||||
if (dnsIP1 != INADDR_NONE) {
|
||||
root["dns_ip_1"] = dnsIP1.toString();
|
||||
}
|
||||
|
||||
31
src/core/ModuleLibrary.cpp
Normal file
31
src/core/ModuleLibrary.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020-2025 emsesp.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <emsesp.h>
|
||||
|
||||
void ModuleLibrary::list(JsonObject output) {};
|
||||
|
||||
void ModuleLibrary::loop() {};
|
||||
|
||||
void ModuleLibrary::start(emsesp::EMSESP * emsesp_main, bool test_mode) {};
|
||||
|
||||
bool ModuleLibrary::enable(const char * key, const char * license, bool enable) {
|
||||
return true;
|
||||
};
|
||||
52
src/core/ModuleLibrary.h
Normal file
52
src/core/ModuleLibrary.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020-2025 emsesp.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MODULELIBRARY_H
|
||||
#define MODULELIBRARY_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <emsesp.h>
|
||||
|
||||
class ModuleLibrary {
|
||||
public:
|
||||
class Modules {
|
||||
public:
|
||||
Modules(const char * key, std::unique_ptr<Module> module)
|
||||
: key(key)
|
||||
, module(std::move(module)) {
|
||||
}
|
||||
const char * key;
|
||||
std::unique_ptr<Module> module;
|
||||
};
|
||||
|
||||
void start(emsesp::EMSESP * emsesp_main, bool test_mode = false);
|
||||
void loop();
|
||||
void list(JsonObject output);
|
||||
bool enable(const char * key, const char * license, bool enable);
|
||||
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
private:
|
||||
std::vector<Modules> modules_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -346,23 +346,13 @@ void AnalogSensor::reload(bool get_nvs) {
|
||||
sensor.polltime_ = sensor.value() != 0 ? uuid::get_uptime() + (sensor.factor() * 1000) : 0;
|
||||
} else if (sensor.type() >= AnalogType::PWM_0 && sensor.type() <= AnalogType::PWM_2) {
|
||||
LOG_DEBUG("PWM output on GPIO %02d", sensor.gpio());
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
ledcAttach(sensor.gpio(), sensor.factor(), 13);
|
||||
#else
|
||||
uint8_t channel = sensor.type() - AnalogType::PWM_0;
|
||||
ledcSetup(channel, sensor.factor(), 13);
|
||||
ledcAttachPin(sensor.gpio(), channel);
|
||||
#endif
|
||||
if (sensor.offset() > 100) {
|
||||
sensor.set_offset(100);
|
||||
} else if (sensor.offset() < 0) {
|
||||
sensor.set_offset(0);
|
||||
}
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
ledcWrite(sensor.gpio(), (uint32_t)(sensor.offset() * 8191 / 100));
|
||||
#else
|
||||
ledcWrite(channel, (uint32_t)(sensor.offset() * 8191 / 100));
|
||||
#endif
|
||||
sensor.set_value(sensor.offset());
|
||||
sensor.set_uom(DeviceValueUOM::PERCENT);
|
||||
publish_sensor(sensor);
|
||||
@@ -896,9 +886,9 @@ std::string AnalogSensor::get_metrics_prometheus() {
|
||||
result += (std::string) "\n# TYPE emsesp_" + sensor.name() + " gauge\n";
|
||||
result += (std::string) "emsesp_" + sensor.name() + " ";
|
||||
if (sensor.type() != AnalogType::DIGITAL_OUT && sensor.type() != AnalogType::DIGITAL_IN) {
|
||||
result += (std::string) Helpers::render_value(val, sensor.value(), 2) + "\n";
|
||||
result += (std::string)Helpers::render_value(val, sensor.value(), 2) + "\n";
|
||||
} else {
|
||||
result += (std::string) (sensor.value() == 0 ? "0\n" : "1\n");
|
||||
result += (std::string)(sensor.value() == 0 ? "0\n" : "1\n");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -1040,12 +1030,7 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) {
|
||||
}
|
||||
sensor.set_offset(val);
|
||||
sensor.set_value(val);
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
ledcWrite(sensor.gpio(), (uint32_t)(sensor.offset() * 8191 / 100));
|
||||
#else
|
||||
uint8_t channel = sensor.type() - AnalogType::PWM_0;
|
||||
ledcWrite(channel, (uint32_t)(val * 8191 / 100));
|
||||
#endif
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -293,12 +293,9 @@ enum {
|
||||
#ifndef STRINGIZE
|
||||
#define STRINGIZE(s) #s
|
||||
#endif
|
||||
#ifdef TASMOTA_SDK
|
||||
|
||||
#define ARDUINO_VERSION_STR(major, minor, patch) "Tasmota Arduino v" STRINGIZE(major) "." STRINGIZE(minor) "." STRINGIZE(patch)
|
||||
#else
|
||||
#define ARDUINO_VERSION_STR(major, minor, patch) "ESP32 Arduino v" STRINGIZE(major) "." STRINGIZE(minor) "." STRINGIZE(patch)
|
||||
#endif
|
||||
#define ARDUINO_VERSION ARDUINO_VERSION_STR(ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -84,7 +84,7 @@ uuid::log::Logger EMSESP::logger() {
|
||||
RxService EMSESP::rxservice_; // incoming Telegram Rx handler
|
||||
TxService EMSESP::txservice_; // outgoing Telegram Tx handler
|
||||
Mqtt EMSESP::mqtt_; // mqtt handler
|
||||
Modbus * EMSESP::modbus_; // modbus handler
|
||||
Modbus * EMSESP::modbus_ = nullptr; // modbus handler
|
||||
System EMSESP::system_; // core system services
|
||||
TemperatureSensor EMSESP::temperaturesensor_; // Temperature sensors
|
||||
AnalogSensor EMSESP::analogsensor_; // Analog sensors
|
||||
@@ -1802,12 +1802,6 @@ void EMSESP::start() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// start services
|
||||
if (system_.modbus_enabled()) {
|
||||
modbus_ = new Modbus;
|
||||
modbus_->start(1, system_.modbus_port(), system_.modbus_max_clients(), system_.modbus_timeout() * 1000);
|
||||
}
|
||||
|
||||
mqtt_.start(); // mqtt init
|
||||
system_.start(); // starts commands, led, adc, button, network (sets hostname), syslog & uart
|
||||
shower_.start(); // initialize shower timer and shower alert
|
||||
|
||||
@@ -86,6 +86,6 @@ using string_vector = std::vector<const char *>;
|
||||
|
||||
// Translation count - dynamically calculated at compile-time
|
||||
enum { EMSESP_TRANSLATION_COUNT_END = __COUNTER__ };
|
||||
static constexpr uint16_t EMSESP_TRANSLATION_COUNT = EMSESP_TRANSLATION_COUNT_END - EMSESP_TRANSLATION_COUNT_START - 1;
|
||||
static constexpr uint16_t EMSESP_TRANSLATION_COUNT = static_cast<int>(EMSESP_TRANSLATION_COUNT_END) - static_cast<int>(EMSESP_TRANSLATION_COUNT_START) - 1;
|
||||
|
||||
#endif
|
||||
@@ -20,7 +20,7 @@
|
||||
#define EMSESP_HELPERS_H
|
||||
|
||||
#include "telegram.h" // for EMS_VALUE_* settings
|
||||
#include "common.h"
|
||||
#include "emsesp_common.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ MAKE_WORD(raw)
|
||||
MAKE_WORD(watch)
|
||||
MAKE_WORD(syslog)
|
||||
MAKE_WORD(send)
|
||||
MAKE_WORD(sendmail)
|
||||
MAKE_WORD(telegram)
|
||||
MAKE_WORD(bus_id)
|
||||
MAKE_WORD(tx_mode)
|
||||
|
||||
@@ -32,10 +32,10 @@
|
||||
#define EMSESP_LOCALE_SK "sk"
|
||||
#define EMSESP_LOCALE_CZ "cz"
|
||||
|
||||
// IMPORTANT! translations are in the order:,en, de, nl, sv, pl, no, fr, tr, it, sk, cz
|
||||
// IMPORTANT! translations are in the order: en, de, nl, sv, pl, no, fr, tr, it, sk, cz
|
||||
//
|
||||
// if there is no translation, it will default to en
|
||||
//
|
||||
|
||||
// device types, as display in Web and Console
|
||||
MAKE_WORD_TRANSLATION(boiler_hp_device, "Boiler/HP", "Kessel/WP", "CV ketel/WP", "Värmepanna/VP", "Kocioł/PC", "Varmekjele/VP", "Chaudière/PC", "Kazan/IP", "Caldaia/PC", "Kotol/TČ", "Kotel/TČ")
|
||||
MAKE_WORD_TRANSLATION(boiler_device, "Boiler", "Kessel", "CV ketel", "Värmepanna", "Kocioł", "Varmekjele", "Chaudière", "Kazan", "Caldaia", "Kotol", "Kotel")
|
||||
@@ -65,6 +65,7 @@ MAKE_WORD_TRANSLATION(commands_cmd, "list all commands", "Liste aller Kommandos"
|
||||
MAKE_WORD_TRANSLATION(entities_cmd, "list all entities", "Liste aller Entitäten", "lijst van alle entiteiten", "lista all entiteter", "wyświetl wszsytkie encje", "Viser alle enheter", "lister toutes les entités", "Tüm varlıkları listele", "elenca tutte le entità", "zobraziť všetky entity", "vypsat všechny entity")
|
||||
MAKE_WORD_TRANSLATION(metrics_cmd, "list all prometheus metrics", "Liste aller Prometheus Metriken", "lijst van alle Prometheus metriken", "lista alla Prometheus metriker", "wyświetl wszystkie Prometheus metryki", "Viser alle Prometheus metrikker", "lister toutes les métriques Prometheus", "Tüm Prometheus metriklerini listele", "elenca tutte le metriche Prometheus", "zobraziť všetky Prometheus metriky", "vypsat všechny Prometheus metriky")
|
||||
MAKE_WORD_TRANSLATION(send_cmd, "send a telegram", "Sende EMS-Telegramm", "stuur een telegram", "skicka ett telegram", "wyślij telegram", "send et telegram", "envoyer un télégramme", "Bir telegram gönder", "invia un telegramma", "poslať telegram", "odeslat telegram")
|
||||
MAKE_WORD_TRANSLATION(sendmail_cmd, "send email", "Sende eMail", "stuur email", "skicka email", "wyślij email", "send e-post", "envoyer un email", "email gönder", "invia email", "poslať email", "odeslat email")
|
||||
MAKE_WORD_TRANSLATION(read_cmd, "send read request", "Sende Leseanfrage", "stuur leesaanvraag", "skicka en läsförfrågan", "wyślij żądanie odczytu", "send leseforespørsel", "envoyer une demande de lecture", "okuma isteği gönder", "invia richiesta di lettura", "odoslať žiadosť o prečítanie", "odeslat požadavek na čtení")
|
||||
MAKE_WORD_TRANSLATION(setiovalue_cmd, "set I/O value", "Setze Werte E/A", "instellen standaardwaarde", "sätt ett I/O-värde", "ustaw wartość", "sett en io verdi", "définir valeur E/S", "Giriş/Çıkış değerlerini ayarla", "imposta valore io", "nastaviť hodnotu io", "nastavit hodnotu I/O")
|
||||
MAKE_WORD_TRANSLATION(changeloglevel_cmd, "change log level", "Ändere Protokollebene", "aanpassen log niveau", "ändra logg-nivå", "zmień poziom log-u", "endre loggnivå", "changer le niveau de journal", "Kayıt seviyesini değiştir", "cambia livello registrazione", "zmeniť úroveň protokolu", "změnit úroveň protokolování")
|
||||
@@ -104,6 +105,7 @@ MAKE_WORD_TRANSLATION(tag_dhw7, "dhw7", "WWK7", "dhw7", "VVK7", "CWU7", "dhw7",
|
||||
MAKE_WORD_TRANSLATION(tag_dhw8, "dhw8", "WWK8", "dhw8", "VVK8", "CWU8", "dhw8", "ecs8", "SKS8", "dhw8", "TÚV8", "TUV8")
|
||||
MAKE_WORD_TRANSLATION(tag_dhw9, "dhw9", "WWK9", "dhw9", "VVK9", "CWU9", "dhw9", "ecs9", "SKS9", "dhw9", "TÚV9", "TUV9")
|
||||
MAKE_WORD_TRANSLATION(tag_dhw10, "dhw10", "WWK10", "dhw10", "VVK10", "CWU10", "dhw10", "ecs10", "SKS10", "dhw10", "TÚV10", "TUV10")
|
||||
|
||||
// heatingsources
|
||||
MAKE_WORD_TRANSLATION(tag_ahs1, "ahs1", "AHQ1", "ahs1", "AVK1", "AŹC1", "ahs1", "ahs1", "ahs1", "ahs1", "ahs1", "ahs1")
|
||||
MAKE_WORD_TRANSLATION(tag_hs1, "hs1", "HQ1", "hs1", "VK1", "ŹC1", "hs1", "hs1", "hs1", "hs1", "hs1", "hs1")
|
||||
@@ -122,6 +124,7 @@ MAKE_WORD_TRANSLATION(tag_hs13, "hs13", "HQ13", "hs13", "VK13", "ŹC13", "hs13",
|
||||
MAKE_WORD_TRANSLATION(tag_hs14, "hs14", "HQ14", "hs14", "VK14", "ŹC14", "hs14", "hs14", "hs14", "hs14", "hs14", "hs14")
|
||||
MAKE_WORD_TRANSLATION(tag_hs15, "hs15", "HQ15", "hs15", "VK15", "ŹC15", "hs15", "hs15", "hs15", "hs15", "hs15", "hs15")
|
||||
MAKE_WORD_TRANSLATION(tag_hs16, "hs16", "HQ16", "hs16", "VK16", "ŹC16", "hs16", "hs16", "hs16", "hs16", "hs16", "hs16")
|
||||
|
||||
// single room thermostats
|
||||
MAKE_WORD_TRANSLATION(tag_src1, "src1", "SRC1")
|
||||
MAKE_WORD_TRANSLATION(tag_src2, "src2", "SRC2")
|
||||
@@ -426,11 +429,9 @@ MAKE_TRANSLATION(pumpCharacter, "pumpcharacter", "boiler pump characteristic", "
|
||||
MAKE_TRANSLATION(pumpOnTemp, "pumpontemp", "pump logic temperature", "Pumpenlogiktemperatur", "pomplogica temperatuur", "Pumplogiktemperatur", "temperatura logiki pompy", "pumpelogikktemperatur", "température logique pompe", "pompa mantık sıcaklığı", "temperatura logica pompa", "teplota logiky čerpadla", "teplota logiky čerpadla")
|
||||
MAKE_TRANSLATION(headertemp, "headertemp", "low loss header", "Hydr. Weiche", "open verdeler", "Fördelare", "sprzęgło hydrauliczne", "lav tap header", "bouteille de déc. hydr.", "isı bloğu gidiş suyu sıc.", "comp. idr.", "nízkostratová hlavica", "hydraulický oddělovač")
|
||||
MAKE_TRANSLATION(heatblock, "heatblock", "heating block", "Wärmezelle", "Aanvoertemp. warmtecel", "Värmeblock", "blok grzewczy", "varmeblokk", "départ corps de chauffe", "Hid.denge kabı sıcaklığı", "mandata scamb. pr.", "vykurovací blok", "blok topení")
|
||||
|
||||
MAKE_TRANSLATION(pumpKickHour, "pumpkickhour", "pump kick hour", "Stunde Pumpkick")
|
||||
MAKE_TRANSLATION(pumpKickDay, "pumpkickday", "pump kick day", "Tag Pumpkick")
|
||||
MAKE_TRANSLATION(pumpKickDelay, "pumpkickdelay", "pump kick delay", "Pause vor Pumpkick")
|
||||
|
||||
MAKE_TRANSLATION(curveOn, "curveon", "heatingcurve on", "Heizkurve an", "stookkromme aan", "Värmekurva På", "krzywa grzewcza włączona", "varmekurve på", "courbe de chauffage activée", "ısıtma eğrisi açık", "curva di riscaldamento attiva", "vykurovacia krivka zapnutá", "topná křivka zapnutá")
|
||||
MAKE_TRANSLATION(curveBase, "curvebase", "heatingcurve base", "Heizkurve Basis", "stookkromme basis", "Värmekurva Bas", "podstawa krzywej grzewczej", "varmekurve basis", "base de courbe de chauffage", "ısıtma eğrisi tabanı", "base curva di riscaldamento", "základňa vykurovacej krivky", "základ topné křivky")
|
||||
MAKE_TRANSLATION(curveEnd, "curveend", "heatingcurve end", "Heizkurve Ende", "stookkromme einde", "Värmekurva Slut", "koniec krzywej grzewczej", "varmekurve slutt", "fin de courbe de chauffage", "ısıtma eğrisi sonu", "fine curva di riscaldamento", "koniec vykurovacej krivky", "konec topné křivky")
|
||||
@@ -478,7 +479,6 @@ MAKE_TRANSLATION(hpActivity, "hpactivity", "compressor activity", "Kompressorakt
|
||||
MAKE_TRANSLATION(hpTargetSpd, "hptargetspd", "compressor target speed", "Kompressorsolldrehzahl", "", "", "", "", "", "", "", "kompresor cieľové otáčky", "cílová rychlost kompresoru")
|
||||
MAKE_TRANSLATION(receiverValveVr0, "recvalve", "receiver valve VR0", "Eingangsventil VR0", "", "", "", "", "", "", "", "prijímač ventil VR0", "přijímací ventil VR0")
|
||||
MAKE_TRANSLATION(expansionValveVr1, "expvalve", "expansion valve VR1", "Ausdehnungsventil VR1", "", "", "", "", "", "", "", "prijímač ventil VR1", "přijímací ventil VR1")
|
||||
|
||||
MAKE_TRANSLATION(hpMaxPower, "hpmaxpower", "compressor max power", "max. Kompressorleistung", "", "Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "max výkon kompresora", "maximální výkon kompresoru")
|
||||
MAKE_TRANSLATION(pvMaxComp, "pvmaxcomp", "pv compressor max power", "PV max. Kompressorleistung", "", "PV Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "pv max výkon kompresora", "maximální výkon PV kompresoru")
|
||||
MAKE_TRANSLATION(hpPower, "hppower", "compressor power output", "Kompressorleistung", "Compressorvermogen", "Kompressoreffekt", "moc wyjściowa sprężarki", "kompressoreffekt", "puissance de sortie compresseur", "ısı pompası güç çıkışı", "potenza uscita compressore", "výkon kompresora", "výstupní výkon kompresoru")
|
||||
@@ -496,7 +496,6 @@ MAKE_TRANSLATION(hpPl1, "hppl1", "low pressure side temperature (PL1)", "Niederd
|
||||
MAKE_TRANSLATION(hpPh1, "hpph1", "high pressure side temperature (PH1)", "Hochdrucktemperatur (PH1)", "Temperatuur hoge drukzijde (PH1)", "Temperatur Högtryckssidan (PH1)", "temperatura po stronie wysokiego ciśnienia (PH1)", "Temperatur Høytrykksiden (PH1)", "température côté bhauteasse pression (PH1)", "yüksek basınç tarafı sıcaklığı (PH1)", "temperatura lato alta pressione (PH1)", "teplota na strane vysokého tlaku (PH1)", "teplota na vysokotlaké straně (PH1)")
|
||||
MAKE_TRANSLATION(hpTa4, "hpta4", "drain pan temp (TA4)", "Kondensatorwanne (TA4)", "Temperatuur condensorafvoerbak (TA4)", " (TA4)", "temperatura ociekacza (TA4)", "kondenstråg temperatur (TA4)", " (TA4)", "tahliye sıcaklığı (TA4)", "temperatura condensatore (TA4)", "teplota vypúšťacej misky (TA4)", "teplota odvodňovací vany (TA4)")
|
||||
MAKE_TRANSLATION(hpTw1, "hptw1", "reservoir temp (TW1)", "DHW Reservoir (TW1)", "(TW1)", "Varmvattentank Temperatur (TW1)", "temperatura zbiornika (TW1)", "(TW1)", "(TW1)", "(TW1)", "(TW1)", "teplota zásobníka (TW1)", "teplota v nádrži (TW1)")
|
||||
|
||||
MAKE_TRANSLATION(hpInput1, "hpin1", "input 1 state", "Status Eingang 1", "Status input 1", "Status Ingång 1", "stan wejścia 1", "status inggang 1", "état entrée 1", "giriş 1 durumu", "stato ingresso 1", "stav vstupu 1", "stav vstupu 1")
|
||||
MAKE_TRANSLATION(hpInput2, "hpin2", "input 2 state", "Status Eingang 2", "Status input 2", "Status Ingång 2", "stan wejścia 2", "status inggang 2", "état entrée 2", "giriş 2 durumu", "stato ingresso 2", "stav vstupu 2", "stav vstupu 2")
|
||||
MAKE_TRANSLATION(hpInput3, "hpin3", "input 3 state", "Status Eingang 3", "Status input 3", "Status Ingång 3", "stan wejścia 3", "status inggang 3", "état entrée 3", "giriş 3 durumu", "stato ingresso 3", "stav vstupu 3", "stav vstupu 3")
|
||||
@@ -508,7 +507,6 @@ MAKE_TRANSLATION(hpIn4Opt, "hpin4opt", "input 4 options", "Einstellung Eingang 4
|
||||
MAKE_TRANSLATION(maxHeatComp, "maxheatcomp", "heat limit compressor", "Heizstab Limit mit Kompressor", "heat limit compressor", "Max. Värmegräns Kompressor", "ograniczenie mocy sprężarki", "max varmegrense kompressor", "limite chaleur compresseur", "ısı pompası ısıtma sınırı", "limite riscaldamento compressore", "tepelný limit kompresora", "tepelný limit kompresoru")
|
||||
MAKE_TRANSLATION(maxHeatHeat, "maxheatheat", "heat limit heating", "Heizstab Limit Leistung", "Max, Värmegräns Uppvärmning", "heat limit heating", "ograniczenie mocy w trybie ogrzewania", "maks varmegrense oppvarming", "limite chaleur chauffage", "ısınma ısıtma sınırı", "limite calore riscaldamento", "vyhrievanie limitu tepla", "tepelný limit topení")
|
||||
MAKE_TRANSLATION(maxHeatDhw, "maxheat", "heat limit", "Heizstab Limit für WW", "heat limit", "Max. Värmegräns Varmvatten", "ograniczenie mocy w trybie c.w.u.", "varmegrense", "limite chaleur", "sıcak kullanım suyu ısınma sınırı", "limite calore", "tepelný limit", "tepelný limit")
|
||||
|
||||
MAKE_TRANSLATION(auxHeaterOff, "auxheateroff", "disable aux heater", "Zusatzheizer deaktivieren", "Bijverwarming uitsc", "Blockera eltillskott", "wyłącz dogrzewacz", "deaktiver tilleggsvarme", "Désactiver chauff. d'app", "ilave ısıtıcıyı kapat", "disattivare i riscaldatori addizionali", "vypnúť pomocný ohrievač", "zakázat pomocné topení")
|
||||
MAKE_TRANSLATION(auxHeaterStatus, "auxheaterstatus", "aux heater status", "Zusatzheizerstatus", "Bijverwarming", "Eltillskott Status", "status dogrzewacza", "status el. tillegsvarme", "Chauffage auxiliaire", "ilave ısıtıcı durumu", "stato riscaldatori addizionali", "stav pomocného ohrievača", "stav pomocného topení")
|
||||
MAKE_TRANSLATION(auxHeaterLevel, "auxheaterlevel", "aux heater level", "Zusatzheizer", "Bijverwarming", "Eltillskott", "dogrzewacza", "el. tillegsvarme", "Chauffage auxiliaire", "ilave ısıtıcı durumu", "riscaldatori addizionali", "pomocného ohrievača", "pomocného topení")
|
||||
@@ -525,7 +523,6 @@ MAKE_TRANSLATION(tempDiffHeat, "tempdiffheat", "temp diff TC3/TC0 heat", "Temp.d
|
||||
MAKE_TRANSLATION(tempDiffCool, "tempdiffcool", "temp diff TC3/TC0 cool", "Temp.diff. TC3/TC0 Kühlen", "Temp.vers. TC3/TC0 koel.", "Temperaturskillnad TC3/TC0 Kyla", "różnica temperatur TC3/TC0 w trakcie chłodzenia", "temp. diff. TC3/TC0 kjøling", "Delta T TC3/TC0 Refroid.", "TC3-TC0 soğutma sıcaklık farkı", "Delta T raffreddamento TC3/TC0", "teplotný rozdiel TC3/TC0 chladenie", "rozdíl teplot TC3/TC0 pro chlazení")
|
||||
MAKE_TRANSLATION(silentFrom, "silentfrom", "silent mode from", "Silentmodus Start", "Start stille modus", "Tyst drift starttid", "początek trybu cichego", "stillemodus starter", "", "sessiz mod başlangıcı", "avvio della modalità silenziosa", "tichý režim od", "tichý režim od")
|
||||
MAKE_TRANSLATION(silentTo, "silentto", "silent mode to", "Silentmodus Ende", "Einde stille modus", "Tyst drift stopptid", "koniec trybu cichego", "komfortmodus av", "", "sessiz mod bitişi", "spegnere modalità silenziosa", "tichý režim do", "tichý režim do")
|
||||
|
||||
MAKE_TRANSLATION(wwComfOffTemp, "comfoff", "comfort switch off", "Komfort Ausschalttemp.", "Comfort Uitschakeltemp.", "Komfort frånkopplingstemperatur", "temperatura wyłączania w trybie komfort", "eco modus utkoblingstem", "Confort Temp. d'arrêt", "konfor kapalı", "spegnimento modalità comfort", "komfortné vypnutie", "komfortní vypnutí")
|
||||
MAKE_TRANSLATION(wwEcoOffTemp, "ecooff", "eco switch off", "ECO Ausschalttemp.", "Eco Uitschakeltemp.", "Eko frånkopplingstemperatur", "temperatura wyłączania w trybie eko", "Øko avstengningstemp.", "Eco Temp. d'arrêt", "eko kapalı", "spegnimento modalità ECO", "eko vypínač", "eko vypnutí")
|
||||
MAKE_TRANSLATION(wwEcoPlusOffTemp, "ecoplusoff", "eco+ switch off", "ECO+ Ausschalttemp.", "Eco+ Uitschakeltemp.", "Eko+ frånkopplingstemperatur", "temperatura wyłączania w trybie eko+", "Øko+ avstengningstemp.", "Eco+ Temp. d'arrêt", "eko+ kapalı", "spegnimento modalità ECO+", "eko+ vypnutie", "eko+ vypnutí")
|
||||
@@ -535,7 +532,6 @@ MAKE_TRANSLATION(wwEcoPlusDiffTemp, "ecoplusdiff", "eco+ diff", "ECO+ Differenzt
|
||||
MAKE_TRANSLATION(wwComfStopTemp, "comfstop", "comfort stop temp", "Komfort Stopptemp.", "", "Komfort stopptemperatur", "", "", "", "", "", "komfortná stop teplota", "komfortní teplota vypnutí")
|
||||
MAKE_TRANSLATION(wwEcoStopTemp, "ecostop", "eco stop temp", "ECO Stopptemp.", "", "Eko stopptemperatur", "", "", "", "", "", "ECO stop teplota", "eko teplota vypnutí")
|
||||
MAKE_TRANSLATION(wwEcoPlusStopTemp, "ecoplusstop", "eco+ stop temp", "ECO+ Stopptemp.", "", "Eko+ stopptemperatur", "", "", "", "", "", "ECO+ stop teplota", "eko+ teplota vypnutí")
|
||||
|
||||
MAKE_TRANSLATION(auxHeatMode, "auxheatrmode", "aux heater mode", "Zusatzheizungsmodus", "Modus bijverwarmer", "Eltillskott Läge", "tryb pracy dogrzewacza po blokadzie z Zakładu Energetycznego", "tilleggsvarmer modus", "", "ilave ısıtıcı modu", "modalità riscaldatore addizionale", "režim pomocného ohrievača", "režim pomocného topení")
|
||||
MAKE_TRANSLATION(auxMaxLimit, "auxmaxlimit", "aux heater max limit", "Zusatzheizer max. Grenze", "Bijverwarmer grensinstelling maximaal", "Eltillskott max begränsning", "dogrzewacz, maksymalny limit", "tillegsvarme maksgrense", "ilave ısıtıcı maks limit", "limite massimo riscaldatore addizionale", "maximálny limit pomocného ohrievača", "maximální limit pomocného topení")
|
||||
MAKE_TRANSLATION(auxLimitStart, "auxlimitstart", "aux heater limit start", "Zusatzheizer Grenze Start", "Bijverwarmer grens voor start", "Eltillskott begränsningsstart", "dogrzewacz, początek ograniczenia", "tillegsvarme startgrense", "ilave ısıtıcı limir başlangıcı", "avvio limite massimo riscaldatore addizionale", "spustenie limitu pomocného ohrievača", "startovací limit pomocného topení")
|
||||
@@ -832,7 +828,6 @@ MAKE_TRANSLATION(absent, "absent", "absent", "Abwesend", "", "Frånvarande", "",
|
||||
MAKE_TRANSLATION(redthreshold, "redthreshold", "reduction threshold", "Absenkschwelle", "", "Tröskel för sänkning", "", "", "", "", "", "zníženie tresholdu", "práh snížení")
|
||||
MAKE_TRANSLATION(solarinfl, "solarinfl", "solar influence", "Solareinfluß", "", "", "", "", "", "", "", "slnečný vplyv", "sluneční vliv")
|
||||
MAKE_TRANSLATION(currsolarinfl, "currsolarinfl", "current solar influence", "akt. Solareinfluß", "", "", "", "", "", "", "", "aktuálny slnečný vplyv", "aktuální sluneční vliv")
|
||||
|
||||
MAKE_TRANSLATION(hpmode, "hpmode", "HP Mode", "WP-Modus", "Modus warmtepomp", "Värmepumpsläge", "tryb pracy pompy ciepła", "", "", "yüksek güç modu", "Modalità Termopompa", "Režim TČ", "režim tepelného čerpadla")
|
||||
MAKE_TRANSLATION(dewoffset, "dewoffset", "dew point offset", "Taupunktdifferenz", "Offset dauwpunt", "Daggpunktsförskjutning", "przesunięcie punktu rosy", "", "", "çiğ noktası göreli", "differenza del punto di rugiada", "posun rosného bodu", "offset rosného bodu")
|
||||
MAKE_TRANSLATION(roomtempdiff, "roomtempdiff", "room temp difference", "Raumtemperaturdifferenz", "Verschiltemperatuur kamertemp", "Rumstemperaturskillnad", "różnica temp. pomieszczenia", "", "", "oda sıcaklığı farkı", "differenza temperatura ambiente", "rozdiel izbovej teploty", "rozdíl teploty místnosti")
|
||||
|
||||
@@ -52,7 +52,7 @@ void Modbus::stop() {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
modbusServer_->stop();
|
||||
// virtual ~ModbusServerTCPasync() = default;
|
||||
// delete modbusServer_;
|
||||
delete modbusServer_;
|
||||
modbusServer_ = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1184,7 +1184,8 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "temperature";
|
||||
// override uom if fahrenheit
|
||||
doc[uom_ha] = EMSESP::system_.fahrenheit() ? DeviceValue::DeviceValueUOM_s[DeviceValueUOM::FAHRENHEIT] : DeviceValue::DeviceValueUOM_s[uom];
|
||||
doc[uom_ha] = EMSESP::system_.fahrenheit() && uom != DeviceValueUOM::K ? DeviceValue::DeviceValueUOM_s[DeviceValueUOM::FAHRENHEIT]
|
||||
: DeviceValue::DeviceValueUOM_s[uom];
|
||||
break;
|
||||
case DeviceValueUOM::PERCENT:
|
||||
if (display_only) {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "emsesp.h" // for send_raw_telegram() command
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_partition.h"
|
||||
#endif
|
||||
@@ -52,6 +53,15 @@
|
||||
#include <esp_mac.h>
|
||||
#endif
|
||||
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
#define ENABLE_SMTP
|
||||
#define USE_ESP_SSLCLIENT
|
||||
#define READYCLIENT_SSL_CLIENT ESP_SSLClient
|
||||
#define READYCLIENT_TYPE_1 // TYPE 1 when using ESP_SSLClient
|
||||
#include <ESP_SSLClient.h>
|
||||
#include <ReadyMail.h>
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
#include "esp_efuse.h"
|
||||
#endif
|
||||
@@ -124,6 +134,110 @@ bool System::command_send(const char * value, const int8_t id) {
|
||||
return EMSESP::txservice_.send_raw(value); // ignore id
|
||||
}
|
||||
|
||||
bool System::command_sendmail(const char * value, const int8_t id) {
|
||||
bool enabled = false;
|
||||
bool ssl, starttls;
|
||||
uint16_t port;
|
||||
String server, login, pass, sender, recp, subject;
|
||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||
enabled = settings.email_enabled;
|
||||
ssl = settings.email_ssl;
|
||||
starttls = settings.email_starttls;
|
||||
server = settings.email_server;
|
||||
port = settings.email_port;
|
||||
login = settings.email_login;
|
||||
pass = settings.email_pass;
|
||||
sender = settings.email_sender;
|
||||
recp = settings.email_recp;
|
||||
subject = settings.email_subject;
|
||||
});
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
LOG_DEBUG("Command sendmail port %d%s called with '%s'", port, ssl ? " (SSL)" : starttls ? " (STARTTLS)" : "", value);
|
||||
// LOG_DEBUG("Command sendmail port %d called with '%s'", port, value);
|
||||
bool success = false;
|
||||
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
WiFiClient * basic_client;
|
||||
ESP_SSLClient * ssl_client;
|
||||
ReadyClient * r_client; // rClient(ssl_client);
|
||||
SMTPClient * smtp; // smtp(rClient);
|
||||
basic_client = new WiFiClient;
|
||||
ssl_client = new ESP_SSLClient;
|
||||
r_client = new ReadyClient(*ssl_client);
|
||||
smtp = new SMTPClient(*r_client);
|
||||
|
||||
ssl_client->setClient(basic_client);
|
||||
ssl_client->setInsecure();
|
||||
ssl_client->setBufferSizes(1024, 1024);
|
||||
r_client->addPort(port, starttls ? readymail_protocol_tls : ssl ? readymail_protocol_ssl : readymail_protocol_plain_text);
|
||||
|
||||
// smtp->connect(server, port, sendmailCallback);
|
||||
smtp->connect(server, port);
|
||||
if (!smtp->isConnected()) {
|
||||
LOG_ERROR("Sendmail connection error");
|
||||
delete smtp;
|
||||
delete r_client;
|
||||
delete ssl_client;
|
||||
delete basic_client;
|
||||
return false;
|
||||
}
|
||||
|
||||
// LOG_INFO("authenticate %s:%s", login.c_str(), pass.c_str());
|
||||
smtp->authenticate(login, pass, readymail_auth_password);
|
||||
if (!smtp->isAuthenticated()) {
|
||||
LOG_ERROR("Sendmail authenticate error");
|
||||
delete smtp;
|
||||
delete r_client;
|
||||
delete ssl_client;
|
||||
delete basic_client;
|
||||
return false;
|
||||
}
|
||||
JsonDocument doc;
|
||||
String body = value;
|
||||
if (body.length()) {
|
||||
auto error = deserializeJson(doc, (const char *)value);
|
||||
if (!error && doc.as<JsonObject>().size() >= 0) {
|
||||
subject = doc["subject"] | subject;
|
||||
recp = doc["to"] | recp;
|
||||
sender = doc["from"] | sender;
|
||||
body = doc["body"] | body;
|
||||
}
|
||||
}
|
||||
|
||||
SMTPMessage & msg = smtp->getMessage();
|
||||
msg.headers.add(rfc822_subject, subject);
|
||||
msg.headers.add(rfc822_from, sender);
|
||||
msg.headers.add(rfc822_to, recp);
|
||||
|
||||
// Use addCustom to add custom header e.g. Importance and Priority.
|
||||
// msg.headers.addCustom("Importance", PRIORITY);
|
||||
// msg.headers.addCustom("X-MSMail-Priority", PRIORITY);
|
||||
// msg.headers.addCustom("X-Priority", PRIORITY_NUM);
|
||||
|
||||
msg.text.body(body);
|
||||
|
||||
// bodyText.replace("\r\n", "<br>\r\n");
|
||||
// msg.html.body("<html><body><div style=\"color:#cc0066;\">" + bodyText + "</div></body></html>");
|
||||
// msg.html.transferEncoding("base64");
|
||||
|
||||
// With embedFile function, the html message will send as attachment.
|
||||
// if (EMBED_MESSAGE)
|
||||
// msg.html.embedFile(true, "msg.html", embed_message_type_attachment);
|
||||
|
||||
msg.timestamp = time(nullptr);
|
||||
|
||||
success = smtp->send(msg);
|
||||
|
||||
delete smtp;
|
||||
delete r_client;
|
||||
delete ssl_client;
|
||||
delete basic_client;
|
||||
#endif
|
||||
return success;
|
||||
}
|
||||
|
||||
// return string of languages and count
|
||||
std::string System::languages_string() {
|
||||
std::string languages_string = std::to_string(NUM_LANGUAGES) + " languages (";
|
||||
@@ -356,7 +470,13 @@ void System::get_partition_info() {
|
||||
strftime(time_string, sizeof(time_string), "%FT%T", localtime(&d));
|
||||
p_info.install_date = d > 1500000000L ? time_string : "";
|
||||
|
||||
p_info.size = part->size / 1024; // set size in KB
|
||||
esp_image_metadata_t meta = {};
|
||||
esp_partition_pos_t part_pos = {.offset = part->address, .size = part->size};
|
||||
if (esp_image_verify(ESP_IMAGE_VERIFY_SILENT, &part_pos, &meta) == ESP_OK) {
|
||||
p_info.size = meta.image_len / 1024; // actual firmware size in KB
|
||||
} else {
|
||||
p_info.size = 0;
|
||||
}
|
||||
|
||||
partition_info_[part->label] = p_info;
|
||||
}
|
||||
@@ -380,7 +500,7 @@ void System::set_partition_install_date() {
|
||||
snprintf(c, sizeof(c), "d_%s", current_partition);
|
||||
time_t d = EMSESP::nvs_.getULong(c, 0);
|
||||
if (d < 1500000000L) {
|
||||
LOG_INFO("Firmware is fresh, setting the new install date in partition %s", current_partition);
|
||||
LOG_DEBUG("Setting the install date in partition %s", current_partition);
|
||||
auto t = time(nullptr) - uuid::get_uptime_sec();
|
||||
EMSESP::nvs_.putULong(c, t);
|
||||
}
|
||||
@@ -556,11 +676,6 @@ void System::store_settings(WebSettings & settings) {
|
||||
board_profile_ = settings.board_profile;
|
||||
telnet_enabled_ = settings.telnet_enabled;
|
||||
|
||||
modbus_enabled_ = settings.modbus_enabled;
|
||||
modbus_port_ = settings.modbus_port;
|
||||
modbus_max_clients_ = settings.modbus_max_clients;
|
||||
modbus_timeout_ = settings.modbus_timeout;
|
||||
|
||||
tx_mode_ = settings.tx_mode;
|
||||
syslog_enabled_ = settings.syslog_enabled;
|
||||
syslog_level_ = settings.syslog_level;
|
||||
@@ -581,6 +696,24 @@ void System::store_settings(WebSettings & settings) {
|
||||
|
||||
locale_ = settings.locale;
|
||||
developer_mode_ = settings.developer_mode;
|
||||
// start services
|
||||
if (settings.modbus_enabled) {
|
||||
if (EMSESP::modbus_ == nullptr) {
|
||||
EMSESP::modbus_ = new Modbus;
|
||||
EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000);
|
||||
} else if (settings.modbus_port != modbus_port_ || settings.modbus_max_clients != modbus_max_clients_ || settings.modbus_timeout != modbus_timeout_) {
|
||||
EMSESP::modbus_->stop();
|
||||
EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000);
|
||||
}
|
||||
} else if (EMSESP::modbus_ != nullptr) {
|
||||
EMSESP::modbus_->stop();
|
||||
delete EMSESP::modbus_;
|
||||
EMSESP::modbus_ = nullptr;
|
||||
}
|
||||
modbus_enabled_ = settings.modbus_enabled;
|
||||
modbus_port_ = settings.modbus_port;
|
||||
modbus_max_clients_ = settings.modbus_max_clients;
|
||||
modbus_timeout_ = settings.modbus_timeout;
|
||||
}
|
||||
|
||||
// Starts up core services
|
||||
@@ -604,20 +737,11 @@ void System::start() {
|
||||
appfree_ = esp_ota_get_running_partition()->size / 1024 - appused_;
|
||||
refreshHeapMem(); // refresh free heap and max alloc heap
|
||||
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
temp_sensor_config_t temp_sensor = TSENS_CONFIG_DEFAULT();
|
||||
temp_sensor_get_config(&temp_sensor);
|
||||
temp_sensor.dac_offset = TSENS_DAC_DEFAULT; // DEFAULT: range:-10℃ ~ 80℃, error < 1℃.
|
||||
temp_sensor_set_config(temp_sensor);
|
||||
temp_sensor_start();
|
||||
temp_sensor_read_celsius(&temperature_);
|
||||
#else
|
||||
temperature_sensor_config_t temp_sensor_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
|
||||
temperature_sensor_install(&temp_sensor_config, &temperature_handle_);
|
||||
temperature_sensor_enable(temperature_handle_);
|
||||
temperature_sensor_get_celsius(temperature_handle_, &temperature_);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
EMSESP::esp32React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
|
||||
@@ -838,16 +962,9 @@ void System::send_info_mqtt() {
|
||||
doc["IPv4 gateway"] = uuid::printable_to_string(WiFi.gatewayIP());
|
||||
doc["IPv4 nameserver"] = uuid::printable_to_string(WiFi.dnsIP());
|
||||
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
if (WiFi.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.localIPv6().toString() != "::") {
|
||||
doc["IPv6 address"] = uuid::printable_to_string(WiFi.localIPv6());
|
||||
}
|
||||
#else
|
||||
if (WiFi.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.linkLocalIPv6().toString() != "::") {
|
||||
doc["IPv6 address"] = uuid::printable_to_string(WiFi.linkLocalIPv6());
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
Mqtt::queue_publish_retain(F_(info), doc.as<JsonObject>()); // topic called "info" and it's Retained
|
||||
@@ -956,13 +1073,8 @@ void System::network_init() {
|
||||
delay(500);
|
||||
digitalWrite(eth_power_, HIGH);
|
||||
}
|
||||
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
eth_present_ = ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode);
|
||||
#else
|
||||
eth_present_ = ETH.begin(type, phy_addr, mdc, mdio, power, clock_mode);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// check health of system, done every 5 seconds
|
||||
@@ -973,13 +1085,9 @@ void System::system_check() {
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
temp_sensor_read_celsius(&temperature_);
|
||||
#else
|
||||
temperature_sensor_get_celsius(temperature_handle_, &temperature_);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef EMSESP_PINGTEST
|
||||
static uint64_t ping_count = 0;
|
||||
@@ -1031,6 +1139,7 @@ void System::commands_init() {
|
||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(read), System::command_read, FL_(read_cmd), CommandFlag::ADMIN_ONLY);
|
||||
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);
|
||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(sendmail), System::command_sendmail, FL_(sendmail_cmd), CommandFlag::ADMIN_ONLY);
|
||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, FL_(restart_cmd), CommandFlag::ADMIN_ONLY);
|
||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(format), System::command_format, FL_(format_cmd), CommandFlag::ADMIN_ONLY);
|
||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(txpause), System::command_txpause, FL_(txpause_cmd), CommandFlag::ADMIN_ONLY);
|
||||
@@ -1234,7 +1343,7 @@ void System::show_system(uuid::console::Shell & shell) {
|
||||
partition.first.c_str(),
|
||||
partition.second.version.c_str(),
|
||||
partition.second.size,
|
||||
partition.second.install_date.empty() ? "" : (std::string(", installed ") + partition.second.install_date).c_str(),
|
||||
partition.second.install_date.empty() ? "" : (std::string(", installed on ") + partition.second.install_date).c_str(),
|
||||
(strcmp(esp_ota_get_running_partition()->label, partition.first.c_str()) == 0) ? "** active **" : "");
|
||||
}
|
||||
|
||||
@@ -1265,16 +1374,9 @@ void System::show_system(uuid::console::Shell & shell) {
|
||||
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(WiFi.localIP()).c_str(), uuid::printable_to_string(WiFi.subnetMask()).c_str());
|
||||
shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(WiFi.gatewayIP()).c_str());
|
||||
shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(WiFi.dnsIP()).c_str());
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
if (WiFi.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.localIPv6().toString() != "::") {
|
||||
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(WiFi.localIPv6()).c_str());
|
||||
}
|
||||
#else
|
||||
if (WiFi.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.linkLocalIPv6().toString() != "::") {
|
||||
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(WiFi.linkLocalIPv6()).c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
case WL_CONNECT_FAILED:
|
||||
@@ -1305,15 +1407,9 @@ void System::show_system(uuid::console::Shell & shell) {
|
||||
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(ETH.localIP()).c_str(), uuid::printable_to_string(ETH.subnetMask()).c_str());
|
||||
shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(ETH.gatewayIP()).c_str());
|
||||
shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(ETH.dnsIP()).c_str());
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
if (ETH.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && ETH.localIPv6().toString() != "::") {
|
||||
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(ETH.localIPv6()).c_str());
|
||||
}
|
||||
#else
|
||||
if (ETH.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && ETH.linkLocalIPv6().toString() != "::") {
|
||||
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(ETH.linkLocalIPv6()).c_str());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
shell.println();
|
||||
|
||||
@@ -1353,23 +1449,59 @@ bool System::check_restore() {
|
||||
JsonObject input = jsonDocument.as<JsonObject>();
|
||||
// see what type of file it is, either settings or customization. anything else is ignored
|
||||
std::string settings_type = input["type"];
|
||||
|
||||
// system backup, which is a consolidated json object with all the settings files
|
||||
if (settings_type == "systembackup") {
|
||||
JsonArray sections = input["systembackup"].to<JsonArray>();
|
||||
for (JsonObject section : sections) {
|
||||
std::string section_type = section["type"];
|
||||
if (section_type == "settings") {
|
||||
reboot_required = saveSettings(NETWORK_SETTINGS_FILE, section);
|
||||
reboot_required |= saveSettings(AP_SETTINGS_FILE, section);
|
||||
reboot_required |= saveSettings(MQTT_SETTINGS_FILE, section);
|
||||
reboot_required |= saveSettings(NTP_SETTINGS_FILE, section);
|
||||
reboot_required |= saveSettings(SECURITY_SETTINGS_FILE, section);
|
||||
reboot_required |= saveSettings(EMSESP_SETTINGS_FILE, section);
|
||||
}
|
||||
if (section_type == "schedule") {
|
||||
reboot_required = saveSettings(EMSESP_SCHEDULER_FILE, section);
|
||||
}
|
||||
if (section_type == "customizations") {
|
||||
reboot_required = saveSettings(EMSESP_CUSTOMIZATION_FILE, section);
|
||||
}
|
||||
if (section_type == "entities") {
|
||||
reboot_required = saveSettings(EMSESP_CUSTOMENTITY_FILE, section);
|
||||
}
|
||||
if (section_type == "modules") {
|
||||
reboot_required = saveSettings(EMSESP_MODULES_FILE, section);
|
||||
}
|
||||
if (section_type == "customSupport") {
|
||||
// it's a custom support file - save it to /config
|
||||
new_file.close();
|
||||
if (LittleFS.rename(TEMP_FILENAME_PATH, EMSESP_CUSTOMSUPPORT_FILE)) {
|
||||
LOG_INFO("Custom support file stored");
|
||||
return false; // no need to reboot
|
||||
} else {
|
||||
LOG_ERROR("Failed to save custom support file");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It's a settings file. Parse each section separately. If it's system related it will require a reboot
|
||||
if (settings_type == "settings") {
|
||||
// It's a settings file. Parse each section separately. If it's system related it will require a reboot
|
||||
reboot_required = saveSettings(NETWORK_SETTINGS_FILE, "Network", input);
|
||||
reboot_required |= saveSettings(AP_SETTINGS_FILE, "AP", input);
|
||||
reboot_required |= saveSettings(MQTT_SETTINGS_FILE, "MQTT", input);
|
||||
reboot_required |= saveSettings(NTP_SETTINGS_FILE, "NTP", input);
|
||||
reboot_required |= saveSettings(SECURITY_SETTINGS_FILE, "Security", input);
|
||||
reboot_required |= saveSettings(EMSESP_SETTINGS_FILE, "Settings", input);
|
||||
reboot_required = saveSettings(NETWORK_SETTINGS_FILE, input);
|
||||
reboot_required |= saveSettings(AP_SETTINGS_FILE, input);
|
||||
reboot_required |= saveSettings(MQTT_SETTINGS_FILE, input);
|
||||
reboot_required |= saveSettings(NTP_SETTINGS_FILE, input);
|
||||
reboot_required |= saveSettings(SECURITY_SETTINGS_FILE, input);
|
||||
reboot_required |= saveSettings(EMSESP_SETTINGS_FILE, input);
|
||||
} else if (settings_type == "customizations") {
|
||||
// it's a customization file, just replace it and there's no need to reboot
|
||||
saveSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", input);
|
||||
saveSettings(EMSESP_CUSTOMIZATION_FILE, input);
|
||||
} else if (settings_type == "schedule") {
|
||||
// it's a schedule file, just replace it and there's no need to reboot
|
||||
saveSettings(EMSESP_SCHEDULER_FILE, "Schedule", input);
|
||||
saveSettings(EMSESP_SCHEDULER_FILE, input);
|
||||
} else if (settings_type == "entities") {
|
||||
// it's a entity file, just replace it and there's no need to reboot
|
||||
saveSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", input);
|
||||
saveSettings(EMSESP_CUSTOMENTITY_FILE, input);
|
||||
} else if (settings_type == "customSupport") {
|
||||
// it's a custom support file - save it to /config
|
||||
new_file.close();
|
||||
@@ -1527,39 +1659,122 @@ bool System::check_upgrade() {
|
||||
return false; // no reboot required
|
||||
}
|
||||
|
||||
// convert settings file into json object
|
||||
void System::extractSettings(const char * filename, const char * section, JsonObject output) {
|
||||
// map each config filename to its human-readable section key
|
||||
static const std::pair<const char *, const char *> SECTION_MAP[] = {
|
||||
{NETWORK_SETTINGS_FILE, "Network"},
|
||||
{AP_SETTINGS_FILE, "AP"},
|
||||
{MQTT_SETTINGS_FILE, "MQTT"},
|
||||
{NTP_SETTINGS_FILE, "NTP"},
|
||||
{SECURITY_SETTINGS_FILE, "Security"},
|
||||
{EMSESP_SETTINGS_FILE, "Settings"},
|
||||
{EMSESP_SCHEDULER_FILE, "Schedule"},
|
||||
{EMSESP_CUSTOMIZATION_FILE, "Customizations"},
|
||||
{EMSESP_CUSTOMENTITY_FILE, "Entities"},
|
||||
{EMSESP_MODULES_FILE, "Modules"},
|
||||
};
|
||||
|
||||
// convert a single config file into a section of the output json object
|
||||
void System::exportSettings(const std::string & type, const char * filename, JsonObject output) {
|
||||
if (type != "settings") {
|
||||
output["type"] = type; // add the type to the output, not for settings as it's already added because its grouped
|
||||
}
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
const char * section = nullptr;
|
||||
for (const auto & [f, label] : SECTION_MAP) {
|
||||
if (strcmp(f, filename) == 0) {
|
||||
section = label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!section) {
|
||||
return;
|
||||
}
|
||||
|
||||
File settingsFile = LittleFS.open(filename);
|
||||
if (settingsFile) {
|
||||
JsonDocument jsonDocument;
|
||||
DeserializationError error = deserializeJson(jsonDocument, settingsFile);
|
||||
if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) {
|
||||
JsonObject jsonObject = jsonDocument.as<JsonObject>();
|
||||
JsonObject node = output[section].to<JsonObject>();
|
||||
for (JsonPair kvp : jsonObject) {
|
||||
JsonObject node = output[section].to<JsonObject>();
|
||||
for (JsonPair kvp : jsonDocument.as<JsonObject>()) {
|
||||
node[kvp.key()] = kvp.value();
|
||||
}
|
||||
}
|
||||
settingsFile.close();
|
||||
}
|
||||
settingsFile.close();
|
||||
#endif
|
||||
}
|
||||
|
||||
// save settings file using input from a json object
|
||||
bool System::saveSettings(const char * filename, const char * section, JsonObject input) {
|
||||
// full backup of all settings files
|
||||
void System::exportSystemBackup(JsonObject output) {
|
||||
output["type"] = "systembackup"; // add the type to the output
|
||||
|
||||
// create an array of objects for each file
|
||||
JsonArray nodes = output["systembackup"].to<JsonArray>();
|
||||
|
||||
// start with settings by grouping them together
|
||||
JsonObject node = nodes.add<JsonObject>();
|
||||
node["type"] = "settings"; // add type once for this group
|
||||
exportSettings("settings", NETWORK_SETTINGS_FILE, node);
|
||||
exportSettings("settings", AP_SETTINGS_FILE, node);
|
||||
exportSettings("settings", MQTT_SETTINGS_FILE, node);
|
||||
exportSettings("settings", NTP_SETTINGS_FILE, node);
|
||||
exportSettings("settings", SECURITY_SETTINGS_FILE, node);
|
||||
exportSettings("settings", EMSESP_SETTINGS_FILE, node);
|
||||
|
||||
node = nodes.add<JsonObject>();
|
||||
exportSettings("schedule", EMSESP_SCHEDULER_FILE, node);
|
||||
node = nodes.add<JsonObject>();
|
||||
exportSettings("customizations", EMSESP_CUSTOMIZATION_FILE, node);
|
||||
node = nodes.add<JsonObject>();
|
||||
exportSettings("entities", EMSESP_CUSTOMENTITY_FILE, node);
|
||||
node = nodes.add<JsonObject>();
|
||||
exportSettings("modules", EMSESP_MODULES_FILE, node);
|
||||
#ifndef EMSESP_STANDALONE
|
||||
// special case for custom support
|
||||
File file = LittleFS.open(EMSESP_CUSTOMSUPPORT_FILE, "r");
|
||||
if (file) {
|
||||
JsonDocument jsonDocument;
|
||||
DeserializationError error = deserializeJson(jsonDocument, file);
|
||||
if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) {
|
||||
JsonObject node = nodes.add<JsonObject>();
|
||||
node["type"] = "customSupport";
|
||||
node["data"] = jsonDocument.as<JsonObject>();
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// save a file using input from a json object, called from upload/restore
|
||||
bool System::saveSettings(const char * filename, JsonObject input) {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
const char * section = nullptr;
|
||||
for (const auto & [f, label] : SECTION_MAP) {
|
||||
if (strcmp(f, filename) == 0) {
|
||||
section = label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!section) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonObject section_json = input[section];
|
||||
if (section_json) {
|
||||
File section_file = LittleFS.open(filename, "w");
|
||||
if (section_file) {
|
||||
LOG_INFO("Applying new uploaded %s data", section);
|
||||
LOG_DEBUG("Applying new uploaded %s data", section);
|
||||
serializeJson(section_json, section_file);
|
||||
section_file.close();
|
||||
return true; // reboot required
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return false; // not found
|
||||
}
|
||||
|
||||
@@ -2211,6 +2426,15 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
}
|
||||
#endif
|
||||
|
||||
// Modbus Status
|
||||
node = output["Modbus"].to<JsonObject>();
|
||||
node["enabled"] = EMSESP::system_.modbus_enabled_;
|
||||
if (EMSESP::system_.modbus_enabled_) {
|
||||
node["maxClients"] = EMSESP::system_.modbus_max_clients_;
|
||||
node["port"] = EMSESP::system_.modbus_port_;
|
||||
node["timeout"] = EMSESP::system_.modbus_timeout_;
|
||||
}
|
||||
|
||||
// Sensor Status
|
||||
node = output["sensor"].to<JsonObject>();
|
||||
if (EMSESP::sensor_enabled()) {
|
||||
@@ -2218,6 +2442,9 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
node["temperatureSensorReads"] = EMSESP::temperaturesensor_.reads();
|
||||
node["temperatureSensorFails"] = EMSESP::temperaturesensor_.fails();
|
||||
}
|
||||
|
||||
node = output["Analog"].to<JsonObject>();
|
||||
node["enabled"] = EMSESP::analog_enabled();
|
||||
if (EMSESP::analog_enabled()) {
|
||||
node["analogSensors"] = EMSESP::analogsensor_.count_entities();
|
||||
node["analogSensorReads"] = EMSESP::analogsensor_.reads();
|
||||
|
||||
@@ -37,11 +37,7 @@
|
||||
#include <uuid/log.h>
|
||||
#include <PButton.h>
|
||||
|
||||
#if ESP_ARDUINO_VERSION_MAJOR < 3
|
||||
#define EMSESP_RGB_WRITE neopixelWrite
|
||||
#else
|
||||
#define EMSESP_RGB_WRITE rgbLedWrite
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
// there is no official API available on the original ESP32
|
||||
@@ -49,12 +45,8 @@ extern "C" {
|
||||
uint8_t temprature_sens_read();
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
#include "driver/temp_sensor.h"
|
||||
#else
|
||||
#include "driver/temperature_sensor.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using uuid::console::Shell;
|
||||
|
||||
@@ -103,6 +95,7 @@ class System {
|
||||
static bool command_info(const char * value, const int8_t id, JsonObject output);
|
||||
static bool command_response(const char * value, const int8_t id, JsonObject output);
|
||||
static bool command_service(const char * cmd, const char * value);
|
||||
static bool command_sendmail(const char * value, const int8_t id);
|
||||
static bool command_txpause(const char * value, const int8_t id);
|
||||
|
||||
static bool get_value_info(JsonObject root, const char * cmd);
|
||||
@@ -156,8 +149,9 @@ class System {
|
||||
void systemStatus(uint8_t status_code);
|
||||
uint8_t systemStatus();
|
||||
|
||||
static void extractSettings(const char * filename, const char * section, JsonObject output);
|
||||
static bool saveSettings(const char * filename, const char * section, JsonObject input);
|
||||
static void exportSettings(const std::string & type, const char * filename, JsonObject output);
|
||||
static void exportSystemBackup(JsonObject output);
|
||||
static bool saveSettings(const char * filename, JsonObject input);
|
||||
|
||||
static bool add_gpio(uint8_t pin, const char * source_name);
|
||||
static std::vector<uint8_t> available_gpios();
|
||||
@@ -501,9 +495,7 @@ class System {
|
||||
uint32_t appfree_;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
temperature_sensor_handle_t temperature_handle_ = NULL;
|
||||
#endif
|
||||
#endif
|
||||
float temperature_ = 0;
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.8.2-dev.10"
|
||||
#define EMSESP_APP_VERSION "3.8.2-dev.C11"
|
||||
|
||||
@@ -52,7 +52,7 @@ void EMSuart::uart_event_task(void * pvParameters) {
|
||||
uart_read_bytes(EMSUART_NUM, telegram, length, portMAX_DELAY);
|
||||
EMSESP::incoming_telegram(telegram, (uint8_t)(length - 1));
|
||||
} else { // flush buffer up to break
|
||||
uint8_t buf[UART_FIFO_LEN];
|
||||
uint8_t buf[SOC_UART_FIFO_LEN];
|
||||
uart_read_bytes(EMSUART_NUM, buf, length, portMAX_DELAY);
|
||||
}
|
||||
length = 0;
|
||||
@@ -74,12 +74,8 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.rx_flow_ctrl_thresh = 0,
|
||||
.source_clk = UART_SCLK_APB
|
||||
#if ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
,
|
||||
.flags = {0, 0}
|
||||
#endif
|
||||
};
|
||||
.source_clk = UART_SCLK_APB,
|
||||
.flags = {0}};
|
||||
#if defined(EMSUART_RX_INVERT)
|
||||
inverse_mask |= UART_SIGNAL_RXD_INV;
|
||||
#endif
|
||||
@@ -89,7 +85,7 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t
|
||||
uart_param_config(EMSUART_NUM, &uart_config);
|
||||
uart_set_pin(EMSUART_NUM, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
uart_set_line_inverse(EMSUART_NUM, inverse_mask);
|
||||
uart_driver_install(EMSUART_NUM, UART_FIFO_LEN + 1, 0, (EMS_MAXBUFFERSIZE + 1) * 2, &uart_queue, 0); // buffer must be > fifo
|
||||
uart_driver_install(EMSUART_NUM, SOC_UART_FIFO_LEN + 1, 0, (EMS_MAXBUFFERSIZE + 1) * 2, &uart_queue, 0); // buffer must be > fifo
|
||||
uart_set_rx_full_threshold(EMSUART_NUM, 1);
|
||||
uart_set_rx_timeout(EMSUART_NUM, 0); // disable
|
||||
|
||||
|
||||
@@ -83,6 +83,20 @@ void WebSettings::read(WebSettings & settings, JsonObject root) {
|
||||
root["modbus_max_clients"] = settings.modbus_max_clients;
|
||||
root["modbus_timeout"] = settings.modbus_timeout;
|
||||
root["developer_mode"] = settings.developer_mode;
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
root["email_enabled"] = settings.email_enabled;
|
||||
#else
|
||||
root["email_enabled"] = false;
|
||||
#endif
|
||||
root["email_ssl"] = settings.email_ssl;
|
||||
root["email_starttls"] = settings.email_starttls;
|
||||
root["email_server"] = settings.email_server;
|
||||
root["email_port"] = settings.email_port;
|
||||
root["email_login"] = settings.email_login;
|
||||
root["email_pass"] = settings.email_pass;
|
||||
root["email_sender"] = settings.email_sender;
|
||||
root["email_recp"] = settings.email_recp;
|
||||
root["email_subject"] = settings.email_subject;
|
||||
}
|
||||
|
||||
// call on initialization and also when settings are updated/saved via web or console
|
||||
@@ -243,13 +257,9 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
||||
|
||||
// Modbus settings
|
||||
settings.modbus_enabled = root["modbus_enabled"] | EMSESP_DEFAULT_MODBUS_ENABLED;
|
||||
check_flag(original_settings.modbus_enabled, settings.modbus_enabled, ChangeFlags::RESTART);
|
||||
settings.modbus_port = root["modbus_port"] | EMSESP_DEFAULT_MODBUS_PORT;
|
||||
check_flag(original_settings.modbus_port, settings.modbus_port, ChangeFlags::RESTART);
|
||||
settings.modbus_max_clients = root["modbus_max_clients"] | EMSESP_DEFAULT_MODBUS_MAX_CLIENTS;
|
||||
check_flag(original_settings.modbus_max_clients, settings.modbus_max_clients, ChangeFlags::RESTART);
|
||||
settings.modbus_timeout = root["modbus_timeout"] | EMSESP_DEFAULT_MODBUS_TIMEOUT;
|
||||
check_flag(original_settings.modbus_timeout, settings.modbus_timeout, ChangeFlags::RESTART);
|
||||
|
||||
//
|
||||
// these may need mqtt restart to rebuild HA discovery topics
|
||||
@@ -300,6 +310,20 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
||||
settings.weblog_level = root["weblog_level"] | EMSESP_DEFAULT_WEBLOG_LEVEL;
|
||||
settings.weblog_compact = root["weblog_compact"] | EMSESP_DEFAULT_WEBLOG_COMPACT;
|
||||
|
||||
settings.email_enabled = root["email_enabled"] | FACTORY_EMAIL_ENABLE;
|
||||
settings.email_ssl = root["email_ssl"] | FACTORY_EMAIL_SSL;
|
||||
settings.email_starttls = root["email_starttls"] | FACTORY_EMAIL_STARTTLS;
|
||||
settings.email_server = root["email_server"] | FACTORY_EMAIL_SERVER;
|
||||
settings.email_port = root["email_port"] | FACTORY_EMAIL_PORT;
|
||||
settings.email_login = root["email_login"] | FACTORY_EMAIL_LOGIN;
|
||||
settings.email_pass = root["email_pass"] | FACTORY_EMAIL_PASSWORD;
|
||||
settings.email_sender = root["email_sender"] | FACTORY_EMAIL_FROM;
|
||||
settings.email_recp = root["email_recp"] | FACTORY_EMAIL_TO;
|
||||
settings.email_subject = root["email_subject"] | FACTORY_EMAIL_SUBJECT;
|
||||
|
||||
if (settings.email_ssl && settings.email_starttls) {
|
||||
settings.email_ssl = false;
|
||||
}
|
||||
// if no psram limit weblog buffer to 25 messages
|
||||
if (EMSESP::system_.PSram() > 0) {
|
||||
settings.weblog_buffer = root["weblog_buffer"] | EMSESP_DEFAULT_WEBLOG_BUFFER;
|
||||
@@ -458,23 +482,14 @@ void WebSettings::set_board_profile(WebSettings & settings) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
// check for no PSRAM, could be a E32 or S32?
|
||||
if (!ESP.getPsramSize()) {
|
||||
#if ESP_ARDUINO_VERSION_MAJOR < 3
|
||||
if (ETH.begin(1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN)) {
|
||||
#else
|
||||
if (ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN)) {
|
||||
#endif
|
||||
settings.board_profile = "E32"; // Ethernet without PSRAM
|
||||
} else {
|
||||
settings.board_profile = "S32"; // ESP32 standard WiFi without PSRAM
|
||||
}
|
||||
} else {
|
||||
// check for boards with PSRAM, could be a E32V2 otherwise default back to the S32
|
||||
#if ESP_ARDUINO_VERSION_MAJOR < 3
|
||||
if (ETH.begin(0, 15, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_OUT)) {
|
||||
#else
|
||||
// check for boards with PSRAM, could be a E32V2 otherwise default back to the S32
|
||||
if (ETH.begin(ETH_PHY_LAN8720, 0, 23, 18, 15, ETH_CLOCK_GPIO0_OUT)) {
|
||||
#endif
|
||||
|
||||
if (analogReadMilliVolts(39) > 700) { // core voltage > 2.6V
|
||||
settings.board_profile = "E32V2_2"; // Ethernet, PSRAM, internal sensors
|
||||
} else {
|
||||
|
||||
@@ -26,6 +26,36 @@
|
||||
#define EMSESP_SETTINGS_SERVICE_PATH "/rest/settings"
|
||||
#define EMSESP_BOARD_PROFILE_SERVICE_PATH "/rest/boardProfile"
|
||||
|
||||
#ifndef FACTORY_EMAIL_ENABLE
|
||||
#define FACTORY_EMAIL_ENABLE false
|
||||
#endif
|
||||
#ifndef FACTORY_EMAIL_SSL
|
||||
#define FACTORY_EMAIL_SSL false
|
||||
#endif
|
||||
#ifndef FACTORY_EMAIL_STARTTLS
|
||||
#define FACTORY_EMAIL_STARTTLS true
|
||||
#endif
|
||||
#ifndef FACTORY_EMAIL_PORT
|
||||
#define FACTORY_EMAIL_PORT 587
|
||||
#endif
|
||||
#ifndef FACTORY_EMAIL_SERVER
|
||||
#define FACTORY_EMAIL_SERVER "smtp.example.net"
|
||||
#endif
|
||||
#ifndef FACTORY_EMAIL_LOGIN
|
||||
#define FACTORY_EMAIL_LOGIN ""
|
||||
#endif
|
||||
#ifndef FACTORY_EMAIL_PASSWORD
|
||||
#define FACTORY_EMAIL_PASSWORD ""
|
||||
#endif
|
||||
#ifndef FACTORY_EMAIL_FROM
|
||||
#define FACTORY_EMAIL_FROM "ems-esp@example.net"
|
||||
#endif
|
||||
#ifndef FACTORY_EMAIL_TO
|
||||
#define FACTORY_EMAIL_TO ""
|
||||
#endif
|
||||
#ifndef FACTORY_EMAIL_SUBJECT
|
||||
#define FACTORY_EMAIL_SUBJECT "ems-esp notification"
|
||||
#endif
|
||||
namespace emsesp {
|
||||
|
||||
class WebSettings {
|
||||
@@ -77,6 +107,16 @@ class WebSettings {
|
||||
uint16_t modbus_port;
|
||||
uint8_t modbus_max_clients;
|
||||
uint32_t modbus_timeout;
|
||||
bool email_enabled;
|
||||
bool email_ssl;
|
||||
bool email_starttls;
|
||||
String email_server;
|
||||
uint16_t email_port;
|
||||
String email_login;
|
||||
String email_pass;
|
||||
String email_sender;
|
||||
String email_recp;
|
||||
String email_subject;
|
||||
|
||||
uint8_t phy_type;
|
||||
int8_t eth_power; // -1 means disabled
|
||||
|
||||
@@ -310,26 +310,24 @@ void WebStatusService::allvalues(JsonObject output) {
|
||||
// action = export
|
||||
// returns data for a specific feature/settings as a json object
|
||||
bool WebStatusService::exportData(JsonObject root, std::string & type) {
|
||||
root["type"] = type;
|
||||
|
||||
if (type == "settings") {
|
||||
JsonObject node = root["System"].to<JsonObject>();
|
||||
node["version"] = EMSESP_APP_VERSION;
|
||||
System::extractSettings(NETWORK_SETTINGS_FILE, "Network", root);
|
||||
System::extractSettings(AP_SETTINGS_FILE, "AP", root);
|
||||
System::extractSettings(MQTT_SETTINGS_FILE, "MQTT", root);
|
||||
System::extractSettings(NTP_SETTINGS_FILE, "NTP", root);
|
||||
System::extractSettings(SECURITY_SETTINGS_FILE, "Security", root);
|
||||
System::extractSettings(EMSESP_SETTINGS_FILE, "Settings", root);
|
||||
root["type"] = type; // add settings as a group
|
||||
System::exportSettings(type, NETWORK_SETTINGS_FILE, root);
|
||||
System::exportSettings(type, AP_SETTINGS_FILE, root);
|
||||
System::exportSettings(type, MQTT_SETTINGS_FILE, root);
|
||||
System::exportSettings(type, NTP_SETTINGS_FILE, root);
|
||||
System::exportSettings(type, SECURITY_SETTINGS_FILE, root);
|
||||
System::exportSettings(type, EMSESP_SETTINGS_FILE, root);
|
||||
} else if (type == "schedule") {
|
||||
System::extractSettings(EMSESP_SCHEDULER_FILE, "Schedule", root);
|
||||
System::exportSettings(type, EMSESP_SCHEDULER_FILE, root);
|
||||
} else if (type == "customizations") {
|
||||
System::extractSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", root);
|
||||
System::exportSettings(type, EMSESP_CUSTOMIZATION_FILE, root);
|
||||
} else if (type == "entities") {
|
||||
System::extractSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", root);
|
||||
System::exportSettings(type, EMSESP_CUSTOMENTITY_FILE, root);
|
||||
} else if (type == "allvalues") {
|
||||
root.clear(); // don't need the "type" key added to the output
|
||||
allvalues(root);
|
||||
} else if (type == "systembackup") {
|
||||
System::exportSystemBackup(root);
|
||||
} else {
|
||||
return false; // error
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user