ESPHome  2024.3.2
gcja5.cpp
Go to the documentation of this file.
1 /* From snooping with a logic analyzer, the I2C on this sensor is broken. I was only able
2  * to receive 1's as a response from the sensor. I was able to get the UART working.
3  *
4  * The datasheet says the values should be divided by 1000, but this must only be for the I2C
5  * implementation. Comparing UART values with another sensor, there is no need to divide by 1000.
6  */
7 #include "gcja5.h"
8 #include "esphome/core/log.h"
9 #include <cstring>
10 
11 namespace esphome {
12 namespace gcja5 {
13 
14 static const char *const TAG = "gcja5";
15 
16 void GCJA5Component::setup() { ESP_LOGCONFIG(TAG, "Setting up gcja5..."); }
17 
19  const uint32_t now = millis();
20  if (now - this->last_transmission_ >= 500) {
21  // last transmission too long ago. Reset RX index.
22  this->rx_message_.clear();
23  }
24 
25  if (this->available() == 0) {
26  return;
27  }
28 
29  // There must now be data waiting
30  this->last_transmission_ = now;
31  uint8_t val;
32  while (this->available() != 0) {
33  this->read_byte(&val);
34  this->rx_message_.push_back(val);
35 
36  // check if rx_message_ has 32 bytes of data
37  if (this->rx_message_.size() == 32) {
38  this->parse_data_();
39 
40  if (this->have_good_data_) {
41  if (this->pm_1_0_sensor_ != nullptr)
43  if (this->pm_2_5_sensor_ != nullptr)
45  if (this->pm_10_0_sensor_ != nullptr)
47  if (this->pmc_0_3_sensor_ != nullptr)
49  if (this->pmc_0_5_sensor_ != nullptr)
51  if (this->pmc_1_0_sensor_ != nullptr)
53  if (this->pmc_2_5_sensor_ != nullptr)
55  if (this->pmc_5_0_sensor_ != nullptr)
57  if (this->pmc_10_0_sensor_ != nullptr)
59  } else {
60  this->status_set_warning();
61  ESP_LOGV(TAG, "Have 32 bytes but not good data. Skipping.");
62  }
63 
64  this->rx_message_.clear();
65  }
66  }
67 }
68 
70  uint8_t crc = 0;
71 
72  for (uint8_t i = 1; i < 30; i++)
73  crc = crc ^ this->rx_message_[i];
74 
75  ESP_LOGVV(TAG, "Checksum packet was (0x%02X), calculated checksum was (0x%02X)", this->rx_message_[30], crc);
76 
77  return (crc == this->rx_message_[30]);
78 }
79 
80 uint32_t GCJA5Component::get_32_bit_uint_(uint8_t start_index) {
81  return (((uint32_t) this->rx_message_[start_index + 3]) << 24) |
82  (((uint32_t) this->rx_message_[start_index + 2]) << 16) |
83  (((uint32_t) this->rx_message_[start_index + 1]) << 8) | ((uint32_t) this->rx_message_[start_index]);
84 }
85 
86 uint16_t GCJA5Component::get_16_bit_uint_(uint8_t start_index) {
87  return (((uint32_t) this->rx_message_[start_index + 1]) << 8) | ((uint32_t) this->rx_message_[start_index]);
88 }
89 
91  ESP_LOGVV(TAG, "GCJA5 Data: ");
92  for (uint8_t i = 0; i < 32; i++) {
93  ESP_LOGVV(TAG, " %u: 0b" BYTE_TO_BINARY_PATTERN " (0x%02X)", i + 1, BYTE_TO_BINARY(this->rx_message_[i]),
94  this->rx_message_[i]);
95  }
96 
97  if (this->rx_message_[0] != 0x02 || this->rx_message_[31] != 0x03 || !this->calculate_checksum_()) {
98  ESP_LOGVV(TAG, "Discarding bad packet - failed checks.");
99  return;
100  } else
101  ESP_LOGVV(TAG, "Good packet found.");
102 
103  this->have_good_data_ = true;
104  uint8_t status = this->rx_message_[29];
105  if (!this->first_status_log_) {
106  this->first_status_log_ = true;
107 
108  ESP_LOGI(TAG, "GCJA5 Status");
109  ESP_LOGI(TAG, "Overall Status : %i", (status >> 6) & 0x03);
110  ESP_LOGI(TAG, "PD Status : %i", (status >> 4) & 0x03);
111  ESP_LOGI(TAG, "LD Status : %i", (status >> 2) & 0x03);
112  ESP_LOGI(TAG, "Fan Status : %i", (status >> 0) & 0x03);
113  }
114 }
115 
117 
118 } // namespace gcja5
119 } // namespace esphome
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:146
sensor::Sensor * pmc_2_5_sensor_
Definition: gcja5.h:46
sensor::Sensor * pmc_10_0_sensor_
Definition: gcja5.h:48
uint32_t get_32_bit_uint_(uint8_t start_index)
Definition: gcja5.cpp:80
mopeka_std_values val[4]
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
uint16_t get_16_bit_uint_(uint8_t start_index)
Definition: gcja5.cpp:86
void setup() override
Definition: gcja5.cpp:16
bool read_byte(uint8_t *data)
Definition: uart.h:29
sensor::Sensor * pmc_5_0_sensor_
Definition: gcja5.h:47
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
sensor::Sensor * pm_1_0_sensor_
Definition: gcja5.h:39
void loop() override
Definition: gcja5.cpp:18
uint8_t status
Definition: bl0942.h:23
void dump_config() override
Definition: gcja5.cpp:116
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
std::vector< uint8_t > rx_message_
Definition: gcja5.h:35
sensor::Sensor * pmc_1_0_sensor_
Definition: gcja5.h:45
sensor::Sensor * pm_2_5_sensor_
Definition: gcja5.h:40
sensor::Sensor * pmc_0_3_sensor_
Definition: gcja5.h:43
sensor::Sensor * pmc_0_5_sensor_
Definition: gcja5.h:44
sensor::Sensor * pm_10_0_sensor_
Definition: gcja5.h:41