1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-23 12:13:49 +01:00

[uponor_smatrix] Use combined 32 bit addresses instead of separate 16 bit system and device addresses (#11066)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Stefan Rado
2025-10-20 04:49:06 +02:00
committed by GitHub
parent c15f1a9be8
commit 8f1c4634ec
6 changed files with 37 additions and 45 deletions

View File

@@ -17,6 +17,12 @@ UponorSmatrixDevice = uponor_smatrix_ns.class_(
"UponorSmatrixDevice", cg.Parented.template(UponorSmatrixComponent)
)
device_address = cv.All(
cv.hex_int,
cv.Range(min=0x1000000, max=0xFFFFFFFF, msg="Expected a 32 bit device address"),
)
CONF_UPONOR_SMATRIX_ID = "uponor_smatrix_id"
CONF_TIME_DEVICE_ADDRESS = "time_device_address"
@@ -24,9 +30,12 @@ CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(UponorSmatrixComponent),
cv.Optional(CONF_ADDRESS): cv.hex_uint16_t,
cv.Optional(CONF_ADDRESS): cv.invalid(
f"The '{CONF_ADDRESS}' option has been removed. "
"Use full 32 bit addresses in the device definitions instead."
),
cv.Optional(CONF_TIME_ID): cv.use_id(time.RealTimeClock),
cv.Optional(CONF_TIME_DEVICE_ADDRESS): cv.hex_uint16_t,
cv.Optional(CONF_TIME_DEVICE_ADDRESS): device_address,
}
)
.extend(cv.COMPONENT_SCHEMA)
@@ -47,7 +56,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
UPONOR_SMATRIX_DEVICE_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_UPONOR_SMATRIX_ID): cv.use_id(UponorSmatrixComponent),
cv.Required(CONF_ADDRESS): cv.hex_uint16_t,
cv.Required(CONF_ADDRESS): device_address,
}
)
@@ -58,17 +67,15 @@ async def to_code(config):
await cg.register_component(var, config)
await uart.register_uart_device(var, config)
if address := config.get(CONF_ADDRESS):
cg.add(var.set_system_address(address))
if time_id := config.get(CONF_TIME_ID):
time_ = await cg.get_variable(time_id)
cg.add(var.set_time_id(time_))
if time_device_address := config.get(CONF_TIME_DEVICE_ADDRESS):
cg.add(var.set_time_device_address(time_device_address))
if time_device_address := config.get(CONF_TIME_DEVICE_ADDRESS):
cg.add(var.set_time_device_address(time_device_address))
async def register_uponor_smatrix_device(var, config):
parent = await cg.get_variable(config[CONF_UPONOR_SMATRIX_ID])
cg.add(var.set_parent(parent))
cg.add(var.set_device_address(config[CONF_ADDRESS]))
cg.add(var.set_address(config[CONF_ADDRESS]))
cg.add(parent.register_device(var))

View File

@@ -10,7 +10,7 @@ static const char *const TAG = "uponor_smatrix.climate";
void UponorSmatrixClimate::dump_config() {
LOG_CLIMATE("", "Uponor Smatrix Climate", this);
ESP_LOGCONFIG(TAG, " Device address: 0x%04X", this->address_);
ESP_LOGCONFIG(TAG, " Device address: 0x%08X", this->address_);
}
void UponorSmatrixClimate::loop() {

View File

@@ -9,7 +9,7 @@ static const char *const TAG = "uponor_smatrix.sensor";
void UponorSmatrixSensor::dump_config() {
ESP_LOGCONFIG(TAG,
"Uponor Smatrix Sensor\n"
" Device address: 0x%04X",
" Device address: 0x%08X",
this->address_);
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
LOG_SENSOR(" ", "External Temperature", this->external_temperature_sensor_);

View File

@@ -18,11 +18,10 @@ void UponorSmatrixComponent::setup() {
void UponorSmatrixComponent::dump_config() {
ESP_LOGCONFIG(TAG, "Uponor Smatrix");
ESP_LOGCONFIG(TAG, " System address: 0x%04X", this->address_);
#ifdef USE_TIME
if (this->time_id_ != nullptr) {
ESP_LOGCONFIG(TAG, " Time synchronization: YES");
ESP_LOGCONFIG(TAG, " Time master device address: 0x%04X", this->time_device_address_);
ESP_LOGCONFIG(TAG, " Time master device address: 0x%08X", this->time_device_address_);
}
#endif
@@ -31,7 +30,7 @@ void UponorSmatrixComponent::dump_config() {
if (!this->unknown_devices_.empty()) {
ESP_LOGCONFIG(TAG, " Detected unknown device addresses:");
for (auto device_address : this->unknown_devices_) {
ESP_LOGCONFIG(TAG, " 0x%04X", device_address);
ESP_LOGCONFIG(TAG, " 0x%08X", device_address);
}
}
}
@@ -89,8 +88,7 @@ bool UponorSmatrixComponent::parse_byte_(uint8_t byte) {
return false;
}
uint16_t system_address = encode_uint16(packet[0], packet[1]);
uint16_t device_address = encode_uint16(packet[2], packet[3]);
uint32_t device_address = encode_uint32(packet[0], packet[1], packet[2], packet[3]);
uint16_t crc = encode_uint16(packet[packet_len - 1], packet[packet_len - 2]);
uint16_t computed_crc = crc16(packet, packet_len - 2);
@@ -99,24 +97,14 @@ bool UponorSmatrixComponent::parse_byte_(uint8_t byte) {
return false;
}
ESP_LOGV(TAG, "Received packet: sys=%04X, dev=%04X, data=%s, crc=%04X", system_address, device_address,
ESP_LOGV(TAG, "Received packet: addr=%08X, data=%s, crc=%04X", device_address,
format_hex(&packet[4], packet_len - 6).c_str(), crc);
// Detect or check system address
if (this->address_ == 0) {
ESP_LOGI(TAG, "Using detected system address 0x%04X", system_address);
this->address_ = system_address;
} else if (this->address_ != system_address) {
// This should never happen except if the system address was set or detected incorrectly, so warn the user.
ESP_LOGW(TAG, "Received packet from unknown system address 0x%04X", system_address);
return true;
}
// Handle packet
size_t data_len = (packet_len - 6) / 3;
if (data_len == 0) {
if (packet[4] == UPONOR_ID_REQUEST)
ESP_LOGVV(TAG, "Ignoring request packet for device 0x%04X", device_address);
ESP_LOGVV(TAG, "Ignoring request packet for device 0x%08X", device_address);
return true;
}
@@ -141,7 +129,7 @@ bool UponorSmatrixComponent::parse_byte_(uint8_t byte) {
if (data[i].id == UPONOR_ID_DATETIME1)
found_time = true;
if (found_temperature && found_time) {
ESP_LOGI(TAG, "Using detected time device address 0x%04X", device_address);
ESP_LOGI(TAG, "Using detected time device address 0x%08X", device_address);
this->time_device_address_ = device_address;
break;
}
@@ -160,7 +148,7 @@ bool UponorSmatrixComponent::parse_byte_(uint8_t byte) {
// Log unknown device addresses
if (!found && !this->unknown_devices_.count(device_address)) {
ESP_LOGI(TAG, "Received packet for unknown device address 0x%04X ", device_address);
ESP_LOGI(TAG, "Received packet for unknown device address 0x%08X ", device_address);
this->unknown_devices_.insert(device_address);
}
@@ -168,16 +156,16 @@ bool UponorSmatrixComponent::parse_byte_(uint8_t byte) {
return true;
}
bool UponorSmatrixComponent::send(uint16_t device_address, const UponorSmatrixData *data, size_t data_len) {
if (this->address_ == 0 || device_address == 0 || data == nullptr || data_len == 0)
bool UponorSmatrixComponent::send(uint32_t device_address, const UponorSmatrixData *data, size_t data_len) {
if (device_address == 0 || data == nullptr || data_len == 0)
return false;
// Assemble packet for send queue. All fields are big-endian except for the little-endian checksum.
std::vector<uint8_t> packet;
packet.reserve(6 + 3 * data_len);
packet.push_back(this->address_ >> 8);
packet.push_back(this->address_ >> 0);
packet.push_back(device_address >> 24);
packet.push_back(device_address >> 16);
packet.push_back(device_address >> 8);
packet.push_back(device_address >> 0);

View File

@@ -71,23 +71,21 @@ class UponorSmatrixComponent : public uart::UARTDevice, public Component {
void dump_config() override;
void loop() override;
void set_system_address(uint16_t address) { this->address_ = address; }
void register_device(UponorSmatrixDevice *device) { this->devices_.push_back(device); }
bool send(uint16_t device_address, const UponorSmatrixData *data, size_t data_len);
bool send(uint32_t device_address, const UponorSmatrixData *data, size_t data_len);
#ifdef USE_TIME
void set_time_id(time::RealTimeClock *time_id) { this->time_id_ = time_id; }
void set_time_device_address(uint16_t address) { this->time_device_address_ = address; }
void set_time_device_address(uint32_t address) { this->time_device_address_ = address; }
void send_time() { this->send_time_requested_ = true; }
#endif
protected:
bool parse_byte_(uint8_t byte);
uint16_t address_;
std::vector<UponorSmatrixDevice *> devices_;
std::set<uint16_t> unknown_devices_;
std::set<uint32_t> unknown_devices_;
std::vector<uint8_t> rx_buffer_;
std::queue<std::vector<uint8_t>> tx_queue_;
@@ -96,7 +94,7 @@ class UponorSmatrixComponent : public uart::UARTDevice, public Component {
#ifdef USE_TIME
time::RealTimeClock *time_id_{nullptr};
uint16_t time_device_address_;
uint32_t time_device_address_;
bool send_time_requested_;
bool do_send_time_();
#endif
@@ -104,7 +102,7 @@ class UponorSmatrixComponent : public uart::UARTDevice, public Component {
class UponorSmatrixDevice : public Parented<UponorSmatrixComponent> {
public:
void set_device_address(uint16_t address) { this->address_ = address; }
void set_address(uint32_t address) { this->address_ = address; }
virtual void on_device_data(const UponorSmatrixData *data, size_t data_len) = 0;
bool send(const UponorSmatrixData *data, size_t data_len) {
@@ -113,7 +111,7 @@ class UponorSmatrixDevice : public Parented<UponorSmatrixComponent> {
protected:
friend UponorSmatrixComponent;
uint16_t address_;
uint32_t address_;
};
inline float raw_to_celsius(uint16_t raw) {

View File

@@ -11,18 +11,17 @@ time:
- 192.168.178.1
uponor_smatrix:
address: 0x110B
time_id: sntp_time
time_device_address: 0xDE13
time_device_address: 0x110BDE13
climate:
- platform: uponor_smatrix
address: 0xDE13
address: 0x110BDE13
name: Thermostat Living Room
sensor:
- platform: uponor_smatrix
address: 0xDE13
address: 0x110BDE13
humidity:
name: Thermostat Humidity Living Room
temperature: