9namespace uponor_smatrix {
11static const char *
const TAG =
"uponor_smatrix";
14static constexpr size_t UPONOR_MAX_LOG_BYTES = 36;
25 ESP_LOGCONFIG(TAG,
"Uponor Smatrix");
28 ESP_LOGCONFIG(TAG,
" Time synchronization: YES");
36 ESP_LOGCONFIG(TAG,
" Detected unknown device addresses:");
38 ESP_LOGCONFIG(TAG,
" 0x%08" PRIX32
"", device_address);
47 if (!this->
rx_buffer_.empty() && (now - this->last_rx_ > 50)) {
48 ESP_LOGD(TAG,
"Discarding %d bytes of unparsed data", this->
rx_buffer_.size());
66 if (this->
rx_buffer_.empty() && (now - this->last_rx_ > 50) && (now - this->last_rx_ < 100) &&
67 (now - this->last_tx_ > 200)) {
75 auto packet = std::move(this->
tx_queue_.front());
88 const uint8_t *packet = this->
rx_buffer_.data();
97 uint16_t crc =
encode_uint16(packet[packet_len - 1], packet[packet_len - 2]);
99 uint16_t computed_crc =
crc16(packet, packet_len - 2);
100 if (crc != computed_crc) {
105#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
108 ESP_LOGV(TAG,
"Received packet: addr=%08" PRIX32
", data=%s, crc=%04X", device_address,
112 size_t data_len = (packet_len - 6) / 3;
114 if (packet[4] == UPONOR_ID_REQUEST)
115 ESP_LOGVV(TAG,
"Ignoring request packet for device 0x%08" PRIX32
"", device_address);
121 for (
size_t i = 0; i < data_len; i++) {
122 data[i].id = packet[(i * 3) + 4];
123 data[i].value =
encode_uint16(packet[(i * 3) + 5], packet[(i * 3) + 6]);
132 bool found_temperature =
false;
133 bool found_time =
false;
134 for (
size_t i = 0; i < data_len; i++) {
135 if (data[i].
id == UPONOR_ID_ROOM_TEMP)
136 found_temperature =
true;
137 if (data[i].
id == UPONOR_ID_DATETIME1)
139 if (found_temperature && found_time) {
140 ESP_LOGI(TAG,
"Using detected time device address 0x%08" PRIX32
"", device_address);
150 for (
auto *device : this->
devices_) {
151 if (device->address_ == device_address) {
153 device->on_device_data(data, data_len);
159 ESP_LOGI(TAG,
"Received packet for unknown device address 0x%08" PRIX32
" ", device_address);
168 if (device_address == 0 || data ==
nullptr || data_len == 0)
172 std::vector<uint8_t> packet;
173 packet.reserve(6 + 3 * data_len);
175 packet.push_back(device_address >> 24);
176 packet.push_back(device_address >> 16);
177 packet.push_back(device_address >> 8);
178 packet.push_back(device_address >> 0);
180 for (
size_t i = 0; i < data_len; i++) {
181 packet.push_back(data[i].
id);
182 packet.push_back(data[i].value >> 8);
183 packet.push_back(data[i].value >> 0);
186 auto crc =
crc16(packet.data(), packet.size());
187 packet.push_back(crc >> 0);
188 packet.push_back(crc >> 8);
212 uint16_t time1 = (
year & 0x7F) << 7 | (
month & 0x0F) << 3 | (day_of_week & 0x07);
213 uint16_t time2 = (day_of_month & 0x1F) << 11 | (
hour & 0x1F) << 6 | (
minute & 0x3F);
219 UponorSmatrixData data[] = {{UPONOR_ID_DATETIME1, time1}, {UPONOR_ID_DATETIME2, time2}, {UPONOR_ID_DATETIME3, time3}};
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
ESPTime now()
Get the time in the currently defined timezone.
void add_on_time_sync_callback(F &&callback)
void check_uart_settings(uint32_t baud_rate, uint8_t stop_bits=1, UARTParityOptions parity=UART_CONFIG_PARITY_NONE, uint8_t data_bits=8)
Check that the configuration of the UART bus matches the provided values and otherwise print a warnin...
bool read_byte(uint8_t *data)
void write_array(const uint8_t *data, size_t len)
uint32_t time_device_address_
bool parse_byte_(uint8_t byte)
std::vector< UponorSmatrixDevice * > devices_
bool send(uint32_t device_address, const UponorSmatrixData *data, size_t data_len)
void dump_config() override
time::RealTimeClock * time_id_
std::vector< uint8_t > rx_buffer_
std::queue< std::vector< uint8_t > > tx_queue_
std::set< uint32_t > unknown_devices_
bool send_time_requested_
Providing packet encoding functions for exchanging data with a remote host.
uint16_t crc16(const uint8_t *data, uint16_t len, uint16_t crc, uint16_t reverse_poly, bool refin, bool refout)
Calculate a CRC-16 checksum of data with size len.
constexpr size_t format_hex_size(size_t byte_count)
Calculate buffer size needed for format_hex_to: "XXXXXXXX...\0" = bytes * 2 + 1.
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
char * format_hex_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length)
Format byte array as lowercase hex to buffer (base implementation).
Application App
Global storage of Application pointer - only one Application can exist.
A more user-friendly version of struct tm from time.h.
uint8_t minute
minutes after the hour [0-59]
uint8_t second
seconds after the minute [0-60]
uint8_t hour
hours since midnight [0-23]
bool is_valid(bool check_day_of_week=true, bool check_day_of_year=true) const
Check if this ESPTime is valid (year >= 2019 and the requested fields are in range).
uint8_t day_of_month
day of the month [1-31]
uint8_t month
month; january=1 [1-12]
uint8_t day_of_week
day of the week; sunday=1 [1-7]