ESPHome  2024.5.5
pvvx_display.cpp
Go to the documentation of this file.
1 #include "pvvx_display.h"
2 #include "esphome/core/log.h"
3 
4 #ifdef USE_ESP32
5 namespace esphome {
6 namespace pvvx_mithermometer {
7 
8 static const char *const TAG = "display.pvvx_mithermometer";
9 
11  ESP_LOGCONFIG(TAG, "PVVX MiThermometer display:");
12  ESP_LOGCONFIG(TAG, " MAC address : %s", this->parent_->address_str().c_str());
13  ESP_LOGCONFIG(TAG, " Service UUID : %s", this->service_uuid_.to_string().c_str());
14  ESP_LOGCONFIG(TAG, " Characteristic UUID : %s", this->char_uuid_.to_string().c_str());
15  ESP_LOGCONFIG(TAG, " Auto clear : %s", YESNO(this->auto_clear_enabled_));
16 #ifdef USE_TIME
17  ESP_LOGCONFIG(TAG, " Set time on connection: %s", YESNO(this->time_ != nullptr));
18 #endif
19  ESP_LOGCONFIG(TAG, " Disconnect delay : %" PRIu32 "ms", this->disconnect_delay_ms_);
20  LOG_UPDATE_INTERVAL(this);
21 }
22 
23 void PVVXDisplay::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
24  esp_ble_gattc_cb_param_t *param) {
25  switch (event) {
26  case ESP_GATTC_OPEN_EVT:
27  if (param->open.status == ESP_GATT_OK) {
28  ESP_LOGV(TAG, "[%s] Connected successfully!", this->parent_->address_str().c_str());
29  this->delayed_disconnect_();
30  }
31  break;
32  case ESP_GATTC_DISCONNECT_EVT:
33  ESP_LOGV(TAG, "[%s] Disconnected", this->parent_->address_str().c_str());
34  this->connection_established_ = false;
35  this->cancel_timeout("disconnect");
36  this->char_handle_ = 0;
37  break;
38  case ESP_GATTC_SEARCH_CMPL_EVT: {
39  auto *chr = this->parent_->get_characteristic(this->service_uuid_, this->char_uuid_);
40  if (chr == nullptr) {
41  ESP_LOGW(TAG, "[%s] Characteristic not found.", this->parent_->address_str().c_str());
42  break;
43  }
44  this->connection_established_ = true;
45  this->char_handle_ = chr->handle;
46 #ifdef USE_TIME
47  this->sync_time_();
48 #endif
49  this->display();
50  break;
51  }
52  default:
53  break;
54  }
55 }
56 
58  if (this->auto_clear_enabled_)
59  this->clear();
60  if (this->writer_.has_value())
61  (*this->writer_)(*this);
62  this->display();
63 }
64 
66  if (!this->parent_->enabled) {
67  ESP_LOGD(TAG, "[%s] BLE client not enabled. Init connection.", this->parent_->address_str().c_str());
68  this->parent_->set_enabled(true);
69  return;
70  }
71  if (!this->connection_established_) {
72  ESP_LOGW(TAG, "[%s] Not connected to BLE client. State update can not be written.",
73  this->parent_->address_str().c_str());
74  return;
75  }
76  if (!this->char_handle_) {
77  ESP_LOGW(TAG, "[%s] No ble handle to BLE client. State update can not be written.",
78  this->parent_->address_str().c_str());
79  return;
80  }
81  ESP_LOGD(TAG, "[%s] Send to display: bignum %d, smallnum: %d, cfg: 0x%02x, validity period: %u.",
82  this->parent_->address_str().c_str(), this->bignum_, this->smallnum_, this->cfg_, this->validity_period_);
83  uint8_t blk[8] = {};
84  blk[0] = 0x22;
85  blk[1] = this->bignum_ & 0xff;
86  blk[2] = (this->bignum_ >> 8) & 0xff;
87  blk[3] = this->smallnum_ & 0xff;
88  blk[4] = (this->smallnum_ >> 8) & 0xff;
89  blk[5] = this->validity_period_ & 0xff;
90  blk[6] = (this->validity_period_ >> 8) & 0xff;
91  blk[7] = this->cfg_;
92  this->send_to_setup_char_(blk, sizeof(blk));
93 }
94 
95 void PVVXDisplay::setcfgbit_(uint8_t bit, bool value) {
96  uint8_t mask = 1 << bit;
97  if (value) {
98  this->cfg_ |= mask;
99  } else {
100  this->cfg_ &= (0xFF ^ mask);
101  }
102 }
103 
104 void PVVXDisplay::send_to_setup_char_(uint8_t *blk, size_t size) {
105  if (!this->connection_established_) {
106  ESP_LOGW(TAG, "[%s] Not connected to BLE client.", this->parent_->address_str().c_str());
107  return;
108  }
109  auto status =
110  esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, size,
111  blk, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
112  if (status) {
113  ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
114  } else {
115  ESP_LOGV(TAG, "[%s] send %u bytes", this->parent_->address_str().c_str(), size);
116  this->delayed_disconnect_();
117  }
118 }
119 
121  if (this->disconnect_delay_ms_ == 0)
122  return;
123  this->cancel_timeout("disconnect");
124  this->set_timeout("disconnect", this->disconnect_delay_ms_, [this]() { this->parent_->set_enabled(false); });
125 }
126 
127 #ifdef USE_TIME
129  if (this->time_ == nullptr)
130  return;
131  if (!this->connection_established_) {
132  ESP_LOGW(TAG, "[%s] Not connected to BLE client. Time can not be synced.", this->parent_->address_str().c_str());
133  return;
134  }
135  if (!this->char_handle_) {
136  ESP_LOGW(TAG, "[%s] No ble handle to BLE client. Time can not be synced.", this->parent_->address_str().c_str());
137  return;
138  }
139  auto time = this->time_->now();
140  if (!time.is_valid()) {
141  ESP_LOGW(TAG, "[%s] Time is not yet valid. Time can not be synced.", this->parent_->address_str().c_str());
142  return;
143  }
144  time.recalc_timestamp_utc(true); // calculate timestamp of local time
145  uint8_t blk[5] = {};
146 #if ESP_IDF_VERSION_MAJOR >= 5
147  ESP_LOGD(TAG, "[%s] Sync time with timestamp %" PRIu64 ".", this->parent_->address_str().c_str(), time.timestamp);
148 #else
149  ESP_LOGD(TAG, "[%s] Sync time with timestamp %lu.", this->parent_->address_str().c_str(), time.timestamp);
150 #endif
151  blk[0] = 0x23;
152  blk[1] = time.timestamp & 0xff;
153  blk[2] = (time.timestamp >> 8) & 0xff;
154  blk[3] = (time.timestamp >> 16) & 0xff;
155  blk[4] = (time.timestamp >> 24) & 0xff;
156  this->send_to_setup_char_(blk, sizeof(blk));
157 }
158 #endif
159 
160 } // namespace pvvx_mithermometer
161 } // namespace esphome
162 
163 #endif
ESPTime now()
Get the time in the currently defined timezone.
bool cancel_timeout(const std::string &name)
Cancel a timeout function.
Definition: component.cpp:73
optional< pvvx_writer_t > writer_
Definition: pvvx_display.h:129
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition: component.cpp:69
void setcfgbit_(uint8_t bit, bool value)
bool has_value() const
Definition: optional.h:87
void set_enabled(bool enabled)
Definition: ble_client.cpp:38
void send_to_setup_char_(uint8_t *blk, size_t size)
esp32_ble_tracker::ESPBTUUID char_uuid_
Definition: pvvx_display.h:126
std::string to_string() const
Definition: ble_uuid.cpp:165
uint8_t status
Definition: bl0942.h:23
BLECharacteristic * get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr)
esp32_ble_tracker::ESPBTUUID service_uuid_
Definition: pvvx_display.h:124
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
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:152
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) override