ESPHome  2024.5.2
kamstrup_kmp.h
Go to the documentation of this file.
1 #pragma once
2 
6 
7 namespace esphome {
8 namespace kamstrup_kmp {
9 
10 /*
11  ===========================================================================
12  === KAMSTRUP KMP ===
13  ===========================================================================
14 
15  Kamstrup Meter Protocol (KMP) is a protocol used with Kamstrup district
16  heating meters, e.g. Kamstrup MULTICAL 403.
17  These devices register consumed heat from a district heating system.
18  It does this by measuring the incoming and outgoing water temperature
19  and by measuring the water flow. The temperature difference (delta T)
20  together with the water flow results in consumed energy, typically
21  in giga joule (GJ).
22 
23  The Kamstrup Multical has an optical interface just above the display.
24  This interface is essentially an RS-232 interface using a proprietary
25  protocol (Kamstrup Meter Protocol [KMP]).
26 
27  The integration uses this optical interface to periodically read the
28  configured values (sensors) from the meter. Supported sensors are:
29  - Heat Energy [GJ]
30  - Current Power Consumption [kW]
31  - Temperature 1 [°C]
32  - Temperature 2 [°C]
33  - Temperature Difference [°K]
34  - Water Flow [l/h]
35  - Volume [m3]
36 
37  Apart from these supported 'fixed' sensors, the user can configure up to
38  five custom sensors. The KMP command (16 bit unsigned int) has to be
39  provided in that case.
40 
41  Note:
42  The optical interface is enabled as soon as a button on the meter is pushed.
43  The interface stays active for a few minutes. To keep the interface 'alive'
44  magnets must be placed around the optical sensor.
45 
46  Units:
47  Units are set using the regular Sensor config in the user yaml. However,
48  KMP does also send the correct unit with every value. When DEBUG logging
49  is enabled, the received value with the received unit are logged.
50 
51  Acknowledgement:
52  This interface was inspired by:
53  - https://atomstar.tweakblogs.net/blog/19110/reading-out-kamstrup-multical-402-403-with-home-built-optical-head
54  - https://wiki.hal9k.dk/projects/kamstrup
55 */
56 
57 // KMP Commands
58 static const uint16_t CMD_HEAT_ENERGY = 0x003C;
59 static const uint16_t CMD_POWER = 0x0050;
60 static const uint16_t CMD_TEMP1 = 0x0056;
61 static const uint16_t CMD_TEMP2 = 0x0057;
62 static const uint16_t CMD_TEMP_DIFF = 0x0059;
63 static const uint16_t CMD_FLOW = 0x004A;
64 static const uint16_t CMD_VOLUME = 0x0044;
65 
66 // KMP units
67 static const char *const UNITS[] = {
68  "", "Wh", "kWh", "MWh", "GWh", "J", "kJ", "MJ", "GJ", "Cal",
69  "kCal", "Mcal", "Gcal", "varh", "kvarh", "Mvarh", "Gvarh", "VAh", "kVAh", "MVAh",
70  "GVAh", "kW", "kW", "MW", "GW", "kvar", "kvar", "Mvar", "Gvar", "VA",
71  "kVA", "MVA", "GVA", "V", "A", "kV", "kA", "C", "K", "l",
72  "m3", "l/h", "m3/h", "m3xC", "ton", "ton/h", "h", "hh:mm:ss", "yy:mm:dd", "yyyy:mm:dd",
73  "mm:dd", "", "bar", "RTC", "ASCII", "m3 x 10", "ton x 10", "GJ x 10", "minutes", "Bitfield",
74  "s", "ms", "days", "RTC-Q", "Datetime"};
75 
77  public:
78  void set_heat_energy_sensor(sensor::Sensor *sensor) { this->heat_energy_sensor_ = sensor; }
79  void set_power_sensor(sensor::Sensor *sensor) { this->power_sensor_ = sensor; }
80  void set_temp1_sensor(sensor::Sensor *sensor) { this->temp1_sensor_ = sensor; }
81  void set_temp2_sensor(sensor::Sensor *sensor) { this->temp2_sensor_ = sensor; }
82  void set_temp_diff_sensor(sensor::Sensor *sensor) { this->temp_diff_sensor_ = sensor; }
83  void set_flow_sensor(sensor::Sensor *sensor) { this->flow_sensor_ = sensor; }
84  void set_volume_sensor(sensor::Sensor *sensor) { this->volume_sensor_ = sensor; }
85  void dump_config() override;
86  float get_setup_priority() const override;
87  void update() override;
88  void loop() override;
89  void add_custom_sensor(sensor::Sensor *sensor, uint16_t command) {
90  this->custom_sensors_.push_back(sensor);
91  this->custom_commands_.push_back(command);
92  }
93 
94  protected:
95  // Sensors
103 
104  // Custom sensors and commands
105  std::vector<sensor::Sensor *> custom_sensors_;
106  std::vector<uint16_t> custom_commands_;
107 
108  // Command queue
109  std::queue<uint16_t> command_queue_;
110 
111  // Methods
112 
113  // Sends a command to the meter and receives its response
114  void send_command_(uint16_t command);
115  // Sends a message to the meter. A prefix/suffix and CRC are added
116  void send_message_(const uint8_t *msg, int msg_len);
117  // Clears and data that might be in the UART Rx buffer
118  void clear_uart_rx_buffer_();
119  // Reads and validates the response to a send command
120  void read_command_(uint16_t command);
121  // Parses a received message
122  void parse_command_message_(uint16_t command, const uint8_t *msg, int msg_len);
123  // Sets the received value to the correct sensor
124  void set_sensor_value_(uint16_t command, float value, uint8_t unit_idx);
125 };
126 
127 // "true" CCITT CRC-16
128 uint16_t crc16_ccitt(const uint8_t *buffer, int len);
129 
130 } // namespace kamstrup_kmp
131 } // namespace esphome
void set_temp_diff_sensor(sensor::Sensor *sensor)
Definition: kamstrup_kmp.h:82
void set_heat_energy_sensor(sensor::Sensor *sensor)
Definition: kamstrup_kmp.h:78
void send_message_(const uint8_t *msg, int msg_len)
void parse_command_message_(uint16_t command, const uint8_t *msg, int msg_len)
void set_temp2_sensor(sensor::Sensor *sensor)
Definition: kamstrup_kmp.h:81
This class simplifies creating components that periodically check a state.
Definition: component.h:283
void set_sensor_value_(uint16_t command, float value, uint8_t unit_idx)
std::vector< sensor::Sensor * > custom_sensors_
Definition: kamstrup_kmp.h:105
void set_temp1_sensor(sensor::Sensor *sensor)
Definition: kamstrup_kmp.h:80
void set_flow_sensor(sensor::Sensor *sensor)
Definition: kamstrup_kmp.h:83
std::string size_t len
Definition: helpers.h:292
void set_power_sensor(sensor::Sensor *sensor)
Definition: kamstrup_kmp.h:79
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
Base-class for all sensors.
Definition: sensor.h:57
void add_custom_sensor(sensor::Sensor *sensor, uint16_t command)
Definition: kamstrup_kmp.h:89
void set_volume_sensor(sensor::Sensor *sensor)
Definition: kamstrup_kmp.h:84
uint16_t crc16_ccitt(const uint8_t *buffer, int len)