mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00: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:
		| @@ -152,6 +152,7 @@ esphome/components/ft63x6/* @gpambrozio | ||||
| esphome/components/gcja5/* @gcormier | ||||
| esphome/components/gdk101/* @Szewcson | ||||
| esphome/components/globals/* @esphome/core | ||||
| esphome/components/gp2y1010au0f/* @zry98 | ||||
| esphome/components/gp8403/* @jesserockz | ||||
| esphome/components/gpio/* @esphome/core | ||||
| 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 | ||||
		Reference in New Issue
	
	Block a user