mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +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()) { | ||||
|         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(); | ||||
|  | ||||
|       if (this->current_request_ > 0) { | ||||
|       if (this->current_request_ > 1) { | ||||
|         AnovaPacket *pkt = nullptr; | ||||
|         switch (this->current_request_++) { | ||||
|           case 1: | ||||
|           case 2: | ||||
|             pkt = this->codec_->get_read_target_temp_request(); | ||||
|             break; | ||||
|           case 2: | ||||
|           case 3: | ||||
|             pkt = this->codec_->get_read_current_temp_request(); | ||||
|             break; | ||||
|           default: | ||||
|             this->current_request_ = 0; | ||||
|             this->current_request_ = 1; | ||||
|             break; | ||||
|         } | ||||
|         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() { | ||||
|   if (this->node_state != espbt::ClientState::Established) | ||||
|     return; | ||||
|  | ||||
|   if (this->current_request_ == 0) { | ||||
|   if (this->current_request_ < 2) { | ||||
|     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_, | ||||
|                                            pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||
|     if (status) | ||||
|   | ||||
| @@ -36,12 +36,14 @@ class Anova : public climate::Climate, public esphome::ble_client::BLEClientNode | ||||
|     traits.set_visual_temperature_step(0.1); | ||||
|     return traits; | ||||
|   } | ||||
|   void set_unit_of_measurement(const char *); | ||||
|  | ||||
|  protected: | ||||
|   AnovaCodec *codec_; | ||||
|   void control(const climate::ClimateCall &call) override; | ||||
|   uint16_t char_handle_; | ||||
|   uint8_t current_request_; | ||||
|   bool fahrenheit_; | ||||
| }; | ||||
|  | ||||
| }  // namespace anova | ||||
|   | ||||
| @@ -3,6 +3,10 @@ | ||||
| namespace esphome { | ||||
| 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_() { | ||||
|   this->packet_.length = strlen((char *) this->packet_.data); | ||||
|   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) { | ||||
|   this->current_query_ = SET_TARGET_TEMPERATURE; | ||||
|   if (this->fahrenheit_) | ||||
|     temperature = ctof(temperature); | ||||
|   sprintf((char *) this->packet_.data, CMD_SET_TARGET_TEMP, temperature); | ||||
|   return this->clean_packet_(); | ||||
| } | ||||
| @@ -67,7 +73,6 @@ AnovaPacket *AnovaCodec::get_stop_request() { | ||||
| void AnovaCodec::decode(const uint8_t *data, uint16_t length) { | ||||
|   memset(this->buf_, 0, 32); | ||||
|   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; | ||||
|   switch (this->current_query_) { | ||||
|     case READ_DEVICE_STATUS: { | ||||
| @@ -97,19 +102,32 @@ void AnovaCodec::decode(const uint8_t *data, uint16_t length) { | ||||
|     } | ||||
|     case READ_TARGET_TEMPERATURE: { | ||||
|       this->target_temp_ = strtof(this->buf_, nullptr); | ||||
|       if (this->fahrenheit_) | ||||
|         this->target_temp_ = ftoc(this->target_temp_); | ||||
|       this->has_target_temp_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case SET_TARGET_TEMPERATURE: { | ||||
|       this->target_temp_ = strtof(this->buf_, nullptr); | ||||
|       if (this->fahrenheit_) | ||||
|         this->target_temp_ = ftoc(this->target_temp_); | ||||
|       this->has_target_temp_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case READ_CURRENT_TEMPERATURE: { | ||||
|       this->current_temp_ = strtof(this->buf_, nullptr); | ||||
|       if (this->fahrenheit_) | ||||
|         this->current_temp_ = ftoc(this->current_temp_); | ||||
|       this->has_current_temp_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case SET_UNIT: | ||||
|     case READ_UNIT: { | ||||
|       this->unit_ = this->buf_[0]; | ||||
|       this->fahrenheit_ = this->buf_[0] == 'f'; | ||||
|       this->has_unit_ = true; | ||||
|       break; | ||||
|     } | ||||
|     default: | ||||
|       break; | ||||
|   } | ||||
|   | ||||
| @@ -71,6 +71,7 @@ class AnovaCodec { | ||||
|   bool has_unit_; | ||||
|   bool has_running_; | ||||
|   char buf_[32]; | ||||
|   bool fahrenheit_; | ||||
|  | ||||
|   CurrentQuery current_query_; | ||||
| }; | ||||
|   | ||||
| @@ -1,7 +1,12 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| 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"] | ||||
| DEPENDENCIES = ["ble_client"] | ||||
| @@ -12,7 +17,12 @@ Anova = anova_ns.class_( | ||||
| ) | ||||
|  | ||||
| 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(cv.polling_component_schema("60s")) | ||||
| ) | ||||
| @@ -23,3 +33,4 @@ async def to_code(config): | ||||
|     await cg.register_component(var, config) | ||||
|     await climate.register_climate(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 | ||||
|     name: Anova cooker | ||||
|     ble_client_id: ble_blah | ||||
|     unit_of_measurement: c | ||||
|  | ||||
| midea_dongle: | ||||
|   uart_id: uart0 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user