1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
-
-
|
|
|
-
|
!
|
-
|
|
|
!
|
|
|
-
-
!
|
|
|
-
!
|
|
-
!
|
|
-
!
|
-
!
|
|
|
|
|
|
|
|
|
|
-
-
!
!
!
-
|
|
|
-
!
-
|
|
|
!
|
|
|
|
-
!
|
-
|
!
|
|
|
|
|
|
|
|
|
|
|
|
|
!
-
|
|
|
|
|
|
|
|
|
|
|
|
|
-
!
|
-
!
|
|
!
-
|
|
|
|
|
|
-
|
-
|
!
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
!
!
!
|
!
!
| #include "ccs811.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ccs811 {
static const char *TAG = "ccs811";
#define CHECK_TRUE(f, error_code) \
if (!(f)) { \
this->mark_failed(); \
this->error_code_ = (error_code); \
return; \
}
#define CHECKED_IO(f) CHECK_TRUE(f, COMMUNICAITON_FAILED)
void CCS811Component::setup() {
uint8_t hw_id;
CHECKED_IO(this->read_byte(0x20, &hw_id))
CHECK_TRUE(hw_id == 0x81, INVALID_ID)
this->write_bytes(0xFF, {0x11, 0xE5, 0x72, 0x8A});
delay(5);
CHECK_TRUE(!this->status_has_error_(), SENSOR_REPORTED_ERROR)
CHECK_TRUE(this->status_app_is_valid_(), APP_INVALID)
CHECK_TRUE(this->write_bytes(0xF4, {}), APP_START_FAILED)
delay(1);
uint8_t meas_mode = 0;
uint32_t interval = this->get_update_interval();
if (interval <= 1000)
meas_mode = 1 << 4;
else if (interval <= 10000)
meas_mode = 2 << 4;
else
meas_mode = 3 << 4;
CHECKED_IO(this->write_byte(0x01, meas_mode))
if (this->baseline_.has_value()) {
this->write_bytes(0x11, decode_uint16(*this->baseline_));
}
}
void CCS811Component::update() {
if (!this->status_has_data_())
this->status_set_warning();
auto alg_data = this->read_bytes<4>(0x02);
if (!alg_data.has_value()) {
ESP_LOGW(TAG, "Reading CCS811 data failed!");
this->status_set_warning();
return;
}
auto res = *alg_data;
uint16_t co2 = encode_uint16(res[0], res[1]);
uint16_t tvoc = encode_uint16(res[2], res[3]);
auto baseline_data = this->read_bytes<2>(0x11);
uint16_t baseline = 0;
if (baseline_data.has_value()) {
baseline = encode_uint16((*baseline_data)[0], (*baseline_data)[1]);
}
ESP_LOGD(TAG, "Got co2=%u ppm, tvoc=%u ppb, baseline=0x%04X", co2, tvoc, baseline);
if (this->co2_ != nullptr)
this->co2_->publish_state(co2);
if (this->tvoc_ != nullptr)
this->tvoc_->publish_state(tvoc);
if (this->cur_baseline_ != nullptr)
this->cur_baseline_->publish_state(baseline);
this->status_clear_warning();
this->send_env_data_();
}
void CCS811Component::send_env_data_() {
if (this->humidity_ == nullptr && this->temperature_ == nullptr)
return;
float humidity = NAN;
if (this->humidity_ != nullptr)
humidity = this->humidity_->state;
if (isnan(humidity) || humidity < 0 || humidity > 100)
humidity = 50;
float temperature = NAN;
if (this->temperature_ != nullptr)
temperature = this->temperature_->state;
if (isnan(temperature) || temperature < -25 || temperature > 50)
temperature = 25;
temperature += 25;
auto hum_value = static_cast<uint8_t>(roundf(humidity * 2));
auto temp_value = static_cast<uint8_t>(roundf(temperature * 2));
this->write_bytes(0x05, {hum_value, 0x00, temp_value, 0x00});
}
void CCS811Component::dump_config() {
ESP_LOGCONFIG(TAG, "CCS811");
LOG_I2C_DEVICE(this)
LOG_UPDATE_INTERVAL(this)
LOG_SENSOR(" ", "CO2 Sensor", this->co2_)
LOG_SENSOR(" ", "TVOC Sensor", this->tvoc_)
LOG_SENSOR(" ", "Current Baseline", this->cur_baseline_)
if (this->baseline_) {
ESP_LOGCONFIG(TAG, " Baseline: %04X", *this->baseline_);
} else {
ESP_LOGCONFIG(TAG, " Baseline: NOT SET");
}
if (this->is_failed()) {
switch (this->error_code_) {
case COMMUNICAITON_FAILED:
ESP_LOGW(TAG, "Communication failed! Is the sensor connected?");
break;
case INVALID_ID:
ESP_LOGW(TAG, "Sensor reported an invalid ID. Is this a CCS811?");
break;
case SENSOR_REPORTED_ERROR:
ESP_LOGW(TAG, "Sensor reported internal error");
break;
case APP_INVALID:
ESP_LOGW(TAG, "Sensor reported invalid APP installed.");
break;
case APP_START_FAILED:
ESP_LOGW(TAG, "Sensor reported APP start failed.");
break;
case UNKNOWN:
default:
ESP_LOGW(TAG, "Unknown setup error!");
break;
}
}
}
} }
|