ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
pm1006.cpp
Go to the documentation of this file.
1#include "pm1006.h"
2#include "esphome/core/log.h"
3
4namespace esphome::pm1006 {
5
6ESPHOME_LOG_TAG(TAG, "pm1006");
7
8static const uint8_t PM1006_RESPONSE_HEADER[] = {0x16, 0x11, 0x0B};
9static const uint8_t PM1006_REQUEST[] = {0x11, 0x02, 0x0B, 0x01, 0xE1};
10
12 // because this implementation is currently rx-only, there is nothing to setup
13}
14
16 ESP_LOGCONFIG(TAG, "PM1006:");
17 LOG_SENSOR(" ", "PM2.5", this->pm_2_5_sensor_);
18 LOG_UPDATE_INTERVAL(this);
19}
20
22 ESP_LOGV(TAG, "sending measurement request");
23 this->write_array(PM1006_REQUEST, sizeof(PM1006_REQUEST));
24}
25
27 this->read_available([this](uint8_t byte) {
28 this->data_[this->data_index_] = byte;
29 auto check = this->check_byte_();
30 if (!check.has_value()) {
31 // finished
32 this->parse_data_();
33 this->data_index_ = 0;
34 } else if (!*check) {
35 // wrong data
36 ESP_LOGV(TAG, "Byte %i of received data frame is invalid.", this->data_index_);
37 this->data_index_ = 0;
38 } else {
39 // next byte
40 this->data_index_++;
41 }
42 });
43}
44
45uint8_t PM1006Component::pm1006_checksum_(const uint8_t *command_data, uint8_t length) const {
46 return sum_bytes(command_data, length);
47}
48
49optional<bool> PM1006Component::check_byte_() const {
50 const uint8_t index = this->data_index_;
51 const uint8_t byte = this->data_[index];
52
53 // index 0..2 are the fixed header
54 if (index < sizeof(PM1006_RESPONSE_HEADER)) {
55 return byte == PM1006_RESPONSE_HEADER[index];
56 }
57
58 // just some additional notes here:
59 // index 3..4 is unused
60 // index 5..6 is our PM2.5 reading (3..6 is called DF1-DF4 in the datasheet at
61 // http://www.jdscompany.co.kr/download.asp?gubun=07&filename=PM1006_LED_PARTICLE_SENSOR_MODULE_SPECIFICATIONS.pdf
62 // that datasheet goes on up to DF16, which is unused for PM1006 but used in PM1006K
63 // so this code should be trivially extensible to support that one later
64 if (index < (sizeof(PM1006_RESPONSE_HEADER) + 16))
65 return true;
66
67 // checksum
68 if (index == (sizeof(PM1006_RESPONSE_HEADER) + 16)) {
69 uint8_t checksum = pm1006_checksum_(this->data_, sizeof(PM1006_RESPONSE_HEADER) + 17);
70 if (checksum != 0) {
71 ESP_LOGW(TAG, "PM1006 checksum is wrong: %02x, expected zero", checksum);
72 return false;
73 }
74 return {};
75 }
76
77 return false;
78}
79
81 const uint16_t pm_2_5_concentration = this->get_16_bit_uint_(5);
82
83 ESP_LOGD(TAG, "Got PM2.5 Concentration: %d µg/m³", pm_2_5_concentration);
84
85 if (this->pm_2_5_sensor_ != nullptr) {
86 this->pm_2_5_sensor_->publish_state(pm_2_5_concentration);
87 }
88}
89
90} // namespace esphome::pm1006
uint8_t checksum
Definition bl0906.h:3
uint8_t pm1006_checksum_(const uint8_t *command_data, uint8_t length) const
Definition pm1006.cpp:45
uint16_t get_16_bit_uint_(uint8_t start_index) const
Definition pm1006.h:24
sensor::Sensor * pm_2_5_sensor_
Definition pm1006.h:28
optional< bool > check_byte_() const
Definition pm1006.cpp:49
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:65
bool read_available(F &&on_byte)
Same as read_available_chunks(), calling on_byte(uint8_t) once per byte.
Definition uart.h:77
void write_array(const uint8_t *data, size_t len)
Definition uart.h:30
ESPHOME_LOG_TAG(TAG, "pm1006")
constexpr uint8_t sum_bytes(const uint8_t *data, size_t len, uint8_t sum=0)
Add up the bytes of data with size len, truncated to 8 bits: the checksum many serial and IR protocol...
Definition helpers.h:894
uint16_t length
Definition tt21100.cpp:0