mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Support for AM2320 temperature and humidity sensor (#554)
Support for AM2320 temperature and humidity sensor Co-authored-by: Mikkonen Teemu <teemu.mikkonen@iki.fi>
This commit is contained in:
		
				
					committed by
					
						 Otto Winter
						Otto Winter
					
				
			
			
				
	
			
			
			
						parent
						
							b7daee533a
						
					
				
				
					commit
					3b48aa5911
				
			
							
								
								
									
										0
									
								
								esphome/components/am2320/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/am2320/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										107
									
								
								esphome/components/am2320/am2320.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								esphome/components/am2320/am2320.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| // Implementation based on: | ||||
| //  - ESPEasy: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P034_DHT12.ino | ||||
| //  - DHT12_sensor_library: https://github.com/xreef/DHT12_sensor_library/blob/master/DHT12.cpp | ||||
| //  - Arduino - AM2320: https://github.com/EngDial/AM2320/blob/master/src/AM2320.cpp | ||||
|  | ||||
| #include "am2320.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace am2320 { | ||||
|  | ||||
| static const char *TAG = "am2320"; | ||||
|  | ||||
| // ---=== Calc CRC16 ===--- | ||||
| uint16_t crc_16(uint8_t *ptr, uint8_t length) { | ||||
|   uint16_t crc = 0xFFFF; | ||||
|   uint8_t i; | ||||
|   //------------------------------ | ||||
|   while (length--) { | ||||
|     crc ^= *ptr++; | ||||
|     for (i = 0; i < 8; i++) | ||||
|       if ((crc & 0x01) != 0) { | ||||
|         crc >>= 1; | ||||
|         crc ^= 0xA001; | ||||
|       } else | ||||
|         crc >>= 1; | ||||
|   } | ||||
|   return crc; | ||||
| } | ||||
|  | ||||
| void AM2320Component::update() { | ||||
|   uint8_t data[8]; | ||||
|   data[0] = 0; | ||||
|   data[1] = 4; | ||||
|   if (!this->read_data_(data)) { | ||||
|     this->status_set_warning(); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   float temperature = (((data[4] & 0x7F) << 8) + data[5]) / 10.0; | ||||
|   temperature = (data[4] & 0x80) ? -temperature : temperature; | ||||
|   float humidity = ((data[2] << 8) + data[3]) / 10.0; | ||||
|  | ||||
|   ESP_LOGD(TAG, "Got temperature=%.1f°C humidity=%.1f%%", temperature, humidity); | ||||
|   if (this->temperature_sensor_ != nullptr) | ||||
|     this->temperature_sensor_->publish_state(temperature); | ||||
|   if (this->humidity_sensor_ != nullptr) | ||||
|     this->humidity_sensor_->publish_state(humidity); | ||||
|   this->status_clear_warning(); | ||||
| } | ||||
| void AM2320Component::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up AM2320..."); | ||||
|   uint8_t data[8]; | ||||
|   data[0] = 0; | ||||
|   data[1] = 4; | ||||
|   if (!this->read_data_(data)) { | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
| } | ||||
| void AM2320Component::dump_config() { | ||||
|   ESP_LOGD(TAG, "AM2320:"); | ||||
|   LOG_I2C_DEVICE(this); | ||||
|   if (this->is_failed()) { | ||||
|     ESP_LOGE(TAG, "Communication with AM2320 failed!"); | ||||
|   } | ||||
|   LOG_SENSOR("  ", "Temperature", this->temperature_sensor_); | ||||
|   LOG_SENSOR("  ", "Humidity", this->humidity_sensor_); | ||||
| } | ||||
| float AM2320Component::get_setup_priority() const { return setup_priority::DATA; } | ||||
|  | ||||
| bool AM2320Component::read_bytes_(uint8_t a_register, uint8_t *data, uint8_t len, uint32_t conversion) { | ||||
|   if (!this->write_bytes(a_register, data, 2)) { | ||||
|     ESP_LOGW(TAG, "Writing bytes for AM2320 failed!"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (conversion > 0) | ||||
|     delay(conversion); | ||||
|   return this->parent_->raw_receive(this->address_, data, len); | ||||
| } | ||||
|  | ||||
| bool AM2320Component::read_data_(uint8_t *data) { | ||||
|   // Wake up | ||||
|   this->write_bytes(0, data, 0); | ||||
|  | ||||
|   // Write instruction 3, 2 bytes, get 8 bytes back (2 preamble, 2 bytes temperature, 2 bytes humidity, 2 bytes CRC) | ||||
|   if (!this->read_bytes_(3, data, 8, 2)) { | ||||
|     ESP_LOGW(TAG, "Updating AM2320 failed!"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   uint16_t checksum; | ||||
|  | ||||
|   checksum = data[7] << 8; | ||||
|   checksum += data[6]; | ||||
|  | ||||
|   if (crc_16(data, 6) != checksum) { | ||||
|     ESP_LOGW(TAG, "AM2320 Checksum invalid!"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| }  // namespace am2320 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										29
									
								
								esphome/components/am2320/am2320.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								esphome/components/am2320/am2320.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/sensor/sensor.h" | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace am2320 { | ||||
|  | ||||
| class AM2320Component : public PollingComponent, public i2c::I2CDevice { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|   float get_setup_priority() const override; | ||||
|   void update() override; | ||||
|  | ||||
|   void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } | ||||
|   void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; } | ||||
|  | ||||
|  protected: | ||||
|   bool read_data_(uint8_t *data); | ||||
|   bool read_bytes_(uint8_t a_register, uint8_t *data, uint8_t len, uint32_t conversion = 0); | ||||
|  | ||||
|   sensor::Sensor *temperature_sensor_; | ||||
|   sensor::Sensor *humidity_sensor_; | ||||
| }; | ||||
|  | ||||
| }  // namespace am2320 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										30
									
								
								esphome/components/am2320/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								esphome/components/am2320/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import i2c, sensor | ||||
| from esphome.const import CONF_HUMIDITY, CONF_ID, CONF_TEMPERATURE, \ | ||||
|     UNIT_CELSIUS, ICON_THERMOMETER, ICON_WATER_PERCENT, UNIT_PERCENT | ||||
|  | ||||
| DEPENDENCIES = ['i2c'] | ||||
|  | ||||
| am2320_ns = cg.esphome_ns.namespace('am2320') | ||||
| AM2320Component = am2320_ns.class_('AM2320Component', cg.PollingComponent, i2c.I2CDevice) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema({ | ||||
|     cv.GenerateID(): cv.declare_id(AM2320Component), | ||||
|     cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1), | ||||
|     cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1), | ||||
| }).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x5C)) | ||||
|  | ||||
|  | ||||
| def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     yield cg.register_component(var, config) | ||||
|     yield i2c.register_i2c_device(var, config) | ||||
|  | ||||
|     if CONF_TEMPERATURE in config: | ||||
|         sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) | ||||
|         cg.add(var.set_temperature_sensor(sens)) | ||||
|  | ||||
|     if CONF_HUMIDITY in config: | ||||
|         sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) | ||||
|         cg.add(var.set_humidity_sensor(sens)) | ||||
| @@ -94,6 +94,11 @@ sensor: | ||||
|   - platform: homeassistant | ||||
|     entity_id: sensor.hello_world | ||||
|     id: ha_hello_world | ||||
|   - platform: am2320 | ||||
|     temperature: | ||||
|       name: "Temperature" | ||||
|     humidity: | ||||
|       name: "Humidity" | ||||
|   - platform: adc | ||||
|     pin: VCC | ||||
|     id: my_sensor | ||||
|   | ||||
		Reference in New Issue
	
	Block a user