mirror of
https://github.com/esphome/esphome.git
synced 2026-10-23 06:15:58 +00:00
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fef73dbd15 | ||
|
|
0628e4e492 | ||
|
|
abbf3a6960 | ||
|
|
a97d4241bd | ||
|
|
f1031bc64d | ||
|
|
71064efc25 | ||
|
|
f5ea2d9f01 | ||
|
|
5d69784adc | ||
|
|
22a0440348 | ||
|
|
46379d8cbc | ||
|
|
f00328f45d | ||
|
|
61bd5e2657 | ||
|
|
7a1dc1279d | ||
|
|
04165e289f | ||
|
|
a7e5a2a621 |
No files matched your search
@@ -1,10 +1,7 @@
|
||||
#include "dfrobot_sen0465_uart.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace esphome::dfrobot_sen0465_uart {
|
||||
|
||||
using dfrobot_sen0465_base::FRAME_HEAD;
|
||||
using dfrobot_sen0465_base::FRAME_SIZE;
|
||||
using dfrobot_sen0465_base::RESPONSE_TIMEOUT_ID;
|
||||
|
||||
@@ -18,30 +15,21 @@ void DFRobotSEN0465UARTComponent::setup() {
|
||||
}
|
||||
|
||||
void DFRobotSEN0465UARTComponent::loop() {
|
||||
// The tail of a reading the probe sent on its own may precede the answer; start at the next frame head.
|
||||
uint8_t byte;
|
||||
while (this->rx_count_ == 0 && this->peek_byte(&byte) && byte != FRAME_HEAD)
|
||||
this->read_byte(&byte);
|
||||
const size_t available = this->available();
|
||||
if (available == 0)
|
||||
return;
|
||||
const size_t len = std::min<size_t>(available, FRAME_SIZE - this->rx_count_);
|
||||
if (!this->read_array(this->rx_buffer_ + this->rx_count_, len))
|
||||
return;
|
||||
this->rx_count_ += len;
|
||||
if (this->rx_count_ < FRAME_SIZE)
|
||||
// The tail of a reading the probe sent on its own may precede the answer; the reader skips to the frame head.
|
||||
const uint8_t *frame = nullptr;
|
||||
this->read_available<FRAME_SIZE>([&](uint8_t c) { return (frame = this->reader_.feed(c)) == nullptr; });
|
||||
if (frame == nullptr)
|
||||
return;
|
||||
|
||||
this->rx_count_ = 0;
|
||||
this->cancel_timeout(RESPONSE_TIMEOUT_ID);
|
||||
this->disable_loop();
|
||||
this->handle_response_(this->rx_buffer_);
|
||||
this->handle_response_(frame);
|
||||
}
|
||||
|
||||
bool DFRobotSEN0465UARTComponent::write_frame(const uint8_t *frame) {
|
||||
// Drop anything left over, such as the answer to the mode change or readings sent before passive mode was set
|
||||
this->discard_available();
|
||||
this->rx_count_ = 0;
|
||||
this->reader_.reset();
|
||||
this->write_array(frame, FRAME_SIZE);
|
||||
return true;
|
||||
}
|
||||
@@ -50,7 +38,7 @@ void DFRobotSEN0465UARTComponent::read_response() {
|
||||
this->enable_loop();
|
||||
this->set_timeout(RESPONSE_TIMEOUT_ID, RESPONSE_TIMEOUT_MS, [this]() {
|
||||
this->disable_loop();
|
||||
this->rx_count_ = 0;
|
||||
this->reader_.reset();
|
||||
this->handle_no_response_();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "esphome/components/dfrobot_sen0465_base/dfrobot_sen0465_base.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
#include "esphome/core/frame_reader.h"
|
||||
|
||||
namespace esphome::dfrobot_sen0465_uart {
|
||||
|
||||
@@ -17,8 +18,7 @@ class DFRobotSEN0465UARTComponent final : public dfrobot_sen0465_base::DFRobotSE
|
||||
bool write_frame(const uint8_t *frame) override;
|
||||
void read_response() override;
|
||||
|
||||
uint8_t rx_buffer_[dfrobot_sen0465_base::FRAME_SIZE];
|
||||
uint8_t rx_count_{0};
|
||||
FrameReader<dfrobot_sen0465_base::FRAME_SIZE, dfrobot_sen0465_base::FRAME_HEAD> reader_;
|
||||
};
|
||||
|
||||
} // namespace esphome::dfrobot_sen0465_uart
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "ds1603l.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
@@ -10,35 +8,28 @@ namespace esphome::ds1603l {
|
||||
ESPHOME_LOG_TAG(TAG, "ds1603l.sensor");
|
||||
|
||||
void DS1603L::loop() {
|
||||
// Assemble frames one byte at a time so a stream that starts mid-frame can realign
|
||||
uint8_t byte;
|
||||
while (this->available() > 0 && this->read_byte(&byte)) {
|
||||
if (this->rx_count_ == 0 && byte != HEADER_BYTE) {
|
||||
ESP_LOGV(TAG, "Skipping byte 0x%02X while looking for header", byte);
|
||||
continue;
|
||||
this->read_available([this](uint8_t byte) {
|
||||
const uint8_t *frame = this->reader_.feed(byte);
|
||||
if (frame == nullptr) {
|
||||
if (this->reader_.length() == 0) {
|
||||
ESP_LOGV(TAG, "Skipping byte 0x%02X while looking for header", byte);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this->rx_buffer_[this->rx_count_++] = byte;
|
||||
if (this->rx_count_ < FRAME_SIZE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this->parse_data_()) {
|
||||
this->rx_count_ = 0;
|
||||
} else {
|
||||
if (!this->parse_data_(frame)) {
|
||||
// The header byte was part of the payload of a misaligned frame, so realign instead of dropping everything
|
||||
this->resync_();
|
||||
this->reader_.resync();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void DS1603L::dump_config() { LOG_SENSOR("", "DS1603L", this); }
|
||||
|
||||
bool DS1603L::parse_data_() {
|
||||
uint8_t header = this->rx_buffer_[0];
|
||||
uint8_t data_h = this->rx_buffer_[1];
|
||||
uint8_t data_l = this->rx_buffer_[2];
|
||||
uint8_t checksum = this->rx_buffer_[3];
|
||||
bool DS1603L::parse_data_(const uint8_t *frame) {
|
||||
uint8_t header = frame[0];
|
||||
uint8_t data_h = frame[1];
|
||||
uint8_t data_l = frame[2];
|
||||
uint8_t checksum = frame[3];
|
||||
|
||||
uint8_t computed_checksum = (header + data_h + data_l) & 0xFF;
|
||||
|
||||
@@ -53,16 +44,4 @@ bool DS1603L::parse_data_() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DS1603L::resync_() {
|
||||
// Drop the byte that was treated as the header, then look for the next candidate header in what is left
|
||||
size_t start = 1;
|
||||
while (start < this->rx_count_ && this->rx_buffer_[start] != HEADER_BYTE) {
|
||||
start++;
|
||||
}
|
||||
this->rx_count_ -= start;
|
||||
if (this->rx_count_ > 0) {
|
||||
memmove(this->rx_buffer_, this->rx_buffer_ + start, this->rx_count_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome::ds1603l
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/frame_reader.h"
|
||||
|
||||
namespace esphome::ds1603l {
|
||||
|
||||
@@ -18,13 +19,10 @@ class DS1603L final : public sensor::Sensor, public Component, public uart::UART
|
||||
static constexpr uint8_t HEADER_BYTE = 0xFF;
|
||||
static constexpr size_t FRAME_SIZE = 4;
|
||||
|
||||
// Validates the checksum of the frame in rx_buffer_ and publishes it. Returns false if the frame is invalid.
|
||||
bool parse_data_();
|
||||
// Drops the first buffered byte and realigns the buffer on the next possible header byte.
|
||||
void resync_();
|
||||
// Validates the checksum of the frame and publishes it. Returns false if the frame is invalid.
|
||||
bool parse_data_(const uint8_t *frame);
|
||||
|
||||
uint8_t rx_buffer_[FRAME_SIZE]; // Buffer for the frame being assembled
|
||||
size_t rx_count_{0}; // Number of bytes currently in rx_buffer_
|
||||
FrameReader<FRAME_SIZE, HEADER_BYTE> reader_;
|
||||
};
|
||||
|
||||
} // namespace esphome::ds1603l
|
||||
@@ -1,33 +1,27 @@
|
||||
#include "sm300d2.h"
|
||||
#include "esphome/core/frame_reader.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::sm300d2 {
|
||||
|
||||
ESPHOME_LOG_TAG(TAG, "sm300d2");
|
||||
static const uint8_t SM300D2_RESPONSE_LENGTH = 17;
|
||||
static constexpr uint8_t SM300D2_RESPONSE_LENGTH = 17;
|
||||
|
||||
void SM300D2Sensor::update() {
|
||||
uint8_t response[SM300D2_RESPONSE_LENGTH];
|
||||
uint8_t peeked;
|
||||
// Takes the first frame already received; only one cut off at the end of the buffer is waited for
|
||||
FrameReader<SM300D2_RESPONSE_LENGTH, 0x3C, 0x02> reader;
|
||||
const uint8_t *response = nullptr;
|
||||
this->read_available<1>([&](uint8_t c) { return (response = reader.feed(c)) == nullptr; });
|
||||
for (uint8_t c; response == nullptr && reader.length() > 0 && this->read_byte(&c);)
|
||||
response = reader.feed(c);
|
||||
|
||||
while (this->available() > 0 && this->peek_byte(&peeked) && peeked != 0x3C)
|
||||
this->read();
|
||||
|
||||
bool read_success = read_array(response, SM300D2_RESPONSE_LENGTH);
|
||||
|
||||
if (!read_success) {
|
||||
if (response == nullptr) {
|
||||
ESP_LOGW(TAG, "Reading data from SM300D2 failed!");
|
||||
status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
if (response[0] != 0x3C || response[1] != 0x02) {
|
||||
ESP_LOGW(TAG, "Invalid preamble for SM300D2 response!");
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t calculated_checksum = this->sm300d2_checksum_(response);
|
||||
uint16_t calculated_checksum = sum_bytes(response, SM300D2_RESPONSE_LENGTH - 1);
|
||||
// Occasionally the checksum has a +/- 0x80 offset. Negative temperatures are
|
||||
// responsible for some of these. The rest are unknown/undocumented.
|
||||
if ((calculated_checksum != response[SM300D2_RESPONSE_LENGTH - 1]) &&
|
||||
@@ -83,8 +77,6 @@ void SM300D2Sensor::update() {
|
||||
this->humidity_sensor_->publish_state(humidity);
|
||||
}
|
||||
|
||||
uint16_t SM300D2Sensor::sm300d2_checksum_(uint8_t *ptr) { return sum_bytes(ptr, SM300D2_RESPONSE_LENGTH - 1); }
|
||||
|
||||
void SM300D2Sensor::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "SM300D2:");
|
||||
LOG_SENSOR(" ", "CO2", this->co2_sensor_);
|
||||
|
||||
@@ -20,8 +20,6 @@ class SM300D2Sensor final : public PollingComponent, public uart::UARTDevice {
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
uint16_t sm300d2_checksum_(uint8_t *ptr);
|
||||
|
||||
sensor::Sensor *co2_sensor_{nullptr};
|
||||
sensor::Sensor *formaldehyde_sensor_{nullptr};
|
||||
sensor::Sensor *tvoc_sensor_{nullptr};
|
||||
|
||||
@@ -44,8 +44,6 @@ static constexpr std::array<uint8_t, 7> GET_SOFTWARE_VERSION = {0xFE, 0xFE, 0x11
|
||||
static constexpr size_t FRAME_DEVICE_ID_INDEX = 2;
|
||||
static constexpr size_t FRAME_CHECKSUM_INDEX = 30;
|
||||
static constexpr size_t FRAME_STOP_INDEX = 31;
|
||||
static constexpr uint8_t FRAME_START_BYTE_1 = 0x3C;
|
||||
static constexpr uint8_t FRAME_START_BYTE_2 = 0x32;
|
||||
static constexpr uint8_t PASSIVE_START_BYTE_2 = 0x64;
|
||||
static constexpr uint8_t PASSIVE_START_BYTE_2_WITH_ID = 0x96;
|
||||
static constexpr uint8_t FRAME_STOP_BYTE = 0x16;
|
||||
@@ -120,9 +118,8 @@ static bool check_byte(const uint8_t data[FRAME_SIZE], size_t index, uint8_t exp
|
||||
|
||||
static bool validate_active_frame(const uint8_t data[FRAME_SIZE]) {
|
||||
const uint8_t sum = sum_bytes(data, FRAME_CHECKSUM_INDEX);
|
||||
return check_byte(data, 0, FRAME_START_BYTE_1, "start byte 1") &&
|
||||
check_byte(data, 1, FRAME_START_BYTE_2, "start byte 2") &&
|
||||
check_byte(data, FRAME_INDEX_INSTANT_FLOW_FLAG, FRAME_FLAG_INSTANT_FLOW, "instant flow flag") &&
|
||||
// FrameReader already matched the start bytes
|
||||
return check_byte(data, FRAME_INDEX_INSTANT_FLOW_FLAG, FRAME_FLAG_INSTANT_FLOW, "instant flow flag") &&
|
||||
check_byte(data, FRAME_INDEX_RESERVED_SECTION, FRAME_FLAG_RESERVED_SECTION, "reserved section flag") &&
|
||||
check_byte(data, FRAME_INDEX_TEMP_FLAG, FRAME_FLAG_TEMP, "temperature flag") &&
|
||||
check_byte(data, FRAME_CHECKSUM_INDEX, sum, "checksum") &&
|
||||
@@ -215,7 +212,7 @@ static bool read_flow_rate_out_of_range(const uint8_t data[FRAME_SIZE]) {
|
||||
|
||||
void UFM01Component::flush_rx_() {
|
||||
this->discard_available();
|
||||
this->read_index_ = 0;
|
||||
this->active_reader_.reset();
|
||||
}
|
||||
|
||||
void UFM01Component::send_command_no_wait_(const std::array<uint8_t, 7> &command) {
|
||||
@@ -423,7 +420,7 @@ bool UFM01Component::service_software_version_(uint32_t now) {
|
||||
}
|
||||
#endif // USE_UFM01_SOFTWARE_VERSION
|
||||
|
||||
void UFM01Component::on_active_frame_(uint8_t data[FRAME_SIZE], uint32_t now) {
|
||||
void UFM01Component::on_active_frame_(const uint8_t data[FRAME_SIZE], uint32_t now) {
|
||||
#ifdef USE_UFM01_METER_ID
|
||||
this->publish_meter_id_from_frame_(data);
|
||||
#endif
|
||||
@@ -461,40 +458,26 @@ void UFM01Component::on_active_frame_(uint8_t data[FRAME_SIZE], uint32_t now) {
|
||||
bool UFM01Component::process_active_stream_(uint32_t now) {
|
||||
bool got_valid_frame = false;
|
||||
|
||||
while (this->available()) {
|
||||
if (!this->read_byte(&this->data_[this->read_index_])) {
|
||||
ESP_LOGW(TAG, "unable to read byte");
|
||||
this->read_index_ = 0;
|
||||
continue;
|
||||
}
|
||||
if ((this->read_index_ == 0 && this->data_[0] != FRAME_START_BYTE_1) ||
|
||||
(this->read_index_ == 1 && this->data_[1] != FRAME_START_BYTE_2)) {
|
||||
ESP_LOGD(TAG, "not start of data at %" PRId32 " (is 0x%02X)", this->read_index_, this->data_[this->read_index_]);
|
||||
this->read_index_ = 0;
|
||||
continue;
|
||||
}
|
||||
if (++this->read_index_ < static_cast<int32_t>(FRAME_SIZE))
|
||||
continue;
|
||||
|
||||
if (validate_active_frame(this->data_)) {
|
||||
this->on_active_frame_(this->data_, now);
|
||||
this->read_index_ = 0;
|
||||
got_valid_frame = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
log_hex(this->data_, sizeof(this->data_));
|
||||
ESP_LOGW(TAG, "unable to read data");
|
||||
for (int32_t i = 2;
|
||||
i < static_cast<int32_t>(FRAME_STOP_INDEX) && this->read_index_ == static_cast<int32_t>(FRAME_SIZE); ++i) {
|
||||
if ((this->data_[i] == FRAME_START_BYTE_1) && (this->data_[i + 1] == FRAME_START_BYTE_2)) {
|
||||
for (int32_t j = i; j < static_cast<int32_t>(FRAME_SIZE); ++j)
|
||||
this->data_[j - i] = this->data_[j];
|
||||
this->read_index_ = static_cast<int32_t>(FRAME_SIZE) - i;
|
||||
const bool read_ok = this->read_available([this, now, &got_valid_frame](uint8_t byte) {
|
||||
const uint8_t *frame = this->active_reader_.feed(byte);
|
||||
if (frame == nullptr) {
|
||||
if (this->active_reader_.length() == 0) {
|
||||
ESP_LOGD(TAG, "not start of data (is 0x%02X)", byte);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this->read_index_ == static_cast<int32_t>(FRAME_SIZE))
|
||||
this->read_index_ = 0;
|
||||
if (validate_active_frame(frame)) {
|
||||
this->on_active_frame_(frame, now);
|
||||
got_valid_frame = true;
|
||||
return;
|
||||
}
|
||||
log_hex(frame, FRAME_SIZE);
|
||||
ESP_LOGW(TAG, "unable to read data");
|
||||
this->active_reader_.resync();
|
||||
});
|
||||
if (!read_ok) {
|
||||
ESP_LOGW(TAG, "unable to read byte");
|
||||
this->active_reader_.reset();
|
||||
}
|
||||
|
||||
return got_valid_frame;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/frame_reader.h"
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
#endif
|
||||
@@ -25,6 +26,8 @@ class TestableUFM01;
|
||||
} // namespace testing
|
||||
|
||||
static constexpr size_t FRAME_SIZE = 32;
|
||||
static constexpr uint8_t FRAME_START_BYTE_1 = 0x3C;
|
||||
static constexpr uint8_t FRAME_START_BYTE_2 = 0x32;
|
||||
static constexpr size_t PASSIVE_FRAME_SIZE = 23;
|
||||
static constexpr size_t PASSIVE_FRAME_WITH_ID_SIZE = 39;
|
||||
#ifdef USE_UFM01_METER_ID
|
||||
@@ -108,7 +111,7 @@ class UFM01Component : public uart::UARTDevice, public Component {
|
||||
bool consume_ack_();
|
||||
void flush_rx_();
|
||||
bool process_active_stream_(uint32_t now);
|
||||
void on_active_frame_(uint8_t data[FRAME_SIZE], uint32_t now);
|
||||
void on_active_frame_(const uint8_t data[FRAME_SIZE], uint32_t now);
|
||||
#ifdef USE_UFM01_METER_ID
|
||||
void publish_meter_id_from_frame_(const uint8_t data[FRAME_SIZE]);
|
||||
#endif
|
||||
@@ -145,7 +148,6 @@ class UFM01Component : public uart::UARTDevice, public Component {
|
||||
#ifdef USE_UFM01_CLEAR_ACCUMULATED_FLOW_ACTION
|
||||
uint32_t pending_clear_start_ms_{0};
|
||||
#endif
|
||||
int32_t read_index_{0};
|
||||
|
||||
OperatingMode operating_mode_{OperatingMode::STARTUP};
|
||||
StartupPhase startup_phase_{StartupPhase::WAIT};
|
||||
@@ -170,7 +172,7 @@ class UFM01Component : public uart::UARTDevice, public Component {
|
||||
#endif
|
||||
|
||||
uint8_t passive_frame_[PASSIVE_FRAME_MAX_SIZE];
|
||||
uint8_t data_[FRAME_SIZE];
|
||||
FrameReader<FRAME_SIZE, FRAME_START_BYTE_1, FRAME_START_BYTE_2> active_reader_;
|
||||
|
||||
friend class testing::TestableUFM01;
|
||||
};
|
||||
|
||||
@@ -4,70 +4,38 @@
|
||||
|
||||
namespace esphome::wts01 {
|
||||
|
||||
constexpr uint8_t HEADER_1 = 0x55;
|
||||
constexpr uint8_t HEADER_2 = 0x01;
|
||||
constexpr uint8_t HEADER_3 = 0x01;
|
||||
constexpr uint8_t HEADER_4 = 0x04;
|
||||
|
||||
ESPHOME_LOG_TAG(TAG, "wts01");
|
||||
|
||||
void WTS01Sensor::loop() {
|
||||
this->read_available([this](uint8_t c) { this->handle_char_(c); });
|
||||
this->read_available([this](uint8_t c) {
|
||||
if (const uint8_t *packet = this->reader_.feed(c)) {
|
||||
this->process_packet_(packet);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void WTS01Sensor::dump_config() { LOG_SENSOR("", "WTS01 Sensor", this); }
|
||||
|
||||
void WTS01Sensor::handle_char_(uint8_t c) {
|
||||
// State machine for processing the header. Reset if something doesn't match.
|
||||
if (this->buffer_pos_ == 0 && c != HEADER_1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->buffer_pos_ == 1 && c != HEADER_2) {
|
||||
this->buffer_pos_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->buffer_pos_ == 2 && c != HEADER_3) {
|
||||
this->buffer_pos_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->buffer_pos_ == 3 && c != HEADER_4) {
|
||||
this->buffer_pos_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Add byte to buffer
|
||||
this->buffer_[this->buffer_pos_++] = c;
|
||||
|
||||
// Process complete packet
|
||||
if (this->buffer_pos_ >= PACKET_SIZE) {
|
||||
this->process_packet_();
|
||||
this->buffer_pos_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WTS01Sensor::process_packet_() {
|
||||
void WTS01Sensor::process_packet_(const uint8_t *packet) {
|
||||
// Based on Tasmota implementation
|
||||
// Format: 55 01 01 04 01 11 16 12 95
|
||||
// header T Td Ck - T = Temperature, Td = Temperature decimal, Ck = Checksum
|
||||
const uint8_t calculated_checksum = sum_bytes(this->buffer_, PACKET_SIZE - 1);
|
||||
const uint8_t calculated_checksum = sum_bytes(packet, PACKET_SIZE - 1);
|
||||
|
||||
uint8_t received_checksum = this->buffer_[PACKET_SIZE - 1];
|
||||
uint8_t received_checksum = packet[PACKET_SIZE - 1];
|
||||
if (calculated_checksum != received_checksum) {
|
||||
ESP_LOGW(TAG, "WTS01 Checksum doesn't match: 0x%02X != 0x%02X", received_checksum, calculated_checksum);
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract temperature value
|
||||
const uint8_t raw = this->buffer_[6];
|
||||
const uint8_t raw = packet[6];
|
||||
|
||||
// WTS01 encodes sign in bit 7, magnitude in bits 0-6
|
||||
const bool negative = (raw & 0x80) != 0;
|
||||
const uint8_t magnitude = raw & 0x7F;
|
||||
|
||||
const float decimal = static_cast<float>(this->buffer_[7]) / 100.0f;
|
||||
const float decimal = static_cast<float>(packet[7]) / 100.0f;
|
||||
|
||||
float temperature = static_cast<float>(magnitude) + decimal;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/frame_reader.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
|
||||
@@ -14,11 +15,9 @@ class WTS01Sensor final : public sensor::Sensor, public uart::UARTDevice, public
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
uint8_t buffer_[PACKET_SIZE];
|
||||
uint8_t buffer_pos_{0};
|
||||
void process_packet_(const uint8_t *packet);
|
||||
|
||||
void handle_char_(uint8_t c);
|
||||
void process_packet_();
|
||||
FrameReader<PACKET_SIZE, 0x55, 0x01, 0x01, 0x04> reader_;
|
||||
};
|
||||
|
||||
} // namespace esphome::wts01
|
||||
@@ -20,8 +20,6 @@
|
||||
|
||||
namespace esphome::ufm01::testing {
|
||||
|
||||
static constexpr uint8_t FRAME_START_BYTE_1 = 0x3C;
|
||||
static constexpr uint8_t FRAME_START_BYTE_2 = 0x32;
|
||||
static constexpr uint8_t PASSIVE_START_BYTE_2 = 0x64;
|
||||
static constexpr uint8_t PASSIVE_START_BYTE_2_WITH_ID = 0x96;
|
||||
static constexpr uint8_t FRAME_STOP_BYTE = 0x16;
|
||||
@@ -131,7 +129,7 @@ class TestableUFM01 : public UFM01Component {
|
||||
|
||||
StartupPhase startup_phase() const { return this->startup_phase_; }
|
||||
|
||||
int32_t read_index() const { return this->read_index_; }
|
||||
int32_t read_index() const { return this->active_reader_.length(); }
|
||||
|
||||
uint8_t passive_index() const { return this->passive_index_; }
|
||||
|
||||
@@ -165,7 +163,7 @@ class TestableUFM01 : public UFM01Component {
|
||||
this->operating_mode_ = OperatingMode::ACTIVE_STREAM;
|
||||
this->last_valid_frame_ms_ = now();
|
||||
this->passive_read_pending_ = false;
|
||||
this->read_index_ = 0;
|
||||
this->active_reader_.reset();
|
||||
}
|
||||
|
||||
void begin_active_wait_frame() {
|
||||
@@ -182,7 +180,7 @@ class TestableUFM01 : public UFM01Component {
|
||||
}
|
||||
|
||||
void reset_state() {
|
||||
this->read_index_ = 0;
|
||||
this->active_reader_.reset();
|
||||
this->last_valid_frame_ms_ = 0;
|
||||
this->passive_index_ = 0;
|
||||
this->passive_read_pending_ = false;
|
||||
|
||||
@@ -30,6 +30,15 @@ TEST_F(UFM01Test, InvalidActiveFrameChecksumRejected) {
|
||||
EXPECT_EQ(this->ufm01_.last_valid_frame_ms(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(UFM01Test, RejectedActiveFrameResyncsOnStartBytesInside) {
|
||||
// A cut off frame start makes the first 32 bytes invalid; the real frame starts inside them
|
||||
this->mock_uart_.enqueue({FRAME_START_BYTE_1, FRAME_START_BYTE_2, 0x00, 0x00});
|
||||
this->mock_uart_.enqueue(make_active_frame());
|
||||
|
||||
EXPECT_TRUE(this->ufm01_.process_active_stream());
|
||||
EXPECT_EQ(this->ufm01_.read_index(), 0);
|
||||
}
|
||||
|
||||
TEST_F(UFM01Test, ValidPassiveFrameReadSuccess) {
|
||||
auto frame = make_passive_frame();
|
||||
this->mock_uart_.enqueue(frame);
|
||||
|
||||
Reference in new issue
Block a user