ESPHome 2026.3.0
Loading...
Searching...
No Matches
hc8.cpp
Go to the documentation of this file.
1#include "hc8.h"
4#include "esphome/core/log.h"
5
6#include <array>
7
8namespace esphome::hc8 {
9
10static const char *const TAG = "hc8";
11static const std::array<uint8_t, 5> HC8_COMMAND_GET_PPM{0x64, 0x69, 0x03, 0x5E, 0x4E};
12static const std::array<uint8_t, 3> HC8_COMMAND_CALIBRATE_PREAMBLE{0x11, 0x03, 0x03};
13
15 // send an initial query to the device, this will
16 // get it out of "active output mode", where it
17 // generates data every second
18 this->write_array(HC8_COMMAND_GET_PPM);
19 this->flush();
20
21 // ensure the buffer is empty
22 while (this->available())
23 this->read();
24}
25
27 if (!this->warmup_complete_) {
29 uint32_t warmup_ms = this->warmup_seconds_ * 1000;
30 if (now_ms < warmup_ms) {
31 ESP_LOGW(TAG, "HC8 warming up, %" PRIu32 " s left", (warmup_ms - now_ms) / 1000);
32 this->status_set_warning();
33 return;
34 }
35 this->warmup_complete_ = true;
37 }
38
39 while (this->available())
40 this->read();
41
42 this->write_array(HC8_COMMAND_GET_PPM);
43 this->flush();
44
45 // the sensor is a bit slow in responding, so trying to
46 // read immediately after sending a query will timeout
47 this->set_timeout(50, [this]() {
48 std::array<uint8_t, 14> response;
49 if (!this->read_array(response.data(), response.size())) {
50 ESP_LOGW(TAG, "Reading data from HC8 failed!");
51 this->status_set_warning();
52 return;
53 }
54
55 if (response[0] != 0x64 || response[1] != 0x69) {
56 ESP_LOGW(TAG, "Invalid preamble from HC8!");
57 this->status_set_warning();
58 return;
59 }
60
61 if (crc16(response.data(), 12) != encode_uint16(response[13], response[12])) {
62 ESP_LOGW(TAG, "HC8 Checksum mismatch");
63 this->status_set_warning();
64 return;
65 }
66
68
69 const uint16_t ppm = encode_uint16(response[5], response[4]);
70 ESP_LOGD(TAG, "HC8 Received CO₂=%uppm", ppm);
71 if (this->co2_sensor_ != nullptr)
72 this->co2_sensor_->publish_state(ppm);
73 });
74}
75
76void HC8Component::calibrate(uint16_t baseline) {
77 ESP_LOGD(TAG, "HC8 Calibrating baseline to %uppm", baseline);
78
79 std::array<uint8_t, 6> command{};
80 std::copy(begin(HC8_COMMAND_CALIBRATE_PREAMBLE), end(HC8_COMMAND_CALIBRATE_PREAMBLE), begin(command));
81 command[3] = baseline >> 8;
82 command[4] = baseline;
83 command[5] = 0;
84
85 // the last byte is a checksum over the data
86 for (uint8_t i = 0; i < 5; ++i)
87 command[5] -= command[i];
88
89 this->write_array(command);
90 this->flush();
91}
92
94 ESP_LOGCONFIG(TAG,
95 "HC8:\n"
96 " Warmup time: %" PRIu32 " s",
97 this->warmup_seconds_);
98 LOG_SENSOR(" ", "CO2", this->co2_sensor_);
99 this->check_uart_settings(9600);
100}
101
102} // namespace esphome::hc8
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
void status_set_warning(const char *message=nullptr)
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.h:451
void status_clear_warning()
Definition component.h:254
void calibrate(uint16_t baseline)
Definition hc8.cpp:76
uint32_t warmup_seconds_
Definition hc8.h:25
void update() override
Definition hc8.cpp:26
sensor::Sensor * co2_sensor_
Definition hc8.h:24
void dump_config() override
Definition hc8.cpp:93
void setup() override
Definition hc8.cpp:14
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:65
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:16
FlushResult flush()
Definition uart.h:48
void write_array(const uint8_t *data, size_t len)
Definition uart.h:26
uint16_t crc16(const uint8_t *data, uint16_t len, uint16_t crc, uint16_t reverse_poly, bool refin, bool refout)
Calculate a CRC-16 checksum of data with size len.
Definition helpers.cpp:73
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition helpers.h:728
Application App
Global storage of Application pointer - only one Application can exist.
static void uint32_t
uint8_t end[39]
Definition sun_gtil2.cpp:17