Merge pull request #3141 from proddy/core3

Core3 updates
This commit is contained in:
Proddy
2026-06-28 14:52:55 +02:00
committed by GitHub
19 changed files with 420 additions and 384 deletions
+4
View File
@@ -14,9 +14,13 @@ For more details go to [emsesp.org](https://emsesp.org/).
- signed value for solarInfuence [#3077](https://github.com/emsesp/EMS-ESP32/issues/3077)
- TLS support with 4MB boards without PSRAM
- Prevent system crash during WiFi network discovery on ESP32-S3 hardware [#3128](https://github.com/emsesp/EMS-ESP32/pull/3128)
- check arithmetric operations on strings [#3127](https://github.com/emsesp/EMS-ESP32/discussions/3127)
## Changed
- various memory optimizations [#3083](https://github.com/emsesp/EMS-ESP32/issues/3083)
- Scheduler name is now mandatory
- network fallback to AP only after start [#3090](https://github.com/emsesp/EMS-ESP32/issues/3090)
- replaced Web async-validator with custom validator and toast with native snackbar to reduce bundle size
- Dewtemperature for Easycontrol calculated by ems-esp [3135](https://github.com/emsesp/EMS-ESP32/issues/3135)
+8 -8
View File
@@ -27,13 +27,13 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@mui/icons-material": "^9.1.1",
"@mui/material": "^9.1.1",
"@mui/material": "^9.1.2",
"@table-library/react-table-library": "4.1.15",
"alova": "^3.5.1",
"etag": "^1.8.1",
"jwt-decode": "^4.0.0",
"mime-types": "^3.0.2",
"preact": "^10.29.2",
"preact": "^10.29.3",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"react-icons": "^5.6.0",
@@ -45,18 +45,18 @@
"@eslint/js": "^10.0.1",
"@preact/preset-vite": "^2.10.5",
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/node": "^26.0.0",
"@types/node": "^26.0.1",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"concurrently": "^10.0.3",
"eslint": "^10.5.0",
"eslint": "^10.6.0",
"eslint-config-prettier": "^10.1.8",
"prettier": "^3.8.4",
"prettier": "^3.9.0",
"rollup-plugin-visualizer": "^7.0.1",
"terser": "^5.48.0",
"typescript-eslint": "^8.61.1",
"vite": "^8.0.16",
"typescript-eslint": "^8.62.0",
"vite": "^8.1.0",
"vite-plugin-imagemin": "^0.6.1"
},
"packageManager": "pnpm@11.8.0+sha512.c1f5e7c4cb241c8f174b743851d82f42b802324afc8b0f116b96adb15aa06664948dde36960a3ba1079ba5b4b29dd0140135b94b5b5f5263592249d68e555f26"
"packageManager": "pnpm@11.9.0+sha512.bd682d5d03fe525ef7c9fd6780c6884d1e756ac4c9c9fe00c538782824310dcf90e3ddc4f53835f06dfaebd5085e41855e0bcbb3b60de2ac5bbab89e5036f03b"
}
+262 -262
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -4,8 +4,8 @@ allowBuilds:
gifsicle: false
jpegtran-bin: false
mozjpeg: false
optipng-bin: false
pngquant-bin: false
optipng-bin: true
pngquant-bin: true
minimumReleaseAgeExclude:
- '@types/node@25.9.2'
- '@types/react@19.2.17'
+1 -5
View File
@@ -13,11 +13,7 @@ import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
import type { SvgIconProps } from '@mui/material';
export type OptionType =
| 'deleted'
| 'readonly'
| 'web_exclude'
| 'api_mqtt_exclude'
| 'favorite';
'deleted' | 'readonly' | 'web_exclude' | 'api_mqtt_exclude' | 'favorite';
type IconPair = [
React.ComponentType<SvgIconProps>,
+2 -2
View File
@@ -13,7 +13,7 @@
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"formidable": "^3.5.4",
"itty-router": "^5.0.24",
"prettier": "^3.8.4"
"prettier": "^3.9.0"
},
"packageManager": "pnpm@11.8.0+sha512.c1f5e7c4cb241c8f174b743851d82f42b802324afc8b0f116b96adb15aa06664948dde36960a3ba1079ba5b4b29dd0140135b94b5b5f5263592249d68e555f26"
"packageManager": "pnpm@11.9.0+sha512.bd682d5d03fe525ef7c9fd6780c6884d1e756ac4c9c9fe00c538782824310dcf90e3ddc4f53835f06dfaebd5085e41855e0bcbb3b60de2ac5bbab89e5036f03b"
}
+8 -8
View File
@@ -13,7 +13,7 @@ importers:
version: 3.1.3
'@trivago/prettier-plugin-sort-imports':
specifier: ^6.0.2
version: 6.0.2(prettier@3.8.4)
version: 6.0.2(prettier@3.9.0)
formidable:
specifier: ^3.5.4
version: 3.5.4
@@ -21,8 +21,8 @@ importers:
specifier: ^5.0.24
version: 5.0.24
prettier:
specifier: ^3.8.4
version: 3.8.4
specifier: ^3.9.0
version: 3.9.0
packages:
@@ -167,8 +167,8 @@ packages:
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
prettier@3.8.4:
resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==}
prettier@3.9.0:
resolution: {integrity: sha512-LjIqSIC5VYLzs9WedVmJ2ljNAGnU+DteIClbahu4L/DBeWjZ6iT/k1lAYyu9JUh+1xINxWadaPw/Pl63y/agAw==}
engines: {node: '>=14'}
hasBin: true
@@ -246,7 +246,7 @@ snapshots:
dependencies:
'@noble/hashes': 1.8.0
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.4)':
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.9.0)':
dependencies:
'@babel/generator': 7.29.7
'@babel/parser': 7.29.7
@@ -256,7 +256,7 @@ snapshots:
lodash-es: 4.18.1
minimatch: 9.0.9
parse-imports-exports: 0.2.4
prettier: 3.8.4
prettier: 3.9.0
transitivePeerDependencies:
- supports-color
@@ -311,6 +311,6 @@ snapshots:
picocolors@1.1.1: {}
prettier@3.8.4: {}
prettier@3.9.0: {}
wrappy@1.0.2: {}
+29 -2
View File
@@ -146,9 +146,9 @@ let LATEST_DEV_VERSION = '3.9.0-dev.1';
// scenarios for testing versioning
// let version_test = 0; // on latest stable, or switch to dev
// let version_test = 1; // on latest dev, or switch back to stable
let version_test = 1; // on latest dev, or switch back to stable
// let version_test = 2; // upgrade an older stable to latest stable or switch to latest dev
let version_test = 3; // upgrade dev to latest, or switch to stable
// let version_test = 3; // upgrade dev to latest, or switch to stable
// let version_test = 4; // downgrade to an older dev, or switch back to stable
switch (version_test as number) {
@@ -4147,6 +4147,21 @@ let emsesp_customentities = {
value_type: 0,
writeable: true,
value: 21
},
{
id: 0,
ram: 1,
device_id: 0,
type_id: 0,
offset: 0,
factor: 1,
name: 'message',
uom: 0,
value_type: 9,
writeable: true,
hide: false,
value:
'{"stable":{"version":"3.8.2","date":"2026-05-12"},"dev":{"version":"3.8.3-dev.5","date":"2026-05-28T09:55:29Z"}}'
}
]
};
@@ -4189,6 +4204,18 @@ let emsesp_commands = {
cmd: 'system/message',
value: '"hello world"',
name: 'send_message'
},
{
id: 7,
cmd: 'custom/message',
value: '{"url":"http://emsesp.org/versions.json"}',
name: 'get_versions'
},
{
id: 8,
cmd: 'system/sendmail',
value: '"test email with version " + custom/message',
name: 'sendmail'
}
]
};
+7 -5
View File
@@ -1,7 +1,5 @@
#include "WiFiScanner.h"
#include "../core/psram_async_json_response.h"
WiFiScanner::WiFiScanner(AsyncWebServer * server, SecurityManager * securityManager) {
securityManager->addEndpoint(server, SCAN_NETWORKS_SERVICE_PATH, AuthenticationPredicates::IS_ADMIN, [this](AsyncWebServerRequest * request) {
scanNetworks(request);
@@ -17,14 +15,14 @@ void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) {
if (WiFi.scanComplete() != -1) {
WiFi.scanDelete();
WiFi.scanNetworks(true);
WiFi.scanNetworks(true, false, true, 250);
}
}
void WiFiScanner::listNetworks(AsyncWebServerRequest * request) {
const int numNetworks = WiFi.scanComplete();
if (numNetworks > -1) {
auto * response = new emsesp::PsramAsyncJsonResponse(false);
auto * response = new AsyncJsonResponse(false);
JsonObject root = response->getRoot();
JsonArray networks = root["networks"].to<JsonArray>();
for (uint8_t i = 0; i < numNetworks; i++) {
@@ -40,6 +38,10 @@ void WiFiScanner::listNetworks(AsyncWebServerRequest * request) {
} else if (numNetworks == -1) {
request->send(202); // special code to indicate scan in progress
} else {
scanNetworks(request);
auto * response = new AsyncJsonResponse(false);
JsonObject root = response->getRoot();
root["networks"].to<JsonArray>();
response->setLength();
request->send(response);
}
}
+2 -2
View File
@@ -381,8 +381,8 @@ uint8_t Command::call(const uint8_t device_type, const char * command, const cha
// for the Commands device, calling a named command executes it (using its stored value)
// rather than returning its definition, so skip the value-info lookup and fall through
// to the registered command function. The list keywords above are still handled.
bool is_named_command = (device_type == EMSdevice::DeviceType::COMMAND) && strcmp(cmd, F_(info)) && strcmp(cmd, F_(values))
&& strcmp(cmd, F_(entities)) && strcmp(cmd, F_(metrics));
bool is_named_command = (device_type == EMSdevice::DeviceType::COMMAND) && strcmp(cmd, F_(info)) && strcmp(cmd, F_(values)) && strcmp(cmd, F_(entities))
&& strcmp(cmd, F_(metrics));
if (!is_named_command && EMSESP::get_device_value_info(output, cmd, id, device_type)) { // entity = cmd
LOG_DEBUG("Fetched device entity/attributes for %s/%s (id=%d)", dname, cmd, id);
return CommandRet::OK;
+5 -2
View File
@@ -116,8 +116,11 @@ class Command {
static void
add(const uint8_t device_type, const char * cmd, const cmd_function_p cb, const char * const * description, uint8_t flags = CommandFlag::CMD_FLAG_DEFAULT);
// command that writes a JSON object as its output; bypasses the readonly check
static void
add_json(const uint8_t device_type, const char * cmd, const cmd_function_p cb, const char * const * description, uint8_t flags = CommandFlag::CMD_FLAG_DEFAULT);
static void add_json(const uint8_t device_type,
const char * cmd,
const cmd_function_p cb,
const char * const * description,
uint8_t flags = CommandFlag::CMD_FLAG_DEFAULT);
static void reserve(size_t num) {
cmdfunctions_.reserve(num);
+8 -4
View File
@@ -377,18 +377,22 @@ void Roomctrl::temperature(uint8_t addr, uint8_t dst, uint8_t hc) {
// send telegram 0x047B only for RC100H
void Roomctrl::humidity(uint8_t addr, uint8_t dst, uint8_t hc) {
int16_t dew = calc_dew(remotetemp_[hc], remotehum_[hc]);
int8_t dew8 = EMS_VALUE_INT8_NOTSET;
if (dew != EMS_VALUE_INT16_NOTSET) {
dew8 = static_cast<int8_t>((dew >= 0 ? dew + 5 : dew - 5) / 10);
}
uint8_t data[11];
data[0] = addr | EMSbus::ems_mask();
data[1] = dst & 0x7F;
uint16_t dew = calc_dew(remotetemp_[hc], remotehum_[hc]);
data[2] = 0xFF;
data[3] = 0;
data[4] = 3;
data[5] = 0x7B + hc;
data[6] = dew == EMS_VALUE_INT16_NOTSET ? EMS_VALUE_INT8_NOTSET : (uint8_t)((dew + 5) / 10);
data[6] = static_cast<uint8_t>(dew8);
data[7] = remotehum_[hc];
data[8] = (uint8_t)(dew << 8);
data[9] = (uint8_t)(dew & 0xFF);
data[8] = static_cast<uint8_t>(static_cast<uint16_t>(dew) >> 8);
data[9] = static_cast<uint8_t>(static_cast<uint16_t>(dew) & 0xFF);
data[10] = EMSbus::calculate_crc(data, 10); // append CRC
EMSuart::transmit(data, 11);
}
+1 -1
View File
@@ -35,6 +35,7 @@ class Roomctrl {
return (hc < 4 && remotetemp_[hc] != EMS_VALUE_INT16_NOTSET);
}
static void set_timeout(uint8_t t);
static int16_t calc_dew(int16_t temp, uint8_t hum);
private:
static constexpr uint32_t SEND_INTERVAL = 15000; // 15 sec
@@ -50,7 +51,6 @@ class Roomctrl {
static void nack_write();
static void ack_write();
static void replyF7(uint8_t addr, uint8_t dst, uint8_t offset, uint8_t typehh, uint8_t typeh, uint8_t typel, uint8_t hc);
static int16_t calc_dew(int16_t temp, uint8_t hum);
static bool switch_off_[HCS];
static uint32_t send_time_[HCS];
+9 -9
View File
@@ -816,16 +816,16 @@ void Thermostat::process_RemoteTemp(const std::shared_ptr<const Telegram> & tele
// e.g. "38 10 FF 00 03 7B 08 24 00 4B"
void Thermostat::process_RemoteHumidity(const std::shared_ptr<const Telegram> & telegram) {
// has_update(telegram, dewtemperature_, 0); // this is int8
has_update(telegram, humidity_, 1);
has_update(telegram, dewtemperature_, 2); // this is int16
// some thermostats use short telegram with int8 dewpoint, https://github.com/emsesp/EMS-ESP32/issues/1491
if (telegram->offset == 0 && telegram->message_length < 4) {
int8_t dew = dewtemperature_ / 10;
telegram->read_value(dew, 0);
if (dew != EMS_VALUE_INT8_NOTSET && dewtemperature_ != dew * 10) {
dewtemperature_ = dew * 10;
has_update(dewtemperature_);
}
// but it's not a dewpoint in offset 0, removed, see https://github.com/emsesp/EMS-ESP32/issues/3135
has_update(telegram, humidity_, 1);
// has_update(telegram, dewtemperature_, 2); // this is int16
int16_t dew = EMS_VALUE_INT16_NOTSET;
if (telegram->read_value(dew, 2)) {
has_update(dewtemperature_, dew);
} else if (telegram->offset == 0 && telegram->message_length < 4) {
has_update(dewtemperature_, Roomctrl::calc_dew(tempsensor1_, humidity_));
}
}
+1 -1
View File
@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.9.0-dev.14"
#define EMSESP_APP_VERSION "3.9.0-dev.15"