ESPHome 2025.5.0
Loading...
Searching...
No Matches
ccs811.cpp
Go to the documentation of this file.
1#include "ccs811.h"
2#include "esphome/core/log.h"
3#include "esphome/core/hal.h"
4
5namespace esphome {
6namespace ccs811 {
7
8static const char *const TAG = "ccs811";
9
10// based on
11// - https://cdn.sparkfun.com/datasheets/BreakoutBoards/CCS811_Programming_Guide.pdf
12
13#define CHECK_TRUE(f, error_code) \
14 if (!(f)) { \
15 this->mark_failed(); \
16 this->error_code_ = (error_code); \
17 return; \
18 }
19
20#define CHECKED_IO(f) CHECK_TRUE(f, COMMUNICATION_FAILED)
21
23 // page 9 programming guide - hwid is always 0x81
24 uint8_t hw_id;
25 CHECKED_IO(this->read_byte(0x20, &hw_id))
26 CHECK_TRUE(hw_id == 0x81, INVALID_ID)
27
28 // software reset, page 3 - allowed to fail
29 this->write_bytes(0xFF, {0x11, 0xE5, 0x72, 0x8A});
30 delay(5);
31
32 // page 10, APP_START
33 CHECK_TRUE(!this->status_has_error_(), SENSOR_REPORTED_ERROR)
34 CHECK_TRUE(this->status_app_is_valid_(), APP_INVALID)
35 CHECK_TRUE(this->write_bytes(0xF4, {}), APP_START_FAILED)
36 // App setup, wait for it to load
37 delay(1);
38
39 // set MEAS_MODE (page 5)
40 uint8_t meas_mode = 0;
41 uint32_t interval = this->get_update_interval();
42 if (interval >= 60 * 1000) {
43 meas_mode = 3 << 4; // sensor takes a reading every 60 seconds
44 } else if (interval >= 10 * 1000) {
45 meas_mode = 2 << 4; // sensor takes a reading every 10 seconds
46 } else if (interval >= 1 * 1000) {
47 meas_mode = 1 << 4; // sensor takes a reading every second
48 } else {
49 meas_mode = 4 << 4; // sensor takes a reading every 250ms
50 }
51
52 CHECKED_IO(this->write_byte(0x01, meas_mode))
53
54 if (this->baseline_.has_value()) {
55 // baseline available, write to sensor
56 this->write_bytes(0x11, decode_value(*this->baseline_));
57 }
58
59 auto hardware_version_data = this->read_bytes<1>(0x21);
60 auto bootloader_version_data = this->read_bytes<2>(0x23);
61 auto application_version_data = this->read_bytes<2>(0x24);
62
63 uint8_t hardware_version = 0;
64 uint16_t bootloader_version = 0;
65 uint16_t application_version = 0;
66
67 if (hardware_version_data.has_value()) {
68 hardware_version = (*hardware_version_data)[0];
69 }
70
71 if (bootloader_version_data.has_value()) {
72 bootloader_version = encode_uint16((*bootloader_version_data)[0], (*bootloader_version_data)[1]);
73 }
74
75 if (application_version_data.has_value()) {
76 application_version = encode_uint16((*application_version_data)[0], (*application_version_data)[1]);
77 }
78
79 ESP_LOGD(TAG, "hardware_version=0x%x bootloader_version=0x%x application_version=0x%x\n", hardware_version,
80 bootloader_version, application_version);
81 if (this->version_ != nullptr) {
82 char version[20]; // "15.15.15 (0xffff)" is 17 chars, plus NUL, plus wiggle room
83 sprintf(version, "%d.%d.%d (0x%02x)", (application_version >> 12 & 15), (application_version >> 8 & 15),
84 (application_version >> 4 & 15), application_version);
85 ESP_LOGD(TAG, "publishing version state: %s", version);
86 this->version_->publish_state(version);
87 }
88}
90 if (!this->status_has_data_()) {
91 ESP_LOGD(TAG, "Status indicates no data ready!");
92 this->status_set_warning();
93 return;
94 }
95
96 // page 12 - alg result data
97 auto alg_data = this->read_bytes<4>(0x02);
98 if (!alg_data.has_value()) {
99 ESP_LOGW(TAG, "Reading CCS811 data failed!");
100 this->status_set_warning();
101 return;
102 }
103 auto res = *alg_data;
104 uint16_t co2 = encode_uint16(res[0], res[1]);
105 uint16_t tvoc = encode_uint16(res[2], res[3]);
106
107 // also print baseline
108 auto baseline_data = this->read_bytes<2>(0x11);
109 uint16_t baseline = 0;
110 if (baseline_data.has_value()) {
111 baseline = encode_uint16((*baseline_data)[0], (*baseline_data)[1]);
112 }
113
114 ESP_LOGD(TAG, "Got co2=%u ppm, tvoc=%u ppb, baseline=0x%04X", co2, tvoc, baseline);
115
116 if (this->co2_ != nullptr)
117 this->co2_->publish_state(co2);
118 if (this->tvoc_ != nullptr)
119 this->tvoc_->publish_state(tvoc);
120
121 this->status_clear_warning();
122
123 this->send_env_data_();
124}
126 if (this->humidity_ == nullptr && this->temperature_ == nullptr)
127 return;
128
129 float humidity = NAN;
130 if (this->humidity_ != nullptr)
131 humidity = this->humidity_->state;
132 if (std::isnan(humidity) || humidity < 0 || humidity > 100)
133 humidity = 50;
134 float temperature = NAN;
135 if (this->temperature_ != nullptr)
136 temperature = this->temperature_->state;
138 temperature = 25;
139 // temperature has a 25° offset to allow negative temperatures
140 temperature += 25;
141
142 // At page 18 of:
143 // https://cdn.sparkfun.com/datasheets/BreakoutBoards/CCS811_Programming_Guide.pdf
144 // Reference code:
145 // https://github.com/adafruit/Adafruit_CCS811/blob/0990f5c620354d8bc087c4706bec091d8e6e5dfd/Adafruit_CCS811.cpp#L135-L142
146 uint16_t hum_conv = static_cast<uint16_t>(lroundf(humidity * 512.0f + 0.5f));
147 uint16_t temp_conv = static_cast<uint16_t>(lroundf(temperature * 512.0f + 0.5f));
148 this->write_bytes(0x05, {(uint8_t) ((hum_conv >> 8) & 0xff), (uint8_t) ((hum_conv & 0xff)),
149 (uint8_t) ((temp_conv >> 8) & 0xff), (uint8_t) ((temp_conv & 0xff))});
150}
152 ESP_LOGCONFIG(TAG, "CCS811");
153 LOG_I2C_DEVICE(this)
154 LOG_UPDATE_INTERVAL(this)
155 LOG_SENSOR(" ", "CO2 Sensor", this->co2_)
156 LOG_SENSOR(" ", "TVOC Sensor", this->tvoc_)
157 LOG_TEXT_SENSOR(" ", "Firmware Version Sensor", this->version_)
158 if (this->baseline_) {
159 ESP_LOGCONFIG(TAG, " Baseline: %04X", *this->baseline_);
160 } else {
161 ESP_LOGCONFIG(TAG, " Baseline: NOT SET");
162 }
163 if (this->is_failed()) {
164 switch (this->error_code_) {
166 ESP_LOGW(TAG, "Communication failed! Is the sensor connected?");
167 break;
168 case INVALID_ID:
169 ESP_LOGW(TAG, "Sensor reported an invalid ID. Is this a CCS811?");
170 break;
172 ESP_LOGW(TAG, "Sensor reported internal error");
173 break;
174 case APP_INVALID:
175 ESP_LOGW(TAG, "Sensor reported invalid APP installed.");
176 break;
177 case APP_START_FAILED:
178 ESP_LOGW(TAG, "Sensor reported APP start failed.");
179 break;
180 case UNKNOWN:
181 default:
182 ESP_LOGW(TAG, "Unknown setup error!");
183 break;
184 }
185 }
186}
187
188} // namespace ccs811
189} // namespace esphome
bool is_failed() const
void status_set_warning(const char *message="unspecified")
void status_clear_warning()
virtual uint32_t get_update_interval() const
Get the update interval in ms of this sensor.
enum esphome::ccs811::CCS811Component::ErrorCode UNKNOWN
optional< uint16_t > baseline_
Definition ccs811.h:49
text_sensor::TextSensor * version_
Definition ccs811.h:48
sensor::Sensor * temperature_
Input sensor for temperature reading.
Definition ccs811.h:53
sensor::Sensor * humidity_
Input sensor for humidity reading.
Definition ccs811.h:51
void setup() override
Setup the sensor and test for a connection.
Definition ccs811.cpp:22
void update() override
Schedule temperature+pressure readings.
Definition ccs811.cpp:89
bool write_bytes(uint8_t a_register, const uint8_t *data, uint8_t len, bool stop=true)
Definition i2c.h:252
bool write_byte(uint8_t a_register, uint8_t data, bool stop=true)
Definition i2c.h:266
bool read_byte(uint8_t a_register, uint8_t *data, bool stop=true)
Definition i2c.h:239
bool read_bytes(uint8_t a_register, uint8_t *data, uint8_t len)
Compat APIs All methods below have been added for compatibility reasons.
Definition i2c.h:216
bool has_value() const
Definition optional.h:87
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:39
float state
This member variable stores the last state that has passed through all filters.
Definition sensor.h:131
void publish_state(const std::string &state)
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
constexpr14 std::array< uint8_t, sizeof(T)> decode_value(T val)
Decode a value into its constituent bytes (from most to least significant).
Definition helpers.h:221
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:191
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:28
uint16_t temperature
Definition sun_gtil2.cpp:12