25 Commits

Author SHA1 Message Date
Proddy
224bf63ded Merge pull request #3075 from proddy/core3
version update
2026-05-12 19:52:22 +02:00
proddy
a7fbde48ef bump version 2026-05-12 19:51:48 +02:00
proddy
3a3d0fb05e package update 2026-05-12 19:51:43 +02:00
proddy
8ed71e0192 formatting 2026-05-12 19:51:36 +02:00
Proddy
434b6a81c4 Merge pull request #3073 from MichaelDvP/core3
merge latest dev changes, sendmail security as list
2026-05-12 19:48:08 +02:00
Proddy
ec20f0743c Merge branch 'core3' into core3 2026-05-12 19:47:59 +02:00
Proddy
09a72068e6 Merge pull request #3069 from proddy/core3
enable OTA uploads of filesystem (pre_load.json)
2026-05-12 19:45:27 +02:00
proddy
fcc56a9bf6 package update 2026-05-12 19:45:04 +02:00
proddy
84d321f1b4 fix json uploads 2026-05-12 19:44:59 +02:00
MichaelDvP
ea7c2a1548 Merge branch 'dev' into core3 2026-05-11 15:06:11 +02:00
MichaelDvP
a897afd4e6 Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev 2026-05-11 14:36:44 +02:00
MichaelDvP
344dcd0019 add polarity setting for digital_in sensor, #3070 2026-05-11 14:35:48 +02:00
MichaelDvP
34d12bfb49 Merge branch 'core3' of https://github.com/MichaelDvP/EMS-ESP32 into core3 2026-05-10 11:28:04 +02:00
MichaelDvP
ff0990ec0e update core, pnpm, and pkg 2026-05-10 11:11:17 +02:00
MichaelDvP
459270e035 rename sendmail and add security list instead of checkbox 2026-05-10 11:10:53 +02:00
MichaelDvP
2af709b3d5 update core, pnpm, and pkg 2026-05-10 10:41:51 +02:00
MichaelDvP
b84d53dc39 rename sendmail and add security list instead of checkbox 2026-05-10 10:41:24 +02:00
proddy
57997d0acb enable OTA uploads of filesystem (pre_load.json) 2026-05-09 15:25:06 +02:00
proddy
76a23870d5 force littlefs to v2.0 2026-05-09 15:24:45 +02:00
proddy
193e43ddc5 package update 2026-05-09 15:24:14 +02:00
MichaelDvP
fc451863c0 Merge branch 'dev' into core3 2026-05-09 08:13:31 +02:00
Proddy
017a7de639 Merge pull request #3068 from MichaelDvP/dev
tx-mode: auto, default bus-id 0x49
2026-05-09 08:11:59 +02:00
MichaelDvP
7b61429a02 fix testdata to device-id 0x49, txMode 5 2026-05-09 08:01:29 +02:00
MichaelDvP
fed15f0f96 tx-mode: auto, default bus-id 0x49 2026-05-07 21:08:56 +02:00
Proddy
ad5d13168b Merge pull request #3066 from MichaelDvP/dev
fix modbus start #3064
2026-05-07 18:05:48 +02:00
36 changed files with 503 additions and 708 deletions

1
.gitignore vendored
View File

@@ -77,3 +77,4 @@ pnpm-lock.yaml
interface/.tsbuildinfo
test/test_api/package-lock.json
.clangd
mklittlefs

View File

@@ -16,6 +16,8 @@ For more details go to [emsesp.org](https://emsesp.org/).
- 2.nd freshwater module (dhw4, dhw5) [#2991](https://github.com/emsesp/EMS-ESP32/issues/2991)
- full system backup and restore
- updated version check [#3047](https://github.com/emsesp/EMS-ESP32/issues/3047)
- auto-logic to set ht3/ems+ tx-mode
- polarity for digital_in sensors [#3070](https://github.com/emsesp/EMS-ESP32/discussions/3070)
## Fixed
@@ -41,3 +43,4 @@ For more details go to [emsesp.org](https://emsesp.org/).
- heap optimizations [#3021](https://github.com/emsesp/EMS-ESP32/discussions/3021)
- refactored network code into a single class [#3052](https://github.com/emsesp/EMS-ESP32/pull/3052)
- check and read 0x470 as summer2_typeids[0] only if received [#2686](https://github.com/emsesp/EMS-ESP32/issues/2686), [#3055](https://github.com/emsesp/EMS-ESP32/issues/3055)
- default bus-id: gateway1(0x49), tx-mode: auto

View File

@@ -1,7 +1,6 @@
{
"type": "systembackup",
"version": "3.8.2",
"date": "2026-03-29T13:28:15",
"version": "3.9.0",
"systembackup": [
{
"type": "settings",
@@ -9,7 +8,7 @@
"ssid": "",
"bssid": "",
"password": "",
"hostname": "ems-esp",
"hostname": "ems-esp2",
"static_ip_config": false,
"bandwidth20": false,
"nosleep": true,
@@ -19,7 +18,7 @@
"tx_power": 0
},
"AP": {
"provision_mode": 2,
"provision_mode": 1,
"ssid": "ems-esp",
"password": "ems-esp-neo",
"channel": 1,
@@ -62,7 +61,7 @@
"send_response": false
},
"NTP": {
"enabled": true,
"enabled": false,
"server": "time.google.com",
"tz_label": "Europe/Amsterdam",
"tz_format": "CET-1CEST,M3.5.0,M10.5.0/3"
@@ -83,7 +82,7 @@
]
},
"Settings": {
"version": "3.8.2",
"version": "3.9.0",
"board_profile": "E32V2_2",
"platform": "ESP32",
"locale": "en",
@@ -132,10 +131,9 @@
"modbus_port": 502,
"modbus_max_clients": 10,
"modbus_timeout": 300,
"developer_mode": true,
"developer_mode": false,
"email_enabled": false,
"email_ssl": false,
"email_starttls": true,
"email_security": 2,
"email_server": "smtp.example.net",
"email_port": 587,
"email_login": "",
@@ -154,14 +152,6 @@
{
"type": "customizations",
"Customizations": {
"ts": [
{
"id": "28_1767_7B13_2502",
"name": "gateway_temperature",
"offset": 0,
"is_system": true
}
],
"as": [
{
"gpio": 39,
@@ -207,22 +197,14 @@
}
},
{
"type": "customSupport",
"Support": {
"html": [
"This product is installed and managed by:",
"",
"<b>Bosch Installer Example</b>",
"",
"Nefit Road 12",
"1234 AB Amsterdam",
"Phone: +31 123 456 789",
"email: support@boschinstaller.nl",
"",
"For help and questions please <a target='_blank' href='https://emsesp.org'>contact</a> your installer."
],
"img_url": "https://emsesp.org/media/images/designer.png"
}
"type": "nvs",
"nvs": [
{
"type": 1,
"key": "fresh_firmware",
"value": 0
}
]
}
]
}

View File

@@ -47,7 +47,7 @@
"@eslint/js": "^10.0.1",
"@preact/preset-vite": "^2.10.5",
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/node": "^25.6.0",
"@types/node": "^25.7.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"concurrently": "^9.2.1",
@@ -55,10 +55,10 @@
"eslint-config-prettier": "^10.1.8",
"prettier": "^3.8.3",
"rollup-plugin-visualizer": "^7.0.1",
"terser": "^5.47.0",
"typescript-eslint": "^8.59.2",
"vite": "^8.0.11",
"terser": "^5.47.1",
"typescript-eslint": "^8.59.3",
"vite": "^8.0.12",
"vite-plugin-imagemin": "^0.6.1"
},
"packageManager": "pnpm@10.33.4"
"packageManager": "pnpm@10.33.4+sha512.1c67b3b359b2d408119ba1ed289f34b8fc3c6873412bec6fd264fbdc82489e510fcbecb9ce9d22dae7f3b76269d8441046014bdca53b9979cd7a561ad631b800"
}

680
interface/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,11 @@
allowBuilds:
cwebp-bin: true
esbuild: true
gifsicle: true
jpegtran-bin: true
mozjpeg: true
optipng-bin: true
pngquant-bin: true
onlyBuiltDependencies:
- cwebp-bin
- esbuild

View File

@@ -208,6 +208,23 @@ const SensorsAnalogDialog = ({
</ValidatedTextField>
</Grid>
)}
{editItem.t === AnalogType.DIGITAL_IN && (
<Grid>
<ValidatedTextField
name="f"
label={LL.POLARITY()}
value={editItem.f}
sx={{ width: '15ch' }}
fullWidth
select
onChange={updateFormValue}
disabled={editItem.s}
>
<MenuItem value={1}>{LL.ACTIVEHIGH()}</MenuItem>
<MenuItem value={0}>{LL.ACTIVELOW()}</MenuItem>
</ValidatedTextField>
</Grid>
)}
{editItem.t === AnalogType.ADC && (
<Grid>
<ValidatedTextField
@@ -413,7 +430,7 @@ const SensorsAnalogDialog = ({
name="o"
label={LL.POLARITY()}
value={editItem.o}
sx={{ width: '11ch' }}
sx={{ width: '15ch' }}
select
onChange={updateFormValue}
disabled={editItem.s}

View File

@@ -44,8 +44,7 @@ export interface Settings {
modbus_max_clients: number;
modbus_timeout: number;
email_enabled: boolean;
email_ssl?: boolean;
email_starttls?: boolean;
email_security: number;
email_server: string;
email_port: number;
email_login: string;

View File

@@ -165,10 +165,10 @@ const ApplicationSettings = () => {
await doRestart();
};
const sendemail = async () => {
const sendmail = async () => {
await sendAPI({
device: 'system',
cmd: 'sendemail',
cmd: 'sendmail',
data: 'Email notification test successful!',
id: 0
})
@@ -403,42 +403,21 @@ const ApplicationSettings = () => {
margin="normal"
/>
</Grid>
<Grid
size={4}
sx={{ 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>
<TextField
sx={{ width: '20ch' }}
name="email_security"
label={LL.SECURITY(0)}
value={data.email_security}
variant="outlined"
onChange={updateFormValue}
margin="normal"
select
>
<MenuItem value={0}>{LL.OFF()}</MenuItem>
<MenuItem value={1}>SSL</MenuItem>
<MenuItem value={2}>StartTLS</MenuItem>
</TextField>
</Grid>
</Grid>
<Grid container spacing={2} rowSpacing={0}>
@@ -505,7 +484,7 @@ const ApplicationSettings = () => {
variant="outlined"
color="primary"
disabled={dirtyFlags.length !== 0}
onClick={sendemail}
onClick={sendmail}
>
Send test email
</Button>
@@ -839,6 +818,7 @@ const ApplicationSettings = () => {
<MenuItem value={2}>EMS+</MenuItem>
<MenuItem value={3}>HT3</MenuItem>
<MenuItem value={4}>{LL.HARDWARE()}</MenuItem>
<MenuItem value={5}>Auto</MenuItem>
</TextField>
</Grid>
<Grid>

View File

@@ -22,10 +22,11 @@
#include "Arduino.h"
#define EMS_TXMODE_OFF 0
#define EMS_TXMODE_DEFAULT 1
#define EMS_TXMODE_EMS 1
#define EMS_TXMODE_EMSPLUS 2
#define EMS_TXMODE_HT3 3
#define EMS_TXMODE_HW 4
#define EMS_TXMODE_AUTO 5
namespace emsesp {

View File

@@ -15,5 +15,5 @@
"itty-router": "^5.0.23",
"prettier": "^3.8.3"
},
"packageManager": "pnpm@10.33.3+sha512.a19744364a7e248b92657a4ca5973f9354d21caf982579674b1c539f32c7420c47138ad8b1254df07aba9bc782d9b3029e3db34d5dbff974326eb74dac8ff489"
"packageManager": "pnpm@10.33.4+sha512.1c67b3b359b2d408119ba1ed289f34b8fc3c6873412bec6fd264fbdc82489e510fcbecb9ce9d22dae7f3b76269d8441046014bdca53b9979cd7a561ad631b800"
}

View File

@@ -59,7 +59,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/tasmota/platform-espressif32/releases/download/2026.04.50/platform-espressif32.zip ; Platform 2026.04.50 Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.05.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
; 16MB Flash variants
[espressif32_base_16M]
@@ -67,7 +67,7 @@ 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/2026.04.50/platform-espressif32.zip ; Platform 2026.04.50 Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.05.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
; 32MB Flash variants
[espressif32_base_32M]
@@ -75,7 +75,7 @@ framework = arduino
board_build.partitions = partitions/esp32_partition_32M.csv
board_upload.flash_size = 32MB
board_build.app_partition_name = app0
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.04.50/platform-espressif32.zip ; Platform 2026.04.50 Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.05.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
[env]
build_flags =
@@ -88,6 +88,7 @@ monitor_speed = 115200
monitor_filters = direct
build_type = release
board_build.filesystem = littlefs
board_build.littlefs_version = 2.0
lib_deps =
bblanchon/ArduinoJson @ 7.4.3
ESP32Async/AsyncTCP @ 3.4.10

View File

@@ -1336,4 +1336,4 @@ handshaked
startm
netifs
testemail
sendemail
sendmail

View File

@@ -4,6 +4,7 @@
#include <esp_app_format.h>
#include <esp_ota_ops.h>
// #include <esp_partition.h>
static String getFilenameExtension(const String & filename) {
const auto pos = filename.lastIndexOf('.');
@@ -16,8 +17,8 @@ static String getFilenameExtension(const String & filename) {
UploadFileService::UploadFileService(AsyncWebServer * server, SecurityManager * securityManager)
: _securityManager(securityManager)
, _is_firmware(false)
, _is_filesystem(false)
, _md5() {
// upload a file via a form
server->on(
UPLOAD_FILE_PATH,
HTTP_POST,
@@ -41,8 +42,14 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
const String extension = getFilenameExtension(filename);
const std::size_t filesize = request->contentLength();
_is_firmware = false;
if ((extension == "bin") && (filesize > 1000000)) {
_is_firmware = false;
_is_filesystem = false;
if (extension == "bin" && filename.endsWith("littlefs.bin")) {
// LittleFS filesystem image
_is_filesystem = true;
_md5[0] = '\0'; // clear any stale md5 so Update.end() doesn't compare against it
} else if ((extension == "bin") && (filesize > 2000000)) {
_is_firmware = true;
} else if (extension == "json") {
_md5[0] = '\0'; // clear md5
@@ -88,6 +95,7 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
#endif
// it's firmware - initialize the ArduinoOTA updater
emsesp::EMSESP::logger().info("Uploading firmware file %s (size: %d KB). Please wait...", filename.c_str(), filesize / 1024);
// turn off UART to prevent interference with the upload
emsesp::EMSuart::stop();
@@ -96,28 +104,57 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
Update.setMD5(_md5.data());
_md5.front() = '\0';
}
request->onDisconnect([this] { handleEarlyDisconnect(); }); // success, let's make sure we end the update if the client hangs up
request->onDisconnect([this] { handleDisconnect(); }); // success, let's make sure we end the update if the client hangs up
} else {
handleError(request, 507); // failed to begin, send an error response Insufficient Storage
return;
}
} else if (_is_filesystem) {
// LittleFS filesystem image - flash directly to the spiffs/littlefs partition
emsesp::EMSESP::logger().info("Uploading filesystem image %s (size: %u KB). Please wait...", filename.c_str(), static_cast<unsigned>(filesize / 1024));
emsesp::EMSuart::stop();
LittleFS.end(); // unmount LittleFS before we overwrite the partition under it
// request->contentLength() is the multipart HTTP body size, not the file size,
// so it can exceed the partition by a few hundred bytes. Use UPDATE_SIZE_UNKNOWN
// and let the Update library size against the whole partition.
if (Update.begin(UPDATE_SIZE_UNKNOWN, U_SPIFFS)) {
// emsesp::EMSESP::logger().info("Update.begin(U_SPIFFS) ok, partition size %u bytes", static_cast<unsigned>(Update.size()));
request->onDisconnect([this] { handleDisconnect(); });
} else {
emsesp::EMSESP::logger().err("Update.begin(U_SPIFFS) failed: %s", Update.errorString());
handleError(request, 507);
return;
}
} else {
// its a normal file, open a new temp file to write the contents too
request->_tempFile = LittleFS.open(TEMP_FILENAME_PATH, "w");
}
}
if (!_is_firmware) {
if (len && len != request->_tempFile.write(data, len)) { // stream the incoming chunk to the opened file
handleError(request, 507); // 507-Insufficient Storage
if (_is_firmware || _is_filesystem) {
if (!request->_tempObject) {
//continue with the OTA update
if (Update.write(data, len) != len) {
emsesp::EMSESP::logger().err("OTA update failed at offset %u (chunk %u): %s",
static_cast<unsigned>(Update.progress()),
static_cast<unsigned>(len),
Update.errorString());
handleError(request, 500); // internal error, failed
return;
}
if (final) {
if (!Update.end(true)) {
emsesp::EMSESP::logger().err("OTA update failed: %s", Update.errorString());
handleError(request, 500); // internal error, failed
return;
}
}
}
} else if (!request->_tempObject) { // if we haven't delt with an error, continue with the firmware update
if (Update.write(data, len) != len) {
handleError(request, 500); // internal error, failed
return;
}
if (final && !Update.end(true)) {
handleError(request, 500); // internal error, failed
} else {
// stream the incoming chunk to the opened file
if (len && len != request->_tempFile.write(data, len)) {
handleError(request, 507); // 507-Insufficient Storage
}
}
}
@@ -135,11 +172,13 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) {
return;
}
// check if it was a firmware upgrade
// if no error, send the success response as a JSON
if (_is_firmware && !request->_tempObject) {
// set NVS to tell EMS-ESP this is a new fresh firmware on next restart
emsesp::EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, true);
// check if it was a firmware or filesystem image upgrade
// if no error, send the success response and request a restart
if ((_is_firmware || _is_filesystem) && !request->_tempObject) {
if (_is_firmware) {
// set NVS to tell EMS-ESP this is a new fresh firmware on next restart
emsesp::EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, true);
}
AsyncWebServerResponse * response = request->beginResponse(200);
request->send(response);
@@ -178,15 +217,21 @@ void UploadFileService::handleError(AsyncWebServerRequest * request, int code) {
// that is caught by the web code. Unfortunately the http error code is not sent to the client on fast network connections
if (code == 406) {
request->client()->close();
_is_firmware = false;
_is_firmware = false;
_is_filesystem = false;
Update.abort();
}
// if we aborted a filesystem upload, remount LittleFS so the device keeps working
if (_is_filesystem) {
LittleFS.begin();
}
}
void UploadFileService::handleEarlyDisconnect() {
void UploadFileService::handleDisconnect() {
emsesp::EMSESP::logger().info("Upload finished");
emsesp::EMSESP::system_.uart_init(); // re-enable UART
_is_firmware = false;
Update.abort();
_is_firmware = false;
_is_filesystem = false;
}

View File

@@ -22,13 +22,14 @@ class UploadFileService {
private:
SecurityManager * _securityManager;
bool _is_firmware;
bool _is_filesystem;
std::array<char, 33> _md5;
void handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final);
void uploadComplete(AsyncWebServerRequest * request);
void handleError(AsyncWebServerRequest * request, int code);
void handleEarlyDisconnect();
void handleDisconnect();
};
#endif

View File

@@ -287,8 +287,8 @@ void AnalogSensor::reload(bool get_nvs) {
#endif
} else if (sensor.type() == AnalogType::DIGITAL_IN) {
LOG_DEBUG("Digital Read on GPIO %02d", sensor.gpio());
sensor.set_value(digitalRead(sensor.gpio())); // initial value
sensor.set_uom(0); // no uom, just for safe measures
sensor.set_value(sensor.factor() == 0 ? !digitalRead(sensor.gpio()) : digitalRead(sensor.gpio())); // initial value
sensor.set_uom(0); // no uom, just for safe measures
sensor.polltime_ = 0;
sensor.poll_ = digitalRead(sensor.gpio());
publish_sensor(sensor);
@@ -455,7 +455,7 @@ void AnalogSensor::measure() {
if (uuid::get_uptime() - sensor.polltime_ >= 15 && sensor.poll_ != sensor.last_reading_) {
sensor.last_reading_ = sensor.poll_;
if (sensor.type() == AnalogType::DIGITAL_IN) {
sensor.set_value(sensor.poll_);
sensor.set_value(sensor.factor() == 0 ? !sensor.poll_ : sensor.poll_);
} else if (!sensor.poll_) { // falling edge
if (sensor.type() == AnalogType::COUNTER) {
sensor.set_value(old_value + sensor.factor());

View File

@@ -26,11 +26,11 @@
#endif
#ifndef EMSESP_DEFAULT_TX_MODE
#define EMSESP_DEFAULT_TX_MODE 1 // EMS1.0
#define EMSESP_DEFAULT_TX_MODE 5 // Auto
#endif
#ifndef EMSESP_DEFAULT_EMS_BUS_ID
#define EMSESP_DEFAULT_EMS_BUS_ID 0x0B // service key
#define EMSESP_DEFAULT_EMS_BUS_ID 0x49 // gateway 2
#endif
#ifndef EMSESP_DEFAULT_SYSLOG_ENABLED

View File

@@ -448,6 +448,14 @@ class EMSdevice {
static constexpr uint8_t EMS_DEVICE_ID_DHW2 = 0x29; // MM100 module as water station
static constexpr uint8_t EMS_DEVICE_ID_DHW8 = 0x2F; // last DHW module id?
static constexpr uint8_t EMS_DEVICE_ID_IPM_DHW = 0x41; // IPM module as water station
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY1 = 0x48; // KM200, MX300, MX400
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY2 = 0x49;
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY3 = 0x4A;
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY4 = 0x4B;
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY5 = 0x4C;
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY6 = 0x4D;
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY7 = 0x4E;
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY8 = 0x4F;
// generic type IDs
static constexpr uint16_t EMS_TYPE_NAME = 0x01; // device config for ems devices, name ascii on offset 27ff for ems+

View File

@@ -1711,6 +1711,11 @@ void EMSESP::start() {
bool factory_settings = false;
#endif
#if defined(EMSESP_DEBUG)
// LOG_DEBUG("Listing root directory before:");
// system_.listDir("/", 3); // show the contents of the root directory
#endif
// start NVS storage
if (!nvs_.begin("ems-esp", false, "nvs1")) { // try bigger nvs partition on 16M flash first
nvs_.begin("ems-esp", false, "nvs"); // fallback to small nvs
@@ -1725,6 +1730,11 @@ void EMSESP::start() {
// loads core system services settings (mqtt, ap, ntp etc)
esp32React.begin();
#if defined(EMSESP_DEBUG)
// LOG_DEBUG("Listing root directory after:");
// system_.listDir("/", 3); // show the contents of the root directory
#endif
#ifndef EMSESP_STANDALONE
if (factory_settings) {
LOG_WARNING("No settings found on filesystem. Using factory settings.");

View File

@@ -47,7 +47,7 @@ MAKE_WORD(raw)
MAKE_WORD(watch)
MAKE_WORD(syslog)
MAKE_WORD(send)
MAKE_WORD(sendemail)
MAKE_WORD(sendmail)
MAKE_WORD(telegram)
MAKE_WORD(bus_id)
MAKE_WORD(tx_mode)

View File

@@ -65,7 +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(sendemail_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(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í")

View File

@@ -412,7 +412,7 @@ void Network::startmDNS() const {
MDNS.addService("telnet", "tcp", 23); // add our telnet console
MDNS.addServiceTxt("http", "tcp", "address", address_s.c_str());
emsesp::EMSESP::logger().info("Starting mDNS Responder service");
emsesp::EMSESP::logger().info("Starting mDNS Responder service for %s", address_s.c_str());
#endif
}

View File

@@ -116,15 +116,14 @@ bool System::command_send(const char * value, const int8_t id) {
}
// send email via SMTP
bool System::command_sendemail(const char * value, const int8_t id) {
bool System::command_sendmail(const char * value, const int8_t id) {
bool enabled = false;
bool ssl, starttls;
uint8_t security;
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;
security = settings.email_security;
server = settings.email_server;
port = settings.email_port;
login = settings.email_login;
@@ -136,8 +135,13 @@ bool System::command_sendemail(const char * value, const int8_t id) {
if (!enabled) {
return false;
}
LOG_DEBUG("Command sendemail port %d%s called with '%s'", port, ssl ? " (SSL)" : starttls ? " (STARTTLS)" : "", value);
// LOG_DEBUG("Command sendemail port %d called with '%s'", port, value);
LOG_DEBUG("Command sendmail port %d%s called with '%s'",
port,
security == EMAIL_SECURITY::SSL ? " (SSL)"
: security == EMAIL_SECURITY::STARTTLS ? ""
: " (STARTTLS)",
value);
bool success = false;
#ifndef NO_TLS_SUPPORT
@@ -149,9 +153,13 @@ bool System::command_sendemail(const char * value, const int8_t id) {
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);
r_client->addPort(port,
security == EMAIL_SECURITY::NONE ? readymail_protocol_plain_text
: security == EMAIL_SECURITY::SSL ? readymail_protocol_ssl
: readymail_protocol_tls);
// smtp->connect(server, port, sendemailCallback);
// smtp->connect(server, port, sendmailCallback);
smtp->connect(server, port);
if (!smtp->isConnected()) {
LOG_ERROR("send email connection error");
@@ -732,18 +740,16 @@ void System::start() {
last_system_check_ = 0; // force the LED to go from fast flash to pulse
uart_init(); // start UART
syslog_init(); // start syslog
modbus_init(); // start modbus
modbus_init(); // start modbus
}
// button single click
void System::button_OnClick(PButton & b) {
LOG_NOTICE("Button pressed - single click");
#if defined(EMSESP_TEST)
#ifndef EMSESP_STANDALONE
// show filesystem
Test::listDir(LittleFS, "/", 3);
#endif
listDir("/", 3);
#endif
}
@@ -1086,7 +1092,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_(sendemail), System::command_sendemail, FL_(sendemail_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);
@@ -3478,4 +3484,39 @@ void System::restore_snapshot_gpios(std::vector<int8_t> & u_gpios, std::vector<i
}
}
// show the contents of a directory in the LittleFS filesystem
void System::listDir(const char * dirname, uint8_t levels) {
#if defined(EMSESP_DEBUG)
#ifndef EMSESP_STANDALONE
File root = LittleFS.open(dirname);
if (!root) {
LOG_DEBUG("Failed to open directory %s", dirname);
return;
}
if (!root.isDirectory()) {
LOG_DEBUG("%s is not a directory", dirname);
return;
}
LOG_DEBUG("(directory) %s", dirname);
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
std::string line = std::string(file.name()) + "/";
if (levels) {
// prefix a / to the name to make it a full path
listDir(("/" + String(file.name())).c_str(), levels - 1);
}
} else {
std::string line = " (file) " + std::string(file.name()) + " (" + std::to_string(file.size()) + " bytes)";
LOG_DEBUG("%s", line.c_str());
}
file = root.openNextFile();
}
#endif
#endif
}
} // namespace emsesp

View File

@@ -72,6 +72,7 @@ enum SYSTEM_STATUS : uint8_t {
enum FUSE_VALUE : uint8_t { ALL = 0, MFG = 1, MODEL = 2, BOARD = 3, REV = 4, BATCH = 5, FUSE = 6 };
enum EMAIL_SECURITY : uint8_t { NONE = 0, SSL = 1, STARTTLS = 2 };
struct PartitionInfo {
std::string version;
size_t size;
@@ -95,13 +96,15 @@ 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_sendemail(const char * value, const int8_t id);
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);
static void get_value_json(JsonObject output, const std::string & circuit, const std::string & name, JsonVariant val);
static std::string get_metrics_prometheus();
static void listDir(const char * dirname, uint8_t levels);
#if defined(EMSESP_TEST)
static bool command_test(const char * value, const int8_t id);
#endif

View File

@@ -43,6 +43,7 @@ uint8_t EMSbus::ems_mask_ = EMS_MASK_UNSET; // unset so its triggered
uint8_t EMSbus::ems_bus_id_ = EMSESP_DEFAULT_EMS_BUS_ID;
uint8_t EMSbus::tx_mode_ = EMSESP_DEFAULT_TX_MODE;
uint8_t EMSbus::tx_state_ = Telegram::Operation::NONE;
bool EMSbus::isEMS2_ = false;
uuid::log::Logger EMSbus::logger_{F_(telegram), uuid::log::Facility::CONSOLE};
@@ -206,7 +207,9 @@ void RxService::add(uint8_t * data, uint8_t length) {
message_data = data + 6;
message_length = length - 7;
}
if (type_id > 0x0FF && message_length > 1) { // used for auto tx_mode
set_ems2();
}
// if we're watching and "raw" print out actual telegram as bytes to the console
// including the CRC at the end
if (EMSESP::watch() == EMSESP::Watch::WATCH_RAW) {

View File

@@ -169,6 +169,14 @@ class EMSbus {
return (ems_mask_ == EMS_MASK_HT3);
}
static bool is_ems2() {
return isEMS2_;
}
static void set_ems2() {
isEMS2_ = true;;
}
static uint8_t ems_mask() {
return ems_mask_;
}
@@ -242,6 +250,7 @@ class EMSbus {
static uint8_t ems_bus_id_; // the bus id, which configurable and stored in settings
static uint8_t tx_mode_; // local copy of the tx mode
static uint8_t tx_state_; // state of the Tx line (NONE or waiting on a TX_READ or TX_WRITE)
static bool isEMS2_;
};
class RxService : public EMSbus {

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.9.0-dev.4"
#define EMSESP_APP_VERSION "3.9.0-dev.7"

View File

@@ -68,7 +68,7 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
uart_telegram({0x08, 0x98, 0x33, 0x00, 0x23, 0x24});
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
// Thermostat RCPLUSStatusMessage_HC1(0x01A5)
uart_telegram({0x98, 0x00, 0xFF, 0x00, 0x01, 0xA5, 0x00, 0xCF, 0x21, 0x2E, 0x00, 0x00, 0x2E, 0x24,
@@ -89,7 +89,7 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
add_device(0x08, 219); // Greenstar HIU/Logamax kompakt WS170
// [emsesp] boiler(0x08) -W-> Me(0x0B), UBAMonitorFastPlus(0xE4), data: 00 01 35 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 80 00 (offset 6)
// [emsesp] boiler(0x08) -W-> Me(0x49), UBAMonitorFastPlus(0xE4), data: 00 01 35 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 80 00 (offset 6)
uart_telegram({0x08, 0x00, 0xE4, 0x00, //
00, 01, 0x35, 00, 00, 00, 00, 00, 00, 00, 00, 0x80, 00, 00, 00, 00, 00, 00, 00, 0x80, 00});
@@ -112,7 +112,7 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
uart_telegram({0x08, 0x90, 0x33, 0x00, 0x23, 0x24});
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
// Thermostat 0x2A5 for HC1
uart_telegram({0x10, 00, 0xFF, 00, 01, 0xA5, 0x80, 00, 01, 0x30, 0x28, 00, 0x30, 0x28, 01, 0x54,
@@ -144,7 +144,7 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
uart_telegram({0x08, 0x90, 0x33, 0x00, 0x23, 0x24});
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
// Thermostat 0x2A5 for HC1
uart_telegram({0x10, 00, 0xFF, 00, 01, 0xA5, 0x80, 00, 01, 0x30, 0x28, 00, 0x30, 0x28, 01, 0x54,
@@ -160,7 +160,7 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
EMSESP::logger().notice("Adding a Gateway...");
// add 0x48 KM200, via a version command
rx_telegram({0x48, 0x0B, 0x02, 0x00, 0xBD, 0x04, 0x06, 00, 00, 00, 00, 00, 00, 00});
rx_telegram({0x48, 0x49, 0x02, 0x00, 0xBD, 0x04, 0x06, 00, 00, 00, 00, 00, 00, 00});
// Boiler(0x08) -> All(0x00), UBADevices(0x07), data: 09 01 00 00 00 00 00 00 01 00 00 00 00
// check: make sure 0x48 is not detected again !
@@ -203,14 +203,14 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
add_device(0x08, 123); // Nefit Trendline
// UBAuptime
uart_telegram({0x08, 0x0B, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
uart_telegram({0x08, 0x49, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
// Boiler -> Me, UBAMonitorFast(0x18), telegram: 08 00 18 00 00 02 5A 73 3D 0A 10 65 40 02 1A 80 00 01 E1 01 76 0E 3D 48 00 C9 44 02 00 (#data=25)
uart_telegram({0x08, 0x00, 0x18, 0x00, 0x00, 0x02, 0x5A, 0x73, 0x3D, 0x0A, 0x10, 0x65, 0x40, 0x02, 0x1A,
0x80, 0x00, 0x01, 0xE1, 0x01, 0x76, 0x0E, 0x3D, 0x48, 0x00, 0xC9, 0x44, 0x02, 0x00});
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
return true;
}
@@ -234,10 +234,10 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
add_device(0x30, 163); // SM100
// SM100Monitor - type 0x0362 EMS+ - for SM100 and SM200
uart_telegram({0xB0, 0x0B, 0xFF, 00, 0x02, 0x62, 00, 0x44, 0x02, 0x7A, 0x80, 00, 0x80, 0x00, 0x80, 00,
uart_telegram({0xB0, 0x49, 0xFF, 00, 0x02, 0x62, 00, 0x44, 0x02, 0x7A, 0x80, 00, 0x80, 0x00, 0x80, 00,
0x80, 00, 0x80, 00, 0x80, 00, 00, 0x7C, 0x80, 00, 0x80, 00, 0x80, 00, 0x80});
uart_telegram({0xB0, 0x0B, 0xFF, 0x00, 0x02, 0x62, 0x01, 0x44, 0x03, 0x30, 0x80, 00, 0x80, 00, 0x80, 00,
uart_telegram({0xB0, 0x49, 0xFF, 0x00, 0x02, 0x62, 0x01, 0x44, 0x03, 0x30, 0x80, 00, 0x80, 00, 0x80, 00,
0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 0x33});
uart_telegram({0xB0, 00, 0xFF, 0x18, 02, 0x62, 0x80, 00, 0xB8});
@@ -580,7 +580,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
add_device(0x09, 206); // Nefit Excellent HR30 Controller
// UBAuptime
uart_telegram({0x08, 0x0B, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
uart_telegram({0x08, 0x49, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
ok = true;
}
@@ -588,10 +588,10 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
EMSESP::logger().notice("Testing 620...");
// Version Controller
uart_telegram({0x09, 0x0B, 0x02, 0x00, 0x5F, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
uart_telegram({0x09, 0x49, 0x02, 0x00, 0x5F, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
// Version Boiler
uart_telegram({0x08, 0x0B, 0x02, 0x00, 0x5F, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
uart_telegram({0x08, 0x49, 0x02, 0x00, 0x5F, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
ok = true;
}
@@ -607,7 +607,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// simulate getting version information back from an unknown device
// note there is no brand (byte 9)
rx_telegram({0x09, 0x0B, 0x02, 0x00, 0x59, 0x09, 0x0a});
rx_telegram({0x09, 0x49, 0x02, 0x00, 0x59, 0x09, 0x0a});
shell.invoke_command("show devices");
shell.invoke_command("call system report");
@@ -618,7 +618,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
shell.printfln("Testing unknown2...");
// simulate getting version information back from an unknown device
rx_telegram({0x09, 0x0B, 0x02, 0x00, 0x5A, 0x01, 0x02}); // productID is 90 which doesn't exist
rx_telegram({0x09, 0x49, 0x02, 0x00, 0x5A, 0x01, 0x02}); // productID is 90 which doesn't exist
ok = true;
}
@@ -815,9 +815,9 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// test("thermostat");
// 0xC2
// [emsesp] Boiler(0x08) -> Me(0x0B), UBAErrorMessage3(0xC2), data: 08 AC 00 10 31 48 30 31 15 80 95 0B 0E 10 38 00 7F FF FF FF 08 AC 00 10 09 41 30
// [emsesp] Boiler(0x08) -> Me(0x49), UBAErrorMessage3(0xC2), data: 08 AC 00 10 31 48 30 31 15 80 95 0B 0E 10 38 00 7F FF FF FF 08 AC 00 10 09 41 30
uart_telegram(
{0x08, 0x0B, 0xC2, 0, 0x08, 0xAC, 00, 0x10, 0x31, 0x48, 0x30, 0x31, 0x15, 0x80, 0x95, 0x0B, 0x0E, 0x10, 0x38, 00, 0x7F, 0xFF, 0xFF, 0xFF});
{0x08, 0x49, 0xC2, 0, 0x08, 0xAC, 00, 0x10, 0x31, 0x48, 0x30, 0x31, 0x15, 0x80, 0x95, 0x0B, 0x0E, 0x10, 0x38, 00, 0x7F, 0xFF, 0xFF, 0xFF});
// shell.invoke_command("show values");
@@ -1042,7 +1042,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// Boiler -> Me, UBAParameterWW(0x33)
// wwseltemp = goes from 52 degrees (0x34) to void (0xFF)
// it should delete the HA config topic homeassistant/sensor/ems-esp/boiler_wwseltemp/config
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0xFF, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0xFF, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
shell.invoke_command("call boiler wwseltemp");
shell.invoke_command("call system publish");
@@ -1785,7 +1785,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
add_device(0x18, 202); // Bosch TC100 - https://github.com/emsesp/EMS-ESP/issues/474
// 0x0A
uart_telegram({0x98, 0x0B, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
uart_telegram({0x98, 0x49, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
ok = true;
}
@@ -1819,10 +1819,10 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// SM100Monitor - type 0x0362 EMS+ - for SM100 and SM200
// B0 0B FF 00 02 62 00 44 02 7A 80 00 80 00 80 00 80 00 80 00 80 00 00 7C 80 00 80 00 80 00 80
rx_telegram({0xB0, 0x0B, 0xFF, 00, 0x02, 0x62, 00, 0x44, 0x02, 0x7A, 0x80, 00, 0x80, 0x00, 0x80, 00,
rx_telegram({0xB0, 0x49, 0xFF, 00, 0x02, 0x62, 00, 0x44, 0x02, 0x7A, 0x80, 00, 0x80, 0x00, 0x80, 00,
0x80, 00, 0x80, 00, 0x80, 00, 00, 0x7C, 0x80, 00, 0x80, 00, 0x80, 00, 0x80});
rx_telegram({0xB0, 0x0B, 0xFF, 0x00, 0x02, 0x62, 0x01, 0x44, 0x03, 0x30, 0x80, 00, 0x80, 00, 0x80, 00,
rx_telegram({0xB0, 0x49, 0xFF, 0x00, 0x02, 0x62, 0x01, 0x44, 0x03, 0x30, 0x80, 00, 0x80, 00, 0x80, 00,
0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 0x33});
rx_telegram({0xB0, 00, 0xFF, 0x18, 02, 0x62, 0x80, 00, 0xB8});
@@ -1926,7 +1926,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
if (command == "rx2") {
shell.printfln("Testing Rx2...");
for (uint8_t i = 0; i < 30; i++) {
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
ok = true;
}
}
@@ -1943,23 +1943,23 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
uart_telegram({0x08, 0x97, 0x33, 0x00, 0x23, 0x24});
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
// Thermostat -> Me, RC20StatusMessage(0x91), telegram: 17 0B 91 05 44 45 46 47 (#data=4)
uart_telegram({0x17, 0x0B, 0x91, 0x05, 0x44, 0x45, 0x46, 0x47});
uart_telegram({0x17, 0x49, 0x91, 0x05, 0x44, 0x45, 0x46, 0x47});
// bad CRC - corrupt telegram - CRC should be 0x8E
uint8_t t5[] = {0x17, 0x0B, 0x91, 0x05, 0x44, 0x45, 0x46, 0x47, 0x99};
uint8_t t5[] = {0x17, 0x49, 0x91, 0x05, 0x44, 0x45, 0x46, 0x47, 0x99};
EMSESP::rxservice_.add(t5, sizeof(t5));
// simulating a Tx record
uart_telegram({0x0B, 0x88, 0x07, 0x00, 0x20});
uart_telegram({0x49, 0x88, 0x07, 0x00, 0x20});
// Version Boiler
uart_telegram({0x08, 0x0B, 0x02, 0x00, 0x7B, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04});
uart_telegram({0x08, 0x49, 0x02, 0x00, 0x7B, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04});
// Version Thermostat, device_id 0x11
uart_telegram({0x11, 0x0B, 0x02, 0x00, 0x4D, 0x03, 0x03});
uart_telegram({0x11, 0x49, 0x02, 0x00, 0x4D, 0x03, 0x03});
// Thermostat -> all, telegram: 10 00 FF 00 01 A5 00 D7 21 00 00 00 00 30 01 84 01 01 03 01 84 01 F1 00 00 11 01 00 08 63 00
// 0x1A5 test ems+
@@ -1977,7 +1977,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
uart_telegram({0x17, 0x08, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00});
// Thermostat -> Me, RC20Set(0xA8), telegram: 17 0B A8 00 01 00 FF F6 01 06 00 01 0D 01 00 FF FF 01 02 02 02 00 00 05 1F 05 1F 02 0E 00 FF (#data=27)
uart_telegram({0x17, 0x0B, 0xA8, 0x00, 0x01, 0x00, 0xFF, 0xF6, 0x01, 0x06, 0x00, 0x01, 0x0D, 0x01, 0x00, 0xFF,
uart_telegram({0x17, 0x49, 0xA8, 0x00, 0x01, 0x00, 0xFF, 0xF6, 0x01, 0x06, 0x00, 0x01, 0x0D, 0x01, 0x00, 0xFF,
0xFF, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x05, 0x1F, 0x05, 0x1F, 0x02, 0x0E, 0x00, 0xFF});
// Boiler(0x08) -> All(0x00), UBAMonitorWW(0x34), data: 36 01 A5 80 00 21 00 00 01 00 01 3E 8D 03 77 91 00 80 00
@@ -2011,7 +2011,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
EMSESP::send_write_request(0x91, 0x17, 0x00, t18, sizeof(t18), 0x00);
// TX - send EMS+
const uint8_t t13[] = {0x90, 0x0B, 0xFF, 00, 01, 0xBA, 00, 0x2E, 0x2A, 0x26, 0x1E, 0x03,
const uint8_t t13[] = {0x90, 0x49, 0xFF, 00, 01, 0xBA, 00, 0x2E, 0x2A, 0x26, 0x1E, 0x03,
00, 0xFF, 0xFF, 05, 0x2A, 01, 0xE1, 0x20, 0x01, 0x0F, 05, 0x2A};
EMSESP::txservice_.add(Telegram::Operation::TX_RAW, t13, sizeof(t13), 0);
@@ -2135,7 +2135,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
uart_telegram({0x08, 0x98, 0x33, 0x00, 0x23, 0x24});
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
// add a thermostat
add_device(0x18, 157); // Bosch CR100
@@ -2477,7 +2477,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
if (command == "rx3") {
shell.printfln("Testing rx3...");
uart_telegram({0x21, 0x0B, 0xFF, 0x00});
uart_telegram({0x21, 0x49, 0xFF, 0x00});
ok = true;
}
@@ -2485,7 +2485,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
if (command == "tx2") {
shell.printfln("Testing tx2...");
uint8_t t[] = {0x0B, 0x88, 0x18, 0x00, 0x20, 0xD4}; // including CRC
uint8_t t[] = {0x49, 0x88, 0x18, 0x00, 0x20, 0xD4}; // including CRC
EMSuart::transmit(t, sizeof(t));
ok = true;
}
@@ -2666,45 +2666,6 @@ void Test::add_device(uint8_t device_id, uint8_t product_id) {
uart_telegram({device_id, EMSESP_DEFAULT_EMS_BUS_ID, EMSdevice::EMS_TYPE_VERSION, 0, product_id, 1, 0});
}
#ifdef EMSESP_TEST
#ifndef EMSESP_STANDALONE
void Test::listDir(fs::FS & fs, const char * dirname, uint8_t levels) {
Serial.println();
Serial.printf("%s\r\n", dirname);
File root = fs.open(dirname);
if (!root) {
Serial.println("- failed to open directory");
return;
}
if (!root.isDirectory()) {
Serial.println(" - not a directory");
return;
}
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print(file.name());
Serial.println("/");
if (levels) {
// prefix a / to the name to make it a full path
listDir(fs, ("/" + String(file.name())).c_str(), levels - 1);
}
Serial.println();
} else {
Serial.print(" ");
Serial.print(file.name());
Serial.print(" (");
Serial.print(file.size());
Serial.println(" bytes)");
}
file = root.openNextFile();
}
}
#endif
#endif
} // namespace emsesp
#endif

View File

@@ -80,7 +80,6 @@ class Test {
static void uart_telegram_withCRC(const char * rx_data);
static void add_device(uint8_t device_id, uint8_t product_id);
static void refresh();
static void listDir(fs::FS & fs, const char * dirname, uint8_t levels);
};
} // namespace emsesp

View File

@@ -159,8 +159,10 @@ uint8_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
return EMS_TX_STATUS_OK;
}
auto tx_mode = tx_mode_ != EMS_TXMODE_AUTO ? tx_mode_ : EMSbus::is_ht3() ? EMS_TXMODE_HT3 : EMSbus::is_ems2() ? EMS_TXMODE_EMSPLUS : EMS_TXMODE_EMS;
// TXMODE is EMS+ with long delay
if (tx_mode_ == EMS_TXMODE_EMSPLUS) {
if (tx_mode == EMS_TXMODE_EMSPLUS) {
for (uint8_t i = 0; i < len; i++) {
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
delayMicroseconds(EMSUART_TX_WAIT_PLUS);
@@ -170,7 +172,7 @@ uint8_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
}
// TXMODE is HT3 with 7 bittimes delay
if (tx_mode_ == EMS_TXMODE_HT3) {
if (tx_mode == EMS_TXMODE_HT3) {
for (uint8_t i = 0; i < len; i++) {
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
delayMicroseconds(EMSUART_TX_WAIT_HT3);

View File

@@ -42,10 +42,11 @@
#define EMS_TXMODE_INIT 0xFF
#define EMS_TXMODE_OFF 0
#define EMS_TXMODE_DEFAULT 1
#define EMS_TXMODE_EMS 1
#define EMS_TXMODE_EMSPLUS 2
#define EMS_TXMODE_HT3 3
#define EMS_TXMODE_HW 4
#define EMS_TXMODE_AUTO 5
// LEGACY
#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud

View File

@@ -88,8 +88,7 @@ void WebSettings::read(WebSettings & settings, JsonObject root) {
#else
root["email_enabled"] = false;
#endif
root["email_ssl"] = settings.email_ssl;
root["email_starttls"] = settings.email_starttls;
root["email_security"] = settings.email_security;
root["email_server"] = settings.email_server;
root["email_port"] = settings.email_port;
root["email_login"] = settings.email_login;
@@ -315,8 +314,7 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
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_security = root["email_security"] | FACTORY_EMAIL_SECURITY;
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;
@@ -325,9 +323,6 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
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;

View File

@@ -29,11 +29,8 @@
#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
#ifndef FACTORY_EMAIL_SECURITY
#define FACTORY_EMAIL_SECURITY 2
#endif
#ifndef FACTORY_EMAIL_PORT
#define FACTORY_EMAIL_PORT 587
@@ -108,8 +105,7 @@ class WebSettings {
uint8_t modbus_max_clients;
uint32_t modbus_timeout;
bool email_enabled;
bool email_ssl;
bool email_starttls;
uint8_t email_security;
String email_server;
uint16_t email_port;
String email_login;

View File

@@ -132,7 +132,7 @@ void uart_telegram(const char * rx_data) {
// add an EMS device and register it
void add_device(uint8_t device_id, uint8_t product_id) {
uart_telegram({device_id, 0x0B, EMSdevice::EMS_TYPE_VERSION, 0, product_id, 1, 0});
uart_telegram({device_id, 0x49, EMSdevice::EMS_TYPE_VERSION, 0, product_id, 1, 0});
}
// add our EMS test devices
@@ -143,14 +143,14 @@ void add_devices() {
add_device(0x08, 123); // Nefit Trendline
// UBAuptime
uart_telegram({0x08, 0x0B, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
uart_telegram({0x08, 0x49, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
// Boiler -> Me, UBAMonitorFast(0x18), telegram: 08 00 18 00 00 02 5A 73 3D 0A 10 65 40 02 1A 80 00 01 E1 01 76 0E 3D 48 00 C9 44 02 00 (#data=25)
uart_telegram({0x08, 0x00, 0x18, 0x00, 0x00, 0x02, 0x5A, 0x73, 0x3D, 0x0A, 0x10, 0x65, 0x40, 0x02, 0x1A,
0x80, 0x00, 0x01, 0xE1, 0x01, 0x76, 0x0E, 0x3D, 0x48, 0x00, 0xC9, 0x44, 0x02, 0x00});
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 49 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
//
// thermostat

View File

@@ -228,7 +228,7 @@ void test_23() {
"\"temperatureSensorReads\":0,\"temperatureSensorFails\":0},\"analog\":{\"enabled\":true,\"analogSensors\":5,\"analogSensorReads\":0,"
"\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\","
"\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0,\"busReadsFailed\":0,\"busWritesFailed\":0,"
"\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":1,\"emsBusID\":11,"
"\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":5,\"emsBusID\":73,"
"\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false,\"readonlyMode\":false,\"fahrenheit\":"
"false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true,\"telnetEnabled\":true,"
"\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":\"boiler\",\"name\":\"My "
@@ -259,7 +259,7 @@ void test_24() {
"\"temperatureSensorReads\":0,\"temperatureSensorFails\":0},\"analog\":{\"enabled\":true,\"analogSensors\":5,\"analogSensorReads\":0,"
"\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\","
"\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0,\"busReadsFailed\":0,\"busWritesFailed\":0,"
"\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":1,\"emsBusID\":11,"
"\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":5,\"emsBusID\":73,"
"\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false,\"readonlyMode\":false,\"fahrenheit\":"
"false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true,\"telnetEnabled\":true,"
"\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":\"boiler\",\"name\":\"My "
@@ -330,8 +330,8 @@ void test_25() {
"gauge\\nemsesp_bus_buswritesfailed 0\\n# HELP emsesp_bus_busrxlinequality busRxLineQuality\\n# TYPE emsesp_bus_busrxlinequality "
"gauge\\nemsesp_bus_busrxlinequality 100\\n# HELP emsesp_bus_bustxlinequality busTxLineQuality\\n# TYPE emsesp_bus_bustxlinequality "
"gauge\\nemsesp_bus_bustxlinequality 100\\n# HELP emsesp_bus_info info\\n# TYPE emsesp_bus_info gauge\\nemsesp_bus_info{busstatus=\\\"connected\\\", "
"busprotocol=\\\"Buderus\\\"} 1\\n# HELP emsesp_settings_txmode txMode\\n# TYPE emsesp_settings_txmode gauge\\nemsesp_settings_txmode 1\\n# HELP "
"emsesp_settings_emsbusid emsBusID\\n# TYPE emsesp_settings_emsbusid gauge\\nemsesp_settings_emsbusid 11\\n# HELP emsesp_settings_showertimer "
"busprotocol=\\\"Buderus\\\"} 1\\n# HELP emsesp_settings_txmode txMode\\n# TYPE emsesp_settings_txmode gauge\\nemsesp_settings_txmode 5\\n# HELP "
"emsesp_settings_emsbusid emsBusID\\n# TYPE emsesp_settings_emsbusid gauge\\nemsesp_settings_emsbusid 73\\n# HELP emsesp_settings_showertimer "
"showerTimer\\n# TYPE emsesp_settings_showertimer gauge\\nemsesp_settings_showertimer 0\\n# HELP emsesp_settings_showerminduration "
"showerMinDuration\\n# TYPE emsesp_settings_showerminduration gauge\\nemsesp_settings_showerminduration 180\\n# HELP emsesp_settings_showeralert "
"showerAlert\\n# TYPE emsesp_settings_showeralert gauge\\nemsesp_settings_showeralert 0\\n# HELP emsesp_settings_hideled hideLed\\n# TYPE "

View File

@@ -132,8 +132,7 @@
"modbus_timeout": 300,
"developer_mode": true,
"email_enabled": false,
"email_ssl": false,
"email_starttls": true,
"email_security": 2,
"email_server": "smtp.example.net",
"email_port": 587,
"email_login": "",