ESPHome 2026.1.5
Loading...
Searching...
No Matches
mhz19.cpp
Go to the documentation of this file.
1#include "mhz19.h"
2#include "esphome/core/log.h"
3
4#include <cinttypes>
5
6namespace esphome {
7namespace mhz19 {
8
9static const char *const TAG = "mhz19";
10static const uint8_t MHZ19_REQUEST_LENGTH = 8;
11static const uint8_t MHZ19_RESPONSE_LENGTH = 9;
12static const uint8_t MHZ19_COMMAND_GET_PPM[] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00};
13static const uint8_t MHZ19_COMMAND_ABC_ENABLE[] = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00};
14static const uint8_t MHZ19_COMMAND_ABC_DISABLE[] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00};
15static const uint8_t MHZ19_COMMAND_CALIBRATE_ZERO[] = {0xFF, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00};
16static const uint8_t MHZ19_COMMAND_DETECTION_RANGE_0_2000PPM[] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x07, 0xD0};
17static const uint8_t MHZ19_COMMAND_DETECTION_RANGE_0_5000PPM[] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x13, 0x88};
18static const uint8_t MHZ19_COMMAND_DETECTION_RANGE_0_10000PPM[] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x27, 0x10};
19
20uint8_t mhz19_checksum(const uint8_t *command) {
21 uint8_t sum = 0;
22 for (uint8_t i = 1; i < MHZ19_REQUEST_LENGTH; i++) {
23 sum += command[i];
24 }
25 return 0xFF - sum + 0x01;
26}
27
30 this->abc_enable();
31 } else if (this->abc_boot_logic_ == MHZ19_ABC_DISABLED) {
32 this->abc_disable();
33 }
34
35 this->range_set(this->detection_range_);
36}
37
39 uint32_t now_ms = millis();
40 uint32_t warmup_ms = this->warmup_seconds_ * 1000;
41 if (now_ms < warmup_ms) {
42 ESP_LOGW(TAG, "MHZ19 warming up, %" PRIu32 " s left", (warmup_ms - now_ms) / 1000);
43 this->status_set_warning();
44 return;
45 }
46
47 uint8_t response[MHZ19_RESPONSE_LENGTH];
48 if (!this->mhz19_write_command_(MHZ19_COMMAND_GET_PPM, response)) {
49 ESP_LOGW(TAG, "Reading data from MHZ19 failed!");
50 this->status_set_warning();
51 return;
52 }
53
54 if (response[0] != 0xFF || response[1] != 0x86) {
55 ESP_LOGW(TAG, "Invalid preamble from MHZ19!");
56 this->status_set_warning();
57 return;
58 }
59
60 uint8_t checksum = mhz19_checksum(response);
61 if (response[8] != checksum) {
62 ESP_LOGW(TAG, "MHZ19 Checksum doesn't match: 0x%02X!=0x%02X", response[8], checksum);
63 this->status_set_warning();
64 return;
65 }
66
68 const uint16_t ppm = (uint16_t(response[2]) << 8) | response[3];
69 const int temp = int(response[4]) - 40;
70 const uint8_t status = response[5];
71
72 ESP_LOGD(TAG, "MHZ19 Received CO₂=%uppm Temperature=%d°C Status=0x%02X", ppm, temp, status);
73 if (this->co2_sensor_ != nullptr)
74 this->co2_sensor_->publish_state(ppm);
75 if (this->temperature_sensor_ != nullptr)
77}
78
80 ESP_LOGD(TAG, "MHZ19 Calibrating zero point");
81 this->mhz19_write_command_(MHZ19_COMMAND_CALIBRATE_ZERO, nullptr);
82}
83
85 ESP_LOGD(TAG, "MHZ19 Enabling automatic baseline calibration");
86 this->mhz19_write_command_(MHZ19_COMMAND_ABC_ENABLE, nullptr);
87}
88
90 ESP_LOGD(TAG, "MHZ19 Disabling automatic baseline calibration");
91 this->mhz19_write_command_(MHZ19_COMMAND_ABC_DISABLE, nullptr);
92}
93
95 switch (detection_ppm) {
97 ESP_LOGV(TAG, "Using previously set detection range (no change)");
98 break;
100 ESP_LOGD(TAG, "Setting detection range to 0 to 2000ppm");
101 this->mhz19_write_command_(MHZ19_COMMAND_DETECTION_RANGE_0_2000PPM, nullptr);
102 break;
104 ESP_LOGD(TAG, "Setting detection range to 0 to 5000ppm");
105 this->mhz19_write_command_(MHZ19_COMMAND_DETECTION_RANGE_0_5000PPM, nullptr);
106 break;
108 ESP_LOGD(TAG, "Setting detection range to 0 to 10000ppm");
109 this->mhz19_write_command_(MHZ19_COMMAND_DETECTION_RANGE_0_10000PPM, nullptr);
110 break;
111 }
112}
113
114bool MHZ19Component::mhz19_write_command_(const uint8_t *command, uint8_t *response) {
115 // Empty RX Buffer
116 while (this->available())
117 this->read();
118 this->write_array(command, MHZ19_REQUEST_LENGTH);
119 this->write_byte(mhz19_checksum(command));
120 this->flush();
121
122 if (response == nullptr)
123 return true;
124
125 return this->read_array(response, MHZ19_RESPONSE_LENGTH);
126}
127
129
131 ESP_LOGCONFIG(TAG, "MH-Z19:");
132 LOG_SENSOR(" ", "CO2", this->co2_sensor_);
133 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
134 this->check_uart_settings(9600);
135
136 if (this->abc_boot_logic_ == MHZ19_ABC_ENABLED) {
137 ESP_LOGCONFIG(TAG, " Automatic baseline calibration enabled on boot");
138 } else if (this->abc_boot_logic_ == MHZ19_ABC_DISABLED) {
139 ESP_LOGCONFIG(TAG, " Automatic baseline calibration disabled on boot");
140 }
141
142 ESP_LOGCONFIG(TAG, " Warmup time: %" PRIu32 " s", this->warmup_seconds_);
143
144 const char *range_str;
145 switch (this->detection_range_) {
147 range_str = "default";
148 break;
150 range_str = "0 to 2000ppm";
151 break;
153 range_str = "0 to 5000ppm";
154 break;
156 range_str = "0 to 10000ppm";
157 break;
158 default:
159 range_str = "default";
160 break;
161 }
162 ESP_LOGCONFIG(TAG, " Detection range: %s", range_str);
163}
164
165} // namespace mhz19
166} // namespace esphome
uint8_t checksum
Definition bl0906.h:3
uint8_t status
Definition bl0942.h:8
void status_set_warning(const char *message=nullptr)
void status_clear_warning()
void dump_config() override
Definition mhz19.cpp:130
MHZ19DetectionRange detection_range_
Definition mhz19.h:52
float get_setup_priority() const override
Definition mhz19.cpp:128
sensor::Sensor * temperature_sensor_
Definition mhz19.h:46
sensor::Sensor * co2_sensor_
Definition mhz19.h:47
bool mhz19_write_command_(const uint8_t *command, uint8_t *response)
Definition mhz19.cpp:114
void range_set(MHZ19DetectionRange detection_ppm)
Definition mhz19.cpp:94
MHZ19ABCLogic abc_boot_logic_
Definition mhz19.h:48
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:76
optional< std::array< uint8_t, N > > read_array()
Definition uart.h:38
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...
Definition uart.cpp:12
void write_byte(uint8_t data)
Definition uart.h:18
void write_array(const uint8_t *data, size_t len)
Definition uart.h:26
@ MHZ19_ABC_DISABLED
Definition mhz19.h:14
@ MHZ19_ABC_ENABLED
Definition mhz19.h:13
uint8_t mhz19_checksum(const uint8_t *command)
Definition mhz19.cpp:20
MHZ19DetectionRange
Definition mhz19.h:17
@ MHZ19_DETECTION_RANGE_0_10000PPM
Definition mhz19.h:21
@ MHZ19_DETECTION_RANGE_0_5000PPM
Definition mhz19.h:20
@ MHZ19_DETECTION_RANGE_0_2000PPM
Definition mhz19.h:19
@ MHZ19_DETECTION_RANGE_DEFAULT
Definition mhz19.h:18
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:81
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:25