ESPHome 2025.5.0
Loading...
Searching...
No Matches
ags10.cpp
Go to the documentation of this file.
1#include "ags10.h"
2
3#include <cinttypes>
4
5namespace esphome {
6namespace ags10 {
7static const char *const TAG = "ags10";
8
9// Data acquisition.
10static const uint8_t REG_TVOC = 0x00;
11// Zero-point calibration.
12static const uint8_t REG_CALIBRATION = 0x01;
13// Read version.
14static const uint8_t REG_VERSION = 0x11;
15// Read current resistance.
16static const uint8_t REG_RESISTANCE = 0x20;
17// Modify target address.
18static const uint8_t REG_ADDRESS = 0x21;
19
20// Zero-point calibration with current resistance.
21static const uint16_t ZP_CURRENT = 0x0000;
22// Zero-point reset.
23static const uint16_t ZP_DEFAULT = 0xFFFF;
24
26 ESP_LOGCONFIG(TAG, "Setting up ags10...");
27
28 auto version = this->read_version_();
29 if (version) {
30 ESP_LOGD(TAG, "AGS10 Sensor Version: 0x%02X", *version);
31 if (this->version_ != nullptr) {
32 this->version_->publish_state(*version);
33 }
34 } else {
35 ESP_LOGE(TAG, "AGS10 Sensor Version: unknown");
36 }
37
38 auto resistance = this->read_resistance_();
39 if (resistance) {
40 ESP_LOGD(TAG, "AGS10 Sensor Resistance: 0x%08" PRIX32, *resistance);
41 if (this->resistance_ != nullptr) {
42 this->resistance_->publish_state(*resistance);
43 }
44 } else {
45 ESP_LOGE(TAG, "AGS10 Sensor Resistance: unknown");
46 }
47
48 ESP_LOGD(TAG, "Sensor initialized");
49}
50
52 auto tvoc = this->read_tvoc_();
53 if (tvoc) {
54 this->tvoc_->publish_state(*tvoc);
56 } else {
57 this->status_set_warning();
58 }
59}
60
62 ESP_LOGCONFIG(TAG, "AGS10:");
63 LOG_I2C_DEVICE(this);
64 switch (this->error_code_) {
65 case NONE:
66 break;
68 ESP_LOGE(TAG, "Communication with AGS10 failed!");
69 break;
71 ESP_LOGE(TAG, "The crc check failed");
72 break;
73 case ILLEGAL_STATUS:
74 ESP_LOGE(TAG, "AGS10 is not ready to return TVOC data or sensor in pre-heat stage.");
75 break;
77 ESP_LOGE(TAG, "AGS10 returns TVOC data in unsupported units.");
78 break;
79 default:
80 ESP_LOGE(TAG, "Unknown error: %d", this->error_code_);
81 break;
82 }
83 LOG_UPDATE_INTERVAL(this);
84 LOG_SENSOR(" ", "TVOC Sensor", this->tvoc_);
85 LOG_SENSOR(" ", "Firmware Version Sensor", this->version_);
86 LOG_SENSOR(" ", "Resistance Sensor", this->resistance_);
87}
88
92bool AGS10Component::new_i2c_address(uint8_t newaddress) {
93 uint8_t rev_newaddress = ~newaddress;
94 std::array<uint8_t, 5> data{newaddress, rev_newaddress, newaddress, rev_newaddress, 0};
95 data[4] = calc_crc8_(data, 4);
96 if (!this->write_bytes(REG_ADDRESS, data)) {
97 this->error_code_ = COMMUNICATION_FAILED;
98 this->status_set_warning();
99 ESP_LOGE(TAG, "couldn't write the new I2C address 0x%02X", newaddress);
100 return false;
101 }
102 this->set_i2c_address(newaddress);
103 ESP_LOGW(TAG, "changed I2C address to 0x%02X", newaddress);
104 this->error_code_ = NONE;
105 this->status_clear_warning();
106 return true;
107}
108
110
112
114 std::array<uint8_t, 5> data{0x00, 0x0C, (uint8_t) ((value >> 8) & 0xFF), (uint8_t) (value & 0xFF), 0};
115 data[4] = calc_crc8_(data, 4);
116 if (!this->write_bytes(REG_CALIBRATION, data)) {
117 this->error_code_ = COMMUNICATION_FAILED;
118 this->status_set_warning();
119 ESP_LOGE(TAG, "unable to set zero-point calibration with 0x%02X", value);
120 return false;
121 }
122 if (value == ZP_CURRENT) {
123 ESP_LOGI(TAG, "zero-point calibration has been set with current resistance");
124 } else if (value == ZP_DEFAULT) {
125 ESP_LOGI(TAG, "zero-point calibration has been reset to the factory defaults");
126 } else {
127 ESP_LOGI(TAG, "zero-point calibration has been set with 0x%02X", value);
128 }
129 this->error_code_ = NONE;
130 this->status_clear_warning();
131 return true;
132}
133
135 auto data = this->read_and_check_<5>(REG_TVOC);
136 if (!data) {
137 return nullopt;
138 }
139
140 auto res = *data;
141 auto status_byte = res[0];
142
143 int units = status_byte & 0x0e;
144 int status_bit = status_byte & 0x01;
145
146 if (status_bit != 0) {
147 this->error_code_ = ILLEGAL_STATUS;
148 ESP_LOGW(TAG, "Reading AGS10 data failed: illegal status (not ready or sensor in pre-heat stage)!");
149 return nullopt;
150 }
151
152 if (units != 0) {
153 this->error_code_ = UNSUPPORTED_UNITS;
154 ESP_LOGE(TAG, "Reading AGS10 data failed: unsupported units (%d)!", units);
155 return nullopt;
156 }
157
158 return encode_uint24(res[1], res[2], res[3]);
159}
160
162 auto data = this->read_and_check_<5>(REG_VERSION);
163 if (data) {
164 auto res = *data;
165 return res[3];
166 }
167 return nullopt;
168}
169
171 auto data = this->read_and_check_<5>(REG_RESISTANCE);
172 if (data) {
173 auto res = *data;
174 return encode_uint32(res[0], res[1], res[2], res[3]);
175 }
176 return nullopt;
177}
178
180 auto data = this->read_bytes<N>(a_register);
181 if (!data.has_value()) {
182 this->error_code_ = COMMUNICATION_FAILED;
183 ESP_LOGE(TAG, "Reading AGS10 version failed!");
185 }
186 auto len = N - 1;
187 auto res = *data;
188 auto crc_byte = res[len];
189
190 if (crc_byte != calc_crc8_(res, len)) {
191 this->error_code_ = CRC_CHECK_FAILED;
192 ESP_LOGE(TAG, "Reading AGS10 version failed: crc error!");
194 }
195
196 return data;
197}
198
199template<size_t N> uint8_t AGS10Component::calc_crc8_(std::array<uint8_t, N> dat, uint8_t num) {
200 uint8_t i, byte1, crc = 0xFF;
201 for (byte1 = 0; byte1 < num; byte1++) {
202 crc ^= (dat[byte1]);
203 for (i = 0; i < 8; i++) {
204 if (crc & 0x80) {
205 crc = (crc << 1) ^ 0x31;
206 } else {
207 crc = (crc << 1);
208 }
209 }
210 }
211 return crc;
212}
213} // namespace ags10
214} // namespace esphome
void status_set_warning(const char *message="unspecified")
void status_clear_warning()
optional< std::array< uint8_t, N > > read_and_check_(uint8_t a_register)
Read, checks and returns data from the sensor.
Definition ags10.cpp:179
bool set_zero_point_with_factory_defaults()
Sets zero-point with factory defaults.
Definition ags10.cpp:109
optional< uint8_t > read_version_()
Reads and returns a firmware version of AGS10.
Definition ags10.cpp:161
enum esphome::ags10::AGS10Component::ErrorCode NONE
sensor::Sensor * tvoc_
TVOC.
Definition ags10.h:62
bool set_zero_point_with_current_resistance()
Sets zero-point with current sensor resistance.
Definition ags10.cpp:111
sensor::Sensor * resistance_
Resistance.
Definition ags10.h:72
uint8_t calc_crc8_(std::array< uint8_t, N > dat, uint8_t num)
Calculates CRC8 value.
Definition ags10.cpp:199
optional< uint32_t > read_resistance_()
Reads and returns the resistance of AGS10.
Definition ags10.cpp:170
optional< uint32_t > read_tvoc_()
Reads and returns value of TVOC.
Definition ags10.cpp:134
sensor::Sensor * version_
Firmvare version.
Definition ags10.h:67
bool set_zero_point_with(uint16_t value)
Sets zero-point with the value.
Definition ags10.cpp:113
bool new_i2c_address(uint8_t newaddress)
Modifies target address of AGS10.
Definition ags10.cpp:92
void dump_config() override
Definition ags10.cpp:61
bool write_bytes(uint8_t a_register, const uint8_t *data, uint8_t len, bool stop=true)
Definition i2c.h:252
void set_i2c_address(uint8_t address)
We store the address of the device on the bus.
Definition i2c.h:140
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
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:39
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:301
constexpr uint32_t encode_uint24(uint8_t byte1, uint8_t byte2, uint8_t byte3)
Encode a 24-bit value given three bytes in most to least significant byte order.
Definition helpers.h:200
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Definition helpers.h:195
const nullopt_t nullopt((nullopt_t::init()))