mirror of
https://github.com/esphome/esphome.git
synced 2026-05-31 07:57:40 +08:00
Add WTS01 temperature sensor component (#8539)
Co-authored-by: Antoine Lépée <alepee@MacBook-Pro-de-Antoine.local> Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
@@ -533,6 +533,7 @@ esphome/components/wk2204_spi/* @DrCoolZic
|
|||||||
esphome/components/wk2212_i2c/* @DrCoolZic
|
esphome/components/wk2212_i2c/* @DrCoolZic
|
||||||
esphome/components/wk2212_spi/* @DrCoolZic
|
esphome/components/wk2212_spi/* @DrCoolZic
|
||||||
esphome/components/wl_134/* @hobbypunk90
|
esphome/components/wl_134/* @hobbypunk90
|
||||||
|
esphome/components/wts01/* @alepee
|
||||||
esphome/components/x9c/* @EtienneMD
|
esphome/components/x9c/* @EtienneMD
|
||||||
esphome/components/xgzp68xx/* @gcormier
|
esphome/components/xgzp68xx/* @gcormier
|
||||||
esphome/components/xiaomi_hhccjcy10/* @fariouche
|
esphome/components/xiaomi_hhccjcy10/* @fariouche
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import sensor, uart
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import (
|
||||||
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
UNIT_CELSIUS,
|
||||||
|
)
|
||||||
|
|
||||||
|
CONF_WTS01_ID = "wts01_id"
|
||||||
|
CODEOWNERS = ["@alepee"]
|
||||||
|
DEPENDENCIES = ["uart"]
|
||||||
|
|
||||||
|
wts01_ns = cg.esphome_ns.namespace("wts01")
|
||||||
|
WTS01Sensor = wts01_ns.class_(
|
||||||
|
"WTS01Sensor", cg.Component, uart.UARTDevice, sensor.Sensor
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
sensor.sensor_schema(
|
||||||
|
WTS01Sensor,
|
||||||
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
|
accuracy_decimals=1,
|
||||||
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
.extend(uart.UART_DEVICE_SCHEMA)
|
||||||
|
)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
|
||||||
|
"wts01",
|
||||||
|
baud_rate=9600,
|
||||||
|
require_rx=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await sensor.new_sensor(config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await uart.register_uart_device(var, config)
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#include "wts01.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace 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;
|
||||||
|
|
||||||
|
static const char *const TAG = "wts01";
|
||||||
|
|
||||||
|
void WTS01Sensor::loop() {
|
||||||
|
// Process all available data at once
|
||||||
|
while (this->available()) {
|
||||||
|
uint8_t c;
|
||||||
|
if (this->read_byte(&c)) {
|
||||||
|
this->handle_char_(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_() {
|
||||||
|
// 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
|
||||||
|
uint8_t calculated_checksum = 0;
|
||||||
|
for (uint8_t i = 0; i < PACKET_SIZE - 1; i++) {
|
||||||
|
calculated_checksum += this->buffer_[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t received_checksum = this->buffer_[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
|
||||||
|
int8_t temp = this->buffer_[6];
|
||||||
|
int32_t sign = 1;
|
||||||
|
|
||||||
|
// Handle negative temperatures
|
||||||
|
if (temp < 0) {
|
||||||
|
sign = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate temperature (temp + decimal/100)
|
||||||
|
float temperature = static_cast<float>(temp) + (sign * static_cast<float>(this->buffer_[7]) / 100.0f);
|
||||||
|
|
||||||
|
ESP_LOGV(TAG, "Received new temperature: %.2f°C", temperature);
|
||||||
|
|
||||||
|
this->publish_state(temperature);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wts01
|
||||||
|
} // namespace esphome
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
#include "esphome/components/uart/uart.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace wts01 {
|
||||||
|
|
||||||
|
constexpr uint8_t PACKET_SIZE = 9;
|
||||||
|
|
||||||
|
class WTS01Sensor : public sensor::Sensor, public uart::UARTDevice, public Component {
|
||||||
|
public:
|
||||||
|
void loop() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t buffer_[PACKET_SIZE];
|
||||||
|
uint8_t buffer_pos_{0};
|
||||||
|
|
||||||
|
void handle_char_(uint8_t c);
|
||||||
|
void process_packet_();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace wts01
|
||||||
|
} // namespace esphome
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
uart:
|
||||||
|
rx_pin: ${rx_pin}
|
||||||
|
baud_rate: 9600
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: wts01
|
||||||
|
id: wts01_sensor
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO16
|
||||||
|
rx_pin: GPIO17
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO6
|
||||||
|
rx_pin: GPIO7
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO6
|
||||||
|
rx_pin: GPIO7
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO16
|
||||||
|
rx_pin: GPIO17
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO1
|
||||||
|
rx_pin: GPIO3
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO0
|
||||||
|
rx_pin: GPIO1
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
||||||
Reference in New Issue
Block a user