ESPHome  2024.4.1
am43_cover.cpp
Go to the documentation of this file.
1 #include "am43_cover.h"
2 #include "esphome/core/log.h"
3 
4 #ifdef USE_ESP32
5 
6 namespace esphome {
7 namespace am43 {
8 
9 static const char *const TAG = "am43_cover";
10 
11 using namespace esphome::cover;
12 
14  LOG_COVER("", "AM43 Cover", this);
15  ESP_LOGCONFIG(TAG, " Device Pin: %d", this->pin_);
16  ESP_LOGCONFIG(TAG, " Invert Position: %d", (int) this->invert_position_);
17 }
18 
20  this->position = COVER_OPEN;
21  this->encoder_ = make_unique<Am43Encoder>();
22  this->decoder_ = make_unique<Am43Decoder>();
23  this->logged_in_ = false;
24 }
25 
27  if (this->node_state == espbt::ClientState::ESTABLISHED && !this->logged_in_) {
28  auto *packet = this->encoder_->get_send_pin_request(this->pin_);
29  auto status =
30  esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
31  packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
32  ESP_LOGI(TAG, "[%s] Logging into AM43", this->get_name().c_str());
33  if (status) {
34  ESP_LOGW(TAG, "[%s] Error writing set_pin to device, error = %d", this->get_name().c_str(), status);
35  } else {
36  this->logged_in_ = true;
37  }
38  }
39 }
40 
42  auto traits = CoverTraits();
43  traits.set_supports_stop(true);
44  traits.set_supports_position(true);
45  traits.set_supports_tilt(false);
46  traits.set_is_assumed_state(false);
47  return traits;
48 }
49 
50 void Am43Component::control(const CoverCall &call) {
51  if (this->node_state != espbt::ClientState::ESTABLISHED) {
52  ESP_LOGW(TAG, "[%s] Cannot send cover control, not connected", this->get_name().c_str());
53  return;
54  }
55  if (call.get_stop()) {
56  auto *packet = this->encoder_->get_stop_request();
57  auto status =
58  esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
59  packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
60  if (status) {
61  ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status);
62  }
63  }
64  if (call.get_position().has_value()) {
65  auto pos = *call.get_position();
66 
67  if (this->invert_position_)
68  pos = 1 - pos;
69  auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t) (pos * 100));
70  auto status =
71  esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
72  packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
73  if (status) {
74  ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", this->get_name().c_str(), status);
75  }
76  }
77 }
78 
79 void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
80  esp_ble_gattc_cb_param_t *param) {
81  switch (event) {
82  case ESP_GATTC_DISCONNECT_EVT: {
83  this->logged_in_ = false;
84  break;
85  }
86  case ESP_GATTC_SEARCH_CMPL_EVT: {
87  auto *chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID);
88  if (chr == nullptr) {
89  if (this->parent_->get_characteristic(AM43_TUYA_SERVICE_UUID, AM43_TUYA_CHARACTERISTIC_UUID) != nullptr) {
90  ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.", this->get_name().c_str());
91  } else {
92  ESP_LOGE(TAG, "[%s] No control service found at device, not an AM43..?", this->get_name().c_str());
93  }
94  break;
95  }
96  this->char_handle_ = chr->handle;
97 
98  auto status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
99  chr->handle);
100  if (status) {
101  ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
102  }
103  break;
104  }
105  case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
106  this->node_state = espbt::ClientState::ESTABLISHED;
107  break;
108  }
109  case ESP_GATTC_NOTIFY_EVT: {
110  if (param->notify.handle != this->char_handle_)
111  break;
112  this->decoder_->decode(param->notify.value, param->notify.value_len);
113 
114  if (this->decoder_->has_position()) {
115  this->position = ((float) this->decoder_->position_ / 100.0);
116  if (!this->invert_position_)
117  this->position = 1 - this->position;
118  if (this->position > 0.97)
119  this->position = 1.0;
120  if (this->position < 0.02)
121  this->position = 0.0;
122  this->publish_state();
123  }
124 
125  if (this->decoder_->has_pin_response()) {
126  if (this->decoder_->pin_ok_) {
127  ESP_LOGI(TAG, "[%s] AM43 pin accepted.", this->get_name().c_str());
128  auto *packet = this->encoder_->get_position_request();
129  auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
130  this->char_handle_, packet->length, packet->data,
131  ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
132  if (status) {
133  ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", this->get_name().c_str(), status);
134  }
135  } else {
136  ESP_LOGW(TAG, "[%s] AM43 pin rejected!", this->get_name().c_str());
137  }
138  }
139 
140  if (this->decoder_->has_set_position_response() && !this->decoder_->set_position_ok_) {
141  ESP_LOGW(TAG, "[%s] Got nack after sending set_position. Bad pin?", this->get_name().c_str());
142  }
143 
144  if (this->decoder_->has_set_state_response() && !this->decoder_->set_state_ok_) {
145  ESP_LOGW(TAG, "[%s] Got nack after sending set_state. Bad pin?", this->get_name().c_str());
146  }
147  break;
148  }
149  default:
150  break;
151  }
152 }
153 
154 } // namespace am43
155 } // namespace esphome
156 
157 #endif
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) override
Definition: am43_cover.cpp:79
bool has_value() const
Definition: optional.h:87
const float COVER_OPEN
Definition: cover.cpp:9
void dump_config() override
Definition: am43_cover.cpp:13
void control(const cover::CoverCall &call) override
Definition: am43_cover.cpp:50
uint8_t status
Definition: bl0942.h:23
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
float position
Definition: cover.h:14
cover::CoverTraits get_traits() override
Definition: am43_cover.cpp:41
const optional< float > & get_position() const
Definition: cover.cpp:97
bool get_stop() const
Definition: cover.cpp:147