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