mirror of
https://github.com/esphome/esphome.git
synced 2024-11-23 23:48:11 +01:00
Add support for Sharp GP2Y1010AU0F PM2.5 sensor (#6007)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
529ff4bd52
commit
023cb4937e
6 changed files with 197 additions and 0 deletions
|
@ -152,6 +152,7 @@ esphome/components/ft63x6/* @gpambrozio
|
||||||
esphome/components/gcja5/* @gcormier
|
esphome/components/gcja5/* @gcormier
|
||||||
esphome/components/gdk101/* @Szewcson
|
esphome/components/gdk101/* @Szewcson
|
||||||
esphome/components/globals/* @esphome/core
|
esphome/components/globals/* @esphome/core
|
||||||
|
esphome/components/gp2y1010au0f/* @zry98
|
||||||
esphome/components/gp8403/* @jesserockz
|
esphome/components/gp8403/* @jesserockz
|
||||||
esphome/components/gpio/* @esphome/core
|
esphome/components/gpio/* @esphome/core
|
||||||
esphome/components/gpio/one_wire/* @ssieb
|
esphome/components/gpio/one_wire/* @ssieb
|
||||||
|
|
0
esphome/components/gp2y1010au0f/__init__.py
Normal file
0
esphome/components/gp2y1010au0f/__init__.py
Normal file
67
esphome/components/gp2y1010au0f/gp2y1010au0f.cpp
Normal file
67
esphome/components/gp2y1010au0f/gp2y1010au0f.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include "gp2y1010au0f.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace gp2y1010au0f {
|
||||||
|
|
||||||
|
static const char *const TAG = "gp2y1010au0f";
|
||||||
|
static const float MIN_VOLTAGE = 0.0f;
|
||||||
|
static const float MAX_VOLTAGE = 4.0f;
|
||||||
|
|
||||||
|
void GP2Y1010AU0FSensor::dump_config() {
|
||||||
|
LOG_SENSOR("", "Sharp GP2Y1010AU0F PM2.5 Sensor", this);
|
||||||
|
ESP_LOGCONFIG(TAG, " Sampling duration: %" PRId32 " ms", this->sample_duration_);
|
||||||
|
ESP_LOGCONFIG(TAG, " ADC voltage multiplier: %.3f", this->voltage_multiplier_);
|
||||||
|
LOG_UPDATE_INTERVAL(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GP2Y1010AU0FSensor::update() {
|
||||||
|
is_sampling_ = true;
|
||||||
|
|
||||||
|
this->set_timeout("read", this->sample_duration_, [this]() {
|
||||||
|
this->is_sampling_ = false;
|
||||||
|
if (this->num_samples_ == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float mean = this->sample_sum_ / float(this->num_samples_);
|
||||||
|
ESP_LOGD(TAG, "ADC read voltage: %.3f V (mean from %" PRId32 " samples)", mean, this->num_samples_);
|
||||||
|
|
||||||
|
// PM2.5 calculation
|
||||||
|
// ref: https://www.howmuchsnow.com/arduino/airquality/
|
||||||
|
int16_t pm_2_5_value = 170 * mean;
|
||||||
|
this->publish_state(pm_2_5_value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// reset readings
|
||||||
|
this->num_samples_ = 0;
|
||||||
|
this->sample_sum_ = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GP2Y1010AU0FSensor::loop() {
|
||||||
|
if (!this->is_sampling_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// enable the internal IR LED
|
||||||
|
this->led_output_->turn_on();
|
||||||
|
// wait for the sensor to stabilize
|
||||||
|
delayMicroseconds(this->sample_wait_before_);
|
||||||
|
// perform a single sample
|
||||||
|
float read_voltage = this->source_->sample();
|
||||||
|
// disable the internal IR LED
|
||||||
|
this->led_output_->turn_off();
|
||||||
|
|
||||||
|
if (std::isnan(read_voltage))
|
||||||
|
return;
|
||||||
|
read_voltage = read_voltage * this->voltage_multiplier_ - this->voltage_offset_;
|
||||||
|
if (read_voltage < MIN_VOLTAGE || read_voltage > MAX_VOLTAGE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->num_samples_++;
|
||||||
|
this->sample_sum_ += read_voltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace gp2y1010au0f
|
||||||
|
} // namespace esphome
|
52
esphome/components/gp2y1010au0f/gp2y1010au0f.h
Normal file
52
esphome/components/gp2y1010au0f/gp2y1010au0f.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
#include "esphome/components/voltage_sampler/voltage_sampler.h"
|
||||||
|
#include "esphome/components/output/binary_output.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace gp2y1010au0f {
|
||||||
|
|
||||||
|
class GP2Y1010AU0FSensor : public sensor::Sensor, public PollingComponent {
|
||||||
|
public:
|
||||||
|
void update() override;
|
||||||
|
void loop() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override {
|
||||||
|
// after the base sensor has been initialized
|
||||||
|
return setup_priority::DATA - 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_adc_source(voltage_sampler::VoltageSampler *source) { source_ = source; }
|
||||||
|
void set_voltage_refs(float offset, float multiplier) {
|
||||||
|
this->voltage_offset_ = offset;
|
||||||
|
this->voltage_multiplier_ = multiplier;
|
||||||
|
}
|
||||||
|
void set_led_output(output::BinaryOutput *output) { led_output_ = output; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// duration in ms of the sampling phase
|
||||||
|
uint32_t sample_duration_ = 100;
|
||||||
|
// duration in us of the wait before sampling
|
||||||
|
// ref: https://global.sharp/products/device/lineup/data/pdf/datasheet/gp2y1010au_appl_e.pdf
|
||||||
|
uint32_t sample_wait_before_ = 280;
|
||||||
|
// duration in us of the wait after sampling
|
||||||
|
// it seems no need to delay on purpose since one ADC sampling takes longer than that (300-400 us on ESP8266)
|
||||||
|
// uint32_t sample_wait_after_ = 40;
|
||||||
|
// the sampling source to read voltage from
|
||||||
|
voltage_sampler::VoltageSampler *source_;
|
||||||
|
// ADC voltage reading offset
|
||||||
|
float voltage_offset_ = 0.0f;
|
||||||
|
// ADC voltage reading multiplier
|
||||||
|
float voltage_multiplier_ = 1.0f;
|
||||||
|
// the binary output to control the sampling LED
|
||||||
|
output::BinaryOutput *led_output_;
|
||||||
|
|
||||||
|
float sample_sum_ = 0.0f;
|
||||||
|
uint32_t num_samples_ = 0;
|
||||||
|
bool is_sampling_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gp2y1010au0f
|
||||||
|
} // namespace esphome
|
61
esphome/components/gp2y1010au0f/sensor.py
Normal file
61
esphome/components/gp2y1010au0f/sensor.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import sensor, voltage_sampler, output
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_SENSOR,
|
||||||
|
CONF_OUTPUT,
|
||||||
|
DEVICE_CLASS_PM25,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
UNIT_MICROGRAMS_PER_CUBIC_METER,
|
||||||
|
ICON_CHEMICAL_WEAPON,
|
||||||
|
)
|
||||||
|
|
||||||
|
DEPENDENCIES = ["output"]
|
||||||
|
AUTO_LOAD = ["voltage_sampler"]
|
||||||
|
CODEOWNERS = ["@zry98"]
|
||||||
|
|
||||||
|
CONF_ADC_VOLTAGE_OFFSET = "adc_voltage_offset"
|
||||||
|
CONF_ADC_VOLTAGE_MULTIPLIER = "adc_voltage_multiplier"
|
||||||
|
|
||||||
|
gp2y1010au0f_ns = cg.esphome_ns.namespace("gp2y1010au0f")
|
||||||
|
GP2Y1010AU0FSensor = gp2y1010au0f_ns.class_(
|
||||||
|
"GP2Y1010AU0FSensor", sensor.Sensor, cg.PollingComponent
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
sensor.sensor_schema(
|
||||||
|
GP2Y1010AU0FSensor,
|
||||||
|
unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER,
|
||||||
|
accuracy_decimals=0,
|
||||||
|
device_class=DEVICE_CLASS_PM25,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
icon=ICON_CHEMICAL_WEAPON,
|
||||||
|
)
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_SENSOR): cv.use_id(voltage_sampler.VoltageSampler),
|
||||||
|
cv.Optional(CONF_ADC_VOLTAGE_OFFSET, default=0.0): cv.float_,
|
||||||
|
cv.Optional(CONF_ADC_VOLTAGE_MULTIPLIER, default=1.0): cv.float_,
|
||||||
|
cv.Required(CONF_OUTPUT): cv.use_id(output.BinaryOutput),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.polling_component_schema("60s"))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await sensor.new_sensor(config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
# the ADC sensor to read voltage from
|
||||||
|
adc_sensor = await cg.get_variable(config[CONF_SENSOR])
|
||||||
|
cg.add(var.set_adc_source(adc_sensor))
|
||||||
|
cg.add(
|
||||||
|
var.set_voltage_refs(
|
||||||
|
config[CONF_ADC_VOLTAGE_OFFSET], config[CONF_ADC_VOLTAGE_MULTIPLIER]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# the binary output to control the module's internal IR LED
|
||||||
|
led_output = await cg.get_variable(config[CONF_OUTPUT])
|
||||||
|
cg.add(var.set_led_output(led_output))
|
16
tests/components/gp2y1010au0f/test.esp32-idf.yaml
Normal file
16
tests/components/gp2y1010au0f/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
sensor:
|
||||||
|
- platform: adc
|
||||||
|
pin: GPIO36
|
||||||
|
id: adc_sensor
|
||||||
|
|
||||||
|
- platform: gp2y1010au0f
|
||||||
|
sensor: adc_sensor
|
||||||
|
name: Dust Sensor
|
||||||
|
adc_voltage_offset: 0.2
|
||||||
|
adc_voltage_multiplier: 3.3
|
||||||
|
output: dust_sensor_led
|
||||||
|
|
||||||
|
output:
|
||||||
|
- platform: gpio
|
||||||
|
id: dust_sensor_led
|
||||||
|
pin: GPIO32
|
Loading…
Reference in a new issue