mirror of
https://github.com/esphome/esphome.git
synced 2025-03-15 07:08:20 +00:00
Add CUBIC PM2005/PM2105 Laser Particle Sensor Module
This commit is contained in:
parent
9f603a474f
commit
bee3f3ecad
1
esphome/components/pm2005/__init__.py
Normal file
1
esphome/components/pm2005/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
"""PM2005/2105 component for ESPHome."""
|
94
esphome/components/pm2005/pm2005.cpp
Normal file
94
esphome/components/pm2005/pm2005.cpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "pm2005.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace pm2005 {
|
||||||
|
|
||||||
|
static const char *const TAG = "pm2005";
|
||||||
|
|
||||||
|
#ifdef TYPE_2005
|
||||||
|
static const uint8_t SITUATION_VALUE_INDEX = 3;
|
||||||
|
static const uint8_t PM_1_0_VALUE_INDEX = 4;
|
||||||
|
static const uint8_t PM_2_5_VALUE_INDEX = 6;
|
||||||
|
static const uint8_t PM_10_0_VALUE_INDEX = 8;
|
||||||
|
static const uint8_t MEASURING_VALUE_INDEX = 10;
|
||||||
|
#else
|
||||||
|
static const uint8_t SITUATION_VALUE_INDEX = 2;
|
||||||
|
static const uint8_t PM_1_0_VALUE_INDEX = 3;
|
||||||
|
static const uint8_t PM_2_5_VALUE_INDEX = 5;
|
||||||
|
static const uint8_t PM_10_0_VALUE_INDEX = 7;
|
||||||
|
static const uint8_t MEASURING_VALUE_INDEX = 9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PM2005Component::update() {
|
||||||
|
if (this->read(data_buffer_, 12) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGW(TAG, "Read result failed");
|
||||||
|
this->status_set_warning();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sensor_situation_ != data_buffer_[SITUATION_VALUE_INDEX]) {
|
||||||
|
sensor_situation_ = data_buffer_[SITUATION_VALUE_INDEX];
|
||||||
|
if (sensor_situation_ == 1)
|
||||||
|
ESP_LOGD(TAG, "Sensor situation: Close.");
|
||||||
|
else if (sensor_situation_ == 2) {
|
||||||
|
ESP_LOGD(TAG, "Sensor situation: Malfunction.");
|
||||||
|
this->status_set_warning();
|
||||||
|
} else if (sensor_situation_ == 3)
|
||||||
|
ESP_LOGD(TAG, "Sensor situation: Under detecting.");
|
||||||
|
else if (sensor_situation_ == 0x80) {
|
||||||
|
ESP_LOGD(TAG, "Sensor situation: Detecting completed.");
|
||||||
|
|
||||||
|
if (this->pm_1_0_sensor_ != nullptr) {
|
||||||
|
int16_t pm1 = get_sensor_value_(data_buffer_, PM_1_0_VALUE_INDEX);
|
||||||
|
ESP_LOGD(TAG, "PM1.0: %d", pm1);
|
||||||
|
this->pm_1_0_sensor_->publish_state(pm1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->pm_2_5_sensor_ != nullptr) {
|
||||||
|
int16_t pm25 = get_sensor_value_(data_buffer_, PM_2_5_VALUE_INDEX);
|
||||||
|
ESP_LOGD(TAG, "PM2.5: %d", pm25);
|
||||||
|
this->pm_2_5_sensor_->publish_state(pm25);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->pm_10_0_sensor_ != nullptr) {
|
||||||
|
int16_t pm10 = get_sensor_value_(data_buffer_, PM_10_0_VALUE_INDEX);
|
||||||
|
ESP_LOGD(TAG, "PM10: %d", pm10);
|
||||||
|
this->pm_10_0_sensor_->publish_state(pm10);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sensor_measuring_mode = get_sensor_value_(data_buffer_, MEASURING_VALUE_INDEX);
|
||||||
|
;
|
||||||
|
if (sensor_measuring_mode == 2)
|
||||||
|
ESP_LOGD(TAG, "The measuring mode of sensor: Single measuring mode.");
|
||||||
|
else if (sensor_measuring_mode == 3)
|
||||||
|
ESP_LOGD(TAG, "The measuring mode of sensor: Continuous measuring mode.");
|
||||||
|
else if (sensor_measuring_mode == 5)
|
||||||
|
ESP_LOGD(TAG, "The measuring mode of sensor: Dynamic measuring mode.");
|
||||||
|
|
||||||
|
this->status_clear_warning();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PM2005Component::get_sensor_value_(const uint8_t *data, uint8_t i) {
|
||||||
|
return data_buffer_[i] * 0x100 + data_buffer_[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void PM2005Component::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "PM2005:");
|
||||||
|
|
||||||
|
#ifdef TYPE_2005
|
||||||
|
ESP_LOGCONFIG(TAG, "Type: PM2005");
|
||||||
|
#else
|
||||||
|
ESP_LOGCONFIG(TAG, "Type: PM2105");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LOG_I2C_DEVICE(this);
|
||||||
|
LOG_SENSOR(" ", "PM1.0", this->pm_1_0_sensor_);
|
||||||
|
LOG_SENSOR(" ", "PM2.5", this->pm_2_5_sensor_);
|
||||||
|
LOG_SENSOR(" ", "PM10 ", this->pm_10_0_sensor_);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pm2005
|
||||||
|
} // namespace esphome
|
35
esphome/components/pm2005/pm2005.h
Normal file
35
esphome/components/pm2005/pm2005.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
#include "esphome/components/i2c/i2c.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace pm2005 {
|
||||||
|
|
||||||
|
class PM2005Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
|
public:
|
||||||
|
float get_setup_priority() const override { return esphome::setup_priority::DATA; }
|
||||||
|
|
||||||
|
PM2005Component() = default;
|
||||||
|
|
||||||
|
void set_pm_1_0_sensor(sensor::Sensor *pm_1_0_sensor) { pm_1_0_sensor_ = pm_1_0_sensor; }
|
||||||
|
void set_pm_2_5_sensor(sensor::Sensor *pm_2_5_sensor) { pm_2_5_sensor_ = pm_2_5_sensor; }
|
||||||
|
void set_pm_10_0_sensor(sensor::Sensor *pm_10_0_sensor) { pm_10_0_sensor_ = pm_10_0_sensor; }
|
||||||
|
|
||||||
|
void dump_config() override;
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t sensor_situation_ = 0;
|
||||||
|
uint8_t data_buffer_[12];
|
||||||
|
|
||||||
|
sensor::Sensor *pm_1_0_sensor_{nullptr};
|
||||||
|
sensor::Sensor *pm_2_5_sensor_{nullptr};
|
||||||
|
sensor::Sensor *pm_10_0_sensor_{nullptr};
|
||||||
|
|
||||||
|
uint16_t get_sensor_value_(const uint8_t *data, uint8_t i);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pm2005
|
||||||
|
} // namespace esphome
|
88
esphome/components/pm2005/sensor.py
Normal file
88
esphome/components/pm2005/sensor.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
"""PM2005/2105 Sensor component for ESPHome."""
|
||||||
|
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import i2c, sensor
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ID,
|
||||||
|
CONF_PM_1_0,
|
||||||
|
CONF_PM_2_5,
|
||||||
|
CONF_PM_10_0,
|
||||||
|
CONF_TYPE,
|
||||||
|
DEVICE_CLASS_PM1,
|
||||||
|
DEVICE_CLASS_PM10,
|
||||||
|
DEVICE_CLASS_PM25,
|
||||||
|
ICON_CHEMICAL_WEAPON,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
UNIT_MICROGRAMS_PER_CUBIC_METER,
|
||||||
|
)
|
||||||
|
|
||||||
|
DEPENDENCIES = ["i2c"]
|
||||||
|
CODEOWNERS = ["@andrewjswan"]
|
||||||
|
|
||||||
|
pm2005_ns = cg.esphome_ns.namespace("pm2005")
|
||||||
|
PM2005Component = pm2005_ns.class_("PM2005Component", cg.PollingComponent, i2c.I2CDevice)
|
||||||
|
|
||||||
|
TYPE_2005 = "PM2005"
|
||||||
|
TYPE_2105 = "PM2105"
|
||||||
|
SENSOR_TYPE = [
|
||||||
|
TYPE_2005,
|
||||||
|
TYPE_2105,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(PM2005Component),
|
||||||
|
cv.Optional(CONF_TYPE, default=TYPE_2005): cv.one_of(*SENSOR_TYPE, upper=True),
|
||||||
|
cv.Optional(CONF_PM_1_0): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER,
|
||||||
|
icon=ICON_CHEMICAL_WEAPON,
|
||||||
|
accuracy_decimals=0,
|
||||||
|
device_class=DEVICE_CLASS_PM1,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_PM_2_5): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER,
|
||||||
|
icon=ICON_CHEMICAL_WEAPON,
|
||||||
|
accuracy_decimals=0,
|
||||||
|
device_class=DEVICE_CLASS_PM25,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_PM_10_0): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER,
|
||||||
|
icon=ICON_CHEMICAL_WEAPON,
|
||||||
|
accuracy_decimals=0,
|
||||||
|
device_class=DEVICE_CLASS_PM10,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.extend(cv.polling_component_schema("60s"))
|
||||||
|
.extend(i2c.i2c_device_schema(0x28)),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config) -> None:
|
||||||
|
"""Code generation entry point."""
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await i2c.register_i2c_device(var, config)
|
||||||
|
|
||||||
|
if config[CONF_TYPE] == TYPE_2005:
|
||||||
|
cg.add_define("TYPE_2005")
|
||||||
|
else:
|
||||||
|
cg.add_define("TYPE_2105")
|
||||||
|
|
||||||
|
if CONF_PM_1_0 in config:
|
||||||
|
sens = await sensor.new_sensor(config[CONF_PM_1_0])
|
||||||
|
cg.add(var.set_pm_1_0_sensor(sens))
|
||||||
|
|
||||||
|
if CONF_PM_2_5 in config:
|
||||||
|
sens = await sensor.new_sensor(config[CONF_PM_2_5])
|
||||||
|
cg.add(var.set_pm_2_5_sensor(sens))
|
||||||
|
|
||||||
|
if CONF_PM_10_0 in config:
|
||||||
|
sens = await sensor.new_sensor(config[CONF_PM_10_0])
|
||||||
|
cg.add(var.set_pm_10_0_sensor(sens))
|
Loading…
x
Reference in New Issue
Block a user