mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	AM2315C Temperature + Humidity Sensor (#6266)
Co-authored-by: Jonathan Swoboda <jonathan.swoboda> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -30,6 +30,7 @@ esphome/components/airthings_wave_mini/* @ncareau | |||||||
| esphome/components/airthings_wave_plus/* @jeromelaban | esphome/components/airthings_wave_plus/* @jeromelaban | ||||||
| esphome/components/alarm_control_panel/* @grahambrown11 @hwstar | esphome/components/alarm_control_panel/* @grahambrown11 @hwstar | ||||||
| esphome/components/alpha3/* @jan-hofmeier | esphome/components/alpha3/* @jan-hofmeier | ||||||
|  | esphome/components/am2315c/* @swoboda1337 | ||||||
| esphome/components/am43/* @buxtronix | esphome/components/am43/* @buxtronix | ||||||
| esphome/components/am43/cover/* @buxtronix | esphome/components/am43/cover/* @buxtronix | ||||||
| esphome/components/am43/sensor/* @buxtronix | esphome/components/am43/sensor/* @buxtronix | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								esphome/components/am2315c/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								esphome/components/am2315c/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | CODEOWNERS = ["@swoboda1337"] | ||||||
							
								
								
									
										200
									
								
								esphome/components/am2315c/am2315c.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								esphome/components/am2315c/am2315c.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | |||||||
|  | // MIT License | ||||||
|  | // | ||||||
|  | // Copyright (c) 2023-2024 Rob Tillaart | ||||||
|  | // | ||||||
|  | // Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | // of this software and associated documentation files (the "Software"), to deal | ||||||
|  | // in the Software without restriction, including without limitation the rights | ||||||
|  | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | // copies of the Software, and to permit persons to whom the Software is | ||||||
|  | // furnished to do so, subject to the following conditions: | ||||||
|  | // | ||||||
|  | // The above copyright notice and this permission notice shall be included in all | ||||||
|  | // copies or substantial portions of the Software. | ||||||
|  | // | ||||||
|  | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | // SOFTWARE. | ||||||
|  | #include "am2315c.h" | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/core/helpers.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace am2315c { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "am2315c"; | ||||||
|  |  | ||||||
|  | uint8_t AM2315C::crc8_(uint8_t *data, uint8_t len) { | ||||||
|  |   uint8_t crc = 0xFF; | ||||||
|  |   while (len--) { | ||||||
|  |     crc ^= *data++; | ||||||
|  |     for (uint8_t i = 0; i < 8; i++) { | ||||||
|  |       if (crc & 0x80) { | ||||||
|  |         crc <<= 1; | ||||||
|  |         crc ^= 0x31; | ||||||
|  |       } else { | ||||||
|  |         crc <<= 1; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return crc; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AM2315C::reset_register_(uint8_t reg) { | ||||||
|  |   //  code based on demo code sent by www.aosong.com | ||||||
|  |   //  no further documentation. | ||||||
|  |   //  0x1B returned 18, 0, 4 | ||||||
|  |   //  0x1C returned 18, 65, 0 | ||||||
|  |   //  0x1E returned 18, 8, 0 | ||||||
|  |   //    18 seems to be status register | ||||||
|  |   //    other values unknown. | ||||||
|  |   uint8_t data[3]; | ||||||
|  |   data[0] = reg; | ||||||
|  |   data[1] = 0; | ||||||
|  |   data[2] = 0; | ||||||
|  |   ESP_LOGD(TAG, "Reset register: 0x%02x", reg); | ||||||
|  |   if (this->write(data, 3) != i2c::ERROR_OK) { | ||||||
|  |     ESP_LOGE(TAG, "Write failed!"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   delay(5); | ||||||
|  |   if (this->read(data, 3) != i2c::ERROR_OK) { | ||||||
|  |     ESP_LOGE(TAG, "Read failed!"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   delay(10); | ||||||
|  |   data[0] = 0xB0 | reg; | ||||||
|  |   if (this->write(data, 3) != i2c::ERROR_OK) { | ||||||
|  |     ESP_LOGE(TAG, "Write failed!"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   delay(5); | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AM2315C::convert_(uint8_t *data, float &humidity, float &temperature) { | ||||||
|  |   uint32_t raw; | ||||||
|  |   raw = (data[1] << 12) | (data[2] << 4) | (data[3] >> 4); | ||||||
|  |   humidity = raw * 9.5367431640625e-5; | ||||||
|  |   raw = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; | ||||||
|  |   temperature = raw * 1.9073486328125e-4 - 50; | ||||||
|  |   return this->crc8_(data, 6) == data[6]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AM2315C::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up AM2315C..."); | ||||||
|  |  | ||||||
|  |   // get status | ||||||
|  |   uint8_t status = 0; | ||||||
|  |   if (this->read(&status, 1) != i2c::ERROR_OK) { | ||||||
|  |     ESP_LOGE(TAG, "Read failed!"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // reset registers if required, according to the datasheet | ||||||
|  |   // this can be required after power on, although this was | ||||||
|  |   // never required during testing | ||||||
|  |   if ((status & 0x18) != 0x18) { | ||||||
|  |     ESP_LOGD(TAG, "Resetting AM2315C registers"); | ||||||
|  |     if (!this->reset_register_(0x1B)) { | ||||||
|  |       this->mark_failed(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if (!this->reset_register_(0x1C)) { | ||||||
|  |       this->mark_failed(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if (!this->reset_register_(0x1E)) { | ||||||
|  |       this->mark_failed(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AM2315C::update() { | ||||||
|  |   // request measurement | ||||||
|  |   uint8_t data[3]; | ||||||
|  |   data[0] = 0xAC; | ||||||
|  |   data[1] = 0x33; | ||||||
|  |   data[2] = 0x00; | ||||||
|  |   if (this->write(data, 3) != i2c::ERROR_OK) { | ||||||
|  |     ESP_LOGE(TAG, "Write failed!"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // wait for hw to complete measurement | ||||||
|  |   set_timeout(160, [this]() { | ||||||
|  |     // check status | ||||||
|  |     uint8_t status = 0; | ||||||
|  |     if (this->read(&status, 1) != i2c::ERROR_OK) { | ||||||
|  |       ESP_LOGE(TAG, "Read failed!"); | ||||||
|  |       this->mark_failed(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if ((status & 0x80) == 0x80) { | ||||||
|  |       ESP_LOGE(TAG, "HW still busy!"); | ||||||
|  |       this->mark_failed(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // read | ||||||
|  |     uint8_t data[7]; | ||||||
|  |     if (this->read(data, 7) != i2c::ERROR_OK) { | ||||||
|  |       ESP_LOGE(TAG, "Read failed!"); | ||||||
|  |       this->mark_failed(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // check for all zeros | ||||||
|  |     bool zeros = true; | ||||||
|  |     for (uint8_t i : data) { | ||||||
|  |       zeros = zeros && (i == 0); | ||||||
|  |     } | ||||||
|  |     if (zeros) { | ||||||
|  |       ESP_LOGW(TAG, "Data all zeros!"); | ||||||
|  |       this->status_set_warning(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // convert | ||||||
|  |     float temperature = 0.0; | ||||||
|  |     float humidity = 0.0; | ||||||
|  |     if (this->convert_(data, humidity, temperature)) { | ||||||
|  |       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(); | ||||||
|  |     } else { | ||||||
|  |       ESP_LOGW(TAG, "CRC failed!"); | ||||||
|  |       this->status_set_warning(); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AM2315C::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "AM2315C:"); | ||||||
|  |   LOG_I2C_DEVICE(this); | ||||||
|  |   if (this->is_failed()) { | ||||||
|  |     ESP_LOGE(TAG, "Communication with AM2315C failed!"); | ||||||
|  |   } | ||||||
|  |   LOG_SENSOR("  ", "Temperature", this->temperature_sensor_); | ||||||
|  |   LOG_SENSOR("  ", "Humidity", this->humidity_sensor_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float AM2315C::get_setup_priority() const { return setup_priority::DATA; } | ||||||
|  |  | ||||||
|  | }  // namespace am2315c | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										51
									
								
								esphome/components/am2315c/am2315c.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								esphome/components/am2315c/am2315c.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | |||||||
|  | // MIT License | ||||||
|  | // | ||||||
|  | // Copyright (c) 2023-2024 Rob Tillaart | ||||||
|  | // | ||||||
|  | // Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | // of this software and associated documentation files (the "Software"), to deal | ||||||
|  | // in the Software without restriction, including without limitation the rights | ||||||
|  | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | // copies of the Software, and to permit persons to whom the Software is | ||||||
|  | // furnished to do so, subject to the following conditions: | ||||||
|  | // | ||||||
|  | // The above copyright notice and this permission notice shall be included in all | ||||||
|  | // copies or substantial portions of the Software. | ||||||
|  | // | ||||||
|  | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | // SOFTWARE. | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/sensor/sensor.h" | ||||||
|  | #include "esphome/components/i2c/i2c.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace am2315c { | ||||||
|  |  | ||||||
|  | class AM2315C : public PollingComponent, public i2c::I2CDevice { | ||||||
|  |  public: | ||||||
|  |   void dump_config() override; | ||||||
|  |   void update() override; | ||||||
|  |   void setup() override; | ||||||
|  |   float get_setup_priority() const override; | ||||||
|  |  | ||||||
|  |   void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; } | ||||||
|  |   void set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   uint8_t crc8_(uint8_t *data, uint8_t len); | ||||||
|  |   bool convert_(uint8_t *data, float &humidity, float &temperature); | ||||||
|  |   bool reset_register_(uint8_t reg); | ||||||
|  |  | ||||||
|  |   sensor::Sensor *temperature_sensor_{nullptr}; | ||||||
|  |   sensor::Sensor *humidity_sensor_{nullptr}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace am2315c | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										54
									
								
								esphome/components/am2315c/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								esphome/components/am2315c/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | 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, | ||||||
|  |     DEVICE_CLASS_HUMIDITY, | ||||||
|  |     DEVICE_CLASS_TEMPERATURE, | ||||||
|  |     STATE_CLASS_MEASUREMENT, | ||||||
|  |     UNIT_CELSIUS, | ||||||
|  |     UNIT_PERCENT, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["i2c"] | ||||||
|  |  | ||||||
|  | am2315c_ns = cg.esphome_ns.namespace("am2315c") | ||||||
|  | AM2315C = am2315c_ns.class_("AM2315C", cg.PollingComponent, i2c.I2CDevice) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = ( | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(AM2315C), | ||||||
|  |             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_CELSIUS, | ||||||
|  |                 accuracy_decimals=1, | ||||||
|  |                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_PERCENT, | ||||||
|  |                 accuracy_decimals=1, | ||||||
|  |                 device_class=DEVICE_CLASS_HUMIDITY, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |     .extend(cv.polling_component_schema("60s")) | ||||||
|  |     .extend(i2c.i2c_device_schema(0x38)) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |     await i2c.register_i2c_device(var, config) | ||||||
|  |  | ||||||
|  |     if temperature_config := config.get(CONF_TEMPERATURE): | ||||||
|  |         sens = await sensor.new_sensor(temperature_config) | ||||||
|  |         cg.add(var.set_temperature_sensor(sens)) | ||||||
|  |  | ||||||
|  |     if humidity_config := config.get(CONF_HUMIDITY): | ||||||
|  |         sens = await sensor.new_sensor(humidity_config) | ||||||
|  |         cg.add(var.set_humidity_sensor(sens)) | ||||||
							
								
								
									
										11
									
								
								tests/components/am2315c/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tests/components/am2315c/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_am2315c | ||||||
|  |     scl: 5 | ||||||
|  |     sda: 4 | ||||||
|  |  | ||||||
|  | sensor: | ||||||
|  |   - platform: am2315c | ||||||
|  |     temperature: | ||||||
|  |       name: Temperature | ||||||
|  |     humidity: | ||||||
|  |       name: Humidity | ||||||
							
								
								
									
										11
									
								
								tests/components/am2315c/test.esp32-c3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tests/components/am2315c/test.esp32-c3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_am2315c | ||||||
|  |     scl: 5 | ||||||
|  |     sda: 4 | ||||||
|  |  | ||||||
|  | sensor: | ||||||
|  |   - platform: am2315c | ||||||
|  |     temperature: | ||||||
|  |       name: Temperature | ||||||
|  |     humidity: | ||||||
|  |       name: Humidity | ||||||
							
								
								
									
										11
									
								
								tests/components/am2315c/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tests/components/am2315c/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_am2315c | ||||||
|  |     scl: 16 | ||||||
|  |     sda: 17 | ||||||
|  |  | ||||||
|  | sensor: | ||||||
|  |   - platform: am2315c | ||||||
|  |     temperature: | ||||||
|  |       name: Temperature | ||||||
|  |     humidity: | ||||||
|  |       name: Humidity | ||||||
							
								
								
									
										11
									
								
								tests/components/am2315c/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tests/components/am2315c/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_am2315c | ||||||
|  |     scl: 16 | ||||||
|  |     sda: 17 | ||||||
|  |  | ||||||
|  | sensor: | ||||||
|  |   - platform: am2315c | ||||||
|  |     temperature: | ||||||
|  |       name: Temperature | ||||||
|  |     humidity: | ||||||
|  |       name: Humidity | ||||||
							
								
								
									
										11
									
								
								tests/components/am2315c/test.esp8266.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tests/components/am2315c/test.esp8266.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_am2315c | ||||||
|  |     scl: 5 | ||||||
|  |     sda: 4 | ||||||
|  |  | ||||||
|  | sensor: | ||||||
|  |   - platform: am2315c | ||||||
|  |     temperature: | ||||||
|  |       name: Temperature | ||||||
|  |     humidity: | ||||||
|  |       name: Humidity | ||||||
							
								
								
									
										11
									
								
								tests/components/am2315c/test.rp2040.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tests/components/am2315c/test.rp2040.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_am2315c | ||||||
|  |     scl: 5 | ||||||
|  |     sda: 4 | ||||||
|  |  | ||||||
|  | sensor: | ||||||
|  |   - platform: am2315c | ||||||
|  |     temperature: | ||||||
|  |       name: Temperature | ||||||
|  |     humidity: | ||||||
|  |       name: Humidity | ||||||
		Reference in New Issue
	
	Block a user