mirror of
https://github.com/esphome/esphome.git
synced 2026-01-30 16:32:10 -07:00
Compare commits
6 Commits
esp32_ard_
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e3561d60b | ||
|
|
ca9ed369f9 | ||
|
|
4e96b20b46 | ||
|
|
a1a60c44da | ||
|
|
898c8a5836 | ||
|
|
20edd11ca7 |
@@ -1 +1 @@
|
||||
cf3d341206b4184ec8b7fe85141aef4fe4696aa720c3f8a06d4e57930574bdab
|
||||
069fa9526c52f7c580a9ec17c7678d12f142221387e9b561c18f95394d4629a3
|
||||
|
||||
@@ -1,6 +1,39 @@
|
||||
#include "mipi_spi.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace mipi_spi {} // namespace mipi_spi
|
||||
} // namespace esphome
|
||||
namespace esphome::mipi_spi {
|
||||
|
||||
void internal_dump_config(const char *model, int width, int height, int offset_width, int offset_height, uint8_t madctl,
|
||||
bool invert_colors, int display_bits, bool is_big_endian, const optional<uint8_t> &brightness,
|
||||
GPIOPin *cs, GPIOPin *reset, GPIOPin *dc, int spi_mode, uint32_t data_rate, int bus_width) {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"MIPI_SPI Display\n"
|
||||
" Model: %s\n"
|
||||
" Width: %d\n"
|
||||
" Height: %d\n"
|
||||
" Swap X/Y: %s\n"
|
||||
" Mirror X: %s\n"
|
||||
" Mirror Y: %s\n"
|
||||
" Invert colors: %s\n"
|
||||
" Color order: %s\n"
|
||||
" Display pixels: %d bits\n"
|
||||
" Endianness: %s\n"
|
||||
" SPI Mode: %d\n"
|
||||
" SPI Data rate: %uMHz\n"
|
||||
" SPI Bus width: %d",
|
||||
model, width, height, YESNO(madctl & MADCTL_MV), YESNO(madctl & (MADCTL_MX | MADCTL_XFLIP)),
|
||||
YESNO(madctl & (MADCTL_MY | MADCTL_YFLIP)), YESNO(invert_colors), (madctl & MADCTL_BGR) ? "BGR" : "RGB",
|
||||
display_bits, is_big_endian ? "Big" : "Little", spi_mode, static_cast<unsigned>(data_rate / 1000000),
|
||||
bus_width);
|
||||
LOG_PIN(" CS Pin: ", cs);
|
||||
LOG_PIN(" Reset Pin: ", reset);
|
||||
LOG_PIN(" DC Pin: ", dc);
|
||||
if (offset_width != 0)
|
||||
ESP_LOGCONFIG(TAG, " Offset width: %d", offset_width);
|
||||
if (offset_height != 0)
|
||||
ESP_LOGCONFIG(TAG, " Offset height: %d", offset_height);
|
||||
if (brightness.has_value())
|
||||
ESP_LOGCONFIG(TAG, " Brightness: %u", brightness.value());
|
||||
}
|
||||
|
||||
} // namespace esphome::mipi_spi
|
||||
|
||||
@@ -63,6 +63,11 @@ enum BusType {
|
||||
BUS_TYPE_SINGLE_16 = 16, // Single bit bus, but 16 bits per transfer
|
||||
};
|
||||
|
||||
// Helper function for dump_config - defined in mipi_spi.cpp to allow use of LOG_PIN macro
|
||||
void internal_dump_config(const char *model, int width, int height, int offset_width, int offset_height, uint8_t madctl,
|
||||
bool invert_colors, int display_bits, bool is_big_endian, const optional<uint8_t> &brightness,
|
||||
GPIOPin *cs, GPIOPin *reset, GPIOPin *dc, int spi_mode, uint32_t data_rate, int bus_width);
|
||||
|
||||
/**
|
||||
* Base class for MIPI SPI displays.
|
||||
* All the methods are defined here in the header file, as it is not possible to define templated methods in a cpp file.
|
||||
@@ -201,37 +206,9 @@ class MipiSpi : public display::Display,
|
||||
}
|
||||
|
||||
void dump_config() override {
|
||||
esph_log_config(TAG,
|
||||
"MIPI_SPI Display\n"
|
||||
" Model: %s\n"
|
||||
" Width: %u\n"
|
||||
" Height: %u",
|
||||
this->model_, WIDTH, HEIGHT);
|
||||
if constexpr (OFFSET_WIDTH != 0)
|
||||
esph_log_config(TAG, " Offset width: %u", OFFSET_WIDTH);
|
||||
if constexpr (OFFSET_HEIGHT != 0)
|
||||
esph_log_config(TAG, " Offset height: %u", OFFSET_HEIGHT);
|
||||
esph_log_config(TAG,
|
||||
" Swap X/Y: %s\n"
|
||||
" Mirror X: %s\n"
|
||||
" Mirror Y: %s\n"
|
||||
" Invert colors: %s\n"
|
||||
" Color order: %s\n"
|
||||
" Display pixels: %d bits\n"
|
||||
" Endianness: %s\n",
|
||||
YESNO(this->madctl_ & MADCTL_MV), YESNO(this->madctl_ & (MADCTL_MX | MADCTL_XFLIP)),
|
||||
YESNO(this->madctl_ & (MADCTL_MY | MADCTL_YFLIP)), YESNO(this->invert_colors_),
|
||||
this->madctl_ & MADCTL_BGR ? "BGR" : "RGB", DISPLAYPIXEL * 8, IS_BIG_ENDIAN ? "Big" : "Little");
|
||||
if (this->brightness_.has_value())
|
||||
esph_log_config(TAG, " Brightness: %u", this->brightness_.value());
|
||||
log_pin(TAG, " CS Pin: ", this->cs_);
|
||||
log_pin(TAG, " Reset Pin: ", this->reset_pin_);
|
||||
log_pin(TAG, " DC Pin: ", this->dc_pin_);
|
||||
esph_log_config(TAG,
|
||||
" SPI Mode: %d\n"
|
||||
" SPI Data rate: %dMHz\n"
|
||||
" SPI Bus width: %d",
|
||||
this->mode_, static_cast<unsigned>(this->data_rate_ / 1000000), BUS_TYPE);
|
||||
internal_dump_config(this->model_, WIDTH, HEIGHT, OFFSET_WIDTH, OFFSET_HEIGHT, this->madctl_, this->invert_colors_,
|
||||
DISPLAYPIXEL * 8, IS_BIG_ENDIAN, this->brightness_, this->cs_, this->reset_pin_, this->dc_pin_,
|
||||
this->mode_, this->data_rate_, BUS_TYPE);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -643,10 +643,34 @@ static bool topic_match(const char *message, const char *subscription) {
|
||||
}
|
||||
|
||||
void MQTTClientComponent::on_message(const std::string &topic, const std::string &payload) {
|
||||
for (auto &subscription : this->subscriptions_) {
|
||||
if (topic_match(topic.c_str(), subscription.topic.c_str()))
|
||||
subscription.callback(topic, payload);
|
||||
}
|
||||
#ifdef USE_ESP8266
|
||||
// IMPORTANT: This defer is REQUIRED to prevent stack overflow crashes on ESP8266.
|
||||
//
|
||||
// On ESP8266, this callback is invoked directly from the lwIP/AsyncTCP network stack
|
||||
// which runs in the "sys" context with a very limited stack (~4KB). By the time we
|
||||
// reach this function, the stack is already partially consumed by the network
|
||||
// processing chain: tcp_input -> AsyncClient::_recv -> AsyncMqttClient::_onMessage -> here.
|
||||
//
|
||||
// MQTT subscription callbacks can trigger arbitrary user actions (automations, HTTP
|
||||
// requests, sensor updates, etc.) which may have deep call stacks of their own.
|
||||
// For example, an HTTP request action requires: DNS lookup -> TCP connect -> TLS
|
||||
// handshake (if HTTPS) -> request formatting. This easily overflows the remaining
|
||||
// system stack space, causing a LoadStoreAlignmentCause exception or silent corruption.
|
||||
//
|
||||
// By deferring to the main loop, we ensure callbacks execute with a fresh, full-size
|
||||
// stack in the normal application context rather than the constrained network task.
|
||||
//
|
||||
// DO NOT REMOVE THIS DEFER without understanding the above. It may appear to work
|
||||
// in simple tests but will cause crashes with complex automations.
|
||||
this->defer([this, topic, payload]() {
|
||||
#endif
|
||||
for (auto &subscription : this->subscriptions_) {
|
||||
if (topic_match(topic.c_str(), subscription.topic.c_str()))
|
||||
subscription.callback(topic, payload);
|
||||
}
|
||||
#ifdef USE_ESP8266
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
// Setters
|
||||
|
||||
@@ -2,21 +2,20 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace pmsx003 {
|
||||
namespace esphome::pmsx003 {
|
||||
|
||||
static const char *const TAG = "pmsx003";
|
||||
|
||||
static const uint8_t START_CHARACTER_1 = 0x42;
|
||||
static const uint8_t START_CHARACTER_2 = 0x4D;
|
||||
|
||||
static const uint16_t PMS_STABILISING_MS = 30000; // time taken for the sensor to become stable after power on in ms
|
||||
static const uint16_t STABILISING_MS = 30000; // time taken for the sensor to become stable after power on in ms
|
||||
|
||||
static const uint16_t PMS_CMD_MEASUREMENT_MODE_PASSIVE =
|
||||
0x0000; // use `PMS_CMD_MANUAL_MEASUREMENT` to trigger a measurement
|
||||
static const uint16_t PMS_CMD_MEASUREMENT_MODE_ACTIVE = 0x0001; // automatically perform measurements
|
||||
static const uint16_t PMS_CMD_SLEEP_MODE_SLEEP = 0x0000; // go to sleep mode
|
||||
static const uint16_t PMS_CMD_SLEEP_MODE_WAKEUP = 0x0001; // wake up from sleep mode
|
||||
static const uint16_t CMD_MEASUREMENT_MODE_PASSIVE =
|
||||
0x0000; // use `Command::MANUAL_MEASUREMENT` to trigger a measurement
|
||||
static const uint16_t CMD_MEASUREMENT_MODE_ACTIVE = 0x0001; // automatically perform measurements
|
||||
static const uint16_t CMD_SLEEP_MODE_SLEEP = 0x0000; // go to sleep mode
|
||||
static const uint16_t CMD_SLEEP_MODE_WAKEUP = 0x0001; // wake up from sleep mode
|
||||
|
||||
void PMSX003Component::setup() {}
|
||||
|
||||
@@ -42,7 +41,7 @@ void PMSX003Component::dump_config() {
|
||||
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
|
||||
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
|
||||
|
||||
if (this->update_interval_ <= PMS_STABILISING_MS) {
|
||||
if (this->update_interval_ <= STABILISING_MS) {
|
||||
ESP_LOGCONFIG(TAG, " Mode: active continuous (sensor default)");
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG, " Mode: passive with sleep/wake cycles");
|
||||
@@ -55,44 +54,44 @@ void PMSX003Component::loop() {
|
||||
const uint32_t now = App.get_loop_component_start_time();
|
||||
|
||||
// Initialize sensor mode on first loop
|
||||
if (this->initialised_ == 0) {
|
||||
if (this->update_interval_ > PMS_STABILISING_MS) {
|
||||
if (!this->initialised_) {
|
||||
if (this->update_interval_ > STABILISING_MS) {
|
||||
// Long update interval: use passive mode with sleep/wake cycles
|
||||
this->send_command_(PMS_CMD_MEASUREMENT_MODE, PMS_CMD_MEASUREMENT_MODE_PASSIVE);
|
||||
this->send_command_(PMS_CMD_SLEEP_MODE, PMS_CMD_SLEEP_MODE_WAKEUP);
|
||||
this->send_command_(Command::MEASUREMENT_MODE, CMD_MEASUREMENT_MODE_PASSIVE);
|
||||
this->send_command_(Command::SLEEP_MODE, CMD_SLEEP_MODE_WAKEUP);
|
||||
} else {
|
||||
// Short/zero update interval: use active continuous mode
|
||||
this->send_command_(PMS_CMD_MEASUREMENT_MODE, PMS_CMD_MEASUREMENT_MODE_ACTIVE);
|
||||
this->send_command_(Command::MEASUREMENT_MODE, CMD_MEASUREMENT_MODE_ACTIVE);
|
||||
}
|
||||
this->initialised_ = 1;
|
||||
this->initialised_ = true;
|
||||
}
|
||||
|
||||
// If we update less often than it takes the device to stabilise, spin the fan down
|
||||
// rather than running it constantly. It does take some time to stabilise, so we
|
||||
// need to keep track of what state we're in.
|
||||
if (this->update_interval_ > PMS_STABILISING_MS) {
|
||||
if (this->update_interval_ > STABILISING_MS) {
|
||||
switch (this->state_) {
|
||||
case PMSX003_STATE_IDLE:
|
||||
case State::IDLE:
|
||||
// Power on the sensor now so it'll be ready when we hit the update time
|
||||
if (now - this->last_update_ < (this->update_interval_ - PMS_STABILISING_MS))
|
||||
if (now - this->last_update_ < (this->update_interval_ - STABILISING_MS))
|
||||
return;
|
||||
|
||||
this->state_ = PMSX003_STATE_STABILISING;
|
||||
this->send_command_(PMS_CMD_SLEEP_MODE, PMS_CMD_SLEEP_MODE_WAKEUP);
|
||||
this->state_ = State::STABILISING;
|
||||
this->send_command_(Command::SLEEP_MODE, CMD_SLEEP_MODE_WAKEUP);
|
||||
this->fan_on_time_ = now;
|
||||
return;
|
||||
case PMSX003_STATE_STABILISING:
|
||||
case State::STABILISING:
|
||||
// wait for the sensor to be stable
|
||||
if (now - this->fan_on_time_ < PMS_STABILISING_MS)
|
||||
if (now - this->fan_on_time_ < STABILISING_MS)
|
||||
return;
|
||||
// consume any command responses that are in the serial buffer
|
||||
while (this->available())
|
||||
this->read_byte(&this->data_[0]);
|
||||
// Trigger a new read
|
||||
this->send_command_(PMS_CMD_MANUAL_MEASUREMENT, 0);
|
||||
this->state_ = PMSX003_STATE_WAITING;
|
||||
this->send_command_(Command::MANUAL_MEASUREMENT, 0);
|
||||
this->state_ = State::WAITING;
|
||||
break;
|
||||
case PMSX003_STATE_WAITING:
|
||||
case State::WAITING:
|
||||
// Just go ahead and read stuff
|
||||
break;
|
||||
}
|
||||
@@ -180,27 +179,31 @@ optional<bool> PMSX003Component::check_byte_() {
|
||||
}
|
||||
|
||||
bool PMSX003Component::check_payload_length_(uint16_t payload_length) {
|
||||
// https://avaldebe.github.io/PyPMS/sensors/Plantower/
|
||||
switch (this->type_) {
|
||||
case PMSX003_TYPE_X003:
|
||||
// The expected payload length is typically 28 bytes.
|
||||
// However, a 20-byte payload check was already present in the code.
|
||||
// No official documentation was found confirming this.
|
||||
// Retaining this check to avoid breaking existing behavior.
|
||||
case Type::PMS1003:
|
||||
return payload_length == 28; // 2*13+2
|
||||
case Type::PMS3003: // Data 7/8/9 not set/reserved
|
||||
return payload_length == 20; // 2*9+2
|
||||
case Type::PMSX003: // Data 13 not set/reserved
|
||||
// Deprecated: Length 20 is for PMS3003 backwards compatibility
|
||||
return payload_length == 28 || payload_length == 20; // 2*13+2
|
||||
case PMSX003_TYPE_5003T:
|
||||
case PMSX003_TYPE_5003S:
|
||||
return payload_length == 28; // 2*13+2 (Data 13 not set/reserved)
|
||||
case PMSX003_TYPE_5003ST:
|
||||
return payload_length == 36; // 2*17+2 (Data 16 not set/reserved)
|
||||
case Type::PMS5003S:
|
||||
case Type::PMS5003T: // Data 13 not set/reserved
|
||||
return payload_length == 28; // 2*13+2
|
||||
case Type::PMS5003ST: // Data 16 not set/reserved
|
||||
return payload_length == 36; // 2*17+2
|
||||
case Type::PMS9003M:
|
||||
return payload_length == 28; // 2*13+2
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PMSX003Component::send_command_(PMSX0003Command cmd, uint16_t data) {
|
||||
void PMSX003Component::send_command_(Command cmd, uint16_t data) {
|
||||
uint8_t send_data[7] = {
|
||||
START_CHARACTER_1, // Start Byte 1
|
||||
START_CHARACTER_2, // Start Byte 2
|
||||
cmd, // Command
|
||||
static_cast<uint8_t>(cmd), // Command
|
||||
uint8_t((data >> 8) & 0xFF), // Data 1
|
||||
uint8_t((data >> 0) & 0xFF), // Data 2
|
||||
0, // Verify Byte 1
|
||||
@@ -265,7 +268,7 @@ void PMSX003Component::parse_data_() {
|
||||
if (this->pm_particles_25um_sensor_ != nullptr)
|
||||
this->pm_particles_25um_sensor_->publish_state(pm_particles_25um);
|
||||
|
||||
if (this->type_ == PMSX003_TYPE_5003T) {
|
||||
if (this->type_ == Type::PMS5003T) {
|
||||
ESP_LOGD(TAG,
|
||||
"Got PM0.3 Particles: %u Count/0.1L, PM0.5 Particles: %u Count/0.1L, PM1.0 Particles: %u Count/0.1L, "
|
||||
"PM2.5 Particles %u Count/0.1L",
|
||||
@@ -289,7 +292,7 @@ void PMSX003Component::parse_data_() {
|
||||
}
|
||||
|
||||
// Formaldehyde
|
||||
if (this->type_ == PMSX003_TYPE_5003ST || this->type_ == PMSX003_TYPE_5003S) {
|
||||
if (this->type_ == Type::PMS5003S || this->type_ == Type::PMS5003ST) {
|
||||
const uint16_t formaldehyde = this->get_16_bit_uint_(28);
|
||||
|
||||
ESP_LOGD(TAG, "Got Formaldehyde: %u µg/m^3", formaldehyde);
|
||||
@@ -299,8 +302,8 @@ void PMSX003Component::parse_data_() {
|
||||
}
|
||||
|
||||
// Temperature and Humidity
|
||||
if (this->type_ == PMSX003_TYPE_5003ST || this->type_ == PMSX003_TYPE_5003T) {
|
||||
const uint8_t temperature_offset = (this->type_ == PMSX003_TYPE_5003T) ? 24 : 30;
|
||||
if (this->type_ == Type::PMS5003T || this->type_ == Type::PMS5003ST) {
|
||||
const uint8_t temperature_offset = (this->type_ == Type::PMS5003T) ? 24 : 30;
|
||||
|
||||
const float temperature = static_cast<int16_t>(this->get_16_bit_uint_(temperature_offset)) / 10.0f;
|
||||
const float humidity = this->get_16_bit_uint_(temperature_offset + 2) / 10.0f;
|
||||
@@ -314,22 +317,22 @@ void PMSX003Component::parse_data_() {
|
||||
}
|
||||
|
||||
// Firmware Version and Error Code
|
||||
if (this->type_ == PMSX003_TYPE_5003ST) {
|
||||
const uint8_t firmware_version = this->data_[36];
|
||||
const uint8_t error_code = this->data_[37];
|
||||
if (this->type_ == Type::PMS1003 || this->type_ == Type::PMS5003ST || this->type_ == Type::PMS9003M) {
|
||||
const uint8_t firmware_error_code_offset = (this->type_ == Type::PMS5003ST) ? 36 : 28;
|
||||
const uint8_t firmware_version = this->data_[firmware_error_code_offset];
|
||||
const uint8_t error_code = this->data_[firmware_error_code_offset + 1];
|
||||
|
||||
ESP_LOGD(TAG, "Got Firmware Version: 0x%02X, Error Code: 0x%02X", firmware_version, error_code);
|
||||
}
|
||||
|
||||
// Spin down the sensor again if we aren't going to need it until more time has
|
||||
// passed than it takes to stabilise
|
||||
if (this->update_interval_ > PMS_STABILISING_MS) {
|
||||
this->send_command_(PMS_CMD_SLEEP_MODE, PMS_CMD_SLEEP_MODE_SLEEP);
|
||||
this->state_ = PMSX003_STATE_IDLE;
|
||||
if (this->update_interval_ > STABILISING_MS) {
|
||||
this->send_command_(Command::SLEEP_MODE, CMD_SLEEP_MODE_SLEEP);
|
||||
this->state_ = State::IDLE;
|
||||
}
|
||||
|
||||
this->status_clear_warning();
|
||||
}
|
||||
|
||||
} // namespace pmsx003
|
||||
} // namespace esphome
|
||||
} // namespace esphome::pmsx003
|
||||
|
||||
@@ -5,27 +5,28 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace pmsx003 {
|
||||
namespace esphome::pmsx003 {
|
||||
|
||||
enum PMSX0003Command : uint8_t {
|
||||
PMS_CMD_MEASUREMENT_MODE =
|
||||
0xE1, // Data Options: `PMS_CMD_MEASUREMENT_MODE_PASSIVE`, `PMS_CMD_MEASUREMENT_MODE_ACTIVE`
|
||||
PMS_CMD_MANUAL_MEASUREMENT = 0xE2,
|
||||
PMS_CMD_SLEEP_MODE = 0xE4, // Data Options: `PMS_CMD_SLEEP_MODE_SLEEP`, `PMS_CMD_SLEEP_MODE_WAKEUP`
|
||||
enum class Type : uint8_t {
|
||||
PMS1003 = 0,
|
||||
PMS3003,
|
||||
PMSX003, // PMS5003, PMS6003, PMS7003, PMSA003 (NOT PMSA003I - see `pmsa003i` component)
|
||||
PMS5003S,
|
||||
PMS5003T,
|
||||
PMS5003ST,
|
||||
PMS9003M,
|
||||
};
|
||||
|
||||
enum PMSX003Type {
|
||||
PMSX003_TYPE_X003 = 0,
|
||||
PMSX003_TYPE_5003T,
|
||||
PMSX003_TYPE_5003ST,
|
||||
PMSX003_TYPE_5003S,
|
||||
enum class Command : uint8_t {
|
||||
MEASUREMENT_MODE = 0xE1, // Data Options: `CMD_MEASUREMENT_MODE_PASSIVE`, `CMD_MEASUREMENT_MODE_ACTIVE`
|
||||
MANUAL_MEASUREMENT = 0xE2,
|
||||
SLEEP_MODE = 0xE4, // Data Options: `CMD_SLEEP_MODE_SLEEP`, `CMD_SLEEP_MODE_WAKEUP`
|
||||
};
|
||||
|
||||
enum PMSX003State {
|
||||
PMSX003_STATE_IDLE = 0,
|
||||
PMSX003_STATE_STABILISING,
|
||||
PMSX003_STATE_WAITING,
|
||||
enum class State : uint8_t {
|
||||
IDLE = 0,
|
||||
STABILISING,
|
||||
WAITING,
|
||||
};
|
||||
|
||||
class PMSX003Component : public uart::UARTDevice, public Component {
|
||||
@@ -37,7 +38,7 @@ class PMSX003Component : public uart::UARTDevice, public Component {
|
||||
|
||||
void set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; }
|
||||
|
||||
void set_type(PMSX003Type type) { this->type_ = type; }
|
||||
void set_type(Type type) { this->type_ = type; }
|
||||
|
||||
void set_pm_1_0_std_sensor(sensor::Sensor *pm_1_0_std_sensor) { this->pm_1_0_std_sensor_ = pm_1_0_std_sensor; }
|
||||
void set_pm_2_5_std_sensor(sensor::Sensor *pm_2_5_std_sensor) { this->pm_2_5_std_sensor_ = pm_2_5_std_sensor; }
|
||||
@@ -77,20 +78,20 @@ class PMSX003Component : public uart::UARTDevice, public Component {
|
||||
optional<bool> check_byte_();
|
||||
void parse_data_();
|
||||
bool check_payload_length_(uint16_t payload_length);
|
||||
void send_command_(PMSX0003Command cmd, uint16_t data);
|
||||
void send_command_(Command cmd, uint16_t data);
|
||||
uint16_t get_16_bit_uint_(uint8_t start_index) const {
|
||||
return encode_uint16(this->data_[start_index], this->data_[start_index + 1]);
|
||||
}
|
||||
|
||||
Type type_;
|
||||
State state_{State::IDLE};
|
||||
bool initialised_{false};
|
||||
uint8_t data_[64];
|
||||
uint8_t data_index_{0};
|
||||
uint8_t initialised_{0};
|
||||
uint32_t fan_on_time_{0};
|
||||
uint32_t last_update_{0};
|
||||
uint32_t last_transmission_{0};
|
||||
uint32_t update_interval_{0};
|
||||
PMSX003State state_{PMSX003_STATE_IDLE};
|
||||
PMSX003Type type_;
|
||||
|
||||
// "Standard Particle"
|
||||
sensor::Sensor *pm_1_0_std_sensor_{nullptr};
|
||||
@@ -118,5 +119,4 @@ class PMSX003Component : public uart::UARTDevice, public Component {
|
||||
sensor::Sensor *humidity_sensor_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace pmsx003
|
||||
} // namespace esphome
|
||||
} // namespace esphome::pmsx003
|
||||
|
||||
@@ -40,34 +40,128 @@ pmsx003_ns = cg.esphome_ns.namespace("pmsx003")
|
||||
PMSX003Component = pmsx003_ns.class_("PMSX003Component", uart.UARTDevice, cg.Component)
|
||||
PMSX003Sensor = pmsx003_ns.class_("PMSX003Sensor", sensor.Sensor)
|
||||
|
||||
TYPE_PMSX003 = "PMSX003"
|
||||
TYPE_PMS1003 = "PMS1003"
|
||||
TYPE_PMS3003 = "PMS3003"
|
||||
TYPE_PMSX003 = "PMSX003" # PMS5003, PMS6003, PMS7003, PMSA003 (NOT PMSA003I - see `pmsa003i` component)
|
||||
TYPE_PMS5003S = "PMS5003S"
|
||||
TYPE_PMS5003T = "PMS5003T"
|
||||
TYPE_PMS5003ST = "PMS5003ST"
|
||||
TYPE_PMS5003S = "PMS5003S"
|
||||
TYPE_PMS9003M = "PMS9003M"
|
||||
|
||||
PMSX003Type = pmsx003_ns.enum("PMSX003Type")
|
||||
Type = pmsx003_ns.enum("Type", is_class=True)
|
||||
|
||||
PMSX003_TYPES = {
|
||||
TYPE_PMSX003: PMSX003Type.PMSX003_TYPE_X003,
|
||||
TYPE_PMS5003T: PMSX003Type.PMSX003_TYPE_5003T,
|
||||
TYPE_PMS5003ST: PMSX003Type.PMSX003_TYPE_5003ST,
|
||||
TYPE_PMS5003S: PMSX003Type.PMSX003_TYPE_5003S,
|
||||
TYPE_PMS1003: Type.PMS1003,
|
||||
TYPE_PMS3003: Type.PMS3003,
|
||||
TYPE_PMSX003: Type.PMSX003,
|
||||
TYPE_PMS5003S: Type.PMS5003S,
|
||||
TYPE_PMS5003T: Type.PMS5003T,
|
||||
TYPE_PMS5003ST: Type.PMS5003ST,
|
||||
TYPE_PMS9003M: Type.PMS9003M,
|
||||
}
|
||||
|
||||
SENSORS_TO_TYPE = {
|
||||
CONF_PM_1_0: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_2_5: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_10_0: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_1_0_STD: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_2_5_STD: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_10_0_STD: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_0_3UM: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_0_5UM: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_1_0UM: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_2_5UM: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_5_0UM: [TYPE_PMSX003, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_10_0UM: [TYPE_PMSX003, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_FORMALDEHYDE: [TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||
CONF_PM_1_0_STD: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMS3003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003T,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_PM_2_5_STD: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMS3003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003T,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_PM_10_0_STD: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMS3003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003T,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_PM_1_0: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMS3003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003T,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_PM_2_5: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMS3003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003T,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_PM_10_0: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMS3003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003T,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_PM_0_3UM: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003T,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_PM_0_5UM: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003T,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_PM_1_0UM: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003T,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_PM_2_5UM: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003T,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_PM_5_0UM: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_PM_10_0UM: [
|
||||
TYPE_PMS1003,
|
||||
TYPE_PMSX003,
|
||||
TYPE_PMS5003S,
|
||||
TYPE_PMS5003ST,
|
||||
TYPE_PMS9003M,
|
||||
],
|
||||
CONF_FORMALDEHYDE: [TYPE_PMS5003S, TYPE_PMS5003ST],
|
||||
CONF_TEMPERATURE: [TYPE_PMS5003T, TYPE_PMS5003ST],
|
||||
CONF_HUMIDITY: [TYPE_PMS5003T, TYPE_PMS5003ST],
|
||||
}
|
||||
|
||||
@@ -53,4 +53,4 @@ async def to_code(config):
|
||||
"lib_ignore", ["ESPAsyncTCP", "AsyncTCP", "AsyncTCP_RP2040W"]
|
||||
)
|
||||
# https://github.com/ESP32Async/ESPAsyncWebServer/blob/main/library.json
|
||||
cg.add_library("ESP32Async/ESPAsyncWebServer", "3.9.5")
|
||||
cg.add_library("ESP32Async/ESPAsyncWebServer", "3.9.6")
|
||||
|
||||
@@ -210,7 +210,7 @@ void Application::loop() {
|
||||
#ifdef USE_ESP32
|
||||
esp_chip_info_t chip_info;
|
||||
esp_chip_info(&chip_info);
|
||||
ESP_LOGI(TAG, "ESP32 Chip: %s r%d.%d, %d core(s)", ESPHOME_VARIANT, chip_info.revision / 100,
|
||||
ESP_LOGI(TAG, "ESP32 Chip: %s rev%d.%d, %d core(s)", ESPHOME_VARIANT, chip_info.revision / 100,
|
||||
chip_info.revision % 100, chip_info.cores);
|
||||
#if defined(USE_ESP32_VARIANT_ESP32) && !defined(USE_ESP32_MIN_CHIP_REVISION_SET)
|
||||
// Suggest optimization for chips that don't need the PSRAM cache workaround
|
||||
|
||||
@@ -114,7 +114,7 @@ lib_deps =
|
||||
ESP8266WiFi ; wifi (Arduino built-in)
|
||||
Update ; ota (Arduino built-in)
|
||||
ESP32Async/ESPAsyncTCP@2.0.0 ; async_tcp
|
||||
ESP32Async/ESPAsyncWebServer@3.9.5 ; web_server_base
|
||||
ESP32Async/ESPAsyncWebServer@3.9.6 ; web_server_base
|
||||
makuna/NeoPixelBus@2.7.3 ; neopixelbus
|
||||
ESP8266HTTPClient ; http_request (Arduino built-in)
|
||||
ESP8266mDNS ; mdns (Arduino built-in)
|
||||
@@ -202,7 +202,7 @@ lib_deps =
|
||||
${common:arduino.lib_deps}
|
||||
ayushsharma82/RPAsyncTCP@1.3.2 ; async_tcp
|
||||
bblanchon/ArduinoJson@7.4.2 ; json
|
||||
ESP32Async/ESPAsyncWebServer@3.9.5 ; web_server_base
|
||||
ESP32Async/ESPAsyncWebServer@3.9.6 ; web_server_base
|
||||
build_flags =
|
||||
${common:arduino.build_flags}
|
||||
-DUSE_RP2040
|
||||
@@ -218,7 +218,7 @@ framework = arduino
|
||||
lib_compat_mode = soft
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson@7.4.2 ; json
|
||||
ESP32Async/ESPAsyncWebServer@3.9.5 ; web_server_base
|
||||
ESP32Async/ESPAsyncWebServer@3.9.6 ; web_server_base
|
||||
droscy/esp_wireguard@0.4.2 ; wireguard
|
||||
build_flags =
|
||||
${common:arduino.build_flags}
|
||||
|
||||
10
tests/components/mipi_spi/test.esp8266-ard.yaml
Normal file
10
tests/components/mipi_spi/test.esp8266-ard.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
substitutions:
|
||||
dc_pin: GPIO15
|
||||
cs_pin: GPIO5
|
||||
enable_pin: GPIO4
|
||||
reset_pin: GPIO16
|
||||
|
||||
packages:
|
||||
spi: !include ../../test_build_components/common/spi/esp8266-ard.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
@@ -8,11 +8,11 @@ sensor:
|
||||
pm_10_0:
|
||||
name: PM 10.0 Concentration
|
||||
pm_1_0_std:
|
||||
name: PM 1.0 Standard Atmospher Concentration
|
||||
name: PM 1.0 Standard Atmospheric Concentration
|
||||
pm_2_5_std:
|
||||
name: PM 2.5 Standard Atmospher Concentration
|
||||
name: PM 2.5 Standard Atmospheric Concentration
|
||||
pm_10_0_std:
|
||||
name: PM 10.0 Standard Atmospher Concentration
|
||||
name: PM 10.0 Standard Atmospheric Concentration
|
||||
pm_0_3um:
|
||||
name: Particulate Count >0.3um
|
||||
pm_0_5um:
|
||||
|
||||
Reference in New Issue
Block a user