ESPHome  2024.11.1
anova.cpp
Go to the documentation of this file.
1 #include "anova.h"
2 #include "esphome/core/log.h"
3 
4 #ifdef USE_ESP32
5 
6 namespace esphome {
7 namespace anova {
8 
9 static const char *const TAG = "anova";
10 
11 using namespace esphome::climate;
12 
13 void Anova::dump_config() { LOG_CLIMATE("", "Anova BLE Cooker", this); }
14 
15 void Anova::setup() {
16  this->codec_ = make_unique<AnovaCodec>();
17  this->current_request_ = 0;
18 }
19 
20 void Anova::loop() {}
21 
22 void Anova::control(const ClimateCall &call) {
23  if (call.get_mode().has_value()) {
24  ClimateMode mode = *call.get_mode();
25  AnovaPacket *pkt;
26  switch (mode) {
28  pkt = this->codec_->get_stop_request();
29  break;
31  pkt = this->codec_->get_start_request();
32  break;
33  default:
34  ESP_LOGW(TAG, "Unsupported mode: %d", mode);
35  return;
36  }
37  auto status =
38  esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
39  pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
40  if (status) {
41  ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
42  }
43  }
44  if (call.get_target_temperature().has_value()) {
45  auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
46  auto status =
47  esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
48  pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
49  if (status) {
50  ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
51  }
52  }
53 }
54 
55 void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) {
56  switch (event) {
57  case ESP_GATTC_DISCONNECT_EVT: {
58  this->current_temperature = NAN;
59  this->target_temperature = NAN;
60  this->publish_state();
61  break;
62  }
63  case ESP_GATTC_SEARCH_CMPL_EVT: {
64  auto *chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID);
65  if (chr == nullptr) {
66  ESP_LOGW(TAG, "[%s] No control service found at device, not an Anova..?", this->get_name().c_str());
67  ESP_LOGW(TAG, "[%s] Note, this component does not currently support Anova Nano.", this->get_name().c_str());
68  break;
69  }
70  this->char_handle_ = chr->handle;
71 
72  auto status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
73  chr->handle);
74  if (status) {
75  ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
76  }
77  break;
78  }
79  case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
80  this->node_state = espbt::ClientState::ESTABLISHED;
81  this->current_request_ = 0;
82  this->update();
83  break;
84  }
85  case ESP_GATTC_NOTIFY_EVT: {
86  if (param->notify.handle != this->char_handle_)
87  break;
88  this->codec_->decode(param->notify.value, param->notify.value_len);
89  if (this->codec_->has_target_temp()) {
90  this->target_temperature = this->codec_->target_temp_;
91  }
92  if (this->codec_->has_current_temp()) {
93  this->current_temperature = this->codec_->current_temp_;
94  }
95  if (this->codec_->has_running()) {
96  this->mode = this->codec_->running_ ? climate::CLIMATE_MODE_HEAT : climate::CLIMATE_MODE_OFF;
97  }
98  if (this->codec_->has_unit()) {
99  this->fahrenheit_ = (this->codec_->unit_ == 'f');
100  ESP_LOGD(TAG, "Anova units is %s", this->fahrenheit_ ? "fahrenheit" : "celsius");
101  this->current_request_++;
102  }
103  this->publish_state();
104 
105  if (this->current_request_ > 1) {
106  AnovaPacket *pkt = nullptr;
107  switch (this->current_request_++) {
108  case 2:
109  pkt = this->codec_->get_read_target_temp_request();
110  break;
111  case 3:
112  pkt = this->codec_->get_read_current_temp_request();
113  break;
114  default:
115  this->current_request_ = 1;
116  break;
117  }
118  if (pkt != nullptr) {
119  auto status =
120  esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
121  pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
122  if (status) {
123  ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
124  status);
125  }
126  }
127  }
128  break;
129  }
130  default:
131  break;
132  }
133 }
134 
135 void Anova::set_unit_of_measurement(const char *unit) { this->fahrenheit_ = !strncmp(unit, "f", 1); }
136 
138  if (this->node_state != espbt::ClientState::ESTABLISHED)
139  return;
140 
141  if (this->current_request_ < 2) {
142  auto *pkt = this->codec_->get_read_device_status_request();
143  if (this->current_request_ == 0)
144  this->codec_->get_set_unit_request(this->fahrenheit_ ? 'f' : 'c');
145  auto status =
146  esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
147  pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
148  if (status) {
149  ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
150  }
151  this->current_request_++;
152  }
153 }
154 
155 } // namespace anova
156 } // namespace esphome
157 
158 #endif
This class is used to encode all control actions on a climate device.
Definition: climate.h:33
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: anova.cpp:55
void control(const climate::ClimateCall &call) override
Definition: anova.cpp:22
const optional< ClimateMode > & get_mode() const
Definition: climate.cpp:273
The climate device is set to heat to reach the target temperature.
Definition: climate_mode.h:18
bool has_value() const
Definition: optional.h:87
void update() override
Definition: anova.cpp:137
void setup() override
Definition: anova.cpp:15
BedjetMode mode
BedJet operating mode.
Definition: bedjet_codec.h:183
void dump_config() override
Definition: anova.cpp:13
void loop() override
Definition: anova.cpp:20
const optional< float > & get_target_temperature() const
Definition: climate.cpp:274
ClimateMode
Enum for all modes a climate device can be in.
Definition: climate_mode.h:10
The climate device is off.
Definition: climate_mode.h:12
uint8_t status
Definition: bl0942.h:74
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
void set_unit_of_measurement(const char *unit)
Definition: anova.cpp:135
float target_temperature
Definition: climate.h:138