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