Merge pull request #2986 from MichaelDvP/core3

update Core3, change TLS library
This commit is contained in:
Proddy
2026-03-17 20:27:45 +01:00
committed by GitHub
63 changed files with 5969 additions and 34160 deletions
+9
View File
@@ -9,6 +9,10 @@ For more details go to [emsesp.org](https://emsesp.org/).
- comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935)
- customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784)
- set model for ems-esp devices temperature, analog, etc. [#2958](https://github.com/emsesp/EMS-ESP32/discussions/2958)
- 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
@@ -21,3 +25,8 @@ For more details go to [emsesp.org](https://emsesp.org/).
- remove wrong burnMinPower [#2918](https://github.com/emsesp/EMS-ESP32/issues/2918)
- store scheduler active state to nvs [#2946](https://github.com/emsesp/EMS-ESP32/discussions/2946)
- translated modes `heat` and `eco` for HA-climate mode-str-tpl
- 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
File diff suppressed because it is too large Load Diff
+1854 -1734
View File
File diff suppressed because it is too large Load Diff
+6 -5
View File
@@ -13,7 +13,7 @@ telegram_type_id,name,is_fetched
0x19,UBAMonitorSlow,
0x1A,UBASetPoints,
0x1C,UBAMaintenanceStatus,
0x1E,WM10TempMessage,
0x1E,HydrTemp,
0x23,JunkersSetMixer,fetched
0x27,UBASettingsWW,fetched
0x28,WeatherComp,fetched
@@ -72,11 +72,12 @@ telegram_type_id,name,is_fetched
0xE6,UBAParametersPlus,fetched
0xE9,UBAMonitorWWPlus,
0xEA,UBAParameterWWPlus,fetched
0xEB,PumpKick,fetched
0x0101,ISM1Set,fetched
0x0103,ISM1StatusMessage,fetched
0x0104,ISM2StatusMessage,
0x010C,IPMStatusMessage,
0x011E,JunkersDisp,fetched
0x011E,IPMTempMessage,
0x012E,HPEnergy1,
0x013B,HPEnergy2,
0x0165,JunkersSet,
@@ -111,8 +112,8 @@ telegram_type_id,name,is_fetched
0x02A0,RC300Curves,
0x02A1,RC300Curves,
0x02A2,RC300Curves,
0x02A5,RC300Monitor,
0x02A6,RC300Monitor,
0x02A5,RC300Monitor,fetched
0x02A6,CRFMonitor,
0x02A7,RC300Monitor,
0x02A8,CRFMonitor,
0x02A9,RC300Monitor,
@@ -197,7 +198,7 @@ telegram_type_id,name,is_fetched
0x04A2,HpInput,fetched
0x04A5,HPFan,fetched
0x04A7,HPPowerLimit,fetched
0x04AA,HPPower2,fetched
0x04AA,HPPower,
0x04AE,HPEnergy,fetched
0x04AF,HPMeters,fetched
0x055C,VentilationSet,fetched
1 telegram_type_id name is_fetched
13 0x19 UBAMonitorSlow
14 0x1A UBASetPoints
15 0x1C UBAMaintenanceStatus
16 0x1E WM10TempMessage HydrTemp
17 0x23 JunkersSetMixer fetched
18 0x27 UBASettingsWW fetched
19 0x28 WeatherComp fetched
72 0xE6 UBAParametersPlus fetched
73 0xE9 UBAMonitorWWPlus
74 0xEA UBAParameterWWPlus fetched
75 0xEB PumpKick fetched
76 0x0101 ISM1Set fetched
77 0x0103 ISM1StatusMessage fetched
78 0x0104 ISM2StatusMessage
79 0x010C IPMStatusMessage
80 0x011E JunkersDisp IPMTempMessage fetched
81 0x012E HPEnergy1
82 0x013B HPEnergy2
83 0x0165 JunkersSet
112 0x02A0 RC300Curves
113 0x02A1 RC300Curves
114 0x02A2 RC300Curves
115 0x02A5 RC300Monitor fetched
116 0x02A6 RC300Monitor CRFMonitor
117 0x02A7 RC300Monitor
118 0x02A8 CRFMonitor
119 0x02A9 RC300Monitor
198 0x04A2 HpInput fetched
199 0x04A5 HPFan fetched
200 0x04A7 HPPowerLimit fetched
201 0x04AA HPPower2 HPPower fetched
202 0x04AE HPEnergy fetched
203 0x04AF HPMeters fetched
204 0x055C VentilationSet fetched
+13 -13
View File
@@ -26,22 +26,22 @@
"@alova/adapter-xhr": "2.3.1",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@mui/icons-material": "^7.3.8",
"@mui/material": "^7.3.8",
"@preact/compat": "^18.3.1",
"@mui/icons-material": "^7.3.9",
"@mui/material": "^7.3.9",
"@preact/compat": "^18.3.2",
"@table-library/react-table-library": "4.1.15",
"alova": "3.5.0",
"alova": "^3.5.1",
"async-validator": "^4.2.5",
"etag": "^1.8.1",
"formidable": "^3.5.4",
"jwt-decode": "^4.0.0",
"magic-string": "^0.30.21",
"mime-types": "^3.0.2",
"preact": "^10.28.3",
"preact": "^10.29.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-icons": "^5.5.0",
"react-router": "^7.13.0",
"react-icons": "^5.6.0",
"react-router": "^7.13.1",
"react-toastify": "^11.0.5",
"typesafe-i18n": "^5.27.1",
"typescript": "^5.9.3"
@@ -50,19 +50,19 @@
"@babel/core": "^7.29.0",
"@eslint/js": "^10.0.1",
"@preact/compat": "^18.3.1",
"@preact/preset-vite": "^2.10.3",
"@preact/preset-vite": "^2.10.4",
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/node": "^25.2.3",
"@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.0",
"eslint": "^10.0.3",
"eslint-config-prettier": "^10.1.8",
"prettier": "^3.8.1",
"rollup-plugin-visualizer": "^6.0.5",
"terser": "^5.46.0",
"typescript-eslint": "^8.55.0",
"rollup-plugin-visualizer": "^7.0.1",
"terser": "^5.46.1",
"typescript-eslint": "^8.57.1",
"vite": "^7.3.1",
"vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^6.1.1"
+1115 -630
View File
File diff suppressed because it is too large Load Diff
+10
View File
@@ -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">
&nbsp; &#40;{LL.IS_REQUIRED('PSRAM')}&#41;
</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>
+4
View File
@@ -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
+6 -1
View File
@@ -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() {
+12 -1
View File
@@ -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
@@ -9,18 +9,16 @@ the LICENSE file.
#ifndef NO_TLS_SUPPORT
#include "ClientSecureSync.h"
#include "mbedtls_ssl.h" // triggers compilation of mbedtls SSL module (stripped from Tasmota libmbedtls.a)
#include <cstring>
#include <lwip/sockets.h>
#include <fcntl.h>
#include "../Config.h"
namespace espMqttClientInternals {
ClientSecureSync::ClientSecureSync()
: _tls(nullptr)
, _cfg{}
, _connected(false) {
: 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() {
@@ -28,133 +26,43 @@ ClientSecureSync::~ClientSecureSync() {
}
bool ClientSecureSync::connect(IPAddress ip, uint16_t port) {
char host[16];
sprintf(host, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
return connect(host, port);
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) {
stop(); // clean up any previous connection
_tls = esp_tls_init();
if (!_tls) {
return false;
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));
}
if (esp_tls_conn_new_sync(host, strlen(host), port, &_cfg, _tls) <= 0) {
esp_tls_conn_destroy(_tls);
_tls = nullptr;
return false;
}
_connected = true;
// Set TCP_NODELAY and non-blocking mode on the underlying socket
int fd = -1;
if (esp_tls_get_conn_sockfd(_tls, &fd) == ESP_OK && fd >= 0) {
int val = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
// Make socket non-blocking so reads don't stall the MQTT event loop
int flags = fcntl(fd, F_GETFL, 0);
if (flags >= 0) {
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
}
return true;
return ret;
}
size_t ClientSecureSync::write(const uint8_t * buf, size_t size) {
if (!_tls || !_connected) {
return 0;
}
// Write all data, retrying on WANT_WRITE (non-blocking socket)
size_t written = 0;
while (written < size) {
int ret = esp_tls_conn_write(_tls, buf + written, size - written);
if (ret > 0) {
written += ret;
} else if (ret == ESP_TLS_ERR_SSL_WANT_WRITE || ret == ESP_TLS_ERR_SSL_WANT_READ) {
continue; // retry
} else {
_connected = false;
break;
}
}
return written;
return client.write(buf, size);
}
int ClientSecureSync::read(uint8_t * buf, size_t size) {
if (!_tls || !_connected) {
return -1;
}
int ret = esp_tls_conn_read(_tls, buf, size);
if (ret > 0) {
return ret;
}
if (ret == ESP_TLS_ERR_SSL_WANT_READ || ret == ESP_TLS_ERR_SSL_WANT_WRITE) {
return -1; // no data available yet, still connected
}
// Connection closed or error
_connected = false;
return -1;
return client.read(buf, size);
}
void ClientSecureSync::stop() {
if (_tls) {
esp_tls_conn_destroy(_tls);
_tls = nullptr;
}
_connected = false;
client.stop();
}
bool ClientSecureSync::connected() {
return _connected && _tls != nullptr;
return client.connected();
}
bool ClientSecureSync::disconnected() {
return !connected();
}
void ClientSecureSync::setCACert(const char * rootCA) {
_cfg.cacert_pem_buf = reinterpret_cast<const unsigned char *>(rootCA);
_cfg.cacert_pem_bytes = strlen(rootCA) + 1;
}
void ClientSecureSync::setCertificate(const char * clientCert) {
_cfg.clientcert_pem_buf = reinterpret_cast<const unsigned char *>(clientCert);
_cfg.clientcert_pem_bytes = strlen(clientCert) + 1;
}
void ClientSecureSync::setPrivateKey(const char * privateKey) {
_cfg.clientkey_pem_buf = reinterpret_cast<const unsigned char *>(privateKey);
_cfg.clientkey_pem_bytes = strlen(privateKey) + 1;
}
void ClientSecureSync::setPreSharedKey(const char * pskIdent, const char * psKey) {
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
_psk.hint = pskIdent;
size_t key_len = strlen(psKey) / 2;
if (key_len > sizeof(_psk_key)) {
key_len = sizeof(_psk_key);
}
for (size_t i = 0; i < key_len; i++) {
sscanf(psKey + 2 * i, "%2hhx", &_psk_key[i]);
}
_psk.key = _psk_key;
_psk.key_size = key_len;
_cfg.psk_hint_key = &_psk;
#endif
}
void ClientSecureSync::setInsecure() {
_cfg.cacert_pem_buf = nullptr;
_cfg.cacert_pem_bytes = 0;
_cfg.crt_bundle_attach = nullptr;
_cfg.use_global_ca_store = false;
_cfg.skip_common_name = true;
return !client.connected();
}
} // namespace espMqttClientInternals
@@ -10,7 +10,9 @@ the LICENSE file.
#ifndef NO_TLS_SUPPORT
#include "esp_tls.h"
// #include "esp_tls.h"
#include <WiFiClient.h>
#include <ESP_SSLClient.h>
#include "Transport.h"
namespace espMqttClientInternals {
@@ -27,21 +29,8 @@ class ClientSecureSync : public Transport {
bool connected() override;
bool disconnected() override;
// TLS configuration (call before connect)
void setCACert(const char * rootCA);
void setCertificate(const char * clientCert);
void setPrivateKey(const char * privateKey);
void setPreSharedKey(const char * pskIdent, const char * psKey);
void setInsecure();
private:
esp_tls_t * _tls;
esp_tls_cfg_t _cfg;
bool _connected;
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
psk_hint_key_t _psk;
unsigned char _psk_key[64];
#endif
WiFiClient basic_client;
ESP_SSLClient client;
};
} // namespace espMqttClientInternals
+4 -54
View File
@@ -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)
@@ -79,35 +35,34 @@ espMqttClientSecure::espMqttClientSecure(uint8_t priority, uint8_t core)
espMqttClientSecure & espMqttClientSecure::setInsecure() {
#ifndef NO_TLS_SUPPORT
_client.setInsecure();
_client.client.setInsecure();
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setCACert(const char * rootCA) {
#ifndef NO_TLS_SUPPORT
_client.setCACert(rootCA);
_client.client.setCACert(rootCA);
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setCertificate(const char * clientCa) {
#ifndef NO_TLS_SUPPORT
_client.setCertificate(clientCa);
_client.client.setCertificate(clientCa);
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setPrivateKey(const char * privateKey) {
#ifndef NO_TLS_SUPPORT
_client.setPrivateKey(privateKey);
_client.client.setPrivateKey(privateKey);
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setPreSharedKey(const char * pskIdent, const char * psKey) {
#ifndef NO_TLS_SUPPORT
_client.setPreSharedKey(pskIdent, psKey);
#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
+7 -7
View File
@@ -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
-40
View File
@@ -1,40 +0,0 @@
Import("env")
import os
# The Tasmota platform builds with CONFIG_MBEDTLS_TLS_DISABLED=y, stripping the
# SSL/TLS module from libmbedtls.a. We compile it from source and re-enable the
# necessary config macros for a minimal TLS 1.2 client.
try:
platform = env.PioPlatform()
framework_dir = platform.get_package_dir("framework-arduinoespressif32")
mcu = env.BoardConfig().get("build.mcu", "esp32")
base = os.path.join(framework_dir, "tools", "esp32-arduino-libs", mcu, "include", "mbedtls")
paths = [
os.path.join(base, "mbedtls", "library"),
os.path.join(base, "mbedtls", "include"),
os.path.join(base, "port", "include"),
]
for p in paths:
if os.path.isdir(p):
env.Append(CPPPATH=[p])
# Re-enable mbedtls TLS 1.2 client support (disabled by Tasmota sdkconfig)
env.Append(CPPDEFINES=[
# Core TLS
"CONFIG_MBEDTLS_TLS_ENABLED",
"CONFIG_MBEDTLS_TLS_CLIENT",
"CONFIG_MBEDTLS_SSL_PROTO_TLS1_2",
("CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN", "16384"),
# Key exchange methods (at least one required)
"CONFIG_MBEDTLS_KEY_EXCHANGE_RSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA",
# Optional but useful
"CONFIG_MBEDTLS_SSL_RENEGOTIATION",
"CONFIG_MBEDTLS_SSL_ALPN",
])
except Exception:
pass
-10
View File
@@ -1,10 +0,0 @@
{
"name": "mbedtls_ssl",
"version": "3.6.5",
"description": "mbedtls SSL/TLS module compiled from source (Tasmota platform strips this from libmbedtls.a)",
"platforms": ["espressif32"],
"build": {
"extraScript": "configure.py",
"libArchive": false
}
}
-684
View File
@@ -1,684 +0,0 @@
/**
* \file alignment.h
*
* \brief Utility code for dealing with unaligned memory accesses
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_LIBRARY_ALIGNMENT_H
#define MBEDTLS_LIBRARY_ALIGNMENT_H
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
/*
* Define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS for architectures where unaligned memory
* accesses are known to be efficient.
*
* All functions defined here will behave correctly regardless, but might be less
* efficient when this is not defined.
*/
#if defined(__ARM_FEATURE_UNALIGNED) \
|| defined(MBEDTLS_ARCH_IS_X86) || defined(MBEDTLS_ARCH_IS_X64) \
|| defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
/*
* __ARM_FEATURE_UNALIGNED is defined where appropriate by armcc, gcc 7, clang 9
* (and later versions) for Arm v7 and later; all x86 platforms should have
* efficient unaligned access.
*
* https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#alignment
* specifies that on Windows-on-Arm64, unaligned access is safe (except for uncached
* device memory).
*/
#define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS
#endif
#if defined(__IAR_SYSTEMS_ICC__) && \
(defined(MBEDTLS_ARCH_IS_ARM64) || defined(MBEDTLS_ARCH_IS_ARM32) \
|| defined(__ICCRX__) || defined(__ICCRL78__) || defined(__ICCRISCV__))
#pragma language=save
#pragma language=extended
#define MBEDTLS_POP_IAR_LANGUAGE_PRAGMA
/* IAR recommend this technique for accessing unaligned data in
* https://www.iar.com/knowledge/support/technical-notes/compiler/accessing-unaligned-data
* This results in a single load / store instruction (if unaligned access is supported).
* According to that document, this is only supported on certain architectures.
*/
#define UINT_UNALIGNED
typedef uint16_t __packed mbedtls_uint16_unaligned_t;
typedef uint32_t __packed mbedtls_uint32_unaligned_t;
typedef uint64_t __packed mbedtls_uint64_unaligned_t;
#elif defined(MBEDTLS_COMPILER_IS_GCC) && (MBEDTLS_GCC_VERSION >= 40504) && \
((MBEDTLS_GCC_VERSION < 60300) || (!defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)))
/*
* gcc may generate a branch to memcpy for calls like `memcpy(dest, src, 4)` rather than
* generating some LDR or LDRB instructions (similar for stores).
*
* This is architecture dependent: x86-64 seems fine even with old gcc; 32-bit Arm
* is affected. To keep it simple, we enable for all architectures.
*
* For versions of gcc < 5.4.0 this issue always happens.
* For gcc < 6.3.0, this issue happens at -O0
* For all versions, this issue happens iff unaligned access is not supported.
*
* For gcc 4.x, this implementation will generate byte-by-byte loads even if unaligned access is
* supported, which is correct but not optimal.
*
* For performance (and code size, in some cases), we want to avoid the branch and just generate
* some inline load/store instructions since the access is small and constant-size.
*
* The manual states:
* "The packed attribute specifies that a variable or structure field should have the smallest
* possible alignment—one byte for a variable"
* https://gcc.gnu.org/onlinedocs/gcc-4.5.4/gcc/Variable-Attributes.html
*
* Previous implementations used __attribute__((__aligned__(1)), but had issues with a gcc bug:
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94662
*
* Tested with several versions of GCC from 4.5.0 up to 13.2.0
* We don't enable for older than 4.5.0 as this has not been tested.
*/
#define UINT_UNALIGNED_STRUCT
typedef struct {
uint16_t x;
} __attribute__((packed)) mbedtls_uint16_unaligned_t;
typedef struct {
uint32_t x;
} __attribute__((packed)) mbedtls_uint32_unaligned_t;
typedef struct {
uint64_t x;
} __attribute__((packed)) mbedtls_uint64_unaligned_t;
#endif
/*
* We try to force mbedtls_(get|put)_unaligned_uintXX to be always inline, because this results
* in code that is both smaller and faster. IAR and gcc both benefit from this when optimising
* for size.
*/
/**
* Read the unsigned 16 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 2 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint16_t mbedtls_get_unaligned_uint16(const void *p)
{
uint16_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
r = *p16;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
r = p16->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 16 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 2 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint16(void *p, uint16_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
*p16 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
p16->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
/**
* Read the unsigned 32 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 4 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint32_t mbedtls_get_unaligned_uint32(const void *p)
{
uint32_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
r = *p32;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
r = p32->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 32 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 4 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint32(void *p, uint32_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
*p32 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
p32->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
/**
* Read the unsigned 64 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 8 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint64_t mbedtls_get_unaligned_uint64(const void *p)
{
uint64_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
r = *p64;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
r = p64->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 64 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 8 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint64(void *p, uint64_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
*p64 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
p64->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
#if defined(MBEDTLS_POP_IAR_LANGUAGE_PRAGMA)
#pragma language=restore
#endif
/** Byte Reading Macros
*
* Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
* byte from x, where byte 0 is the least significant byte.
*/
#define MBEDTLS_BYTE_0(x) ((uint8_t) ((x) & 0xff))
#define MBEDTLS_BYTE_1(x) ((uint8_t) (((x) >> 8) & 0xff))
#define MBEDTLS_BYTE_2(x) ((uint8_t) (((x) >> 16) & 0xff))
#define MBEDTLS_BYTE_3(x) ((uint8_t) (((x) >> 24) & 0xff))
#define MBEDTLS_BYTE_4(x) ((uint8_t) (((x) >> 32) & 0xff))
#define MBEDTLS_BYTE_5(x) ((uint8_t) (((x) >> 40) & 0xff))
#define MBEDTLS_BYTE_6(x) ((uint8_t) (((x) >> 48) & 0xff))
#define MBEDTLS_BYTE_7(x) ((uint8_t) (((x) >> 56) & 0xff))
/*
* Detect GCC built-in byteswap routines
*/
#if defined(__GNUC__) && defined(__GNUC_PREREQ)
#if __GNUC_PREREQ(4, 8)
#define MBEDTLS_BSWAP16 __builtin_bswap16
#endif /* __GNUC_PREREQ(4,8) */
#if __GNUC_PREREQ(4, 3)
#define MBEDTLS_BSWAP32 __builtin_bswap32
#define MBEDTLS_BSWAP64 __builtin_bswap64
#endif /* __GNUC_PREREQ(4,3) */
#endif /* defined(__GNUC__) && defined(__GNUC_PREREQ) */
/*
* Detect Clang built-in byteswap routines
*/
#if defined(__clang__) && defined(__has_builtin)
#if __has_builtin(__builtin_bswap16) && !defined(MBEDTLS_BSWAP16)
#define MBEDTLS_BSWAP16 __builtin_bswap16
#endif /* __has_builtin(__builtin_bswap16) */
#if __has_builtin(__builtin_bswap32) && !defined(MBEDTLS_BSWAP32)
#define MBEDTLS_BSWAP32 __builtin_bswap32
#endif /* __has_builtin(__builtin_bswap32) */
#if __has_builtin(__builtin_bswap64) && !defined(MBEDTLS_BSWAP64)
#define MBEDTLS_BSWAP64 __builtin_bswap64
#endif /* __has_builtin(__builtin_bswap64) */
#endif /* defined(__clang__) && defined(__has_builtin) */
/*
* Detect MSVC built-in byteswap routines
*/
#if defined(_MSC_VER)
#if !defined(MBEDTLS_BSWAP16)
#define MBEDTLS_BSWAP16 _byteswap_ushort
#endif
#if !defined(MBEDTLS_BSWAP32)
#define MBEDTLS_BSWAP32 _byteswap_ulong
#endif
#if !defined(MBEDTLS_BSWAP64)
#define MBEDTLS_BSWAP64 _byteswap_uint64
#endif
#endif /* defined(_MSC_VER) */
/* Detect armcc built-in byteswap routine */
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 410000) && !defined(MBEDTLS_BSWAP32)
#if defined(__ARM_ACLE) /* ARM Compiler 6 - earlier versions don't need a header */
#include <arm_acle.h>
#endif
#define MBEDTLS_BSWAP32 __rev
#endif
/* Detect IAR built-in byteswap routine */
#if defined(__IAR_SYSTEMS_ICC__)
#if defined(__ARM_ACLE)
#include <arm_acle.h>
#define MBEDTLS_BSWAP16(x) ((uint16_t) __rev16((uint32_t) (x)))
#define MBEDTLS_BSWAP32 __rev
#define MBEDTLS_BSWAP64 __revll
#endif
#endif
/*
* Where compiler built-ins are not present, fall back to C code that the
* compiler may be able to detect and transform into the relevant bswap or
* similar instruction.
*/
#if !defined(MBEDTLS_BSWAP16)
static inline uint16_t mbedtls_bswap16(uint16_t x)
{
return
(x & 0x00ff) << 8 |
(x & 0xff00) >> 8;
}
#define MBEDTLS_BSWAP16 mbedtls_bswap16
#endif /* !defined(MBEDTLS_BSWAP16) */
#if !defined(MBEDTLS_BSWAP32)
static inline uint32_t mbedtls_bswap32(uint32_t x)
{
return
(x & 0x000000ff) << 24 |
(x & 0x0000ff00) << 8 |
(x & 0x00ff0000) >> 8 |
(x & 0xff000000) >> 24;
}
#define MBEDTLS_BSWAP32 mbedtls_bswap32
#endif /* !defined(MBEDTLS_BSWAP32) */
#if !defined(MBEDTLS_BSWAP64)
static inline uint64_t mbedtls_bswap64(uint64_t x)
{
return
(x & 0x00000000000000ffULL) << 56 |
(x & 0x000000000000ff00ULL) << 40 |
(x & 0x0000000000ff0000ULL) << 24 |
(x & 0x00000000ff000000ULL) << 8 |
(x & 0x000000ff00000000ULL) >> 8 |
(x & 0x0000ff0000000000ULL) >> 24 |
(x & 0x00ff000000000000ULL) >> 40 |
(x & 0xff00000000000000ULL) >> 56;
}
#define MBEDTLS_BSWAP64 mbedtls_bswap64
#endif /* !defined(MBEDTLS_BSWAP64) */
#if !defined(__BYTE_ORDER__)
#if defined(__LITTLE_ENDIAN__)
/* IAR defines __xxx_ENDIAN__, but not __BYTE_ORDER__ */
#define MBEDTLS_IS_BIG_ENDIAN 0
#elif defined(__BIG_ENDIAN__)
#define MBEDTLS_IS_BIG_ENDIAN 1
#else
static const uint16_t mbedtls_byte_order_detector = { 0x100 };
#define MBEDTLS_IS_BIG_ENDIAN (*((unsigned char *) (&mbedtls_byte_order_detector)) == 0x01)
#endif
#else
#if (__BYTE_ORDER__) == (__ORDER_BIG_ENDIAN__)
#define MBEDTLS_IS_BIG_ENDIAN 1
#else
#define MBEDTLS_IS_BIG_ENDIAN 0
#endif
#endif /* !defined(__BYTE_ORDER__) */
/**
* Get the unsigned 32 bits integer corresponding to four bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the four bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the four bytes to build the 32 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT32_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint32((data) + (offset)) \
: MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
)
/**
* Put in memory a 32 bits unsigned integer in big-endian order.
*
* \param n 32 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 32
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 32 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT32_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), (uint32_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
} \
}
/**
* Get the unsigned 32 bits integer corresponding to four bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the four bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the four bytes to build the 32 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT32_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
: mbedtls_get_unaligned_uint32((data) + (offset)) \
)
/**
* Put in memory a 32 bits unsigned integer in little-endian order.
*
* \param n 32 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 32
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 32 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT32_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), ((uint32_t) (n))); \
} \
}
/**
* Get the unsigned 16 bits integer corresponding to two bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the two bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the two bytes to build the 16 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT16_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
: mbedtls_get_unaligned_uint16((data) + (offset)) \
)
/**
* Put in memory a 16 bits unsigned integer in little-endian order.
*
* \param n 16 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 16
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 16 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT16_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
} \
}
/**
* Get the unsigned 16 bits integer corresponding to two bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the two bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the two bytes to build the 16 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT16_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint16((data) + (offset)) \
: MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
)
/**
* Put in memory a 16 bits unsigned integer in big-endian order.
*
* \param n 16 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 16
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 16 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT16_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
} \
}
/**
* Get the unsigned 24 bits integer corresponding to three bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the three bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the three bytes to build the 24 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT24_BE(data, offset) \
( \
((uint32_t) (data)[(offset)] << 16) \
| ((uint32_t) (data)[(offset) + 1] << 8) \
| ((uint32_t) (data)[(offset) + 2]) \
)
/**
* Put in memory a 24 bits unsigned integer in big-endian order.
*
* \param n 24 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 24
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 24 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT24_BE(n, data, offset) \
{ \
(data)[(offset)] = MBEDTLS_BYTE_2(n); \
(data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
(data)[(offset) + 2] = MBEDTLS_BYTE_0(n); \
}
/**
* Get the unsigned 24 bits integer corresponding to three bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the three bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the three bytes to build the 24 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT24_LE(data, offset) \
( \
((uint32_t) (data)[(offset)]) \
| ((uint32_t) (data)[(offset) + 1] << 8) \
| ((uint32_t) (data)[(offset) + 2] << 16) \
)
/**
* Put in memory a 24 bits unsigned integer in little-endian order.
*
* \param n 24 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 24
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 24 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT24_LE(n, data, offset) \
{ \
(data)[(offset)] = MBEDTLS_BYTE_0(n); \
(data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
(data)[(offset) + 2] = MBEDTLS_BYTE_2(n); \
}
/**
* Get the unsigned 64 bits integer corresponding to eight bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the eight bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the eight bytes to build the 64 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT64_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint64((data) + (offset)) \
: MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
)
/**
* Put in memory a 64 bits unsigned integer in big-endian order.
*
* \param n 64 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 64
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 64 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT64_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
} \
}
/**
* Get the unsigned 64 bits integer corresponding to eight bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the eight bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the eight bytes to build the 64 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT64_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
: mbedtls_get_unaligned_uint64((data) + (offset)) \
)
/**
* Put in memory a 64 bits unsigned integer in little-endian order.
*
* \param n 64 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 64
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 64 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT64_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
} \
}
#endif /* MBEDTLS_LIBRARY_ALIGNMENT_H */
-453
View File
@@ -1,453 +0,0 @@
/**
* \file common.h
*
* \brief Utility macros for internal use in the library
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_LIBRARY_COMMON_H
#define MBEDTLS_LIBRARY_COMMON_H
#include "mbedtls/build_info.h"
#include "alignment.h"
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stddef.h>
#if defined(__ARM_NEON)
#include <arm_neon.h>
#define MBEDTLS_HAVE_NEON_INTRINSICS
#elif defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
#include <arm64_neon.h>
#define MBEDTLS_HAVE_NEON_INTRINSICS
#endif
/** Helper to define a function as static except when building invasive tests.
*
* If a function is only used inside its own source file and should be
* declared `static` to allow the compiler to optimize for code size,
* but that function has unit tests, define it with
* ```
* MBEDTLS_STATIC_TESTABLE int mbedtls_foo(...) { ... }
* ```
* and declare it in a header in the `library/` directory with
* ```
* #if defined(MBEDTLS_TEST_HOOKS)
* int mbedtls_foo(...);
* #endif
* ```
*/
#if defined(MBEDTLS_TEST_HOOKS)
#define MBEDTLS_STATIC_TESTABLE
#else
#define MBEDTLS_STATIC_TESTABLE static
#endif
#if defined(MBEDTLS_TEST_HOOKS)
extern void (*mbedtls_test_hook_test_fail)(const char *test, int line, const char *file);
#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST) \
do { \
if ((!(TEST)) && ((*mbedtls_test_hook_test_fail) != NULL)) \
{ \
(*mbedtls_test_hook_test_fail)( #TEST, __LINE__, __FILE__); \
} \
} while (0)
#else
#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST)
#endif /* defined(MBEDTLS_TEST_HOOKS) */
/** \def ARRAY_LENGTH
* Return the number of elements of a static or stack array.
*
* \param array A value of array (not pointer) type.
*
* \return The number of elements of the array.
*/
/* A correct implementation of ARRAY_LENGTH, but which silently gives
* a nonsensical result if called with a pointer rather than an array. */
#define ARRAY_LENGTH_UNSAFE(array) \
(sizeof(array) / sizeof(*(array)))
#if defined(__GNUC__)
/* Test if arg and &(arg)[0] have the same type. This is true if arg is
* an array but not if it's a pointer. */
#define IS_ARRAY_NOT_POINTER(arg) \
(!__builtin_types_compatible_p(__typeof__(arg), \
__typeof__(&(arg)[0])))
/* A compile-time constant with the value 0. If `const_expr` is not a
* compile-time constant with a nonzero value, cause a compile-time error. */
#define STATIC_ASSERT_EXPR(const_expr) \
(0 && sizeof(struct { unsigned int STATIC_ASSERT : 1 - 2 * !(const_expr); }))
/* Return the scalar value `value` (possibly promoted). This is a compile-time
* constant if `value` is. `condition` must be a compile-time constant.
* If `condition` is false, arrange to cause a compile-time error. */
#define STATIC_ASSERT_THEN_RETURN(condition, value) \
(STATIC_ASSERT_EXPR(condition) ? 0 : (value))
#define ARRAY_LENGTH(array) \
(STATIC_ASSERT_THEN_RETURN(IS_ARRAY_NOT_POINTER(array), \
ARRAY_LENGTH_UNSAFE(array)))
#else
/* If we aren't sure the compiler supports our non-standard tricks,
* fall back to the unsafe implementation. */
#define ARRAY_LENGTH(array) ARRAY_LENGTH_UNSAFE(array)
#endif
/** Allow library to access its structs' private members.
*
* Although structs defined in header files are publicly available,
* their members are private and should not be accessed by the user.
*/
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
/**
* \brief Securely zeroize a buffer then free it.
*
* Similar to making consecutive calls to
* \c mbedtls_platform_zeroize() and \c mbedtls_free(), but has
* code size savings, and potential for optimisation in the future.
*
* Guaranteed to be a no-op if \p buf is \c NULL and \p len is 0.
*
* \param buf Buffer to be zeroized then freed.
* \param len Length of the buffer in bytes
*/
void mbedtls_zeroize_and_free(void *buf, size_t len);
/** Return an offset into a buffer.
*
* This is just the addition of an offset to a pointer, except that this
* function also accepts an offset of 0 into a buffer whose pointer is null.
* (`p + n` has undefined behavior when `p` is null, even when `n == 0`.
* A null pointer is a valid buffer pointer when the size is 0, for example
* as the result of `malloc(0)` on some platforms.)
*
* \param p Pointer to a buffer of at least n bytes.
* This may be \p NULL if \p n is zero.
* \param n An offset in bytes.
* \return Pointer to offset \p n in the buffer \p p.
* Note that this is only a valid pointer if the size of the
* buffer is at least \p n + 1.
*/
static inline unsigned char *mbedtls_buffer_offset(
unsigned char *p, size_t n)
{
return p == NULL ? NULL : p + n;
}
/** Return an offset into a read-only buffer.
*
* Similar to mbedtls_buffer_offset(), but for const pointers.
*
* \param p Pointer to a buffer of at least n bytes.
* This may be \p NULL if \p n is zero.
* \param n An offset in bytes.
* \return Pointer to offset \p n in the buffer \p p.
* Note that this is only a valid pointer if the size of the
* buffer is at least \p n + 1.
*/
static inline const unsigned char *mbedtls_buffer_offset_const(
const unsigned char *p, size_t n)
{
return p == NULL ? NULL : p + n;
}
/* Always inline mbedtls_xor() for similar reasons as mbedtls_xor_no_simd(). */
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
/**
* Perform a fast block XOR operation, such that
* r[i] = a[i] ^ b[i] where 0 <= i < n
*
* \param r Pointer to result (buffer of at least \p n bytes). \p r
* may be equal to either \p a or \p b, but behaviour when
* it overlaps in other ways is undefined.
* \param a Pointer to input (buffer of at least \p n bytes)
* \param b Pointer to input (buffer of at least \p n bytes)
* \param n Number of bytes to process.
*
* \note Depending on the situation, it may be faster to use either mbedtls_xor() or
* mbedtls_xor_no_simd() (these are functionally equivalent).
* If the result is used immediately after the xor operation in non-SIMD code (e.g, in
* AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
* registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
* the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
* For targets without SIMD support, they will behave the same.
*/
static inline void mbedtls_xor(unsigned char *r,
const unsigned char *a,
const unsigned char *b,
size_t n)
{
size_t i = 0;
#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
#if defined(MBEDTLS_HAVE_NEON_INTRINSICS) && \
(!(defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_GCC_VERSION < 70300))
/* Old GCC versions generate a warning here, so disable the NEON path for these compilers */
for (; (i + 16) <= n; i += 16) {
uint8x16_t v1 = vld1q_u8(a + i);
uint8x16_t v2 = vld1q_u8(b + i);
uint8x16_t x = veorq_u8(v1, v2);
vst1q_u8(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
/* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
* where n is a constant multiple of 16.
* For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
* constant, and is a very small perf regression if n is not a compile-time constant. */
if (n % 16 == 0) {
return;
}
#endif
#elif defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
/* This codepath probably only makes sense on architectures with 64-bit registers */
for (; (i + 8) <= n; i += 8) {
uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
mbedtls_put_unaligned_uint64(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 8 == 0) {
return;
}
#endif
#else
for (; (i + 4) <= n; i += 4) {
uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
mbedtls_put_unaligned_uint32(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 4 == 0) {
return;
}
#endif
#endif
#endif
for (; i < n; i++) {
r[i] = a[i] ^ b[i];
}
}
/* Always inline mbedtls_xor_no_simd() as we see significant perf regressions when it does not get
* inlined (e.g., observed about 3x perf difference in gcm_mult_largetable with gcc 7 - 12) */
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
/**
* Perform a fast block XOR operation, such that
* r[i] = a[i] ^ b[i] where 0 <= i < n
*
* In some situations, this can perform better than mbedtls_xor() (e.g., it's about 5%
* better in AES-CBC).
*
* \param r Pointer to result (buffer of at least \p n bytes). \p r
* may be equal to either \p a or \p b, but behaviour when
* it overlaps in other ways is undefined.
* \param a Pointer to input (buffer of at least \p n bytes)
* \param b Pointer to input (buffer of at least \p n bytes)
* \param n Number of bytes to process.
*
* \note Depending on the situation, it may be faster to use either mbedtls_xor() or
* mbedtls_xor_no_simd() (these are functionally equivalent).
* If the result is used immediately after the xor operation in non-SIMD code (e.g, in
* AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
* registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
* the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
* For targets without SIMD support, they will behave the same.
*/
static inline void mbedtls_xor_no_simd(unsigned char *r,
const unsigned char *a,
const unsigned char *b,
size_t n)
{
size_t i = 0;
#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
#if defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
/* This codepath probably only makes sense on architectures with 64-bit registers */
for (; (i + 8) <= n; i += 8) {
uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
mbedtls_put_unaligned_uint64(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
/* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
* where n is a constant multiple of 8.
* For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
* constant, and is a very small perf regression if n is not a compile-time constant. */
if (n % 8 == 0) {
return;
}
#endif
#else
for (; (i + 4) <= n; i += 4) {
uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
mbedtls_put_unaligned_uint32(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 4 == 0) {
return;
}
#endif
#endif
#endif
for (; i < n; i++) {
r[i] = a[i] ^ b[i];
}
}
/* Fix MSVC C99 compatible issue
* MSVC support __func__ from visual studio 2015( 1900 )
* Use MSVC predefine macro to avoid name check fail.
*/
#if (defined(_MSC_VER) && (_MSC_VER <= 1900))
#define /*no-check-names*/ __func__ __FUNCTION__
#endif
/* Define `asm` for compilers which don't define it. */
/* *INDENT-OFF* */
#ifndef asm
#if defined(__IAR_SYSTEMS_ICC__)
#define asm __asm
#else
#define asm __asm__
#endif
#endif
/* *INDENT-ON* */
/*
* Define the constraint used for read-only pointer operands to aarch64 asm.
*
* This is normally the usual "r", but for aarch64_32 (aka ILP32,
* as found in watchos), "p" is required to avoid warnings from clang.
*
* Note that clang does not recognise '+p' or '=p', and armclang
* does not recognise 'p' at all. Therefore, to update a pointer from
* aarch64 assembly, it is necessary to use something like:
*
* uintptr_t uptr = (uintptr_t) ptr;
* asm( "ldr x4, [%x0], #8" ... : "+r" (uptr) : : )
* ptr = (void*) uptr;
*
* Note that the "x" in "%x0" is neccessary; writing "%0" will cause warnings.
*/
#if defined(__aarch64__) && defined(MBEDTLS_HAVE_ASM)
#if UINTPTR_MAX == 0xfffffffful
/* ILP32: Specify the pointer operand slightly differently, as per #7787. */
#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "p"
#elif UINTPTR_MAX == 0xfffffffffffffffful
/* Normal case (64-bit pointers): use "r" as the constraint for pointer operands to asm */
#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "r"
#else
#error "Unrecognised pointer size for aarch64"
#endif
#endif
/* Always provide a static assert macro, so it can be used unconditionally.
* It does nothing on systems where we don't know how to define a static assert.
*/
/* Can't use the C11-style `defined(static_assert)` on FreeBSD, since it
* defines static_assert even with -std=c99, but then complains about it.
*/
#if defined(static_assert) && !defined(__FreeBSD__)
#define MBEDTLS_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
#else
/* Make sure `MBEDTLS_STATIC_ASSERT(expr, msg);` is valid both inside and
* outside a function. We choose a struct declaration, which can be repeated
* any number of times and does not need a matching definition. */
#define MBEDTLS_STATIC_ASSERT(expr, msg) \
struct ISO_C_does_not_allow_extra_semicolon_outside_of_a_function
#endif
#if defined(__has_builtin)
#define MBEDTLS_HAS_BUILTIN(x) __has_builtin(x)
#else
#define MBEDTLS_HAS_BUILTIN(x) 0
#endif
/* Define compiler branch hints */
#if MBEDTLS_HAS_BUILTIN(__builtin_expect)
#define MBEDTLS_LIKELY(x) __builtin_expect(!!(x), 1)
#define MBEDTLS_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define MBEDTLS_LIKELY(x) x
#define MBEDTLS_UNLIKELY(x) x
#endif
/* MBEDTLS_ASSUME may be used to provide additional information to the compiler
* which can result in smaller code-size. */
#if MBEDTLS_HAS_BUILTIN(__builtin_assume)
/* clang provides __builtin_assume */
#define MBEDTLS_ASSUME(x) __builtin_assume(x)
#elif MBEDTLS_HAS_BUILTIN(__builtin_unreachable)
/* gcc and IAR can use __builtin_unreachable */
#define MBEDTLS_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0)
#elif defined(_MSC_VER)
/* Supported by MSVC since VS 2005 */
#define MBEDTLS_ASSUME(x) __assume(x)
#else
#define MBEDTLS_ASSUME(x) do { } while (0)
#endif
/* For gcc -Os, override with -O2 for a given function.
*
* This will not affect behaviour for other optimisation settings, e.g. -O0.
*/
#if defined(MBEDTLS_COMPILER_IS_GCC) && defined(__OPTIMIZE_SIZE__)
#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE __attribute__((optimize("-O2")))
#else
#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE
#endif
/* Suppress compiler warnings for unused functions and variables. */
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__has_attribute)
# if __has_attribute(unused)
# define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
# endif
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__GNUC__)
# define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__IAR_SYSTEMS_ICC__) && defined(__VER__)
/* IAR does support __attribute__((unused)), but only if the -e flag (extended language support)
* is given; the pragma always works.
* Unfortunately the pragma affects the rest of the file where it is used, but this is harmless.
* Check for version 5.2 or later - this pragma may be supported by earlier versions, but I wasn't
* able to find documentation).
*/
# if (__VER__ >= 5020000)
# define MBEDTLS_MAYBE_UNUSED _Pragma("diag_suppress=Pe177")
# endif
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(_MSC_VER)
# define MBEDTLS_MAYBE_UNUSED __pragma(warning(suppress:4189))
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED)
# define MBEDTLS_MAYBE_UNUSED
#endif
/* GCC >= 15 has a warning 'unterminated-string-initialization' which complains if you initialize
* a string into an array without space for a terminating NULL character. In some places in the
* codebase this behaviour is intended, so we add the macro MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING
* to suppress the warning in these places.
*/
#if defined(__has_attribute)
#if __has_attribute(nonstring)
#define MBEDTLS_HAS_ATTRIBUTE_NONSTRING
#endif /* __has_attribute(nonstring) */
#endif /* __has_attribute */
#if defined(MBEDTLS_HAS_ATTRIBUTE_NONSTRING)
#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING __attribute__((nonstring))
#else
#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING
#endif /* MBEDTLS_HAS_ATTRIBUTE_NONSTRING */
#endif /* MBEDTLS_LIBRARY_COMMON_H */
@@ -1,579 +0,0 @@
/**
* Constant-time functions
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_CONSTANT_TIME_INTERNAL_H
#define MBEDTLS_CONSTANT_TIME_INTERNAL_H
#include <stdint.h>
#include <stddef.h>
#include "common.h"
#if defined(MBEDTLS_BIGNUM_C)
#include "mbedtls/bignum.h"
#endif
/* The constant-time interface provides various operations that are likely
* to result in constant-time code that does not branch or use conditional
* instructions for secret data (for secret pointers, this also applies to
* the data pointed to).
*
* It has three main parts:
*
* - boolean operations
* These are all named mbedtls_ct_<type>_<operation>.
* They operate over <type> and return mbedtls_ct_condition_t.
* All arguments are considered secret.
* example: bool x = y | z => x = mbedtls_ct_bool_or(y, z)
* example: bool x = y == z => x = mbedtls_ct_uint_eq(y, z)
*
* - conditional data selection
* These are all named mbedtls_ct_<type>_if and mbedtls_ct_<type>_if_else_0
* All arguments are considered secret.
* example: size_t a = x ? b : c => a = mbedtls_ct_size_if(x, b, c)
* example: unsigned a = x ? b : 0 => a = mbedtls_ct_uint_if_else_0(x, b)
*
* - block memory operations
* Only some arguments are considered secret, as documented for each
* function.
* example: if (x) memcpy(...) => mbedtls_ct_memcpy_if(x, ...)
*
* mbedtls_ct_condition_t must be treated as opaque and only created and
* manipulated via the functions in this header. The compiler should never
* be able to prove anything about its value at compile-time.
*
* mbedtls_ct_uint_t is an unsigned integer type over which constant time
* operations may be performed via the functions in this header. It is as big
* as the larger of size_t and mbedtls_mpi_uint, i.e. it is safe to cast
* to/from "unsigned int", "size_t", and "mbedtls_mpi_uint" (and any other
* not-larger integer types).
*
* For Arm (32-bit, 64-bit and Thumb), x86 and x86-64, assembly implementations
* are used to ensure that the generated code is constant time. For other
* architectures, it uses a plain C fallback designed to yield constant-time code
* (this has been observed to be constant-time on latest gcc, clang and MSVC
* as of May 2023).
*
* For readability, the static inline definitions are separated out into
* constant_time_impl.h.
*/
#if (SIZE_MAX > 0xffffffffffffffffULL)
/* Pointer size > 64-bit */
typedef size_t mbedtls_ct_condition_t;
typedef size_t mbedtls_ct_uint_t;
typedef ptrdiff_t mbedtls_ct_int_t;
#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(SIZE_MAX))
#elif (SIZE_MAX > 0xffffffff) || defined(MBEDTLS_HAVE_INT64)
/* 32-bit < pointer size <= 64-bit, or 64-bit MPI */
typedef uint64_t mbedtls_ct_condition_t;
typedef uint64_t mbedtls_ct_uint_t;
typedef int64_t mbedtls_ct_int_t;
#define MBEDTLS_CT_SIZE_64
#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(UINT64_MAX))
#else
/* Pointer size <= 32-bit, and no 64-bit MPIs */
typedef uint32_t mbedtls_ct_condition_t;
typedef uint32_t mbedtls_ct_uint_t;
typedef int32_t mbedtls_ct_int_t;
#define MBEDTLS_CT_SIZE_32
#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(UINT32_MAX))
#endif
#define MBEDTLS_CT_FALSE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(0))
/* ============================================================================
* Boolean operations
*/
/** Convert a number into a mbedtls_ct_condition_t.
*
* \param x Number to convert.
*
* \return MBEDTLS_CT_TRUE if \p x != 0, or MBEDTLS_CT_FALSE if \p x == 0
*
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x);
/** Boolean "not equal" operation.
*
* Functionally equivalent to:
*
* \p x != \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x != \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
/** Boolean "equals" operation.
*
* Functionally equivalent to:
*
* \p x == \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x == \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_eq(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean "less than" operation.
*
* Functionally equivalent to:
*
* \p x < \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x < \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
/** Boolean "greater than" operation.
*
* Functionally equivalent to:
*
* \p x > \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x > \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_gt(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean "greater or equal" operation.
*
* Functionally equivalent to:
*
* \p x >= \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x >= \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_ge(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean "less than or equal" operation.
*
* Functionally equivalent to:
*
* \p x <= \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x <= \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_le(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean not-equals operation.
*
* Functionally equivalent to:
*
* \p x != \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \note This is more efficient than mbedtls_ct_uint_ne if both arguments are
* mbedtls_ct_condition_t.
*
* \return MBEDTLS_CT_TRUE if \p x != \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_condition_t x,
mbedtls_ct_condition_t y);
/** Boolean "and" operation.
*
* Functionally equivalent to:
*
* \p x && \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x && \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x,
mbedtls_ct_condition_t y);
/** Boolean "or" operation.
*
* Functionally equivalent to:
*
* \p x || \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x || \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x,
mbedtls_ct_condition_t y);
/** Boolean "not" operation.
*
* Functionally equivalent to:
*
* ! \p x
*
* \param x The value to invert
*
* \return MBEDTLS_CT_FALSE if \p x, otherwise MBEDTLS_CT_TRUE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x);
/* ============================================================================
* Data selection operations
*/
/** Choose between two size_t values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition,
size_t if1,
size_t if0);
/** Choose between two unsigned values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition,
unsigned if1,
unsigned if0);
/** Choose between two mbedtls_ct_condition_t values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_if(mbedtls_ct_condition_t condition,
mbedtls_ct_condition_t if1,
mbedtls_ct_condition_t if0);
#if defined(MBEDTLS_BIGNUM_C)
/** Choose between two mbedtls_mpi_uint values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, \
mbedtls_mpi_uint if1, \
mbedtls_mpi_uint if0);
#endif
/** Choose between an unsigned value and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_uint_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1);
/** Choose between an mbedtls_ct_condition_t and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_bool_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_if_else_0(mbedtls_ct_condition_t condition,
mbedtls_ct_condition_t if1);
/** Choose between a size_t value and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_size_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline size_t mbedtls_ct_size_if_else_0(mbedtls_ct_condition_t condition, size_t if1);
#if defined(MBEDTLS_BIGNUM_C)
/** Choose between an mbedtls_mpi_uint value and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_mpi_uint_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if_else_0(mbedtls_ct_condition_t condition,
mbedtls_mpi_uint if1);
#endif
/** Constant-flow char selection
*
* \param low Secret. Bottom of range
* \param high Secret. Top of range
* \param c Secret. Value to compare to range
* \param t Secret. Value to return, if in range
*
* \return \p t if \p low <= \p c <= \p high, 0 otherwise.
*/
static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,
unsigned char high,
unsigned char c,
unsigned char t);
/** Choose between two error values. The values must be in the range [-32767..0].
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline int mbedtls_ct_error_if(mbedtls_ct_condition_t condition, int if1, int if0);
/** Choose between an error value and 0. The error value must be in the range [-32767..0].
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_error_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline int mbedtls_ct_error_if_else_0(mbedtls_ct_condition_t condition, int if1);
/* ============================================================================
* Block memory operations
*/
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
/** Conditionally set a block of memory to zero.
*
* Regardless of the condition, every byte will be read once and written to
* once.
*
* \param condition Secret. Condition to test.
* \param buf Secret. Pointer to the start of the buffer.
* \param len Number of bytes to set to zero.
*
* \warning Unlike mbedtls_platform_zeroize, this does not have the same guarantees
* about not being optimised away if the memory is never read again.
*/
void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len);
/** Shift some data towards the left inside a buffer.
*
* Functionally equivalent to:
*
* memmove(start, start + offset, total - offset);
* memset(start + (total - offset), 0, offset);
*
* Timing independence comes at the expense of performance.
*
* \param start Secret. Pointer to the start of the buffer.
* \param total Total size of the buffer.
* \param offset Secret. Offset from which to copy \p total - \p offset bytes.
*/
void mbedtls_ct_memmove_left(void *start,
size_t total,
size_t offset);
#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */
/** Conditional memcpy.
*
* Functionally equivalent to:
*
* if (condition) {
* memcpy(dest, src1, len);
* } else {
* if (src2 != NULL)
* memcpy(dest, src2, len);
* }
*
* It will always read len bytes from src1.
* If src2 != NULL, it will always read len bytes from src2.
* If src2 == NULL, it will instead read len bytes from dest (as if src2 == dest).
*
* \param condition The condition
* \param dest Secret. Destination pointer.
* \param src1 Secret. Pointer to copy from (if \p condition == MBEDTLS_CT_TRUE).
* This may be equal to \p dest, but may not overlap in other ways.
* \param src2 Secret (contents only - may branch to determine if this parameter is NULL).
* Pointer to copy from (if \p condition == MBEDTLS_CT_FALSE and \p src2 is not NULL). May be NULL.
* This may be equal to \p dest, but may not overlap it in other ways. It may overlap with \p src1.
* \param len Number of bytes to copy.
*/
void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition,
unsigned char *dest,
const unsigned char *src1,
const unsigned char *src2,
size_t len
);
/** Copy data from a secret position.
*
* Functionally equivalent to:
*
* memcpy(dst, src + offset, len)
*
* This function copies \p len bytes from \p src + \p offset to
* \p dst, with a code flow and memory access pattern that does not depend on
* \p offset, but only on \p offset_min, \p offset_max and \p len.
*
* \note This function reads from \p dest, but the value that
* is read does not influence the result and this
* function's behavior is well-defined regardless of the
* contents of the buffers. This may result in false
* positives from static or dynamic analyzers, especially
* if \p dest is not initialized.
*
* \param dest Secret. The destination buffer. This must point to a writable
* buffer of at least \p len bytes.
* \param src Secret. The base of the source buffer. This must point to a
* readable buffer of at least \p offset_max + \p len
* bytes. Shouldn't overlap with \p dest
* \param offset Secret. The offset in the source buffer from which to copy.
* This must be no less than \p offset_min and no greater
* than \p offset_max.
* \param offset_min The minimal value of \p offset.
* \param offset_max The maximal value of \p offset.
* \param len The number of bytes to copy.
*/
void mbedtls_ct_memcpy_offset(unsigned char *dest,
const unsigned char *src,
size_t offset,
size_t offset_min,
size_t offset_max,
size_t len);
/* Documented in include/mbedtls/constant_time.h. a and b are secret.
int mbedtls_ct_memcmp(const void *a,
const void *b,
size_t n);
*/
#if defined(MBEDTLS_NIST_KW_C)
/** Constant-time buffer comparison without branches.
*
* Similar to mbedtls_ct_memcmp, except that the result only depends on part of
* the input data - differences in the head or tail are ignored. Functionally equivalent to:
*
* memcmp(a + skip_head, b + skip_head, size - skip_head - skip_tail)
*
* Time taken depends on \p n, but not on \p skip_head or \p skip_tail .
*
* Behaviour is undefined if ( \p skip_head + \p skip_tail) > \p n.
*
* \param a Secret. Pointer to the first buffer, containing at least \p n bytes. May not be NULL.
* \param b Secret. Pointer to the second buffer, containing at least \p n bytes. May not be NULL.
* \param n The number of bytes to examine (total size of the buffers).
* \param skip_head Secret. The number of bytes to treat as non-significant at the start of the buffer.
* These bytes will still be read.
* \param skip_tail Secret. The number of bytes to treat as non-significant at the end of the buffer.
* These bytes will still be read.
*
* \return Zero if the contents of the two buffers are the same, otherwise non-zero.
*/
int mbedtls_ct_memcmp_partial(const void *a,
const void *b,
size_t n,
size_t skip_head,
size_t skip_tail);
#endif
/* Include the implementation of static inline functions above. */
#include "constant_time_impl.h"
#endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */
-172
View File
@@ -1,172 +0,0 @@
/**
* \file debug_internal.h
*
* \brief Internal part of the public "debug.h".
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_DEBUG_INTERNAL_H
#define MBEDTLS_DEBUG_INTERNAL_H
#include "mbedtls/debug.h"
/**
* \brief Print a message to the debug output. This function is always used
* through the MBEDTLS_SSL_DEBUG_MSG() macro, which supplies the ssl
* context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the message has occurred in
* \param line line number the message has occurred at
* \param format format specifier, in printf format
* \param ... variables used by the format specifier
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_msg(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *format, ...) MBEDTLS_PRINTF_ATTRIBUTE(5, 6);
/**
* \brief Print the return value of a function to the debug output. This
* function is always used through the MBEDTLS_SSL_DEBUG_RET() macro,
* which supplies the ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text the name of the function that returned the error
* \param ret the return code value
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_ret(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, int ret);
/**
* \brief Output a buffer of size len bytes to the debug output. This function
* is always used through the MBEDTLS_SSL_DEBUG_BUF() macro,
* which supplies the ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the buffer being dumped. Normally the
* variable or buffer name
* \param buf the buffer to be outputted
* \param len length of the buffer
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_buf(const mbedtls_ssl_context *ssl, int level,
const char *file, int line, const char *text,
const unsigned char *buf, size_t len);
#if defined(MBEDTLS_BIGNUM_C)
/**
* \brief Print a MPI variable to the debug output. This function is always
* used through the MBEDTLS_SSL_DEBUG_MPI() macro, which supplies the
* ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the MPI being output. Normally the
* variable name
* \param X the MPI variable
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_mpi(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, const mbedtls_mpi *X);
#endif
#if defined(MBEDTLS_ECP_LIGHT)
/**
* \brief Print an ECP point to the debug output. This function is always
* used through the MBEDTLS_SSL_DEBUG_ECP() macro, which supplies the
* ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the ECP point being output. Normally the
* variable name
* \param X the ECP point
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_ecp(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, const mbedtls_ecp_point *X);
#endif
#if defined(MBEDTLS_X509_CRT_PARSE_C) && !defined(MBEDTLS_X509_REMOVE_INFO)
/**
* \brief Print a X.509 certificate structure to the debug output. This
* function is always used through the MBEDTLS_SSL_DEBUG_CRT() macro,
* which supplies the ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the certificate being output
* \param crt X.509 certificate structure
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_crt(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, const mbedtls_x509_crt *crt);
#endif
/* Note: the MBEDTLS_ECDH_C guard here is mandatory because this debug function
only works for the built-in implementation. */
#if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_ANY_ENABLED) && \
defined(MBEDTLS_ECDH_C)
typedef enum {
MBEDTLS_DEBUG_ECDH_Q,
MBEDTLS_DEBUG_ECDH_QP,
MBEDTLS_DEBUG_ECDH_Z,
} mbedtls_debug_ecdh_attr;
/**
* \brief Print a field of the ECDH structure in the SSL context to the debug
* output. This function is always used through the
* MBEDTLS_SSL_DEBUG_ECDH() macro, which supplies the ssl context, file
* and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param ecdh the ECDH context
* \param attr the identifier of the attribute being output
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_printf_ecdh(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const mbedtls_ecdh_context *ecdh,
mbedtls_debug_ecdh_attr attr);
#endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_ANY_ENABLED &&
MBEDTLS_ECDH_C */
#endif /* MBEDTLS_DEBUG_INTERNAL_H */
-9
View File
@@ -1,9 +0,0 @@
/*
* Stub header to trigger PlatformIO Library Dependency Finder.
*
* The Tasmota Arduino platform ships a stripped libmbedtls.a that is missing
* the core SSL/TLS implementation (mbedtls_ssl_read, mbedtls_ssl_write, etc.).
* This library compiles the official mbedtls 3.6.5 SSL source files so that
* esp_tls and other components that depend on mbedtls SSL can link.
*/
#pragma once
-26
View File
@@ -1,26 +0,0 @@
/**
* Translation between MD and PSA identifiers (algorithms, errors).
*
* Note: this internal module will go away when everything becomes based on
* PSA Crypto; it is a helper for the transition period.
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_MD_PSA_H
#define MBEDTLS_MD_PSA_H
#include "common.h"
#include "mbedtls/md.h"
#include "psa/crypto.h"
/** Convert PSA status to MD error code.
*
* \param status PSA status.
*
* \return The corresponding MD error code,
*/
int mbedtls_md_error_from_psa(psa_status_t status);
#endif /* MBEDTLS_MD_PSA_H */
-100
View File
@@ -1,100 +0,0 @@
/**
* \file psa_util_internal.h
*
* \brief Internal utility functions for use of PSA Crypto.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_PSA_UTIL_INTERNAL_H
#define MBEDTLS_PSA_UTIL_INTERNAL_H
/* Include the public header so that users only need one include. */
#include "mbedtls/psa_util.h"
#include "psa/crypto.h"
#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
/*************************************************************************
* FFDH
************************************************************************/
#define MBEDTLS_PSA_MAX_FFDH_PUBKEY_LENGTH \
PSA_KEY_EXPORT_FFDH_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS)
/*************************************************************************
* ECC
************************************************************************/
#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH \
PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)
#define MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH \
PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)
/*************************************************************************
* Error translation
************************************************************************/
typedef struct {
/* Error codes used by PSA crypto are in -255..-128, fitting in 16 bits. */
int16_t psa_status;
/* Error codes used by Mbed TLS are in one of the ranges
* -127..-1 (low-level) or -32767..-4096 (high-level with a low-level
* code optionally added), fitting in 16 bits. */
int16_t mbedtls_error;
} mbedtls_error_pair_t;
#if defined(MBEDTLS_MD_LIGHT)
extern const mbedtls_error_pair_t psa_to_md_errors[4];
#endif
#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
extern const mbedtls_error_pair_t psa_to_cipher_errors[4];
#endif
#if defined(MBEDTLS_LMS_C)
extern const mbedtls_error_pair_t psa_to_lms_errors[3];
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
extern const mbedtls_error_pair_t psa_to_ssl_errors[7];
#endif
#if defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) || \
defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC)
extern const mbedtls_error_pair_t psa_to_pk_rsa_errors[8];
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO) && \
defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY)
extern const mbedtls_error_pair_t psa_to_pk_ecdsa_errors[7];
#endif
/* Generic fallback function for error translation,
* when the received state was not module-specific. */
int psa_generic_status_to_mbedtls(psa_status_t status);
/* This function iterates over provided local error translations,
* and if no match was found - calls the fallback error translation function. */
int psa_status_to_mbedtls(psa_status_t status,
const mbedtls_error_pair_t *local_translations,
size_t local_errors_num,
int (*fallback_f)(psa_status_t));
/* The second out of three-stage error handling functions of the pk module,
* acts as a fallback after RSA / ECDSA error translation, and if no match
* is found, it itself calls psa_generic_status_to_mbedtls. */
int psa_pk_status_to_mbedtls(psa_status_t status);
/* Utility macro to shorten the defines of error translator in modules. */
#define PSA_TO_MBEDTLS_ERR_LIST(status, error_list, fallback_f) \
psa_status_to_mbedtls(status, error_list, \
sizeof(error_list)/sizeof(error_list[0]), \
fallback_f)
#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
#endif /* MBEDTLS_PSA_UTIL_INTERNAL_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-22
View File
@@ -1,22 +0,0 @@
/**
* TLS 1.2 and 1.3 client-side functions
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_SSL_CLIENT_H
#define MBEDTLS_SSL_CLIENT_H
#include "common.h"
#if defined(MBEDTLS_SSL_TLS_C)
#include "ssl_misc.h"
#endif
#include <stddef.h>
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_write_client_hello(mbedtls_ssl_context *ssl);
#endif /* MBEDTLS_SSL_CLIENT_H */
-83
View File
@@ -1,83 +0,0 @@
/**
* \file ssl_debug_helpers.h
*
* \brief Automatically generated helper functions for debugging
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_SSL_DEBUG_HELPERS_H
#define MBEDTLS_SSL_DEBUG_HELPERS_H
#include "common.h"
#if defined(MBEDTLS_DEBUG_C)
#include "mbedtls/ssl.h"
#include "ssl_misc.h"
const char *mbedtls_ssl_states_str(mbedtls_ssl_states in);
#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
const char *mbedtls_ssl_early_data_status_str(mbedtls_ssl_early_data_status in);
const char *mbedtls_ssl_early_data_state_str(mbedtls_ssl_early_data_state in);
#endif
const char *mbedtls_ssl_protocol_version_str(mbedtls_ssl_protocol_version in);
const char *mbedtls_tls_prf_types_str(mbedtls_tls_prf_types in);
const char *mbedtls_ssl_key_export_type_str(mbedtls_ssl_key_export_type in);
const char *mbedtls_ssl_sig_alg_to_str(uint16_t in);
const char *mbedtls_ssl_named_group_to_str(uint16_t in);
const char *mbedtls_ssl_get_extension_name(unsigned int extension_type);
void mbedtls_ssl_print_extensions(const mbedtls_ssl_context *ssl,
int level, const char *file, int line,
int hs_msg_type, uint32_t extensions_mask,
const char *extra);
void mbedtls_ssl_print_extension(const mbedtls_ssl_context *ssl,
int level, const char *file, int line,
int hs_msg_type, unsigned int extension_type,
const char *extra_msg0, const char *extra_msg1);
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
void mbedtls_ssl_print_ticket_flags(const mbedtls_ssl_context *ssl,
int level, const char *file, int line,
unsigned int flags);
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_SESSION_TICKETS */
#define MBEDTLS_SSL_PRINT_EXTS(level, hs_msg_type, extensions_mask) \
mbedtls_ssl_print_extensions(ssl, level, __FILE__, __LINE__, \
hs_msg_type, extensions_mask, NULL)
#define MBEDTLS_SSL_PRINT_EXT(level, hs_msg_type, extension_type, extra) \
mbedtls_ssl_print_extension(ssl, level, __FILE__, __LINE__, \
hs_msg_type, extension_type, \
extra, NULL)
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
#define MBEDTLS_SSL_PRINT_TICKET_FLAGS(level, flags) \
mbedtls_ssl_print_ticket_flags(ssl, level, __FILE__, __LINE__, flags)
#endif
#else
#define MBEDTLS_SSL_PRINT_EXTS(level, hs_msg_type, extension_mask)
#define MBEDTLS_SSL_PRINT_EXT(level, hs_msg_type, extension_type, extra)
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
#define MBEDTLS_SSL_PRINT_TICKET_FLAGS(level, flags)
#endif
#endif /* MBEDTLS_DEBUG_C */
#endif /* MBEDTLS_SSL_DEBUG_HELPERS_H */
@@ -1,251 +0,0 @@
/* Automatically generated by generate_ssl_debug_helpers.py. DO NOT EDIT. */
/**
* \file ssl_debug_helpers_generated.c
*
* \brief Automatically generated helper functions for debugging
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*
*/
#include "ssl_misc.h"
#if defined(MBEDTLS_DEBUG_C)
#include "ssl_debug_helpers.h"
const char *mbedtls_ssl_named_group_to_str( uint16_t in )
{
switch( in )
{
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP192K1:
return "secp192k1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP192R1:
return "secp192r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP224K1:
return "secp224k1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP224R1:
return "secp224r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP256K1:
return "secp256k1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1:
return "secp256r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1:
return "secp384r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP521R1:
return "secp521r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_BP256R1:
return "bp256r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_BP384R1:
return "bp384r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_BP512R1:
return "bp512r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_X25519:
return "x25519";
case MBEDTLS_SSL_IANA_TLS_GROUP_X448:
return "x448";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE2048:
return "ffdhe2048";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE3072:
return "ffdhe3072";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE4096:
return "ffdhe4096";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE6144:
return "ffdhe6144";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE8192:
return "ffdhe8192";
};
return "UNKNOWN";
}
const char *mbedtls_ssl_sig_alg_to_str( uint16_t in )
{
switch( in )
{
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA256:
return "rsa_pkcs1_sha256";
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA384:
return "rsa_pkcs1_sha384";
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA512:
return "rsa_pkcs1_sha512";
case MBEDTLS_TLS1_3_SIG_ECDSA_SECP256R1_SHA256:
return "ecdsa_secp256r1_sha256";
case MBEDTLS_TLS1_3_SIG_ECDSA_SECP384R1_SHA384:
return "ecdsa_secp384r1_sha384";
case MBEDTLS_TLS1_3_SIG_ECDSA_SECP521R1_SHA512:
return "ecdsa_secp521r1_sha512";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA256:
return "rsa_pss_rsae_sha256";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA384:
return "rsa_pss_rsae_sha384";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA512:
return "rsa_pss_rsae_sha512";
case MBEDTLS_TLS1_3_SIG_ED25519:
return "ed25519";
case MBEDTLS_TLS1_3_SIG_ED448:
return "ed448";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA256:
return "rsa_pss_pss_sha256";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA384:
return "rsa_pss_pss_sha384";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA512:
return "rsa_pss_pss_sha512";
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA1:
return "rsa_pkcs1_sha1";
case MBEDTLS_TLS1_3_SIG_ECDSA_SHA1:
return "ecdsa_sha1";
case MBEDTLS_TLS1_3_SIG_NONE:
return "none";
};
return "UNKNOWN";
}
const char *mbedtls_ssl_states_str( mbedtls_ssl_states in )
{
switch (in) {
case MBEDTLS_SSL_HELLO_REQUEST:
return "MBEDTLS_SSL_HELLO_REQUEST";
case MBEDTLS_SSL_CLIENT_HELLO:
return "MBEDTLS_SSL_CLIENT_HELLO";
case MBEDTLS_SSL_SERVER_HELLO:
return "MBEDTLS_SSL_SERVER_HELLO";
case MBEDTLS_SSL_SERVER_CERTIFICATE:
return "MBEDTLS_SSL_SERVER_CERTIFICATE";
case MBEDTLS_SSL_SERVER_KEY_EXCHANGE:
return "MBEDTLS_SSL_SERVER_KEY_EXCHANGE";
case MBEDTLS_SSL_CERTIFICATE_REQUEST:
return "MBEDTLS_SSL_CERTIFICATE_REQUEST";
case MBEDTLS_SSL_SERVER_HELLO_DONE:
return "MBEDTLS_SSL_SERVER_HELLO_DONE";
case MBEDTLS_SSL_CLIENT_CERTIFICATE:
return "MBEDTLS_SSL_CLIENT_CERTIFICATE";
case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:
return "MBEDTLS_SSL_CLIENT_KEY_EXCHANGE";
case MBEDTLS_SSL_CERTIFICATE_VERIFY:
return "MBEDTLS_SSL_CERTIFICATE_VERIFY";
case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC:
return "MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC";
case MBEDTLS_SSL_CLIENT_FINISHED:
return "MBEDTLS_SSL_CLIENT_FINISHED";
case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC:
return "MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC";
case MBEDTLS_SSL_SERVER_FINISHED:
return "MBEDTLS_SSL_SERVER_FINISHED";
case MBEDTLS_SSL_FLUSH_BUFFERS:
return "MBEDTLS_SSL_FLUSH_BUFFERS";
case MBEDTLS_SSL_HANDSHAKE_WRAPUP:
return "MBEDTLS_SSL_HANDSHAKE_WRAPUP";
case MBEDTLS_SSL_NEW_SESSION_TICKET:
return "MBEDTLS_SSL_NEW_SESSION_TICKET";
case MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT:
return "MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT";
case MBEDTLS_SSL_HELLO_RETRY_REQUEST:
return "MBEDTLS_SSL_HELLO_RETRY_REQUEST";
case MBEDTLS_SSL_ENCRYPTED_EXTENSIONS:
return "MBEDTLS_SSL_ENCRYPTED_EXTENSIONS";
case MBEDTLS_SSL_END_OF_EARLY_DATA:
return "MBEDTLS_SSL_END_OF_EARLY_DATA";
case MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY:
return "MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY";
case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED:
return "MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED";
case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO:
return "MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO";
case MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO:
return "MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO";
case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO:
return "MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO";
case MBEDTLS_SSL_SERVER_CCS_AFTER_HELLO_RETRY_REQUEST:
return "MBEDTLS_SSL_SERVER_CCS_AFTER_HELLO_RETRY_REQUEST";
case MBEDTLS_SSL_HANDSHAKE_OVER:
return "MBEDTLS_SSL_HANDSHAKE_OVER";
case MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET:
return "MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET";
case MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH:
return "MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH";
default:
return "UNKNOWN_VALUE";
}
}
#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
const char *mbedtls_ssl_early_data_status_str( mbedtls_ssl_early_data_status in )
{
switch (in) {
case MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_INDICATED:
return "MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_INDICATED";
case MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED:
return "MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED";
case MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED:
return "MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED";
default:
return "UNKNOWN_VALUE";
}
}
#endif /* defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) */
const char *mbedtls_ssl_protocol_version_str( mbedtls_ssl_protocol_version in )
{
switch (in) {
case MBEDTLS_SSL_VERSION_UNKNOWN:
return "MBEDTLS_SSL_VERSION_UNKNOWN";
case MBEDTLS_SSL_VERSION_TLS1_2:
return "MBEDTLS_SSL_VERSION_TLS1_2";
case MBEDTLS_SSL_VERSION_TLS1_3:
return "MBEDTLS_SSL_VERSION_TLS1_3";
default:
return "UNKNOWN_VALUE";
}
}
const char *mbedtls_tls_prf_types_str( mbedtls_tls_prf_types in )
{
switch (in) {
case MBEDTLS_SSL_TLS_PRF_NONE:
return "MBEDTLS_SSL_TLS_PRF_NONE";
case MBEDTLS_SSL_TLS_PRF_SHA384:
return "MBEDTLS_SSL_TLS_PRF_SHA384";
case MBEDTLS_SSL_TLS_PRF_SHA256:
return "MBEDTLS_SSL_TLS_PRF_SHA256";
case MBEDTLS_SSL_HKDF_EXPAND_SHA384:
return "MBEDTLS_SSL_HKDF_EXPAND_SHA384";
case MBEDTLS_SSL_HKDF_EXPAND_SHA256:
return "MBEDTLS_SSL_HKDF_EXPAND_SHA256";
default:
return "UNKNOWN_VALUE";
}
}
const char *mbedtls_ssl_key_export_type_str( mbedtls_ssl_key_export_type in )
{
switch (in) {
case MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET";
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_EARLY_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_EARLY_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_EARLY_EXPORTER_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_EARLY_EXPORTER_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET";
#endif
default:
return "UNKNOWN_VALUE";
}
}
#endif /* MBEDTLS_DEBUG_C */
/* End of automatically generated file. */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-668
View File
@@ -1,668 +0,0 @@
/*
* TLS 1.3 key schedule
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#if !defined(MBEDTLS_SSL_TLS1_3_KEYS_H)
#define MBEDTLS_SSL_TLS1_3_KEYS_H
/* This requires MBEDTLS_SSL_TLS1_3_LABEL( idx, name, string ) to be defined at
* the point of use. See e.g. the definition of mbedtls_ssl_tls13_labels_union
* below. */
#define MBEDTLS_SSL_TLS1_3_LABEL_LIST \
MBEDTLS_SSL_TLS1_3_LABEL(finished, "finished") \
MBEDTLS_SSL_TLS1_3_LABEL(resumption, "resumption") \
MBEDTLS_SSL_TLS1_3_LABEL(traffic_upd, "traffic upd") \
MBEDTLS_SSL_TLS1_3_LABEL(exporter, "exporter") \
MBEDTLS_SSL_TLS1_3_LABEL(key, "key") \
MBEDTLS_SSL_TLS1_3_LABEL(iv, "iv") \
MBEDTLS_SSL_TLS1_3_LABEL(c_hs_traffic, "c hs traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(c_ap_traffic, "c ap traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(c_e_traffic, "c e traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(s_hs_traffic, "s hs traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(s_ap_traffic, "s ap traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(s_e_traffic, "s e traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(e_exp_master, "e exp master") \
MBEDTLS_SSL_TLS1_3_LABEL(res_master, "res master") \
MBEDTLS_SSL_TLS1_3_LABEL(exp_master, "exp master") \
MBEDTLS_SSL_TLS1_3_LABEL(ext_binder, "ext binder") \
MBEDTLS_SSL_TLS1_3_LABEL(res_binder, "res binder") \
MBEDTLS_SSL_TLS1_3_LABEL(derived, "derived") \
MBEDTLS_SSL_TLS1_3_LABEL(client_cv, "TLS 1.3, client CertificateVerify") \
MBEDTLS_SSL_TLS1_3_LABEL(server_cv, "TLS 1.3, server CertificateVerify")
#define MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED 0
#define MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED 1
#define MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL 0
#define MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION 1
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
/* We need to tell the compiler that we meant to leave out the null character. */
#define MBEDTLS_SSL_TLS1_3_LABEL(name, string) \
const unsigned char name [sizeof(string) - 1] MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING;
union mbedtls_ssl_tls13_labels_union {
MBEDTLS_SSL_TLS1_3_LABEL_LIST
};
struct mbedtls_ssl_tls13_labels_struct {
MBEDTLS_SSL_TLS1_3_LABEL_LIST
};
#undef MBEDTLS_SSL_TLS1_3_LABEL
extern const struct mbedtls_ssl_tls13_labels_struct mbedtls_ssl_tls13_labels;
#define MBEDTLS_SSL_TLS1_3_LBL_LEN(LABEL) \
sizeof(mbedtls_ssl_tls13_labels.LABEL)
#define MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN(LABEL) \
mbedtls_ssl_tls13_labels.LABEL, \
MBEDTLS_SSL_TLS1_3_LBL_LEN(LABEL)
/* Maximum length of the label field in the HkdfLabel struct defined in
* RFC 8446, Section 7.1, excluding the "tls13 " prefix. */
#define MBEDTLS_SSL_TLS1_3_HKDF_LABEL_MAX_LABEL_LEN 249
/* The maximum length of HKDF contexts used in the TLS 1.3 standard.
* Since contexts are always hashes of message transcripts, this can
* be approximated from above by the maximum hash size. */
#define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_CONTEXT_LEN \
PSA_HASH_MAX_SIZE
/* Maximum desired length for expanded key material generated
* by HKDF-Expand-Label. This algorithm can output up to 255 * hash_size
* bytes of key material where hash_size is the output size of the
* underlying hash function. */
#define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_EXPANSION_LEN \
(255 * MBEDTLS_TLS1_3_MD_MAX_SIZE)
/**
* \brief The \c HKDF-Expand-Label function from
* the TLS 1.3 standard RFC 8446.
*
* <tt>
* HKDF-Expand-Label( Secret, Label, Context, Length ) =
* HKDF-Expand( Secret, HkdfLabel, Length )
* </tt>
*
* \param hash_alg The identifier for the hash algorithm to use.
* \param secret The \c Secret argument to \c HKDF-Expand-Label.
* This must be a readable buffer of length
* \p secret_len Bytes.
* \param secret_len The length of \p secret in Bytes.
* \param label The \c Label argument to \c HKDF-Expand-Label.
* This must be a readable buffer of length
* \p label_len Bytes.
* \param label_len The length of \p label in Bytes.
* \param ctx The \c Context argument to \c HKDF-Expand-Label.
* This must be a readable buffer of length \p ctx_len Bytes.
* \param ctx_len The length of \p context in Bytes.
* \param buf The destination buffer to hold the expanded secret.
* This must be a writable buffer of length \p buf_len Bytes.
* \param buf_len The desired size of the expanded secret in Bytes.
*
* \returns \c 0 on success.
* \return A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_hkdf_expand_label(
psa_algorithm_t hash_alg,
const unsigned char *secret, size_t secret_len,
const unsigned char *label, size_t label_len,
const unsigned char *ctx, size_t ctx_len,
unsigned char *buf, size_t buf_len);
/**
* \brief This function is part of the TLS 1.3 key schedule.
* It extracts key and IV for the actual client/server traffic
* from the client/server traffic secrets.
*
* From RFC 8446:
*
* <tt>
* [sender]_write_key = HKDF-Expand-Label(Secret, "key", "", key_length)
* [sender]_write_iv = HKDF-Expand-Label(Secret, "iv", "", iv_length)*
* </tt>
*
* \param hash_alg The identifier for the hash algorithm to be used
* for the HKDF-based expansion of the secret.
* \param client_secret The client traffic secret.
* This must be a readable buffer of size
* \p secret_len Bytes
* \param server_secret The server traffic secret.
* This must be a readable buffer of size
* \p secret_len Bytes
* \param secret_len Length of the secrets \p client_secret and
* \p server_secret in Bytes.
* \param key_len The desired length of the key to be extracted in Bytes.
* \param iv_len The desired length of the IV to be extracted in Bytes.
* \param keys The address of the structure holding the generated
* keys and IVs.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_make_traffic_keys(
psa_algorithm_t hash_alg,
const unsigned char *client_secret,
const unsigned char *server_secret, size_t secret_len,
size_t key_len, size_t iv_len,
mbedtls_ssl_key_set *keys);
/**
* \brief The \c Derive-Secret function from the TLS 1.3 standard RFC 8446.
*
* <tt>
* Derive-Secret( Secret, Label, Messages ) =
* HKDF-Expand-Label( Secret, Label,
* Hash( Messages ),
* Hash.Length ) )
* </tt>
*
* \param hash_alg The identifier for the hash function used for the
* applications of HKDF.
* \param secret The \c Secret argument to the \c Derive-Secret function.
* This must be a readable buffer of length
* \p secret_len Bytes.
* \param secret_len The length of \p secret in Bytes.
* \param label The \c Label argument to the \c Derive-Secret function.
* This must be a readable buffer of length
* \p label_len Bytes.
* \param label_len The length of \p label in Bytes.
* \param ctx The hash of the \c Messages argument to the
* \c Derive-Secret function, or the \c Messages argument
* itself, depending on \p ctx_hashed.
* \param ctx_len The length of \p ctx in Bytes.
* \param ctx_hashed This indicates whether the \p ctx contains the hash of
* the \c Messages argument in the application of the
* \c Derive-Secret function
* (value MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED), or whether
* it is the content of \c Messages itself, in which case
* the function takes care of the hashing
* (value MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED).
* \param dstbuf The target buffer to write the output of
* \c Derive-Secret to. This must be a writable buffer of
* size \p dtsbuf_len Bytes.
* \param dstbuf_len The length of \p dstbuf in Bytes.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_secret(
psa_algorithm_t hash_alg,
const unsigned char *secret, size_t secret_len,
const unsigned char *label, size_t label_len,
const unsigned char *ctx, size_t ctx_len,
int ctx_hashed,
unsigned char *dstbuf, size_t dstbuf_len);
/**
* \brief Derive TLS 1.3 early data key material from early secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels.
*
* <tt>
* Early Secret
* |
* +-----> Derive-Secret(., "c e traffic", ClientHello)
* | = client_early_traffic_secret
* |
* +-----> Derive-Secret(., "e exp master", ClientHello)
* . = early_exporter_master_secret
* .
* .
* </tt>
*
* \note To obtain the actual key and IV for the early data traffic,
* the client secret derived by this function need to be
* further processed by mbedtls_ssl_tls13_make_traffic_keys().
*
* \note The binder key, which is also generated from the early secret,
* is omitted here. Its calculation is part of the separate routine
* mbedtls_ssl_tls13_create_psk_binder().
*
* \param hash_alg The hash algorithm associated with the PSK for which
* early data key material is being derived.
* \param early_secret The early secret from which the early data key material
* should be derived. This must be a readable buffer whose
* length is the digest size of the hash algorithm
* represented by \p md_size.
* \param transcript The transcript of the handshake so far, calculated with
* respect to \p hash_alg. This must be a readable buffer
* whose length is the digest size of the hash algorithm
* represented by \p md_size.
* \param derived The address of the structure in which to store
* the early data key material.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_early_secrets(
psa_algorithm_t hash_alg,
unsigned char const *early_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_early_secrets *derived);
/**
* \brief Derive TLS 1.3 handshake key material from the handshake secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels from the standard.
*
* <tt>
* Handshake Secret
* |
* +-----> Derive-Secret( ., "c hs traffic",
* | ClientHello...ServerHello )
* | = client_handshake_traffic_secret
* |
* +-----> Derive-Secret( ., "s hs traffic",
* . ClientHello...ServerHello )
* . = server_handshake_traffic_secret
* .
* </tt>
*
* \note To obtain the actual key and IV for the encrypted handshake traffic,
* the client and server secret derived by this function need to be
* further processed by mbedtls_ssl_tls13_make_traffic_keys().
*
* \param hash_alg The hash algorithm associated with the ciphersuite
* that's being used for the connection.
* \param handshake_secret The handshake secret from which the handshake key
* material should be derived. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param transcript The transcript of the handshake so far, calculated
* with respect to \p hash_alg. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param derived The address of the structure in which to
* store the handshake key material.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_handshake_secrets(
psa_algorithm_t hash_alg,
unsigned char const *handshake_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_handshake_secrets *derived);
/**
* \brief Derive TLS 1.3 application key material from the master secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels from the standard.
*
* <tt>
* Master Secret
* |
* +-----> Derive-Secret( ., "c ap traffic",
* | ClientHello...server Finished )
* | = client_application_traffic_secret_0
* |
* +-----> Derive-Secret( ., "s ap traffic",
* | ClientHello...Server Finished )
* | = server_application_traffic_secret_0
* |
* +-----> Derive-Secret( ., "exp master",
* . ClientHello...server Finished)
* . = exporter_master_secret
* .
* </tt>
*
* \note To obtain the actual key and IV for the (0-th) application traffic,
* the client and server secret derived by this function need to be
* further processed by mbedtls_ssl_tls13_make_traffic_keys().
*
* \param hash_alg The hash algorithm associated with the ciphersuite
* that's being used for the connection.
* \param master_secret The master secret from which the application key
* material should be derived. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param transcript The transcript of the handshake up to and including
* the ServerFinished message, calculated with respect
* to \p hash_alg. This must be a readable buffer whose
* length is the digest size of the hash algorithm
* represented by \p hash_alg.
* \param derived The address of the structure in which to
* store the application key material.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_application_secrets(
psa_algorithm_t hash_alg,
unsigned char const *master_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_application_secrets *derived);
/**
* \brief Derive TLS 1.3 resumption master secret from the master secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels from the standard.
*
* \param hash_alg The hash algorithm used in the application for which
* key material is being derived.
* \param application_secret The application secret from which the resumption master
* secret should be derived. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param transcript The transcript of the handshake up to and including
* the ClientFinished message, calculated with respect
* to \p hash_alg. This must be a readable buffer whose
* length is the digest size of the hash algorithm
* represented by \p hash_alg.
* \param transcript_len The length of \p transcript in Bytes.
* \param derived The address of the structure in which to
* store the resumption master secret.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_resumption_master_secret(
psa_algorithm_t hash_alg,
unsigned char const *application_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_application_secrets *derived);
/**
* \brief Compute the next secret in the TLS 1.3 key schedule
*
* The TLS 1.3 key schedule proceeds as follows to compute
* the three main secrets during the handshake: The early
* secret for early data, the handshake secret for all
* other encrypted handshake messages, and the master
* secret for all application traffic.
*
* <tt>
* 0
* |
* v
* PSK -> HKDF-Extract = Early Secret
* |
* v
* Derive-Secret( ., "derived", "" )
* |
* v
* (EC)DHE -> HKDF-Extract = Handshake Secret
* |
* v
* Derive-Secret( ., "derived", "" )
* |
* v
* 0 -> HKDF-Extract = Master Secret
* </tt>
*
* Each of the three secrets in turn is the basis for further
* key derivations, such as the derivation of traffic keys and IVs;
* see e.g. mbedtls_ssl_tls13_make_traffic_keys().
*
* This function implements one step in this evolution of secrets:
*
* <tt>
* old_secret
* |
* v
* Derive-Secret( ., "derived", "" )
* |
* v
* input -> HKDF-Extract = new_secret
* </tt>
*
* \param hash_alg The identifier for the hash function used for the
* applications of HKDF.
* \param secret_old The address of the buffer holding the old secret
* on function entry. If not \c NULL, this must be a
* readable buffer whose size matches the output size
* of the hash function represented by \p hash_alg.
* If \c NULL, an all \c 0 array will be used instead.
* \param input The address of the buffer holding the additional
* input for the key derivation (e.g., the PSK or the
* ephemeral (EC)DH secret). If not \c NULL, this must be
* a readable buffer whose size \p input_len Bytes.
* If \c NULL, an all \c 0 array will be used instead.
* \param input_len The length of \p input in Bytes.
* \param secret_new The address of the buffer holding the new secret
* on function exit. This must be a writable buffer
* whose size matches the output size of the hash
* function represented by \p hash_alg.
* This may be the same as \p secret_old.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_evolve_secret(
psa_algorithm_t hash_alg,
const unsigned char *secret_old,
const unsigned char *input, size_t input_len,
unsigned char *secret_new);
/**
* \brief Calculate a TLS 1.3 PSK binder.
*
* \param ssl The SSL context. This is used for debugging only and may
* be \c NULL if MBEDTLS_DEBUG_C is disabled.
* \param hash_alg The hash algorithm associated to the PSK \p psk.
* \param psk The buffer holding the PSK for which to create a binder.
* \param psk_len The size of \p psk in bytes.
* \param psk_type This indicates whether the PSK \p psk is externally
* provisioned (#MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL) or a
* resumption PSK (#MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION).
* \param transcript The handshake transcript up to the point where the
* PSK binder calculation happens. This must be readable,
* and its size must be equal to the digest size of
* the hash algorithm represented by \p hash_alg.
* \param result The address at which to store the PSK binder on success.
* This must be writable, and its size must be equal to the
* digest size of the hash algorithm represented by
* \p hash_alg.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_create_psk_binder(mbedtls_ssl_context *ssl,
const psa_algorithm_t hash_alg,
unsigned char const *psk, size_t psk_len,
int psk_type,
unsigned char const *transcript,
unsigned char *result);
/**
* \bref Setup an SSL transform structure representing the
* record protection mechanism used by TLS 1.3
*
* \param transform The SSL transform structure to be created. This must have
* been initialized through mbedtls_ssl_transform_init() and
* not used in any other way prior to calling this function.
* In particular, this function does not clean up the
* transform structure prior to installing the new keys.
* \param endpoint Indicates whether the transform is for the client
* (value #MBEDTLS_SSL_IS_CLIENT) or the server
* (value #MBEDTLS_SSL_IS_SERVER).
* \param ciphersuite The numerical identifier for the ciphersuite to use.
* This must be one of the identifiers listed in
* ssl_ciphersuites.h.
* \param traffic_keys The key material to use. No reference is stored in
* the SSL transform being generated, and the caller
* should destroy the key material afterwards.
* \param ssl (Debug-only) The SSL context to use for debug output
* in case of failure. This parameter is only needed if
* #MBEDTLS_DEBUG_C is set, and is ignored otherwise.
*
* \return \c 0 on success. In this case, \p transform is ready to
* be used with mbedtls_ssl_transform_decrypt() and
* mbedtls_ssl_transform_encrypt().
* \return A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_populate_transform(mbedtls_ssl_transform *transform,
int endpoint,
int ciphersuite,
mbedtls_ssl_key_set const *traffic_keys,
mbedtls_ssl_context *ssl);
/*
* TLS 1.3 key schedule evolutions
*
* Early -> Handshake -> Application
*
* Small wrappers around mbedtls_ssl_tls13_evolve_secret().
*/
/**
* \brief Begin TLS 1.3 key schedule by calculating early secret.
*
* The TLS 1.3 key schedule can be viewed as a simple state machine
* with states Initial -> Early -> Handshake -> Application, and
* this function represents the Initial -> Early transition.
*
* \param ssl The SSL context to operate on.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_key_schedule_stage_early(mbedtls_ssl_context *ssl);
/**
* \brief Compute TLS 1.3 resumption master secret.
*
* \param ssl The SSL context to operate on. This must be in
* key schedule stage \c Application, see
* mbedtls_ssl_tls13_key_schedule_stage_application().
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_resumption_master_secret(mbedtls_ssl_context *ssl);
/**
* \brief Calculate the verify_data value for the client or server TLS 1.3
* Finished message.
*
* \param ssl The SSL context to operate on. This must be in
* key schedule stage \c Handshake, see
* mbedtls_ssl_tls13_key_schedule_stage_application().
* \param dst The address at which to write the verify_data value.
* \param dst_len The size of \p dst in bytes.
* \param actual_len The address at which to store the amount of data
* actually written to \p dst upon success.
* \param which The message to calculate the `verify_data` for:
* - #MBEDTLS_SSL_IS_CLIENT for the Client's Finished message
* - #MBEDTLS_SSL_IS_SERVER for the Server's Finished message
*
* \note Both client and server call this function twice, once to
* generate their own Finished message, and once to verify the
* peer's Finished message.
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_calculate_verify_data(mbedtls_ssl_context *ssl,
unsigned char *dst,
size_t dst_len,
size_t *actual_len,
int which);
#if defined(MBEDTLS_SSL_EARLY_DATA)
/**
* \brief Compute TLS 1.3 early transform
*
* \param ssl The SSL context to operate on.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*
* \warning The function does not compute the early master secret. Call
* mbedtls_ssl_tls13_key_schedule_stage_early() before to
* call this function to generate the early master secret.
* \note For a client/server endpoint, the function computes only the
* encryption/decryption part of the transform as the decryption/
* encryption part is not defined by the specification (no early
* traffic from the server to the client).
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_early_transform(mbedtls_ssl_context *ssl);
#endif /* MBEDTLS_SSL_EARLY_DATA */
/**
* \brief Compute TLS 1.3 handshake transform
*
* \param ssl The SSL context to operate on. The early secret must have been
* computed.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_handshake_transform(mbedtls_ssl_context *ssl);
/**
* \brief Compute TLS 1.3 application transform
*
* \param ssl The SSL context to operate on. The early secret must have been
* computed.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_application_transform(mbedtls_ssl_context *ssl);
#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
/**
* \brief Export TLS 1.3 PSK from handshake context
*
* \param[in] ssl The SSL context to operate on.
* \param[out] psk PSK output pointer.
* \param[out] psk_len Length of PSK.
*
* \returns \c 0 if there is a configured PSK and it was exported
* successfully.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_export_handshake_psk(mbedtls_ssl_context *ssl,
unsigned char **psk,
size_t *psk_len);
#endif
/**
* \brief Calculate TLS-Exporter function as defined in RFC 8446, Section 7.5.
*
* \param[in] hash_alg The hash algorithm.
* \param[in] secret The secret to use. (Should be the exporter master secret.)
* \param[in] secret_len Length of secret.
* \param[in] label The label of the exported key.
* \param[in] label_len The length of label.
* \param[out] out The output buffer for the exported key. Must have room for at least out_len bytes.
* \param[in] out_len Length of the key to generate.
*/
int mbedtls_ssl_tls13_exporter(const psa_algorithm_t hash_alg,
const unsigned char *secret, const size_t secret_len,
const unsigned char *label, const size_t label_len,
const unsigned char *context_value, const size_t context_len,
uint8_t *out, const size_t out_len);
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
#endif /* MBEDTLS_SSL_TLS1_3_KEYS_H */
+6 -4
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.02.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.03.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
; 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.02.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.03.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
; 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.02.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.03.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
[env]
build_flags =
@@ -91,7 +91,9 @@ board_build.filesystem = littlefs
lib_deps =
bblanchon/ArduinoJson @ 7.4.2
ESP32Async/AsyncTCP @ 3.4.10
ESP32Async/ESPAsyncWebServer @ 3.10.0
ESP32Async/ESPAsyncWebServer @ 3.10.1
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
+55 -5
View File
@@ -63,7 +63,16 @@ void NetworkSettingsService::loop() {
manageSTA();
}
static uint8_t connect = 0;
enum uint8_t { CONNECT_IDLE = 0, CONNECT_WAIT_ETH, CONNECT_ETH_ACTIVE, CONNECT_WIFI_ACTIVE };
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;
@@ -71,45 +80,86 @@ void NetworkSettingsService::loop() {
case CONNECT_IDLE:
if (ETH.started() && _state.ssid.length() == 0) {
emsesp::EMSESP::logger().info("ETH started");
connect = CONNECT_WAIT_ETH;
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");
connect = CONNECT_WIFI_ACTIVE;
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");
connect = CONNECT_ETH_ACTIVE;
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");
connect = CONNECT_IDLE;
if (_stopping) {
_lastConnectionAttempt = 0;
_stopping = false;
}
emsesp::EMSESP::system_.has_ipv6(false);
connect = CONNECT_IDLE;
}
break;
}
+38
View File
@@ -842,6 +842,15 @@ bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int
return true;
}
if (!strcmp(cmd, F_(metrics))) {
std::string metrics = get_metrics_prometheus();
if (!metrics.empty()) {
output["api_data"] = metrics;
return true;
}
return false;
}
// this is for a specific sensor, return the value
const char * attribute_s = Command::get_attribute(cmd);
@@ -856,6 +865,35 @@ bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int
return false; // not found
}
// generate Prometheus metrics format from analog values
std::string AnalogSensor::get_metrics_prometheus() {
std::string result;
result.reserve(sensors_.size() * 140);
char val[10];
for (auto & sensor : sensors_) {
result += (std::string) "# HELP emsesp_" + sensor.name() + " " + sensor.name();
if (sensor.type() != AnalogType::DIGITAL_OUT && sensor.type() != AnalogType::DIGITAL_IN) {
result += (std::string) ", " + EMSdevice::uom_to_string(sensor.uom());
} else {
result += (std::string) ", boolean";
}
result += (std::string) ", readable, visible";
if (sensor.type() == AnalogType::COUNTER || sensor.type() == AnalogType::RGB || sensor.type() == AnalogType::PULSE
|| (sensor.type() >= AnalogType::DIGITAL_OUT && sensor.type() <= AnalogType::PWM_2)
|| (sensor.type() >= AnalogType::CNT_0 && sensor.type() <= AnalogType::CNT_2)) {
result += (std::string) ", writable";
}
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";
} else {
result += (std::string) (sensor.value() == 0 ? "0\n" : "1\n");
}
}
return result;
}
// note we don't add the device and state classes here, as we do in the custom entity service
void AnalogSensor::get_value_json(JsonObject output, const Sensor & sensor) {
output["name"] = (const char *)sensor.name();
+1
View File
@@ -177,6 +177,7 @@ class AnalogSensor {
bool update(uint8_t gpio, const char * name, double offset, double factor, uint8_t uom, int8_t type, bool deleted, bool is_system);
bool get_value_info(JsonObject output, const char * cmd, const int8_t id = -1);
void store_counters();
std::string get_metrics_prometheus();
static std::vector<uint8_t> exclude_types() {
return exclude_types_;
}
+11 -11
View File
@@ -104,9 +104,9 @@ const char * EMSdevice::uom_to_string(uint8_t uom) {
}
}
const char * EMSdevice::brand_to_char() {
std::string EMSdevice::brand_to_char() {
if (!custom_brand().empty()) {
return custom_brand().c_str();
return custom_brand();
}
switch (brand_) {
case EMSdevice::Brand::BOSCH:
@@ -331,15 +331,15 @@ uint8_t EMSdevice::decode_brand(uint8_t value) {
std::string EMSdevice::to_string() {
// for devices that haven't been lookup yet, don't show all details
if (product_id_ == 0) {
return std::string(name()) + " (DeviceID:" + Helpers::hextoa(device_id_) + ")";
return name() + " (DeviceID:" + Helpers::hextoa(device_id_) + ")";
}
if (brand_ == Brand::NO_BRAND && custom_brand().empty()) {
return std::string(name()) + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_ + ")";
return name() + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_ + ")";
}
return std::string(brand_to_char()) + " " + name() + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_)
+ ", Version:" + version_ + ")";
return brand_to_char() + " " + name() + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_
+ ")";
}
// returns string of EMS device version and productID
@@ -912,7 +912,7 @@ void EMSdevice::publish_value(void * value_p) const {
// looks up the UOM for a given key from the device value table
std::string EMSdevice::get_value_uom(const std::string & shortname) const {
for (const auto & dv : devicevalues_) {
if ((!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE)) && (dv.short_name == shortname)) {
if ((!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE)) && !strcmp(dv.short_name, shortname.c_str())) {
// ignore TIME since "minutes" is already added to the string value
if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) {
break;
@@ -1282,7 +1282,7 @@ void EMSdevice::setCustomizationEntity(const std::string & entity_id) {
// set the min / max
dv.set_custom_minmax();
if (Mqtt::ha_enabled() && dv.short_name == FL_(seltemp)[0] && (min != dv.min || max != dv.max)) {
if (Mqtt::ha_enabled() && dv.tag <= DeviceValueTAG::TAG_HC8 && !strcmp(dv.short_name, FL_(selRoomTemp)[0]) && (min != dv.min || max != dv.max)) {
set_climate_minmax(dv.tag, dv.min, dv.max);
}
@@ -2160,14 +2160,14 @@ void EMSdevice::mqtt_ha_entity_config_create() {
if (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) && dv.has_state(DeviceValueState::DV_ACTIVE)
&& !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE)) {
// create_device_config is only done once for the EMS device. It can added to any entity, so we take the first
if (Mqtt::publish_ha_sensor_config_dv(dv, name().c_str(), std::string(brand_to_char()).c_str(), to_string_version().c_str(), false, create_device_config)) {
if (Mqtt::publish_ha_sensor_config_dv(dv, name().c_str(), brand_to_char().c_str(), to_string_version().c_str(), false, create_device_config)) {
dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED);
create_device_config = false; // only create the main config once
count++;
}
// SRC thermostats mapped to connect/src1/... always contains mode, seltemp, currtemp
if (dv.tag >= DeviceValueTAG::TAG_SRC1 && dv.tag <= DeviceValueTAG::TAG_SRC16 && !strcmp(dv.short_name, FL_(seltemp)[0])) {
// SRC thermostats mapped to connect/src1/... always contains mode, selRoomTemp, currtemp
if (dv.tag >= DeviceValueTAG::TAG_SRC1 && dv.tag <= DeviceValueTAG::TAG_SRC16 && !strcmp(dv.short_name, FL_(selRoomTemp)[0])) {
// add modes and icon if we have one
const char * icon = nullptr;
const char * const ** mode_options = nullptr;
+5 -1
View File
@@ -63,7 +63,7 @@ class EMSdevice {
const char * device_type_2_device_name_translated(); // returns translated device type name
bool has_tags(const int8_t tag) const;
bool has_cmd(const char * cmd, const int8_t id) const;
const char * brand_to_char();
std::string brand_to_char();
std::string to_string();
std::string to_string_short();
std::string to_string_version();
@@ -90,6 +90,10 @@ class EMSdevice {
return version_;
}
void version(const char * version) {
strlcpy(version_, version, sizeof(version_));
}
uint8_t brand() const {
return brand_;
}
+9 -8
View File
@@ -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
@@ -1307,9 +1307,16 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
// first check to see if we already have it, if so update the record
for (auto it = emsdevices.begin(); it != emsdevices.end(); ++it) {
if ((*it) && (*it)->is_device_id(device_id)) {
if (product_id == 0 || (*it)->product_id() != 0) { // update only with valid product_id
if (product_id == 0) { // no product-id, ignore
return false;
}
if ((*it)->product_id() == product_id) { // update version if we have valid product_id
if (!strcmp((*it)->version(), "00.00")) {
(*it)->version(version);
}
return true;
}
// product-id has changed for this device-id, delete and re-add
(*it)->erase_device_values();
emsdevices.erase(it); // erase the old device without product_id and re detect
break;
@@ -1795,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
+2 -1
View File
@@ -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)
@@ -303,7 +304,7 @@ MAKE_ENUM(enum_comfort, FL_(hot), FL_(eco), FL_(intelligent))
MAKE_ENUM(enum_comfort1, FL_(high_comfort), FL_(eco))
MAKE_ENUM(enum_comfort2, FL_(eco), FL_(high_comfort))
MAKE_ENUM(enum_flow, FL_(off), FL_(flow), FL_(bufferedflow), FL_(buffer), FL_(layeredbuffer))
MAKE_ENUM(enum_reset, FL_(dash), FL_(maintenance), FL_(error), FL_(history), FL_(message))
MAKE_ENUM(enum_reset, FL_(dash), FL_(maintenance), FL_(error), FL_(history), FL_(message), FL_(hp_error), FL_(burn_starts), FL_(factory))
MAKE_ENUM(enum_maxHeat, FL_(0kW), FL_(2kW), FL_(3kW), FL_(4kW), FL_(6kW), FL_(9kW))
MAKE_ENUM(enum_maxHeat1, FL_(0kW), FL_(3kW), FL_(6kW), FL_(9kW))
MAKE_ENUM(enum_maxHeat2, FL_(3kW), FL_(6kW), FL_(9kW))
+9
View File
@@ -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", "", "wyślij email", "send email", "", "email gönder", "invia email", "poslať email") // TODO translate
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í")
@@ -197,6 +198,9 @@ MAKE_WORD_TRANSLATION(lower, "lower", "niedriger", "lager", "lägre", "mniejszy"
MAKE_WORD_TRANSLATION(error, "error", "Fehler", "error", "Fel", "błąd", "feil", "erreur", "Hata", "errore", "error", "chyba")
MAKE_WORD_TRANSLATION(history, "history", "Fehlerspeicher", "geschiedenis", "historik", "historia", "historikk", "historique", "geçmiş", "storico", "história", "historie")
MAKE_WORD_TRANSLATION(message, "message", "Meldung", "melding", "meddelande", "komunikat", "melding", "message", "mesajı", "messaggio", "správa", "zpráva")
MAKE_WORD_TRANSLATION(hp_error, "hp error", "WP Fehler", "hp error", "hp Fel", "hp błąd", "hp feil", "hp erreur", "hp Hata", "hp errore", "hp error", "hp chyba")
MAKE_WORD_TRANSLATION(factory, "factory", "werkseinst.", "", "", "", "", "", "", "", "nastavenie z výroby", "nastavení z výroby")
MAKE_WORD_TRANSLATION(burn_starts, "burner starts", "Brennerstarts", "", "", "", "", "", "", "", "štarty horáka", "")
MAKE_WORD_TRANSLATION(na, "n/a", "n/a", "n/a", "n/a", "nd.", "n/a", "n/c", "mevcut değil", "n/a", "n/a", "n/a")
MAKE_WORD_TRANSLATION(inverted, "inverted", "invertiert", "omgekeerd", "inverterad", "odwrócony", "invertert", "inversé", "ters", "invertito", "invertovaný", "invertovaný")
@@ -424,6 +428,10 @@ MAKE_TRANSLATION(pumpOnTemp, "pumpontemp", "pump logic temperature", "Pumpenlogi
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")
@@ -773,6 +781,7 @@ MAKE_TRANSLATION(comforttemp, "comforttemp", "comfort temperature", "Komforttemp
MAKE_TRANSLATION(summertemp, "summertemp", "summer temperature", "Sommertemperatur", "Zomertemperatuur", "Sommartemperatur", "temperatura przełączania lato/zima", "Sommertemperatur", "température été", "yaz sıcaklığı", "temperatura estiva", "letná teplota", "letní teplota")
MAKE_TRANSLATION(designtemp, "designtemp", "design temperature", "Auslegungstemperatur", "Ontwerptemperatuur", "Design-temperatur", "temperatura projektowa", "designtemperatur", "température conception", "özel sıcaklık", "temperatura predefinita", "návrhová teplota", "dimenzovaná teplota")
MAKE_TRANSLATION(offsettemp, "offsettemp", "offset temperature", "Temperaturanhebung", "Temperatuur offset", "Temperaturkorrigering", "korekta temperatury", "temperaturkorrigering", "température offset", "artış sıcaklığı", "aumento della temperatura", "offsetová teplota", "offset teploty")
MAKE_TRANSLATION(baseflowtemp, "baseflowtemp", "base flow temperature", "Basis Vorlauftemperatur") // ToDo translate
MAKE_TRANSLATION(minflowtemp, "minflowtemp", "min flow temperature", "min. Vorlauftemperatur", "Minimale aanvoertemperatuur", "Min. Flödestemperatur", "minimalna temperatura zasilania", "min. turtemperatur", "température min. flux", "minimun akış sıcaklığı", "temperatura minima di mandata", "min. výstupná teplota", "vytápění minimální teplota")
MAKE_TRANSLATION(maxflowtemp, "maxflowtemp", "max flow temperature", "max. Vorlauftemperatur", "Maximale aanvoertemperatuur", "Max. Flödestemperatur", "maksymalna temperatura zasilania", "maks turtemperatur", "température max flux", "maksimum akış sıcaklığı", "temperatura massima di mandata", "maximálna teplota prívodu", "vytápění maximální teplota")
MAKE_TRANSLATION(roominfluence, "roominfluence", "room influence", "Raumeinfluss", "Ruimteinvloed", "Rumspåverkan", "wpływ pomieszczenia", "rominnflytelse", "influence pièce", "oda etkisi", "influenza della camera", "vplyv miestnosti", "vliv prostoru")
+1 -1
View File
@@ -52,7 +52,7 @@ void Modbus::stop() {
#ifndef EMSESP_STANDALONE
modbusServer_->stop();
// virtual ~ModbusServerTCPasync() = default;
// delete modbusServer_;
delete modbusServer_;
modbusServer_ = nullptr;
#endif
}
+223 -219
View File
@@ -60,144 +60,147 @@ const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_ma
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pc1Flow), 81, 1), // pc1flow
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pc1On), 82, 1), // pc1on
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pc1Rate), 83, 1), // pc1rate
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(manDefrost), 84, 1), // mandefrost
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgTotal), 85, 2), // nrgtotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat), 87, 2), // nrgheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgCool), 89, 2), // nrgcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterTotal), 91, 2), // metertotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterComp), 93, 2), // metercomp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterEHeat), 95, 2), // metereheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterHeat), 97, 2), // meterheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterCool), 99, 2), // metercool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeTotal), 101, 2), // uptimetotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeControl), 103, 2), // uptimecontrol
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeCompHeating), 105, 2), // uptimecompheating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeCompCooling), 107, 2), // uptimecompcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeCompPool), 109, 2), // uptimecomppool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(totalCompStarts), 111, 2), // totalcompstarts
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingStarts), 113, 2), // heatingstarts
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(coolingStarts), 115, 2), // coolingstarts
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(poolStarts), 117, 2), // poolstarts
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsTotal), 119, 2), // nrgconstotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompTotal), 121, 2), // nrgconscomptotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompHeating), 123, 2), // nrgconscompheating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompCooling), 125, 2), // nrgconscompcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompPool), 127, 2), // nrgconscomppool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxElecHeatNrgConsTotal), 129, 2), // auxelecheatnrgconstotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxElecHeatNrgConsHeating), 131, 2), // auxelecheatnrgconsheating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxElecHeatNrgConsPool), 133, 2), // auxelecheatnrgconspool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppTotal), 135, 2), // nrgsupptotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppHeating), 137, 2), // nrgsuppheating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppCooling), 139, 2), // nrgsuppcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppPool), 141, 2), // nrgsupppool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPower), 143, 1), // hppower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpMaxPower), 144, 1), // hpmaxpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pvMaxComp), 145, 1), // pvmaxcomp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(powerReduction), 146, 1), // powerreduction
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpSetDiffPress), 147, 1), // hpsetdiffpress
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCompOn), 148, 1), // hpcompon
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpActivity), 149, 1), // hpactivity
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrinePumpSpd), 150, 1), // hpbrinepumpspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpSwitchValve), 151, 1), // hpswitchvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCompSpd), 152, 1), // hpcompspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTargetSpd), 153, 1), // hptargetspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCircSpd), 154, 1), // hpcircspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(receiverValveVr0), 155, 1), // recvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(expansionValveVr1), 156, 1), // expvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrineIn), 157, 1), // hpbrinein
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrineOut), 158, 1), // hpbrineout
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc0), 159, 1), // hptc0
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc1), 160, 1), // hptc1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc3), 161, 1), // hptc3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr1), 162, 1), // hptr1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr3), 163, 1), // hptr3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr4), 164, 1), // hptr4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr5), 165, 1), // hptr5
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr6), 166, 1), // hptr6
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr7), 167, 1), // hptr7
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTl2), 168, 1), // hptl2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPl1), 169, 1), // hppl1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPh1), 170, 1), // hpph1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTa4), 171, 1), // hpta4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTw1), 172, 1), // hptw1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(poolSetTemp), 173, 1), // poolsettemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp4wayValve), 174, 1), // hp4way
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput1), 175, 1), // hpin1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn1Opt), 176, 8), // hpin1opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput2), 184, 1), // hpin2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn2Opt), 185, 8), // hpin2opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput3), 193, 1), // hpin3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn3Opt), 194, 8), // hpin3opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput4), 202, 1), // hpin4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn4Opt), 203, 8), // hpin4opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatComp), 211, 1), // maxheatcomp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatHeat), 212, 1), // maxheatheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterSource), 213, 1), // auxheatersource
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pvCooling), 214, 1), // pvcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOnly), 215, 1), // auxheateronly
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOff), 216, 1), // auxheateroff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterStatus), 217, 1), // auxheaterstatus
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterLevel), 218, 1), // auxheaterlevel
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterDelay), 219, 1), // auxheaterdelay
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxMaxLimit), 220, 1), // auxmaxlimit
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxLimitStart), 221, 1), // auxlimitstart
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMode), 222, 1), // auxheatrmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystHeat), 223, 1), // hphystheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystCool), 224, 1), // hphystcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystPool), 225, 1), // hphystpool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentMode), 226, 1), // silentmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentFrom), 227, 1), // silentfrom
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentTo), 228, 1), // silentto
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(minTempSilent), 229, 1), // mintempsilent
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempParMode), 230, 1), // tempparmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMixValve), 231, 1), // auxheatmix
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffHeat), 232, 1), // tempdiffheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffCool), 233, 1), // tempdiffcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(vp_cooling), 234, 1), // vpcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatCable), 235, 1), // heatcable
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(VC0valve), 236, 1), // vc0valve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePump), 237, 1), // primepump
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePumpMod), 238, 1), // primepumpmod
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp3wayValve), 239, 1), // hp3way
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep1), 240, 1), // elheatstep1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep2), 241, 1), // elheatstep2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep3), 242, 1), // elheatstep3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpEA0), 243, 1), // hpea0
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPumpMode), 244, 1), // hppumpmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpFan), 245, 1), // fan
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanSpd), 246, 1), // fanspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpShutdown), 247, 1), // shutdown
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCurrPower), 248, 1), // hpcurrpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPowerLimit), 249, 1), // hppowerlimit
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(exhaustTemp), 250, 1), // exhausttemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas), 251, 1), // burngas
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas2), 252, 1), // burngas2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(flameCurr), 253, 1), // flamecurr
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanWork), 254, 1), // fanwork
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(ignWork), 255, 1), // ignwork
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(oilPreHeat), 256, 1), // oilpreheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMaxPower), 257, 1), // burnmaxpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMinPeriod), 258, 1), // burnminperiod
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(absBurnPow), 259, 1), // absburnpow
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatblock), 260, 1), // heatblock
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOn), 261, 1), // boilhyston
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOff), 262, 1), // boilhystoff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOn), 263, 1), // boil2hyston
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOff), 264, 1), // boil2hystoff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveOn), 265, 1), // curveon
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveBase), 266, 1), // curvebase
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveEnd), 267, 1), // curveend
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(summertemp), 268, 1), // summertemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrostmode), 269, 1), // nofrostmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrosttemp), 270, 1), // nofrosttemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(gasMeterHeat), 271, 2), // gasmeterheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat2), 273, 2), // nrgheat2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nomPower), 275, 1), // nompower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(netFlowTemp), 276, 1), // netflowtemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatValve), 277, 1), // heatvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(keepWarmTemp), 278, 1), // keepwarmtemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setReturnTemp), 279, 1), // setreturntemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingOn), 280, 1), // heating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pumpKickHour), 84, 1), // pumpkickhour
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pumpKickDay), 85, 1), // pumpkickday
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pumpKickDelay), 86, 1), // pumpkickdelay
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(manDefrost), 87, 1), // mandefrost
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgTotal), 88, 2), // nrgtotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat), 90, 2), // nrgheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgCool), 92, 2), // nrgcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterTotal), 94, 2), // metertotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterComp), 96, 2), // metercomp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterEHeat), 98, 2), // metereheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterHeat), 100, 2), // meterheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterCool), 102, 2), // metercool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeTotal), 104, 2), // uptimetotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeControl), 106, 2), // uptimecontrol
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeCompHeating), 108, 2), // uptimecompheating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeCompCooling), 110, 2), // uptimecompcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeCompPool), 112, 2), // uptimecomppool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(totalCompStarts), 114, 2), // totalcompstarts
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingStarts), 116, 2), // heatingstarts
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(coolingStarts), 118, 2), // coolingstarts
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(poolStarts), 120, 2), // poolstarts
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsTotal), 122, 2), // nrgconstotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompTotal), 124, 2), // nrgconscomptotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompHeating), 126, 2), // nrgconscompheating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompCooling), 128, 2), // nrgconscompcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompPool), 130, 2), // nrgconscomppool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxElecHeatNrgConsTotal), 132, 2), // auxelecheatnrgconstotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxElecHeatNrgConsHeating), 134, 2), // auxelecheatnrgconsheating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxElecHeatNrgConsPool), 136, 2), // auxelecheatnrgconspool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppTotal), 138, 2), // nrgsupptotal
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppHeating), 140, 2), // nrgsuppheating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppCooling), 142, 2), // nrgsuppcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppPool), 144, 2), // nrgsupppool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPower), 146, 1), // hppower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpMaxPower), 147, 1), // hpmaxpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pvMaxComp), 148, 1), // pvmaxcomp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(powerReduction), 149, 1), // powerreduction
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpSetDiffPress), 150, 1), // hpsetdiffpress
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCompOn), 151, 1), // hpcompon
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpActivity), 152, 1), // hpactivity
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrinePumpSpd), 153, 1), // hpbrinepumpspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpSwitchValve), 154, 1), // hpswitchvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCompSpd), 155, 1), // hpcompspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTargetSpd), 156, 1), // hptargetspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCircSpd), 157, 1), // hpcircspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(receiverValveVr0), 158, 1), // recvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(expansionValveVr1), 159, 1), // expvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrineIn), 160, 1), // hpbrinein
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrineOut), 161, 1), // hpbrineout
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc0), 162, 1), // hptc0
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc1), 163, 1), // hptc1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc3), 164, 1), // hptc3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr1), 165, 1), // hptr1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr3), 166, 1), // hptr3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr4), 167, 1), // hptr4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr5), 168, 1), // hptr5
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr6), 169, 1), // hptr6
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr7), 170, 1), // hptr7
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTl2), 171, 1), // hptl2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPl1), 172, 1), // hppl1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPh1), 173, 1), // hpph1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTa4), 174, 1), // hpta4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTw1), 175, 1), // hptw1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(poolSetTemp), 176, 1), // poolsettemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp4wayValve), 177, 1), // hp4way
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput1), 178, 1), // hpin1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn1Opt), 179, 8), // hpin1opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput2), 187, 1), // hpin2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn2Opt), 188, 8), // hpin2opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput3), 196, 1), // hpin3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn3Opt), 197, 8), // hpin3opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput4), 205, 1), // hpin4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn4Opt), 206, 8), // hpin4opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatComp), 214, 1), // maxheatcomp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatHeat), 215, 1), // maxheatheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterSource), 216, 1), // auxheatersource
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pvCooling), 217, 1), // pvcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOnly), 218, 1), // auxheateronly
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOff), 219, 1), // auxheateroff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterStatus), 220, 1), // auxheaterstatus
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterLevel), 221, 1), // auxheaterlevel
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterDelay), 222, 1), // auxheaterdelay
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxMaxLimit), 223, 1), // auxmaxlimit
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxLimitStart), 224, 1), // auxlimitstart
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMode), 225, 1), // auxheatrmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystHeat), 226, 1), // hphystheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystCool), 227, 1), // hphystcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystPool), 228, 1), // hphystpool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentMode), 229, 1), // silentmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentFrom), 230, 1), // silentfrom
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentTo), 231, 1), // silentto
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(minTempSilent), 232, 1), // mintempsilent
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempParMode), 233, 1), // tempparmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMixValve), 234, 1), // auxheatmix
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffHeat), 235, 1), // tempdiffheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffCool), 236, 1), // tempdiffcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(vp_cooling), 237, 1), // vpcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatCable), 238, 1), // heatcable
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(VC0valve), 239, 1), // vc0valve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePump), 240, 1), // primepump
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePumpMod), 241, 1), // primepumpmod
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp3wayValve), 242, 1), // hp3way
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep1), 243, 1), // elheatstep1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep2), 244, 1), // elheatstep2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep3), 245, 1), // elheatstep3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpEA0), 246, 1), // hpea0
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPumpMode), 247, 1), // hppumpmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpFan), 248, 1), // fan
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanSpd), 249, 1), // fanspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpShutdown), 250, 1), // shutdown
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCurrPower), 251, 1), // hpcurrpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPowerLimit), 252, 1), // hppowerlimit
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(exhaustTemp), 253, 1), // exhausttemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas), 254, 1), // burngas
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas2), 255, 1), // burngas2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(flameCurr), 256, 1), // flamecurr
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanWork), 257, 1), // fanwork
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(ignWork), 258, 1), // ignwork
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(oilPreHeat), 259, 1), // oilpreheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMaxPower), 260, 1), // burnmaxpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMinPeriod), 261, 1), // burnminperiod
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(absBurnPow), 262, 1), // absburnpow
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatblock), 263, 1), // heatblock
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOn), 264, 1), // boilhyston
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOff), 265, 1), // boilhystoff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOn), 266, 1), // boil2hyston
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOff), 267, 1), // boil2hystoff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveOn), 268, 1), // curveon
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveBase), 269, 1), // curvebase
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveEnd), 270, 1), // curveend
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(summertemp), 271, 1), // summertemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrostmode), 272, 1), // nofrostmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrosttemp), 273, 1), // nofrosttemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(gasMeterHeat), 274, 2), // gasmeterheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat2), 276, 2), // nrgheat2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nomPower), 278, 1), // nompower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(netFlowTemp), 279, 1), // netflowtemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatValve), 280, 1), // heatvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(keepWarmTemp), 281, 1), // keepwarmtemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setReturnTemp), 282, 1), // setreturntemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingOn), 283, 1), // heating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(nrgWw), 0, 2), // nrg
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(meterWw), 2, 2), // meter
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(upTimeCompWw), 4, 2), // uptimecomp
@@ -308,87 +311,88 @@ const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_ma
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(summertemp), 8, 1), // summertemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(designtemp), 9, 1), // designtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(offsettemp), 10, 1), // offsettemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(minflowtemp), 11, 1), // minflowtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(maxflowtemp), 12, 1), // maxflowtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roominfluence), 13, 1), // roominfluence
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roominfl_factor), 14, 1), // roominflfactor
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(curroominfl), 15, 1), // curroominfl
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(nofrostmode), 16, 1), // nofrostmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(nofrosttemp), 17, 1), // nofrosttemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(targetflowtemp), 18, 1), // targetflowtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatingtype), 19, 1), // heatingtype
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(summersetmode), 20, 1), // summersetmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpoperatingmode), 21, 1), // hpoperatingmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(summermode), 22, 1), // summermode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpoperatingstate), 23, 1), // hpoperatingstate
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacationmode), 24, 1), // vacationmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(controlmode), 25, 1), // controlmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(program), 26, 1), // program
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(tempautotemp), 27, 1), // tempautotemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(cooltemp), 28, 1), // cooltemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(fastheatup), 29, 1), // fastheatup
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(comfortPointOffset), 30, 1), // comfoffset
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(comfortPointTemp), 31, 1), // comftemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchonoptimization), 32, 1), // switchonoptimization
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reducemode), 33, 1), // reducemode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(noreducetemp), 34, 1), // noreducetemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reducetemp), 35, 1), // reducetemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(wwprio), 36, 1), // dhwprio
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpcooling), 37, 1), // hpcooling
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolingOn), 38, 1), // coolingon
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpmode), 39, 1), // hpmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(dewoffset), 40, 1), // dewoffset
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roomtempdiff), 41, 1), // roomtempdiff
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpminflowtemp), 42, 1), // hpminflowtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(control), 43, 1), // control
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(remotetemp), 44, 1), // remotetemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(remotehum), 45, 1), // remotehum
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatondelay), 46, 1), // heatondelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatoffdelay), 47, 1), // heatoffdelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(instantstart), 48, 1), // instantstart
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(boost), 49, 1), // boost
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(boosttime), 50, 1), // boosttime
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolstart), 51, 1), // coolstart
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolondelay), 52, 1), // coolondelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(cooloffdelay), 53, 1), // cooloffdelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchProgMode), 54, 1), // switchprogmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(redthreshold), 55, 1), // redthreshold
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(solarinfl), 56, 1), // solarinfl
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(currsolarinfl), 57, 1), // currsolarinfl
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatingPID), 58, 1), // heatingpid
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(pumpopt), 59, 1), // pumpopt
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(inttimefloor), 60, 1), // inttimefloor
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(inttime), 61, 1), // inttime
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(daytemp), 62, 1), // daytemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(nighttemp2), 63, 1), // nighttemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(holidaytemp), 64, 1), // holidaytemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(holidaymode), 65, 1), // holidaymode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(flowtempoffset), 66, 1), // flowtempoffset
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(holidays), 67, 13), // holidays
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations), 80, 13), // vacations
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(pause), 93, 1), // pause
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(party), 94, 1), // party
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacreducetemp), 95, 1), // vacreducetemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacreducemode), 96, 1), // vacreducemode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchtime1), 97, 8), // switchtime1
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchtime2), 105, 8), // switchtime2
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(offtemp), 113, 1), // offtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(daylowtemp), 114, 1), // daytemp2
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(daymidtemp), 115, 1), // daytemp3
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(dayhightemp), 116, 1), // daytemp4
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchtime), 117, 8), // switchtime
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations1), 125, 11), // vacations1
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations2), 136, 11), // vacations2
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations3), 147, 11), // vacations3
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations4), 158, 11), // vacations4
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations5), 169, 11), // vacations5
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations6), 180, 11), // vacations6
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations7), 191, 11), // vacations7
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reducehours), 202, 1), // reducehours
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reduceminutes), 203, 1), // reduceminutes
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heattemp), 204, 1), // heattemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roomsensor), 205, 1), // roomsensor
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatup), 206, 1), // heatup
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(baseflowtemp), 11, 1), // baseflowtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(minflowtemp), 12, 1), // minflowtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(maxflowtemp), 13, 1), // maxflowtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roominfluence), 14, 1), // roominfluence
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roominfl_factor), 15, 1), // roominflfactor
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(curroominfl), 16, 1), // curroominfl
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(nofrostmode), 17, 1), // nofrostmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(nofrosttemp), 18, 1), // nofrosttemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(targetflowtemp), 19, 1), // targetflowtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatingtype), 20, 1), // heatingtype
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(summersetmode), 21, 1), // summersetmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpoperatingmode), 22, 1), // hpoperatingmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(summermode), 23, 1), // summermode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpoperatingstate), 24, 1), // hpoperatingstate
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacationmode), 25, 1), // vacationmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(controlmode), 26, 1), // controlmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(program), 27, 1), // program
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(tempautotemp), 28, 1), // tempautotemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(cooltemp), 29, 1), // cooltemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(fastheatup), 30, 1), // fastheatup
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(comfortPointOffset), 31, 1), // comfoffset
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(comfortPointTemp), 32, 1), // comftemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchonoptimization), 33, 1), // switchonoptimization
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reducemode), 34, 1), // reducemode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(noreducetemp), 35, 1), // noreducetemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reducetemp), 36, 1), // reducetemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(wwprio), 37, 1), // dhwprio
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpcooling), 38, 1), // hpcooling
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolingOn), 39, 1), // coolingon
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpmode), 40, 1), // hpmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(dewoffset), 41, 1), // dewoffset
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roomtempdiff), 42, 1), // roomtempdiff
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpminflowtemp), 43, 1), // hpminflowtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(control), 44, 1), // control
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(remotetemp), 45, 1), // remotetemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(remotehum), 46, 1), // remotehum
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatondelay), 47, 1), // heatondelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatoffdelay), 48, 1), // heatoffdelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(instantstart), 49, 1), // instantstart
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(boost), 50, 1), // boost
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(boosttime), 51, 1), // boosttime
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolstart), 52, 1), // coolstart
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolondelay), 53, 1), // coolondelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(cooloffdelay), 54, 1), // cooloffdelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchProgMode), 55, 1), // switchprogmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(redthreshold), 56, 1), // redthreshold
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(solarinfl), 57, 1), // solarinfl
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(currsolarinfl), 58, 1), // currsolarinfl
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatingPID), 59, 1), // heatingpid
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(pumpopt), 60, 1), // pumpopt
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(inttimefloor), 61, 1), // inttimefloor
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(inttime), 62, 1), // inttime
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(daytemp), 63, 1), // daytemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(nighttemp2), 64, 1), // nighttemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(holidaytemp), 65, 1), // holidaytemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(holidaymode), 66, 1), // holidaymode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(flowtempoffset), 67, 1), // flowtempoffset
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(holidays), 68, 13), // holidays
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations), 81, 13), // vacations
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(pause), 94, 1), // pause
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(party), 95, 1), // party
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacreducetemp), 96, 1), // vacreducetemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacreducemode), 97, 1), // vacreducemode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchtime1), 98, 8), // switchtime1
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchtime2), 106, 8), // switchtime2
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(offtemp), 114, 1), // offtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(daylowtemp), 115, 1), // daytemp2
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(daymidtemp), 116, 1), // daytemp3
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(dayhightemp), 117, 1), // daytemp4
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchtime), 118, 8), // switchtime
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations1), 126, 11), // vacations1
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations2), 137, 11), // vacations2
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations3), 148, 11), // vacations3
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations4), 159, 11), // vacations4
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations5), 170, 11), // vacations5
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations6), 181, 11), // vacations6
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations7), 192, 11), // vacations7
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reducehours), 203, 1), // reducehours
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reduceminutes), 204, 1), // reduceminutes
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heattemp), 205, 1), // heattemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roomsensor), 206, 1), // roomsensor
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatup), 207, 1), // heatup
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(mode), 0, 1), // mode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(modetype), 1, 1), // modetype
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwSetTemp), 2, 1), // settemp
+9 -4
View File
@@ -1184,14 +1184,19 @@ 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) {
doc[ic_ha] = F_(iconpercent); // set icon
}
doc[sc_ha] = sc_ha_measurement;
doc[dc_ha] = "power_factor";
if (entity == FL_(airHumidity)[0] || entity == FL_(remotehum)[0]) {
doc[dc_ha] = "humidity";
} else if (entity == FL_(battery)[0]) {
doc[dc_ha] = "battery";
}
break;
case DeviceValueUOM::SECONDS:
case DeviceValueUOM::MINUTES:
@@ -1544,8 +1549,8 @@ void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const bool crea
}
// add mf (manufacturer/brand), mdl (model), sw (software version) and via_device
dev_json["mf"] = brand != nullptr ? brand : "EMS-ESP";
dev_json["mdl"] = model != nullptr ? model : "EMS-ESP";
dev_json["mf"] = brand != nullptr ? brand : "EMS-ESP";
dev_json["mdl"] = model != nullptr ? model : "EMS-ESP";
dev_json["sw"] = version != nullptr ? version : "v" + std::string(EMSESP_APP_VERSION);
dev_json["via_device"] = Mqtt::basename();
}
+150 -7
View File
@@ -52,6 +52,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 +133,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("autenticate %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. Imprtance 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 (";
@@ -556,11 +669,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 +689,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
@@ -1006,6 +1132,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);
@@ -2173,6 +2300,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()) {
@@ -2180,6 +2316,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();
@@ -2914,7 +3053,6 @@ void System::set_valid_system_gpios() {
// excluded:
// GPIO3, GPIO45 - GPIO46 = strapping pins
// GPIO26 - GPIO32 = SPI flash and PSRAM and not recommended
// GPIO33 - GPIO37 = Octal flash/PSRAM
// GPIO19 - GPIO20 = USB-JTAG
// GPIO22 - GPIO25 = don't exist
//
@@ -2922,7 +3060,12 @@ void System::set_valid_system_gpios() {
// GPIO11 - GPIO19 = ADC analog input only pins
// GPIO47 - GPIO48 = valid on a Wemos S3
// GPIO8 = used by Liligo S3 board profile for Rx
valid_system_gpios_ = string_range_to_vector("0-48", "3, 45-46, 26-32, 33-37, 19-20, 22-25");
if (ESP.getPsramSize() > 0) {
// GPIO33 - GPIO37 = Octal flash/PSRAM
valid_system_gpios_ = string_range_to_vector("0-48", "3, 45-46, 26-32, 33-37, 19-20, 22-25");
} else {
valid_system_gpios_ = string_range_to_vector("0-48", "3, 45-46, 26-32, 19-20, 22-25");
}
#elif CONFIG_IDF_TARGET_ESP32
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html
+1
View File
@@ -95,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);
+24
View File
@@ -400,6 +400,15 @@ bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, cons
return true;
}
if (!strcmp(cmd, F_(metrics))) {
std::string metrics = get_metrics_prometheus();
if (!metrics.empty()) {
output["api_data"] = metrics;
return true;
}
return false;
}
// this is for a specific sensor
const char * attribute_s = Command::get_attribute(cmd);
@@ -414,6 +423,21 @@ bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, cons
return false; // not found
}
// generate Prometheus metrics format from temperature values
std::string TemperatureSensor::get_metrics_prometheus() {
std::string result;
result.reserve(sensors_.size() * 120);
char val[10];
for (auto & sensor : sensors_) {
result += (std::string) "# HELP emsesp_" + sensor.name() + " " + sensor.name() + ", "
+ EMSdevice::uom_to_string(EMSESP::system_.fahrenheit() ? DeviceValueUOM::FAHRENHEIT : DeviceValueUOM::DEGREES) + ", readable, visible\n";
result += (std::string) "# TYPE emsesp_" + sensor.name() + " gauge\n";
result +=
(std::string) "emsesp_" + sensor.name() + " " + Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0) + "\n";
}
return result;
}
// note we don't add the device and state classes here, as we do in the custom entity service
void TemperatureSensor::get_value_json(JsonObject output, const Sensor & sensor) {
output["id"] = sensor.id();
+2
View File
@@ -96,6 +96,8 @@ class TemperatureSensor {
bool updated_values();
bool get_value_info(JsonObject output, const char * cmd, const int8_t id = -1);
std::string get_metrics_prometheus();
// return back reference to the sensor list, used by other classes
std::vector<Sensor, AllocatorPSRAM<Sensor>> sensors() const {
return sensors_;
+68 -13
View File
@@ -65,6 +65,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_telegram_type(0xE6, "UBAParametersPlus", true, MAKE_PF_CB(process_UBAParametersPlus));
register_telegram_type(0xE9, "UBAMonitorWWPlus", false, MAKE_PF_CB(process_UBAMonitorWWPlus));
register_telegram_type(0xEA, "UBAParameterWWPlus", true, MAKE_PF_CB(process_UBAParameterWWPlus));
register_telegram_type(0xEB, "PumpKick", true, MAKE_PF_CB(process_PumpKick));
register_telegram_type(0x28, "WeatherComp", true, MAKE_PF_CB(process_WeatherComp));
register_telegram_type(0x2E0, "UBASetPoints", false, MAKE_PF_CB(process_UBASetPoints2));
register_telegram_type(0x2CC, "HPPressure", true, MAKE_PF_CB(process_HpPressure));
@@ -355,6 +356,24 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pc1On_, DeviceValueType::BOOL, FL_(pc1On), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pc1Rate_, DeviceValueType::UINT8, FL_(pc1Rate), DeviceValueUOM::PERCENT);
register_device_value(
DeviceValueTAG::TAG_DEVICE_DATA, &pumpKickHour_, DeviceValueType::UINT8, FL_(pumpKickHour), DeviceValueUOM::HOURS, MAKE_CF_CB(set_pumpKickHour), 0, 23);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&pumpKickDay_,
DeviceValueType::ENUM,
FL_(enum_dayOfWeek),
FL_(pumpKickDay),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_pumpKickDay));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&pumpKickDelay_,
DeviceValueType::UINT16,
FL_(pumpKickDelay),
DeviceValueUOM::MINUTES,
MAKE_CF_CB(set_pumpKickDelay),
0,
32767);
/*
* Hybrid heatpump with telegram 0xBB is readable and writeable in boiler and thermostat
* thermostat always overwrites settings in boiler
@@ -2246,6 +2265,13 @@ void Boiler::process_HpPowerLimit(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, hpPowerLimit_, 0);
}
// 0x0EB
void Boiler::process_PumpKick(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, pumpKickHour_, 0);
has_enumupdate(telegram, pumpKickDay_, 1, 1); // 1-mo, ...
has_update(telegram, pumpKickDelay_, 2);
}
// Boiler(0x08) -B-> All(0x00), ?(0x2E), data: 00 00 1C CE 00 00 05 E8 00 00 00 18 00 00 00 02
void Boiler::process_Meters(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, gasMeterHeat_, 0);
@@ -2979,25 +3005,26 @@ bool Boiler::set_reset(const char * value, const int8_t id) {
}
if (num == 0) {
return true; // dash
} else if (num == 1) {
// LOG_INFO("Reset boiler maintenance message");
return true; // dash
} else if (num == 1) { // Reset boiler maintenance message;
write_command(0x05, 8, 0xFF, 0x1C);
return true;
} else if (num == 2) {
// LOG_INFO("Reset boiler error message");
write_command(0x05, 0, 0x5A); // error reset
} else if (num == 2) { // Reset boiler error message;
write_command(0x05, 0, 0x5A);
return true;
} else if (num == 3) {
// LOG_INFO("Reset boiler history");
write_command(0x05, 42, 0x01); // clear history
} else if (num == 3) { // Reset boiler history
write_command(0x05, 42, 0x01);
return true;
} else if (num == 4) {
// LOG_INFO("Reset boiler message");
write_command(0x05, 8, 0xFF); // same as maintenance
write_command(0x05, 8, 0xFF); // reset messages, same as maintenance reset (1)
return true;
} else if (num == 5) {
// LOG_INFO("Factory Reset");
} else if (num == 5) { // reset Heatpump errors
write_command(0x05, 50, 0xFF);
return true;
} else if (num == 6) { // reset burner starts
write_command(0x05, 2, 165);
return true;
} else if (num == 7) { // factory reset
write_command(0x05, 6, 154);
return true;
}
@@ -3628,4 +3655,32 @@ bool Boiler::set_shutdown(const char * value, const int8_t id) {
return false;
}
bool Boiler::set_pumpKickHour(const char * value, const int8_t id) {
int v;
if (Helpers::value2number(value, v, 0, 23)) {
write_command(0xEB, 0, v, 0xEB);
return true;
}
return false;
}
bool Boiler::set_pumpKickDay(const char * value, const int8_t id) {
uint8_t v;
if (Helpers::value2enum(value, v, FL_(enum_dayOfWeek))) {
write_command(0xEB, 1, v + 1, 0xEB);
return true;
}
return false;
}
bool Boiler::set_pumpKickDelay(const char * value, const int8_t id) {
int v;
if (Helpers::value2number(value, v, 0, 32767)) {
uint8_t data[2] = {(uint8_t)(v >> 8), (uint8_t)v};
write_command(0xEB, 2, data, 2, 0xEB);
return true;
}
return false;
}
} // namespace emsesp
+8
View File
@@ -319,6 +319,9 @@ class Boiler : public EMSdevice {
int16_t pc1Flow_;
uint8_t pc1Rate_;
uint8_t pc1On_;
uint8_t pumpKickHour_; // hour
uint8_t pumpKickDay_; // day 1=mo
uint16_t pumpKickDelay_; // delay minutes after pump running
// HIU
// uint16_t cwFlowRate_; // cold water flow rate *10
@@ -397,6 +400,7 @@ class Boiler : public EMSdevice {
void process_HpFan(std::shared_ptr<const Telegram> telegram);
void process_HpPower2(std::shared_ptr<const Telegram> telegram);
void process_HpPowerLimit(std::shared_ptr<const Telegram> telegram);
void process_PumpKick(std::shared_ptr<const Telegram> telegram);
void process_Meters(std::shared_ptr<const Telegram> telegram);
void process_Energy(std::shared_ptr<const Telegram> telegram);
@@ -602,6 +606,10 @@ class Boiler : public EMSdevice {
bool set_nrgHeat(const char * value, const int8_t id);
bool set_nrgWw(const char * value, const int8_t id);
bool set_nomPower(const char * value, const int8_t id);
bool set_pumpKickHour(const char * value, const int8_t id);
bool set_pumpKickDay(const char * value, const int8_t id);
bool set_pumpKickDelay(const char * value, const int8_t id);
};
} // namespace emsesp
+6 -5
View File
@@ -211,12 +211,13 @@ bool Connect::set_mode(const char * value, const int8_t id) {
return false;
}
uint8_t v;
if (Helpers::value2enum(value, v, FL_(enum_mode2), {3, 1, 0})) {
// if (Helpers::value2enum(value, v, FL_(enum_mode8))) {
write_command(0xBB5 + rc->room(), 0, v); // no validate, mode change is broadcasted
return true;
if (!Helpers::value2enum(value, v, FL_(enum_mode2), {3, 1, 0})) {
if (!Helpers::value2enum(value, v, FL_(enum_mode_ha), {3, 1, 0})) {
return false;
}
}
return false;
write_command(0xBB5 + rc->room(), 0, v); // no validate, mode change is broadcasted
return true;
}
bool Connect::set_seltemp(const char * value, const int8_t id) {
+38 -4
View File
@@ -1101,6 +1101,8 @@ void Thermostat::process_JunkersWW(std::shared_ptr<const Telegram> telegram) {
void Thermostat::process_JunkersDisp(std::shared_ptr<const Telegram> telegram) {
has_enumupdate(telegram, ibaMainDisplay_, 1, 1);
has_update(telegram, ibaLanguage_, 3);
has_update(telegram, ibaMinExtTemperature_, 16);
has_update(telegram, ibaBuildingType_, 17); // percent /10
}
// type 0x02A5 - data from Worchester CRF200
@@ -1250,12 +1252,12 @@ void Thermostat::process_RC300Summer(std::shared_ptr<const Telegram> telegram) {
if (hc->heatingtype != 3) {
has_update(telegram, hc->designtemp, 4);
has_update(telegram, hc->minflowtemp, model() == EMSdevice::EMS_DEVICE_FLAG_BC400 ? 13 : 8);
} else {
has_update(telegram, hc->designtemp, 5);
has_update(telegram, hc->minflowtemp, 8);
}
// minflowtemp could be in 8 or 13 #2969
has_update(telegram, hc->minflowtemp, 13);
has_update(telegram, hc->baseflowtemp, 8);
has_update(telegram, hc->fastHeatup, 10);
has_update(telegram, hc->comfortPointOffset, 11);
has_update(telegram, hc->comfortPointTemp, 12);
@@ -2025,6 +2027,8 @@ bool Thermostat::set_minexttemp(const char * value, const int8_t id) {
write_command(0x241, 10, mt, 0x241);
} else if (isRC300()) {
write_command(0x240, 10, mt, 0x240);
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
write_command(0x110, 16, mt, 0x110);
} else {
write_command(EMS_TYPE_IBASettings, 5, mt, EMS_TYPE_IBASettings);
}
@@ -2181,6 +2185,14 @@ bool Thermostat::set_remotehum(const char * value, const int8_t id) {
// 0xA5/0xA7 - Set the building settings
bool Thermostat::set_building(const char * value, const int8_t id) {
if (model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
int i;
if (Helpers::value2number(value, i, 0, 100)) {
write_command(0x110, 17, i / 10, 0x110);
return true;
}
return false;
}
uint8_t bd;
if (!Helpers::value2enum(value, bd, FL_(enum_ibaBuildingType))) {
return false;
@@ -2326,6 +2338,7 @@ bool Thermostat::set_control(const char * value, const int8_t id) {
// 1-FB10, 2-FB100
if (model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS && !has_flags(EMSdevice::EMS_DEVICE_FLAG_JUNKERS_OLD)) {
if (Helpers::value2enum(value, ctrl, FL_(enum_j_control))) {
hc->control = ctrl; // set in advance, dont wait for verify
write_command(set_typeids[hc->hc()], 1, ctrl);
return true;
}
@@ -2374,6 +2387,7 @@ bool Thermostat::set_control(const char * value, const int8_t id) {
}
} else if (Helpers::value2enum(value, ctrl, FL_(enum_control))) {
write_command(set_typeids[hc->hc()], EMS_OFFSET_RC35Set_control, ctrl);
hc->control = ctrl; // set in advance, dont wait for verify
return true;
}
@@ -4074,10 +4088,16 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
}
factor = 1;
break;
case HeatingCircuit::Mode::BASEFLOW:
set_typeid = summer_typeids[hc->hc()];
validate_typeid = set_typeid;
offset = 8;
factor = 1;
break;
case HeatingCircuit::Mode::MINFLOW:
set_typeid = summer_typeids[hc->hc()];
validate_typeid = set_typeid;
offset = hc->heatingtype != 3 && model == EMS_DEVICE_FLAG_BC400 ? 13 : 8;
offset = 13;
factor = 1;
break;
case HeatingCircuit::Mode::MAXFLOW:
@@ -4730,6 +4750,19 @@ void Thermostat::register_device_values() {
DeviceValueUOM::NONE,
MAKE_CF_CB(set_language));
}
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&ibaBuildingType_,
DeviceValueType::UINT8,
DeviceValueNumOp::DV_NUMOP_MUL10,
FL_(ibaBuildingType),
DeviceValueUOM::PERCENT,
MAKE_CF_CB(set_building));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&ibaMinExtTemperature_,
DeviceValueType::INT8,
FL_(ibaMinExtTemperature),
DeviceValueUOM::DEGREES,
MAKE_CF_CB(set_minexttemp));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&hybridStrategy_,
DeviceValueType::ENUM,
@@ -4880,6 +4913,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
register_device_value(tag, &hc->summertemp, DeviceValueType::UINT8, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp), 10, 30);
register_device_value(tag, &hc->designtemp, DeviceValueType::UINT8, FL_(designtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_designtemp));
register_device_value(tag, &hc->offsettemp, DeviceValueType::INT8, FL_(offsettemp), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_offsettemp));
register_device_value(tag, &hc->baseflowtemp, DeviceValueType::UINT8, FL_(baseflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_baseflowtemp));
register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT8, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp));
register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT8, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp));
register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT8, FL_(roominfluence), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_roominfluence));
+6 -1
View File
@@ -50,7 +50,7 @@ class Thermostat : public EMSdevice {
uint8_t daymidtemp;
uint8_t nighttemp;
uint8_t holidaytemp;
uint8_t heatingtype; // type of heating: 1 radiator, 2 convectors, 3 floors, 4 room supply
uint8_t heatingtype; // type of heating: 1 radiator, 2 convectors, 3 floor, 4 room supply
uint8_t targetflowtemp;
uint8_t summertemp;
int8_t nofrosttemp; // signed -20°C to +10°C
@@ -65,6 +65,7 @@ class Thermostat : public EMSdevice {
int16_t curroominfl;
uint8_t flowtempoffset;
uint8_t minflowtemp;
uint8_t baseflowtemp;
uint8_t maxflowtemp;
uint8_t reducemode;
uint8_t nofrostmode;
@@ -169,6 +170,7 @@ class Thermostat : public EMSdevice {
DAYMID,
COOLTEMP,
COOLSTART,
BASEFLOW,
UNKNOWN
};
@@ -583,6 +585,9 @@ class Thermostat : public EMSdevice {
inline bool set_minflowtemp(const char * value, const int8_t id) {
return set_temperature_value(value, id, HeatingCircuit::Mode::MINFLOW);
}
inline bool set_baseflowtemp(const char * value, const int8_t id) {
return set_temperature_value(value, id, HeatingCircuit::Mode::BASEFLOW);
}
inline bool set_roominfluence(const char * value, const int8_t id) {
return set_temperature_value(value, id, HeatingCircuit::Mode::ROOMINFLUENCE, true);
}
+1 -1
View File
@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.8.2-dev.6"
#define EMSESP_APP_VERSION "3.8.2-dev.10"
+57
View File
@@ -343,6 +343,15 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
return true;
}
if (!strcmp(cmd, F_(metrics))) {
std::string metrics = get_metrics_prometheus();
if (!metrics.empty()) {
output["api_data"] = metrics;
return true;
}
return false;
}
// specific value info
const char * attribute_s = Command::get_attribute(cmd);
for (auto const & entity : *customEntityItems_) {
@@ -354,6 +363,54 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
return false; // not found
}
// generate Prometheus metrics format from custom entities
std::string WebCustomEntityService::get_metrics_prometheus() {
std::string result;
result.reserve(customEntityItems_->size() * 140);
char val[10];
for (CustomEntityItem & entity : *customEntityItems_) {
if (entity.hide || entity.name[0] == '\0') {
continue;
}
result += (std::string) "# HELP emsesp_" + entity.name + " " + entity.name;
if (entity.uom != 0) {
result += (std::string) ", " + EMSdevice::uom_to_string(entity.uom);
}
result += (std::string) ", readable, visible" + (entity.writeable ? ", writable\n" : "\n");
result += (std::string) "# TYPE emsesp_" + entity.name + " gauge\n";
result += (std::string) "emsesp_" + entity.name + " ";
switch (entity.value_type) {
case DeviceValueType::BOOL:
result += (std::string)(entity.value == 0 ? "0" : "1");
break;
case DeviceValueType::INT8:
result += (std::string)Helpers::render_value(val, entity.factor * (int8_t)entity.value, 2);
break;
case DeviceValueType::UINT8:
result += (std::string)Helpers::render_value(val, entity.factor * (uint8_t)entity.value, 2);
break;
case DeviceValueType::INT16:
result += (std::string)Helpers::render_value(val, entity.factor * (int16_t)entity.value, 2);
break;
case DeviceValueType::UINT16:
result += (std::string)Helpers::render_value(val, entity.factor * (uint16_t)entity.value, 2);
break;
case DeviceValueType::UINT24:
case DeviceValueType::TIME:
case DeviceValueType::UINT32:
result += (std::string)Helpers::render_value(val, entity.factor * entity.value, 2);
break;
default:
if (entity.data.length() > 0) {
result += entity.data;
}
break;
}
result += (std::string) "\n";
}
return result;
}
// build the json for specific entity
void WebCustomEntityService::get_value_json(JsonObject output, CustomEntityItem const & entity) {
output["name"] = (const char *)entity.name;
+2
View File
@@ -68,6 +68,8 @@ class WebCustomEntityService : public StatefulService<WebCustomEntity> {
void show_values(JsonObject output);
void generate_value_web(JsonObject output, const bool is_dashboard = false);
std::string get_metrics_prometheus();
uint8_t count_entities();
void ha_reset() {
ha_configdone_ = false;
+34 -15
View File
@@ -102,7 +102,7 @@ StateUpdateResult WebScheduler::update(JsonObject root, WebScheduler & webSchedu
if (webScheduler.scheduleItems.back().name[0] != '\0') {
char key[sizeof(webScheduler.scheduleItems.back().name) + 2];
snprintf(key, sizeof(key), "s:%s", webScheduler.scheduleItems.back().name);
if (EMSESP::nvs_.isKey(key)) {
if (EMSESP::nvs_.isKey(key) && webScheduler.scheduleItems.back().flags != SCHEDULEFLAG_SCHEDULE_IMMEDIATE) {
webScheduler.scheduleItems.back().active = EMSESP::nvs_.getBool(key);
}
Command::add(
@@ -138,20 +138,11 @@ bool WebSchedulerService::command_setvalue(const char * value, const int8_t id,
publish();
}
// save new state to nvs #2946
char key[sizeof(scheduleItem.name) + 2];
snprintf(key, sizeof(key), "s:%s", scheduleItem.name);
EMSESP::nvs_.putBool(key, scheduleItem.active);
/* save to filesystem
EMSESP::webSchedulerService.update([&](WebScheduler & webSchedule) {
for (auto si : webSchedule.scheduleItems) {
if (!strcmp(si.name, scheduleItem.name)) {
si.active = scheduleItem.active;
break;
}
}
return StateUpdateResult::CHANGED;
});
*/
if (scheduleItem.flags != SCHEDULEFLAG_SCHEDULE_IMMEDIATE) {
char key[sizeof(scheduleItem.name) + 2];
snprintf(key, sizeof(key), "s:%s", scheduleItem.name);
EMSESP::nvs_.putBool(key, scheduleItem.active);
}
return true;
}
}
@@ -184,6 +175,15 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
return true;
}
if (!strcmp(cmd, F_(metrics))) {
std::string metrics = get_metrics_prometheus();
if (!metrics.empty()) {
output["api_data"] = metrics;
return true;
}
return false;
}
const char * attribute_s = Command::get_attribute(cmd);
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
if (Helpers::toLower(scheduleItem.name) == cmd) {
@@ -195,6 +195,21 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
return false; // not found
}
// generate Prometheus metrics format from scheduler values
std::string WebSchedulerService::get_metrics_prometheus() {
std::string result;
result.reserve(scheduleItems_->size() * 140);
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
if (scheduleItem.name[0] == '\0') {
continue;
}
result += (std::string) "# HELP emsesp_" + scheduleItem.name + " " + scheduleItem.name + ", boolean, readable, visible, writable\n";
result += (std::string) "# TYPE emsesp_" + scheduleItem.name + " gauge\n";
result += (std::string) "emsesp_" + scheduleItem.name + " " + (scheduleItem.active ? "1\n" : "0\n");
}
return result;
}
// build the json for specific entity
void WebSchedulerService::get_value_json(JsonObject output, const ScheduleItem & scheduleItem) {
output["name"] = (const char *)scheduleItem.name;
@@ -483,6 +498,10 @@ void WebSchedulerService::loop() {
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_IMMEDIATE) {
command(scheduleItem.name, scheduleItem.cmd.c_str(), compute(scheduleItem.value.c_str()));
scheduleItem.active = false;
publish_single(scheduleItem.name, false);
if (EMSESP::mqtt_.get_publish_onchange(0)) {
publish();
}
}
}
+2
View File
@@ -88,6 +88,8 @@ class WebSchedulerService : public StatefulService<WebScheduler> {
uint8_t count_entities(bool cmd_only = false);
bool onChange(const char * cmd);
std::string get_metrics_prometheus();
std::string raw_value;
std::string computed_value;
+28 -4
View File
@@ -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;
+40
View File
@@ -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
+2 -1
View File
@@ -31,7 +31,8 @@ void test_2() {
"off\",\"heatingtemp\":\"heating temperature\",\"maintenance\":\"maintenance scheduled\",\"maintenancedate\":\"next maintenance "
"date\",\"maintenancetime\":\"time to next maintenance\",\"nofrostmode\":\"nofrost mode\",\"nofrosttemp\":\"nofrost "
"temperature\",\"nompower\":\"nominal Power\",\"nrgheat\":\"energy heating\",\"pumpcharacter\":\"boiler pump characteristic\",\"pumpdelay\":\"pump "
"delay\",\"pumpmode\":\"boiler pump mode\",\"pumpmodmax\":\"boiler pump max power\",\"pumpmodmin\":\"boiler pump min power\",\"pumpontemp\":\"pump "
"delay\",\"pumpkickday\":\"pump kick day\",\"pumpkickdelay\":\"pump kick delay\",\"pumpkickhour\":\"pump kick hour\",\"pumpmode\":\"boiler pump "
"mode\",\"pumpmodmax\":\"boiler pump max power\",\"pumpmodmin\":\"boiler pump min power\",\"pumpontemp\":\"pump "
"logic temperature\",\"reset\":\"reset\",\"selburnpow\":\"burner selected max power\",\"selflowtemp\":\"selected flow "
"temperature\",\"summertemp\":\"summer temperature\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/commands"));