ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
am2315c.cpp
Go to the documentation of this file.
1// MIT License
2//
3// Copyright (c) 2023-2024 Rob Tillaart
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22#include "am2315c.h"
23#include "esphome/core/hal.h"
25#include "esphome/core/log.h"
26
28
29static const char *const TAG = "am2315c";
30
31bool AM2315C::reset_register_(uint8_t reg) {
32 // code based on demo code sent by www.aosong.com
33 // no further documentation.
34 // 0x1B returned 18, 0, 4
35 // 0x1C returned 18, 65, 0
36 // 0x1E returned 18, 8, 0
37 // 18 seems to be status register
38 // other values unknown.
39 uint8_t data[3];
40 data[0] = reg;
41 data[1] = 0;
42 data[2] = 0;
43 ESP_LOGD(TAG, "Reset register: 0x%02x", reg);
44 if (this->write(data, 3) != i2c::ERROR_OK) {
45 ESP_LOGE(TAG, "Write failed!");
46 this->mark_failed();
47 return false;
48 }
49 delay(5);
50 if (this->read(data, 3) != i2c::ERROR_OK) {
51 ESP_LOGE(TAG, "Read failed!");
52 this->mark_failed();
53 return false;
54 }
55 delay(10);
56 data[0] = 0xB0 | reg;
57 if (this->write(data, 3) != i2c::ERROR_OK) {
58 ESP_LOGE(TAG, "Write failed!");
59 this->mark_failed();
60 return false;
61 }
62 delay(5);
63 return true;
64}
65
66bool AM2315C::convert_(uint8_t *data, float &humidity, float &temperature) {
68 raw = (data[1] << 12) | (data[2] << 4) | (data[3] >> 4);
69 humidity = raw * 9.5367431640625e-5;
70 raw = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5];
71 temperature = raw * 1.9073486328125e-4 - 50;
72 return crc8(data, 6, 0xFF, 0x31, true) == data[6];
73}
74
76 // get status
77 uint8_t status = 0;
78 if (this->read(&status, 1) != i2c::ERROR_OK) {
79 ESP_LOGE(TAG, "Read failed!");
80 this->mark_failed();
81 return;
82 }
83
84 // reset registers if required, according to the datasheet
85 // this can be required after power on, although this was
86 // never required during testing
87 if ((status & 0x18) != 0x18) {
88 ESP_LOGD(TAG, "Resetting AM2315C registers");
89 if (!this->reset_register_(0x1B)) {
90 this->mark_failed();
91 return;
92 }
93 if (!this->reset_register_(0x1C)) {
94 this->mark_failed();
95 return;
96 }
97 if (!this->reset_register_(0x1E)) {
98 this->mark_failed();
99 return;
100 }
101 }
102}
103
105 // request measurement
106 uint8_t data[3];
107 data[0] = 0xAC;
108 data[1] = 0x33;
109 data[2] = 0x00;
110 if (this->write(data, 3) != i2c::ERROR_OK) {
111 ESP_LOGE(TAG, "Write failed!");
112 this->status_set_warning();
113 return;
114 }
115
116 // wait for hw to complete measurement
117 set_timeout(160, [this]() {
118 // check status
119 uint8_t status = 0;
120 if (this->read(&status, 1) != i2c::ERROR_OK) {
121 ESP_LOGE(TAG, "Read failed!");
122 this->status_set_warning();
123 return;
124 }
125 if ((status & 0x80) == 0x80) {
126 ESP_LOGE(TAG, "HW still busy!");
127 this->status_set_warning();
128 return;
129 }
130
131 // read
132 uint8_t data[7];
133 if (this->read(data, 7) != i2c::ERROR_OK) {
134 ESP_LOGE(TAG, "Read failed!");
135 this->status_set_warning();
136 return;
137 }
138
139 // check for all zeros
140 bool zeros = true;
141 for (uint8_t i : data) {
142 zeros = zeros && (i == 0);
143 }
144 if (zeros) {
145 ESP_LOGW(TAG, "Data all zeros!");
146 this->status_set_warning();
147 return;
148 }
149
150 // convert
151 float temperature = 0.0;
152 float humidity = 0.0;
153 if (this->convert_(data, humidity, temperature)) {
154 if (this->temperature_sensor_ != nullptr) {
155 this->temperature_sensor_->publish_state(temperature);
156 }
157 if (this->humidity_sensor_ != nullptr) {
158 this->humidity_sensor_->publish_state(humidity);
159 }
160 this->status_clear_warning();
161 } else {
162 ESP_LOGW(TAG, "CRC failed!");
163 this->status_set_warning();
164 }
165 });
166}
167
169 ESP_LOGCONFIG(TAG, "AM2315C:");
170 LOG_I2C_DEVICE(this);
171 if (this->is_failed()) {
172 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
173 }
174 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
175 LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
176}
177
178} // namespace esphome::am2315c
uint8_t raw[35]
Definition bl0939.h:0
uint8_t status
Definition bl0942.h:8
void mark_failed()
Mark this component as failed.
bool is_failed() const
Definition component.h:272
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.h:493
void status_clear_warning()
Definition component.h:289
void update() override
Definition am2315c.cpp:104
void dump_config() override
Definition am2315c.cpp:168
void setup() override
Definition am2315c.cpp:75
sensor::Sensor * humidity_sensor_
Definition am2315c.h:44
bool convert_(uint8_t *data, float &humidity, float &temperature)
Definition am2315c.cpp:66
bool reset_register_(uint8_t reg)
Definition am2315c.cpp:31
sensor::Sensor * temperature_sensor_
Definition am2315c.h:43
ErrorCode write(const uint8_t *data, size_t len) const
writes an array of bytes to a device using an I2CBus
Definition i2c.h:183
ErrorCode read(uint8_t *data, size_t len) const
reads an array of bytes from the device using an I2CBus
Definition i2c.h:163
I2CRegister reg(uint8_t a_register)
calls the I2CRegister constructor
Definition i2c.h:152
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:68
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:14
uint8_t crc8(const uint8_t *data, uint8_t len, uint8_t crc, uint8_t poly, bool msb_first)
Calculate a CRC-8 checksum of data with size len.
Definition helpers.cpp:59
void HOT delay(uint32_t ms)
Definition hal.cpp:85
static void uint32_t
uint16_t temperature
Definition sun_gtil2.cpp:12