ESPHome 2025.5.0
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
27namespace esphome {
28namespace am2315c {
29
30static const char *const TAG = "am2315c";
31
32uint8_t AM2315C::crc8_(uint8_t *data, uint8_t len) {
33 uint8_t crc = 0xFF;
34 while (len--) {
35 crc ^= *data++;
36 for (uint8_t i = 0; i < 8; i++) {
37 if (crc & 0x80) {
38 crc <<= 1;
39 crc ^= 0x31;
40 } else {
41 crc <<= 1;
42 }
43 }
44 }
45 return crc;
46}
47
48bool AM2315C::reset_register_(uint8_t reg) {
49 // code based on demo code sent by www.aosong.com
50 // no further documentation.
51 // 0x1B returned 18, 0, 4
52 // 0x1C returned 18, 65, 0
53 // 0x1E returned 18, 8, 0
54 // 18 seems to be status register
55 // other values unknown.
56 uint8_t data[3];
57 data[0] = reg;
58 data[1] = 0;
59 data[2] = 0;
60 ESP_LOGD(TAG, "Reset register: 0x%02x", reg);
61 if (this->write(data, 3) != i2c::ERROR_OK) {
62 ESP_LOGE(TAG, "Write failed!");
63 this->mark_failed();
64 return false;
65 }
66 delay(5);
67 if (this->read(data, 3) != i2c::ERROR_OK) {
68 ESP_LOGE(TAG, "Read failed!");
69 this->mark_failed();
70 return false;
71 }
72 delay(10);
73 data[0] = 0xB0 | reg;
74 if (this->write(data, 3) != i2c::ERROR_OK) {
75 ESP_LOGE(TAG, "Write failed!");
76 this->mark_failed();
77 return false;
78 }
79 delay(5);
80 return true;
81}
82
83bool AM2315C::convert_(uint8_t *data, float &humidity, float &temperature) {
84 uint32_t raw;
85 raw = (data[1] << 12) | (data[2] << 4) | (data[3] >> 4);
86 humidity = raw * 9.5367431640625e-5;
87 raw = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5];
88 temperature = raw * 1.9073486328125e-4 - 50;
89 return this->crc8_(data, 6) == data[6];
90}
91
93 ESP_LOGCONFIG(TAG, "Setting up AM2315C...");
94
95 // get status
96 uint8_t status = 0;
97 if (this->read(&status, 1) != i2c::ERROR_OK) {
98 ESP_LOGE(TAG, "Read failed!");
99 this->mark_failed();
100 return;
101 }
102
103 // reset registers if required, according to the datasheet
104 // this can be required after power on, although this was
105 // never required during testing
106 if ((status & 0x18) != 0x18) {
107 ESP_LOGD(TAG, "Resetting AM2315C registers");
108 if (!this->reset_register_(0x1B)) {
109 this->mark_failed();
110 return;
111 }
112 if (!this->reset_register_(0x1C)) {
113 this->mark_failed();
114 return;
115 }
116 if (!this->reset_register_(0x1E)) {
117 this->mark_failed();
118 return;
119 }
120 }
121}
122
124 // request measurement
125 uint8_t data[3];
126 data[0] = 0xAC;
127 data[1] = 0x33;
128 data[2] = 0x00;
129 if (this->write(data, 3) != i2c::ERROR_OK) {
130 ESP_LOGE(TAG, "Write failed!");
131 this->status_set_warning();
132 return;
133 }
134
135 // wait for hw to complete measurement
136 set_timeout(160, [this]() {
137 // check status
138 uint8_t status = 0;
139 if (this->read(&status, 1) != i2c::ERROR_OK) {
140 ESP_LOGE(TAG, "Read failed!");
141 this->status_set_warning();
142 return;
143 }
144 if ((status & 0x80) == 0x80) {
145 ESP_LOGE(TAG, "HW still busy!");
146 this->status_set_warning();
147 return;
148 }
149
150 // read
151 uint8_t data[7];
152 if (this->read(data, 7) != i2c::ERROR_OK) {
153 ESP_LOGE(TAG, "Read failed!");
154 this->status_set_warning();
155 return;
156 }
157
158 // check for all zeros
159 bool zeros = true;
160 for (uint8_t i : data) {
161 zeros = zeros && (i == 0);
162 }
163 if (zeros) {
164 ESP_LOGW(TAG, "Data all zeros!");
165 this->status_set_warning();
166 return;
167 }
168
169 // convert
170 float temperature = 0.0;
171 float humidity = 0.0;
172 if (this->convert_(data, humidity, temperature)) {
173 if (this->temperature_sensor_ != nullptr) {
174 this->temperature_sensor_->publish_state(temperature);
175 }
176 if (this->humidity_sensor_ != nullptr) {
177 this->humidity_sensor_->publish_state(humidity);
178 }
179 this->status_clear_warning();
180 } else {
181 ESP_LOGW(TAG, "CRC failed!");
182 this->status_set_warning();
183 }
184 });
185}
186
188 ESP_LOGCONFIG(TAG, "AM2315C:");
189 LOG_I2C_DEVICE(this);
190 if (this->is_failed()) {
191 ESP_LOGE(TAG, "Communication with AM2315C failed!");
192 }
193 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
194 LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
195}
196
198
199} // namespace am2315c
200} // namespace esphome
uint8_t raw[35]
Definition bl0939.h:0
uint8_t status
Definition bl0942.h:8
virtual void mark_failed()
Mark this component as failed.
bool is_failed() const
void status_set_warning(const char *message="unspecified")
void status_clear_warning()
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.cpp:72
void update() override
Definition am2315c.cpp:123
void dump_config() override
Definition am2315c.cpp:187
void setup() override
Definition am2315c.cpp:92
sensor::Sensor * humidity_sensor_
Definition am2315c.h:47
float get_setup_priority() const override
Definition am2315c.cpp:197
bool convert_(uint8_t *data, float &humidity, float &temperature)
Definition am2315c.cpp:83
bool reset_register_(uint8_t reg)
Definition am2315c.cpp:48
uint8_t crc8_(uint8_t *data, uint8_t len)
Definition am2315c.cpp:32
sensor::Sensor * temperature_sensor_
Definition am2315c.h:46
ErrorCode write(const uint8_t *data, size_t len, bool stop=true)
writes an array of bytes to a device using an I2CBus
Definition i2c.h:190
I2CRegister reg(uint8_t a_register)
calls the I2CRegister constructor
Definition i2c.h:153
ErrorCode read(uint8_t *data, size_t len)
reads an array of bytes from the device using an I2CBus
Definition i2c.h:164
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:39
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:13
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:19
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:301
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:28
uint16_t temperature
Definition sun_gtil2.cpp:12