6 namespace kamstrup_kmp {
8 static const char *
const TAG =
"kamstrup_kmp";
11 ESP_LOGCONFIG(TAG,
"kamstrup_kmp:");
13 ESP_LOGE(TAG,
"Communication with Kamstrup meter failed!");
15 LOG_UPDATE_INTERVAL(
this);
84 msg[3] = command >> 8;
85 msg[4] = command & 0xFF;
93 int buffer_len = msg_len + 2;
94 uint8_t buffer[buffer_len];
97 for (
int i = 0; i < msg_len; i++) {
101 buffer[buffer_len - 2] = 0;
102 buffer[buffer_len - 1] = 0;
105 buffer[buffer_len - 2] = crc >> 8;
106 buffer[buffer_len - 1] = crc & 0xFF;
113 for (
int i = 0; i < buffer_len; i++) {
114 if (buffer[i] == 0x06 || buffer[i] == 0x0d || buffer[i] == 0x1b || buffer[i] == 0x40 || buffer[i] == 0x80) {
115 tx_msg[tx_msg_len++] = 0x1b;
116 tx_msg[tx_msg_len++] = buffer[i] ^ 0xff;
118 tx_msg[tx_msg_len++] = buffer[i];
122 tx_msg[tx_msg_len++] = 0x0D;
135 uint8_t buffer[20] = {0};
141 while (timeout > 0) {
148 buffer[buffer_len++] = (uint8_t) data;
153 ESP_LOGE(TAG,
"Error while reading from UART");
161 if (timeout == 0 || buffer_len == 0) {
162 ESP_LOGE(TAG,
"Request timed out");
167 if (buffer[0] != 0x40) {
168 ESP_LOGE(TAG,
"Received invalid message (prefix mismatch received 0x%02X, expected 0x40)", buffer[0]);
172 if (buffer[buffer_len - 1] != 0x0D) {
173 ESP_LOGE(TAG,
"Received invalid message (EOM mismatch received 0x%02X, expected 0x0D)", buffer[buffer_len - 1]);
178 uint8_t msg[20] = {0};
180 for (
int i = 1; i < buffer_len - 1; i++) {
181 if (buffer[i] == 0x1B) {
182 msg[msg_len++] = buffer[i + 1] ^ 0xFF;
185 msg[msg_len++] = buffer[i];
191 ESP_LOGE(TAG,
"Received invalid message (CRC mismatch)");
202 ESP_LOGE(TAG,
"Received invalid message (message too small)");
206 if (msg[0] != 0x3F || msg[1] != 0x10) {
207 ESP_LOGE(TAG,
"Received invalid message (invalid header received 0x%02X%02X, expected 0x3F10)", msg[0], msg[1]);
211 uint16_t recv_command = msg[2] << 8 | msg[3];
212 if (recv_command != command) {
213 ESP_LOGE(TAG,
"Received invalid message (invalid unexpected command received 0x%04X, expected 0x%04X)",
214 recv_command, command);
218 uint8_t unit_idx = msg[4];
219 uint8_t mantissa_range = msg[5];
221 if (mantissa_range > 4) {
222 ESP_LOGE(TAG,
"Received invalid message (mantissa size too large %d, expected 4)", mantissa_range);
227 float exponent = msg[6] & 0x3F;
229 exponent = -exponent;
231 exponent = powf(10, exponent);
233 exponent = -exponent;
237 uint32_t mantissa = 0;
238 for (
int i = 0; i < mantissa_range; i++) {
240 mantissa |= msg[i + 7];
244 float value = mantissa * exponent;
251 const char *unit = UNITS[unit_idx];
256 }
else if (command == CMD_POWER && this->
power_sensor_ !=
nullptr) {
258 }
else if (command == CMD_TEMP1 && this->
temp1_sensor_ !=
nullptr) {
260 }
else if (command == CMD_TEMP2 && this->
temp2_sensor_ !=
nullptr) {
264 }
else if (command == CMD_FLOW && this->
flow_sensor_ !=
nullptr) {
266 }
else if (command == CMD_VOLUME && this->
volume_sensor_ !=
nullptr) {
277 ESP_LOGD(TAG,
"Received value for command 0x%04X: %.3f [%s]", command, value, unit);
281 uint32_t poly = 0x1021;
283 for (
int i = 0; i <
len; i++) {
287 if (buffer[i] & mask) {
297 return (uint16_t) reg;
void read_command_(uint16_t command)
const float DATA
For components that import data from directly connected sensors like DHT.
void write_array(const uint8_t *data, size_t len)
sensor::Sensor * heat_energy_sensor_
std::queue< uint16_t > command_queue_
void send_message_(const uint8_t *msg, int msg_len)
sensor::Sensor * temp_diff_sensor_
void parse_command_message_(uint16_t command, const uint8_t *msg, int msg_len)
void clear_uart_rx_buffer_()
float get_setup_priority() const override
void set_sensor_value_(uint16_t command, float value, uint8_t unit_idx)
std::vector< sensor::Sensor * > custom_sensors_
void check_uart_settings(uint32_t baud_rate, uint8_t stop_bits=1, UARTParityOptions parity=UART_CONFIG_PARITY_NONE, uint8_t data_bits=8)
Check that the configuration of the UART bus matches the provided values and otherwise print a warnin...
bool read_byte(uint8_t *data)
sensor::Sensor * temp1_sensor_
sensor::Sensor * power_sensor_
void publish_state(float state)
Publish a new state to the front-end.
void dump_config() override
sensor::Sensor * temp2_sensor_
Implementation of SPI Controller mode.
void send_command_(uint16_t command)
std::vector< uint16_t > custom_commands_
uint16_t crc16_ccitt(const uint8_t *buffer, int len)
sensor::Sensor * flow_sensor_
void IRAM_ATTR HOT delay(uint32_t ms)
sensor::Sensor * volume_sensor_