ESPHome  2024.12.2
mics_4514.cpp
Go to the documentation of this file.
1 #include "mics_4514.h"
2 
3 #include "esphome/core/helpers.h"
4 #include "esphome/core/log.h"
5 
6 namespace esphome {
7 namespace mics_4514 {
8 
9 static const char *const TAG = "mics_4514";
10 
11 static const uint8_t SENSOR_REGISTER = 0x04;
12 static const uint8_t POWER_MODE_REGISTER = 0x0a;
13 
15  ESP_LOGCONFIG(TAG, "Setting up MICS 4514...");
16  uint8_t power_mode;
17  this->read_register(POWER_MODE_REGISTER, &power_mode, 1);
18  if (power_mode == 0x00) {
19  ESP_LOGCONFIG(TAG, "Waking up MICS 4514, sensors will have data after 3 minutes...");
20  power_mode = 0x01;
21  this->write_register(POWER_MODE_REGISTER, &power_mode, 1);
22  delay(100); // NOLINT
23  this->set_timeout("warmup", 3 * 60 * 1000, [this]() {
24  this->warmed_up_ = true;
25  ESP_LOGCONFIG(TAG, "MICS 4514 setup complete.");
26  });
27  this->status_set_warning();
28  return;
29  }
30  ESP_LOGCONFIG(TAG, "Device already awake.");
31  this->warmed_up_ = true;
32  ESP_LOGCONFIG(TAG, "MICS 4514 setup complete.");
33 }
34 void MICS4514Component::dump_config() {
35  ESP_LOGCONFIG(TAG, "MICS 4514:");
36  LOG_I2C_DEVICE(this);
37  LOG_UPDATE_INTERVAL(this);
38  LOG_SENSOR(" ", "Nitrogen Dioxide", this->nitrogen_dioxide_sensor_);
39  LOG_SENSOR(" ", "Carbon Monoxide", this->carbon_monoxide_sensor_);
40  LOG_SENSOR(" ", "Methane", this->methane_sensor_);
41  LOG_SENSOR(" ", "Ethanol", this->ethanol_sensor_);
42  LOG_SENSOR(" ", "Hydrogen", this->hydrogen_sensor_);
43  LOG_SENSOR(" ", "Ammonia", this->ammonia_sensor_);
44 }
45 float MICS4514Component::get_setup_priority() const { return setup_priority::DATA; }
46 void MICS4514Component::update() {
47  if (!this->warmed_up_) {
48  return;
49  }
50  uint8_t data[6];
51  if (this->read_register(SENSOR_REGISTER, data, 6) != i2c::ERROR_OK) {
52  this->status_set_warning();
53  return;
54  }
55  this->status_clear_warning();
56  ESP_LOGV(TAG, "Got data: %02X %02X %02X %02X %02X %02X", data[0], data[1], data[2], data[3], data[4], data[5]);
57  uint16_t ox = encode_uint16(data[0], data[1]);
58  uint16_t red = encode_uint16(data[2], data[3]);
59  uint16_t power = encode_uint16(data[4], data[5]);
60 
61  if (this->initial_) {
62  this->initial_ = false;
63  this->ox_calibration_ = (float) (power - ox);
64  this->red_calibration_ = (float) (power - red);
65  return;
66  }
67 
68  float red_f = (float) (power - red) / this->red_calibration_;
69  float ox_f = (float) (power - ox) / this->ox_calibration_;
70 
71  if (this->carbon_monoxide_sensor_ != nullptr) {
72  float co = 0.0f;
73  if (red_f > 3.4f) {
74  co = 0.0;
75  } else if (red_f < 0.01) {
76  co = 1000.0;
77  } else {
78  co = 4.2 / pow(red_f, 1.2);
79  }
80  this->carbon_monoxide_sensor_->publish_state(co);
81  }
82 
83  if (this->nitrogen_dioxide_sensor_ != nullptr) {
84  float nitrogendioxide = 0.0f;
85  if (ox_f < 0.3f) {
86  nitrogendioxide = 0.0;
87  } else {
88  nitrogendioxide = 0.164 * pow(ox_f, 0.975);
89  }
90  this->nitrogen_dioxide_sensor_->publish_state(nitrogendioxide);
91  }
92 
93  if (this->methane_sensor_ != nullptr) {
94  float methane = 0.0f;
95  if (red_f > 0.9f || red_f < 0.5) { // outside the range->unlikely
96  methane = 0.0;
97  } else {
98  methane = 630 / pow(red_f, 4.4);
99  }
100  this->methane_sensor_->publish_state(methane);
101  }
102 
103  if (this->ethanol_sensor_ != nullptr) {
104  float ethanol = 0.0f;
105  if (red_f > 1.0f || red_f < 0.02) { // outside the range->unlikely
106  ethanol = 0.0;
107  } else {
108  ethanol = 1.52 / pow(red_f, 1.55);
109  }
110  this->ethanol_sensor_->publish_state(ethanol);
111  }
112 
113  if (this->hydrogen_sensor_ != nullptr) {
114  float hydrogen = 0.0f;
115  if (red_f > 0.9f || red_f < 0.02) { // outside the range->unlikely
116  hydrogen = 0.0;
117  } else {
118  hydrogen = 0.85 / pow(red_f, 1.75);
119  }
120  this->hydrogen_sensor_->publish_state(hydrogen);
121  }
122 
123  if (this->ammonia_sensor_ != nullptr) {
124  float ammonia = 0.0f;
125  if (red_f > 0.98f || red_f < 0.2532) { // outside the ammonia range->unlikely
126  ammonia = 0.0;
127  } else {
128  ammonia = 0.9 / pow(red_f, 4.6);
129  }
130  this->ammonia_sensor_->publish_state(ammonia);
131  }
132 }
133 
134 } // namespace mics_4514
135 } // namespace esphome
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:19
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len, bool stop=true)
reads an array of bytes from a specific register in the I²C device
Definition: i2c.cpp:10
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
uint8_t power_mode
Definition: qmp6988.h:70
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition: component.cpp:69
virtual void setup()
Where the component&#39;s initialization should happen.
Definition: component.cpp:48
No error found during execution of method.
Definition: i2c_bus.h:13
void status_clear_warning()
Definition: component.cpp:166
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:183
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len, bool stop=true)
writes an array of bytes to a specific register in the I²C device
Definition: i2c.cpp:25
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26