ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
dsmr.h
Go to the documentation of this file.
1#pragma once
2
3// Ignore Zephyr. It doesn't have any encryption library.
4#if defined(USE_ESP32) || defined(USE_ARDUINO) || defined(USE_HOST)
5
10#include "esphome/core/log.h"
11#include <dsmr_parser/dlms_packet_decryptor.h>
12#include <dsmr_parser/fields.h>
13#include <dsmr_parser/packet_accumulator.h>
14#include <dsmr_parser/parser.h>
15#include <array>
16#include <span>
17#include <vector>
18
19// On ESP8266 Arduino, BearSSL is the native crypto. The mbedtls headers can
20// still be in scope when a sibling component (e.g. wireguard) pulls in
21// esp_mbedtls_esp8266, but that build leaves MBEDTLS_GCM_C disabled so the
22// gcm.h symbols are unresolved at link time. Force BearSSL on ESP8266 to
23// avoid that linker error.
24#if __has_include(<psa/crypto.h>)
25#include <dsmr_parser/decryption/aes128gcm_tfpsa.h>
26#elif !defined(USE_ESP8266) && __has_include(<mbedtls/gcm.h>)
27#if __has_include(<mbedtls/esp_config.h>)
28#include <mbedtls/esp_config.h>
29#endif
30#include <dsmr_parser/decryption/aes128gcm_mbedtls.h>
31#elif __has_include(<bearssl/bearssl.h>)
32#include <dsmr_parser/decryption/aes128gcm_bearssl.h>
33#else
34#error "The platform doesn't provide a compatible encryption library for dsmr_parser"
35#endif
36
37namespace esphome::dsmr {
38
39#if __has_include(<psa/crypto.h>)
40using Aes128GcmDecryptorImpl = dsmr_parser::Aes128GcmTfPsa;
41#elif !defined(USE_ESP8266) && __has_include(<mbedtls/gcm.h>)
42using Aes128GcmDecryptorImpl = dsmr_parser::Aes128GcmMbedTls;
43#else
44using Aes128GcmDecryptorImpl = dsmr_parser::Aes128GcmBearSsl;
45#endif
46
47using namespace dsmr_parser::fields;
48
49#ifndef DSMR_SENSOR_LIST
50#define DSMR_SENSOR_LIST(F, SEP)
51#endif
52
53#ifndef DSMR_TEXT_SENSOR_LIST
54#define DSMR_TEXT_SENSOR_LIST(F, SEP)
55#endif
56
57#define DSMR_IDENTITY(s) s
58#define DSMR_COMMA ,
59#define DSMR_PREPEND_COMMA(...) __VA_OPT__(, ) __VA_ARGS__
60
61#ifdef DSMR_TEXT_SENSOR_LIST_DEFINED
62using MyData = dsmr_parser::ParsedData<DSMR_TEXT_SENSOR_LIST(DSMR_IDENTITY, DSMR_COMMA)
63 DSMR_PREPEND_COMMA(DSMR_SENSOR_LIST(DSMR_IDENTITY, DSMR_COMMA))>;
64#else
65using MyData = dsmr_parser::ParsedData<DSMR_SENSOR_LIST(DSMR_IDENTITY, DSMR_COMMA)>;
66#endif
67
68class Dsmr : public Component, public uart::UARTDevice {
69 public:
70 Dsmr(uart::UARTComponent *uart, bool crc_check, size_t max_telegram_length, uint32_t request_interval,
71 uint32_t receive_timeout, GPIOPin *request_pin, const char *decryption_key)
72 : uart::UARTDevice(uart),
73 request_interval_(request_interval),
74 receive_timeout_(receive_timeout),
75 request_pin_(request_pin),
76 buffer_(max_telegram_length),
77 packet_accumulator_(buffer_, crc_check),
79 this->set_decryption_key_(decryption_key);
80 }
81
82 void setup() override;
83 void loop() override;
84
85 void publish_sensors(MyData &data) {
86#define DSMR_PUBLISH_SENSOR(s) \
87 if (data.s##_present && this->s_##s##_ != nullptr) \
88 s_##s##_->publish_state(data.s);
89 DSMR_SENSOR_LIST(DSMR_PUBLISH_SENSOR, )
90
91#define DSMR_PUBLISH_TEXT_SENSOR(s) \
92 if (data.s##_present && this->s_##s##_ != nullptr) \
93 s_##s##_->publish_state(data.s.data(), data.s.size());
94 DSMR_TEXT_SENSOR_LIST(DSMR_PUBLISH_TEXT_SENSOR, )
95 };
96
97 void dump_config() override;
98
99 // Remove before 2026.8.0
100 ESPDEPRECATED("Use 'decryption_key' configuration parameter. This method will be removed in 2026.8.0", "2026.2.0")
101 void set_decryption_key(const std::string &decryption_key) {
102 // Some YAML configs pass a string longer than 32 symbols. We only need the first 32 symbols,
103 // otherwise `Aes128GcmDecryptionKey::from_hex` will fail.
104 this->set_decryption_key_(std::string(decryption_key, 0, 32).c_str());
105 }
106
107// Sensor setters
108#define DSMR_SET_SENSOR(s) \
109 void set_##s(sensor::Sensor *sensor) { s_##s##_ = sensor; }
110 DSMR_SENSOR_LIST(DSMR_SET_SENSOR, )
111
112#define DSMR_SET_TEXT_SENSOR(s) \
113 void set_##s(text_sensor::TextSensor *sensor) { s_##s##_ = sensor; }
114 DSMR_TEXT_SENSOR_LIST(DSMR_SET_TEXT_SENSOR, )
115
116 // handled outside dsmr
117 void set_telegram(text_sensor::TextSensor *sensor) { s_telegram_ = sensor; }
118
119 protected:
120 void set_decryption_key_(const char *decryption_key);
121 void receive_telegram_();
123 void flush_rx_buffer_();
124
125 bool parse_telegram_(const dsmr_parser::DsmrUnencryptedTelegram &telegram);
126 bool request_interval_reached_() const;
130 std::span<uint8_t> uart_read_chunk_();
131
132 // Config
137#define DSMR_DECLARE_SENSOR(s) sensor::Sensor *s_##s##_{nullptr};
138 DSMR_SENSOR_LIST(DSMR_DECLARE_SENSOR, )
139#define DSMR_DECLARE_TEXT_SENSOR(s) text_sensor::TextSensor *s_##s##_{nullptr};
140 DSMR_TEXT_SENSOR_LIST(DSMR_DECLARE_TEXT_SENSOR, )
141
142 // State
145 bool requesting_data_{false};
147 size_t buffer_pos_{0};
148 std::vector<uint8_t> buffer_;
149 dsmr_parser::PacketAccumulator packet_accumulator_;
151 dsmr_parser::DlmsPacketDecryptor dlms_decryptor_;
152 std::array<uint8_t, 256> uart_chunk_reading_buf_;
153};
154} // namespace esphome::dsmr
155
156#endif
ESPDEPRECATED("Use 'decryption_key' configuration parameter. This method will be removed in 2026.8.0", "2026.2.0") void set_decryption_key(const std
Definition dsmr.h:100
void stop_requesting_data_()
Definition dsmr.cpp:87
Dsmr(uart::UARTComponent *uart, bool crc_check, size_t max_telegram_length, uint32_t request_interval, uint32_t receive_timeout, GPIOPin *request_pin, const char *decryption_key)
Definition dsmr.h:70
uint32_t last_request_time_
Definition dsmr.h:143
GPIOPin * request_pin_
Definition dsmr.h:135
uint32_t receive_timeout_
Definition dsmr.h:134
void set_telegram(text_sensor::TextSensor *sensor)
Definition dsmr.h:117
size_t buffer_pos_
Definition dsmr.h:147
bool request_interval_reached_() const
Definition dsmr.cpp:63
bool ready_to_request_data_()
Definition dsmr.cpp:56
dsmr_parser::DlmsPacketDecryptor dlms_decryptor_
Definition dsmr.h:151
void set_decryption_key_(const char *decryption_key)
Definition dsmr.cpp:196
text_sensor::TextSensor * s_telegram_
Definition dsmr.h:136
void flush_rx_buffer_()
Definition dsmr.cpp:100
void publish_sensors(MyData &data)
Definition dsmr.h:85
void start_requesting_data_()
Definition dsmr.cpp:70
dsmr_parser::PacketAccumulator packet_accumulator_
Definition dsmr.h:149
void receive_telegram_()
Definition dsmr.cpp:106
bool encryption_enabled_
Definition dsmr.h:146
uint32_t last_read_time_
Definition dsmr.h:144
DSMR_SENSOR_LIST(DSMR_SET_SENSOR,) DSMR_TEXT_SENSOR_LIST(DSMR_SET_TEXT_SENSOR
bool requesting_data_
Definition dsmr.h:145
void loop() override
Definition dsmr.cpp:44
uint32_t request_interval_
Definition dsmr.h:133
DSMR_SENSOR_LIST(DSMR_DECLARE_SENSOR,) DSMR_TEXT_SENSOR_LIST(DSMR_DECLARE_TEXT_SENSOR
std::array< uint8_t, 256 > uart_chunk_reading_buf_
Definition dsmr.h:152
void setup() override
Definition dsmr.cpp:37
void dump_config() override
Definition dsmr.cpp:176
Aes128GcmDecryptorImpl gcm_decryptor_
Definition dsmr.h:150
void receive_encrypted_telegram_()
Definition dsmr.cpp:120
bool parse_telegram_(const dsmr_parser::DsmrUnencryptedTelegram &telegram)
Definition dsmr.cpp:153
std::vector< uint8_t > buffer_
Definition dsmr.h:148
std::span< uint8_t > uart_read_chunk_()
Definition dsmr.cpp:215
dsmr_parser::Aes128GcmTfPsa Aes128GcmDecryptorImpl
Definition dsmr.h:40
dsmr_parser::ParsedData< DSMR_TEXT_SENSOR_LIST(DSMR_IDENTITY, DSMR_COMMA) DSMR_PREPEND_COMMA(DSMR_SENSOR_LIST(DSMR_IDENTITY, DSMR_COMMA))> MyData
Definition dsmr.h:62
static void uint32_t