ESPHome 2026.1.5
Loading...
Searching...
No Matches
pvvx_display.cpp
Go to the documentation of this file.
1#include "pvvx_display.h"
3#include "esphome/core/log.h"
4
5#ifdef USE_ESP32
6namespace esphome {
7namespace pvvx_mithermometer {
8
9static const char *const TAG = "display.pvvx_mithermometer";
10
12 char service_buf[esp32_ble::UUID_STR_LEN];
13 char char_buf[esp32_ble::UUID_STR_LEN];
14 ESP_LOGCONFIG(TAG,
15 "PVVX MiThermometer display:\n"
16 " MAC address : %s\n"
17 " Service UUID : %s\n"
18 " Characteristic UUID : %s\n"
19 " Auto clear : %s",
20 this->parent_->address_str(), this->service_uuid_.to_str(service_buf),
21 this->char_uuid_.to_str(char_buf), YESNO(this->auto_clear_enabled_));
22#ifdef USE_TIME
23 ESP_LOGCONFIG(TAG, " Set time on connection: %s", YESNO(this->time_ != nullptr));
24#endif
25 ESP_LOGCONFIG(TAG, " Disconnect delay : %" PRIu32 "ms", this->disconnect_delay_ms_);
26 LOG_UPDATE_INTERVAL(this);
27}
28
29void PVVXDisplay::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
30 esp_ble_gattc_cb_param_t *param) {
31 switch (event) {
32 case ESP_GATTC_OPEN_EVT:
33 if (param->open.status == ESP_GATT_OK) {
34 ESP_LOGV(TAG, "[%s] Connected successfully!", this->parent_->address_str());
35 this->delayed_disconnect_();
36 }
37 break;
38 case ESP_GATTC_DISCONNECT_EVT:
39 ESP_LOGV(TAG, "[%s] Disconnected", this->parent_->address_str());
40 this->connection_established_ = false;
41 this->cancel_timeout("disconnect");
42 this->char_handle_ = 0;
43 break;
44 case ESP_GATTC_SEARCH_CMPL_EVT: {
45 auto *chr = this->parent_->get_characteristic(this->service_uuid_, this->char_uuid_);
46 if (chr == nullptr) {
47 ESP_LOGW(TAG, "[%s] Characteristic not found.", this->parent_->address_str());
48 break;
49 }
50 this->connection_established_ = true;
51 this->char_handle_ = chr->handle;
52
53 // Attempt to write immediately
54 // For devices without security, this will work
55 // For devices with security that are already paired, this will work
56 // For devices that need pairing, the write will be retried after auth completes
58 break;
59 }
60 default:
61 break;
62 }
63}
64
65void PVVXDisplay::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
66 switch (event) {
67 case ESP_GAP_BLE_AUTH_CMPL_EVT: {
68 if (!this->parent_->check_addr(param->ble_security.auth_cmpl.bd_addr))
69 return;
70
71 if (param->ble_security.auth_cmpl.success) {
72 ESP_LOGD(TAG, "[%s] Authentication successful, performing writes.", this->parent_->address_str());
73 // Now that pairing is complete, perform the pending writes
75 } else {
76 ESP_LOGW(TAG, "[%s] Authentication failed.", this->parent_->address_str());
77 }
78 break;
79 }
80 default:
81 break;
82 }
83}
84
86 if (this->auto_clear_enabled_)
87 this->clear();
88 if (this->writer_.has_value())
89 (*this->writer_)(*this);
90 this->display();
91}
92
94 if (!this->parent_->enabled) {
95 ESP_LOGD(TAG, "[%s] BLE client not enabled. Init connection.", this->parent_->address_str());
96 this->parent_->set_enabled(true);
97 return;
98 }
99 if (!this->connection_established_) {
100 ESP_LOGW(TAG, "[%s] Not connected to BLE client. State update can not be written.", this->parent_->address_str());
101 return;
102 }
103 if (!this->char_handle_) {
104 ESP_LOGW(TAG, "[%s] No ble handle to BLE client. State update can not be written.", this->parent_->address_str());
105 return;
106 }
107 ESP_LOGD(TAG, "[%s] Send to display: bignum %d, smallnum: %d, cfg: 0x%02x, validity period: %u.",
108 this->parent_->address_str(), this->bignum_, this->smallnum_, this->cfg_, this->validity_period_);
109 uint8_t blk[8] = {};
110 blk[0] = 0x22;
111 blk[1] = this->bignum_ & 0xff;
112 blk[2] = (this->bignum_ >> 8) & 0xff;
113 blk[3] = this->smallnum_ & 0xff;
114 blk[4] = (this->smallnum_ >> 8) & 0xff;
115 blk[5] = this->validity_period_ & 0xff;
116 blk[6] = (this->validity_period_ >> 8) & 0xff;
117 blk[7] = this->cfg_;
118 this->send_to_setup_char_(blk, sizeof(blk));
119}
120
121void PVVXDisplay::setcfgbit_(uint8_t bit, bool value) {
122 uint8_t mask = 1 << bit;
123 if (value) {
124 this->cfg_ |= mask;
125 } else {
126 this->cfg_ &= (0xFF ^ mask);
127 }
128}
129
130void PVVXDisplay::send_to_setup_char_(uint8_t *blk, size_t size) {
131 if (!this->connection_established_) {
132 ESP_LOGW(TAG, "[%s] Not connected to BLE client.", this->parent_->address_str());
133 return;
134 }
135 auto status =
136 esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, size,
137 blk, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
138 if (status) {
139 ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str(), status);
140 } else {
141 ESP_LOGV(TAG, "[%s] send %u bytes", this->parent_->address_str(), size);
142 this->delayed_disconnect_();
143 }
144}
145
147 if (this->disconnect_delay_ms_ == 0)
148 return;
149 this->cancel_timeout("disconnect");
150 this->set_timeout("disconnect", this->disconnect_delay_ms_, [this]() { this->parent_->set_enabled(false); });
151}
152
154#ifdef USE_TIME
155 this->sync_time_();
156#endif
157 this->display();
158}
159
160#ifdef USE_TIME
162 if (this->time_ == nullptr)
163 return;
164 if (!this->connection_established_) {
165 ESP_LOGW(TAG, "[%s] Not connected to BLE client. Time can not be synced.", this->parent_->address_str());
166 return;
167 }
168 if (!this->char_handle_) {
169 ESP_LOGW(TAG, "[%s] No ble handle to BLE client. Time can not be synced.", this->parent_->address_str());
170 return;
171 }
172 auto time = this->time_->now();
173 if (!time.is_valid()) {
174 ESP_LOGW(TAG, "[%s] Time is not yet valid. Time can not be synced.", this->parent_->address_str());
175 return;
176 }
177 time.recalc_timestamp_utc(true); // calculate timestamp of local time
178 uint8_t blk[5] = {};
179 ESP_LOGD(TAG, "[%s] Sync time with timestamp %" PRIu64 ".", this->parent_->address_str(), time.timestamp);
180 blk[0] = 0x23;
181 blk[1] = time.timestamp & 0xff;
182 blk[2] = (time.timestamp >> 8) & 0xff;
183 blk[3] = (time.timestamp >> 16) & 0xff;
184 blk[4] = (time.timestamp >> 24) & 0xff;
185 this->send_to_setup_char_(blk, sizeof(blk));
186}
187#endif
188
189} // namespace pvvx_mithermometer
190} // namespace esphome
191
192#endif
uint8_t status
Definition bl0942.h:8
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.h:445
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") bool cancel_timeout(const std boo cancel_timeout)(const char *name)
Cancel a timeout function.
Definition component.h:465
void set_enabled(bool enabled)
BLECharacteristic * get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr)
void send_to_setup_char_(uint8_t *blk, size_t size)
void setcfgbit_(uint8_t bit, bool value)
esp32_ble_tracker::ESPBTUUID service_uuid_
esp32_ble_tracker::ESPBTUUID char_uuid_
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) override
ESPTime now()
Get the time in the currently defined timezone.
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void recalc_timestamp_utc(bool use_day_of_year=true)
Recalculate the timestamp field from the other fields of this ESPTime instance (must be UTC).
Definition time.cpp:167