mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 21:44:55 +01:00
Anova fahrenheit support (#2126)
Co-authored-by: Ben Buxton <bb@cactii.net>
This commit is contained in:
parent
29f72037fe
commit
fe7af21c91
6 changed files with 50 additions and 8 deletions
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue