mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Anova fahrenheit support (#2126)
Co-authored-by: Ben Buxton <bb@cactii.net>
This commit is contained in:
		| @@ -90,19 +90,24 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_ | |||||||
|       if (this->codec_->has_running()) { |       if (this->codec_->has_running()) { | ||||||
|         this->mode = this->codec_->running_ ? climate::CLIMATE_MODE_HEAT : climate::CLIMATE_MODE_OFF; |         this->mode = this->codec_->running_ ? climate::CLIMATE_MODE_HEAT : climate::CLIMATE_MODE_OFF; | ||||||
|       } |       } | ||||||
|  |       if (this->codec_->has_unit()) { | ||||||
|  |         this->fahrenheit_ = (this->codec_->unit_ == 'f'); | ||||||
|  |         ESP_LOGD(TAG, "Anova units is %s", this->fahrenheit_ ? "fahrenheit" : "celcius"); | ||||||
|  |         this->current_request_++; | ||||||
|  |       } | ||||||
|       this->publish_state(); |       this->publish_state(); | ||||||
|  |  | ||||||
|       if (this->current_request_ > 0) { |       if (this->current_request_ > 1) { | ||||||
|         AnovaPacket *pkt = nullptr; |         AnovaPacket *pkt = nullptr; | ||||||
|         switch (this->current_request_++) { |         switch (this->current_request_++) { | ||||||
|           case 1: |           case 2: | ||||||
|             pkt = this->codec_->get_read_target_temp_request(); |             pkt = this->codec_->get_read_target_temp_request(); | ||||||
|             break; |             break; | ||||||
|           case 2: |           case 3: | ||||||
|             pkt = this->codec_->get_read_current_temp_request(); |             pkt = this->codec_->get_read_current_temp_request(); | ||||||
|             break; |             break; | ||||||
|           default: |           default: | ||||||
|             this->current_request_ = 0; |             this->current_request_ = 1; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if (pkt != nullptr) { |         if (pkt != nullptr) { | ||||||
| @@ -121,12 +126,16 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_ | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void Anova::set_unit_of_measurement(const char *unit) { this->fahrenheit_ = !strncmp(unit, "f", 1); } | ||||||
|  |  | ||||||
| void Anova::update() { | void Anova::update() { | ||||||
|   if (this->node_state != espbt::ClientState::Established) |   if (this->node_state != espbt::ClientState::Established) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   if (this->current_request_ == 0) { |   if (this->current_request_ < 2) { | ||||||
|     auto pkt = this->codec_->get_read_device_status_request(); |     auto pkt = this->codec_->get_read_device_status_request(); | ||||||
|  |     if (this->current_request_ == 0) | ||||||
|  |       auto pkt = this->codec_->get_set_unit_request(this->fahrenheit_ ? 'f' : 'c'); | ||||||
|     auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, |     auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, | ||||||
|                                            pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); |                                            pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||||
|     if (status) |     if (status) | ||||||
|   | |||||||
| @@ -36,12 +36,14 @@ class Anova : public climate::Climate, public esphome::ble_client::BLEClientNode | |||||||
|     traits.set_visual_temperature_step(0.1); |     traits.set_visual_temperature_step(0.1); | ||||||
|     return traits; |     return traits; | ||||||
|   } |   } | ||||||
|  |   void set_unit_of_measurement(const char *); | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   AnovaCodec *codec_; |   AnovaCodec *codec_; | ||||||
|   void control(const climate::ClimateCall &call) override; |   void control(const climate::ClimateCall &call) override; | ||||||
|   uint16_t char_handle_; |   uint16_t char_handle_; | ||||||
|   uint8_t current_request_; |   uint8_t current_request_; | ||||||
|  |   bool fahrenheit_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace anova | }  // namespace anova | ||||||
|   | |||||||
| @@ -3,6 +3,10 @@ | |||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace anova { | namespace anova { | ||||||
|  |  | ||||||
|  | float ftoc(float f) { return (f - 32.0) * (5.0f / 9.0f); } | ||||||
|  |  | ||||||
|  | float ctof(float c) { return (c * 9.0f / 5.0f) + 32.0; } | ||||||
|  |  | ||||||
| AnovaPacket *AnovaCodec::clean_packet_() { | AnovaPacket *AnovaCodec::clean_packet_() { | ||||||
|   this->packet_.length = strlen((char *) this->packet_.data); |   this->packet_.length = strlen((char *) this->packet_.data); | ||||||
|   this->packet_.data[this->packet_.length] = '\0'; |   this->packet_.data[this->packet_.length] = '\0'; | ||||||
| @@ -42,6 +46,8 @@ AnovaPacket *AnovaCodec::get_read_data_request() { | |||||||
|  |  | ||||||
| AnovaPacket *AnovaCodec::get_set_target_temp_request(float temperature) { | AnovaPacket *AnovaCodec::get_set_target_temp_request(float temperature) { | ||||||
|   this->current_query_ = SET_TARGET_TEMPERATURE; |   this->current_query_ = SET_TARGET_TEMPERATURE; | ||||||
|  |   if (this->fahrenheit_) | ||||||
|  |     temperature = ctof(temperature); | ||||||
|   sprintf((char *) this->packet_.data, CMD_SET_TARGET_TEMP, temperature); |   sprintf((char *) this->packet_.data, CMD_SET_TARGET_TEMP, temperature); | ||||||
|   return this->clean_packet_(); |   return this->clean_packet_(); | ||||||
| } | } | ||||||
| @@ -67,7 +73,6 @@ AnovaPacket *AnovaCodec::get_stop_request() { | |||||||
| void AnovaCodec::decode(const uint8_t *data, uint16_t length) { | void AnovaCodec::decode(const uint8_t *data, uint16_t length) { | ||||||
|   memset(this->buf_, 0, 32); |   memset(this->buf_, 0, 32); | ||||||
|   strncpy(this->buf_, (char *) data, length); |   strncpy(this->buf_, (char *) data, length); | ||||||
|   ESP_LOGV("anova", "Received: %s\n", this->buf_); |  | ||||||
|   this->has_target_temp_ = this->has_current_temp_ = this->has_unit_ = this->has_running_ = false; |   this->has_target_temp_ = this->has_current_temp_ = this->has_unit_ = this->has_running_ = false; | ||||||
|   switch (this->current_query_) { |   switch (this->current_query_) { | ||||||
|     case READ_DEVICE_STATUS: { |     case READ_DEVICE_STATUS: { | ||||||
| @@ -97,19 +102,32 @@ void AnovaCodec::decode(const uint8_t *data, uint16_t length) { | |||||||
|     } |     } | ||||||
|     case READ_TARGET_TEMPERATURE: { |     case READ_TARGET_TEMPERATURE: { | ||||||
|       this->target_temp_ = strtof(this->buf_, nullptr); |       this->target_temp_ = strtof(this->buf_, nullptr); | ||||||
|  |       if (this->fahrenheit_) | ||||||
|  |         this->target_temp_ = ftoc(this->target_temp_); | ||||||
|       this->has_target_temp_ = true; |       this->has_target_temp_ = true; | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|     case SET_TARGET_TEMPERATURE: { |     case SET_TARGET_TEMPERATURE: { | ||||||
|       this->target_temp_ = strtof(this->buf_, nullptr); |       this->target_temp_ = strtof(this->buf_, nullptr); | ||||||
|  |       if (this->fahrenheit_) | ||||||
|  |         this->target_temp_ = ftoc(this->target_temp_); | ||||||
|       this->has_target_temp_ = true; |       this->has_target_temp_ = true; | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|     case READ_CURRENT_TEMPERATURE: { |     case READ_CURRENT_TEMPERATURE: { | ||||||
|       this->current_temp_ = strtof(this->buf_, nullptr); |       this->current_temp_ = strtof(this->buf_, nullptr); | ||||||
|  |       if (this->fahrenheit_) | ||||||
|  |         this->current_temp_ = ftoc(this->current_temp_); | ||||||
|       this->has_current_temp_ = true; |       this->has_current_temp_ = true; | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|  |     case SET_UNIT: | ||||||
|  |     case READ_UNIT: { | ||||||
|  |       this->unit_ = this->buf_[0]; | ||||||
|  |       this->fahrenheit_ = this->buf_[0] == 'f'; | ||||||
|  |       this->has_unit_ = true; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|     default: |     default: | ||||||
|       break; |       break; | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -71,6 +71,7 @@ class AnovaCodec { | |||||||
|   bool has_unit_; |   bool has_unit_; | ||||||
|   bool has_running_; |   bool has_running_; | ||||||
|   char buf_[32]; |   char buf_[32]; | ||||||
|  |   bool fahrenheit_; | ||||||
|  |  | ||||||
|   CurrentQuery current_query_; |   CurrentQuery current_query_; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1,7 +1,12 @@ | |||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.components import climate, ble_client | from esphome.components import climate, ble_client | ||||||
| from esphome.const import CONF_ID | from esphome.const import CONF_ID, CONF_UNIT_OF_MEASUREMENT | ||||||
|  |  | ||||||
|  | UNITS = { | ||||||
|  |     "f": "f", | ||||||
|  |     "c": "c", | ||||||
|  | } | ||||||
|  |  | ||||||
| CODEOWNERS = ["@buxtronix"] | CODEOWNERS = ["@buxtronix"] | ||||||
| DEPENDENCIES = ["ble_client"] | DEPENDENCIES = ["ble_client"] | ||||||
| @@ -12,7 +17,12 @@ Anova = anova_ns.class_( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = ( | CONFIG_SCHEMA = ( | ||||||
|     climate.CLIMATE_SCHEMA.extend({cv.GenerateID(): cv.declare_id(Anova)}) |     climate.CLIMATE_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(Anova), | ||||||
|  |             cv.Required(CONF_UNIT_OF_MEASUREMENT): cv.enum(UNITS), | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|     .extend(ble_client.BLE_CLIENT_SCHEMA) |     .extend(ble_client.BLE_CLIENT_SCHEMA) | ||||||
|     .extend(cv.polling_component_schema("60s")) |     .extend(cv.polling_component_schema("60s")) | ||||||
| ) | ) | ||||||
| @@ -23,3 +33,4 @@ async def to_code(config): | |||||||
|     await cg.register_component(var, config) |     await cg.register_component(var, config) | ||||||
|     await climate.register_climate(var, config) |     await climate.register_climate(var, config) | ||||||
|     await ble_client.register_ble_node(var, config) |     await ble_client.register_ble_node(var, config) | ||||||
|  |     cg.add(var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT])) | ||||||
|   | |||||||
| @@ -1566,6 +1566,7 @@ climate: | |||||||
|   - platform: anova |   - platform: anova | ||||||
|     name: Anova cooker |     name: Anova cooker | ||||||
|     ble_client_id: ble_blah |     ble_client_id: ble_blah | ||||||
|  |     unit_of_measurement: c | ||||||
|  |  | ||||||
| midea_dongle: | midea_dongle: | ||||||
|   uart_id: uart0 |   uart_id: uart0 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user