mirror of
https://github.com/esphome/esphome.git
synced 2025-03-13 14:18:14 +00:00
Implement button controls and refactor action methods in diesel heater BLE component
This commit is contained in:
parent
850e6e0830
commit
1517148f37
53
esphome/components/diesel_heater_ble/button.h
Normal file
53
esphome/components/diesel_heater_ble/button.h
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/button/button.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "heater.h"
|
||||
#include "messages.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace diesel_heater_ble {
|
||||
|
||||
class LevelUpButton : public button::Button, public Parented<DieselHeaterBLE> {
|
||||
public:
|
||||
LevelUpButton() = default;
|
||||
|
||||
protected:
|
||||
void press_action() override {
|
||||
this->parent_->on_level_up_button_press();
|
||||
}
|
||||
};
|
||||
|
||||
class LevelDownButton : public button::Button, public Parented<DieselHeaterBLE> {
|
||||
public:
|
||||
LevelDownButton() = default;
|
||||
|
||||
protected:
|
||||
void press_action() override {
|
||||
this->parent_->on_level_down_button_press();
|
||||
}
|
||||
};
|
||||
|
||||
class TempUpButton : public button::Button, public Parented<DieselHeaterBLE> {
|
||||
public:
|
||||
TempUpButton() = default;
|
||||
|
||||
protected:
|
||||
void press_action() override {
|
||||
this->parent_->on_temp_up_button_press();
|
||||
}
|
||||
};
|
||||
|
||||
class TempDownButton : public button::Button, public Parented<DieselHeaterBLE> {
|
||||
public:
|
||||
TempDownButton() = default;
|
||||
|
||||
protected:
|
||||
void press_action() override {
|
||||
this->parent_->on_temp_down_button_press();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace diesel_heater
|
||||
} // namespace esphome
|
46
esphome/components/diesel_heater_ble/button.py
Normal file
46
esphome/components/diesel_heater_ble/button.py
Normal file
@ -0,0 +1,46 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import button
|
||||
|
||||
from . import DieselHeaterBLE, CONF_HEATER_ID, diesel_heater_ble_ns
|
||||
|
||||
CONF_LEVEL_UP_ID = "level_up"
|
||||
CONF_LEVEL_DOWN_ID = "level_down"
|
||||
CONF_TEMP_UP_ID = "temp_up"
|
||||
CONF_TEMP_DOWN_ID = "temp_down"
|
||||
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_HEATER_ID): cv.use_id(DieselHeaterBLE),
|
||||
cv.Optional(CONF_LEVEL_UP_ID): button.button_schema(
|
||||
diesel_heater_ble_ns.class_("LevelUpButton", button.Button),
|
||||
icon="mdi:arrow-up",
|
||||
),
|
||||
cv.Optional(CONF_LEVEL_DOWN_ID): button.button_schema(
|
||||
diesel_heater_ble_ns.class_("LevelDownButton", button.Button),
|
||||
icon="mdi:arrow-down",
|
||||
),
|
||||
cv.Optional(CONF_TEMP_UP_ID): button.button_schema(
|
||||
diesel_heater_ble_ns.class_("TempUpButton", button.Button),
|
||||
icon="mdi:arrow-up",
|
||||
),
|
||||
cv.Optional(CONF_TEMP_DOWN_ID): button.button_schema(
|
||||
diesel_heater_ble_ns.class_("TempDownButton", button.Button),
|
||||
icon="mdi:arrow-down",
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
parent = await cg.get_variable(config[CONF_HEATER_ID])
|
||||
|
||||
for var in [CONF_LEVEL_UP_ID, CONF_LEVEL_DOWN_ID, CONF_TEMP_UP_ID, CONF_TEMP_DOWN_ID]:
|
||||
if conf := config.get(var):
|
||||
sw_var = await button.new_button(conf)
|
||||
await cg.register_parented(sw_var, parent)
|
||||
cg.add(getattr(parent, f"set_{var}_button")(sw_var))
|
130
esphome/components/diesel_heater_ble/controllers.h
Normal file
130
esphome/components/diesel_heater_ble/controllers.h
Normal file
@ -0,0 +1,130 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
#include <cinttypes>
|
||||
#include "state.h"
|
||||
#include "messages.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace diesel_heater_ble {
|
||||
|
||||
class HeaterController {
|
||||
public:
|
||||
virtual std::vector<Request> gen_power_command(HeaterState state, bool power) = 0;
|
||||
virtual std::vector<Request> gen_level_command(HeaterState state, uint8_t value) = 0;
|
||||
virtual std::vector<Request> gen_level_up_command(HeaterState state) = 0;
|
||||
virtual std::vector<Request> gen_level_down_command(HeaterState state) = 0;
|
||||
virtual std::vector<Request> gen_temp_command(HeaterState state, uint8_t value) = 0;
|
||||
virtual std::vector<Request> gen_temp_up_command(HeaterState state) = 0;
|
||||
virtual std::vector<Request> gen_temp_down_command(HeaterState state) = 0;
|
||||
virtual std::vector<Request> get_manual_mode_command(HeaterState state) = 0;
|
||||
virtual std::vector<Request> get_auto_mode_command(HeaterState state) = 0;
|
||||
};
|
||||
|
||||
class HeaterController_AA55_E : public HeaterController {
|
||||
private:
|
||||
std::vector<Request> change_mode_command(HeaterState state, uint8_t target_mode) {
|
||||
std::vector<Request> requests;
|
||||
if (state.runningmode != target_mode) {
|
||||
requests.push_back(Request(0x02, target_mode, 0x00));
|
||||
}
|
||||
return requests;
|
||||
}
|
||||
|
||||
void debug_request(std::vector<Request> requests) {
|
||||
for (const auto &request : requests) {
|
||||
ESP_LOGI("", "Request: %s", format_hex_pretty(request.toBytes()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<Request> gen_power_command(HeaterState state, bool power) override {
|
||||
std::vector<Request> requests;
|
||||
if (state.runningstate != power) {
|
||||
requests.push_back(Request(0x03, power ? 0x01 : 0x00, 0x00));
|
||||
}
|
||||
this->debug_request(requests);
|
||||
return requests;
|
||||
}
|
||||
|
||||
std::vector<Request> gen_level_command(HeaterState state, uint8_t value) override {
|
||||
auto requests = get_manual_mode_command(state);
|
||||
if (state.setlevel != value) {
|
||||
requests.push_back(Request(0x04, value, 0x00));
|
||||
}
|
||||
this->debug_request(requests);
|
||||
return requests;
|
||||
}
|
||||
|
||||
std::vector<Request> gen_level_up_command(HeaterState state) override {
|
||||
auto requests = get_manual_mode_command(state);
|
||||
if (state.setlevel <= 9) {
|
||||
requests.push_back(Request(0x04, state.setlevel + 1, 0x00));
|
||||
}
|
||||
this->debug_request(requests);
|
||||
return requests;
|
||||
}
|
||||
|
||||
std::vector<Request> gen_level_down_command(HeaterState state) override {
|
||||
auto requests = get_manual_mode_command(state);
|
||||
if (state.setlevel > 1) {
|
||||
requests.push_back(Request(0x04, state.setlevel - 1, 0x00));
|
||||
}
|
||||
this->debug_request(requests);
|
||||
return requests;
|
||||
}
|
||||
|
||||
std::vector<Request> gen_temp_command(HeaterState state, uint8_t value) override {
|
||||
auto requests = get_auto_mode_command(state);
|
||||
if (state.settemp != value) {
|
||||
requests.push_back(Request(0x04, value, 0x00));
|
||||
}
|
||||
this->debug_request(requests);
|
||||
return requests;
|
||||
}
|
||||
|
||||
std::vector<Request> gen_temp_up_command(HeaterState state) override {
|
||||
auto requests = get_auto_mode_command(state);
|
||||
if (state.tempunit == 0x00 && state.settemp < 36) {
|
||||
requests.push_back(Request(0x04, state.settemp + 1, 0x00));
|
||||
} else if (state.tempunit == 0x01 && state.settemp < 97) {
|
||||
requests.push_back(Request(0x04, state.settemp + 1, 0x00));
|
||||
}
|
||||
this->debug_request(requests);
|
||||
return requests;
|
||||
}
|
||||
|
||||
std::vector<Request> gen_temp_down_command(HeaterState state) override {
|
||||
auto requests = get_auto_mode_command(state);
|
||||
if (state.tempunit == 0x00 && state.settemp > 8) {
|
||||
requests.push_back(Request(0x04, state.settemp - 1, 0x00));
|
||||
} else if (state.tempunit == 0x01 && state.settemp > 46) {
|
||||
requests.push_back(Request(0x04, state.settemp - 1, 0x00));
|
||||
}
|
||||
this->debug_request(requests);
|
||||
return requests;
|
||||
}
|
||||
|
||||
std::vector<Request> get_manual_mode_command(HeaterState state) override {
|
||||
return change_mode_command(state, 0x01);
|
||||
}
|
||||
|
||||
std::vector<Request> get_auto_mode_command(HeaterState state) override {
|
||||
return change_mode_command(state, 0x02);
|
||||
}
|
||||
};
|
||||
|
||||
class ControllerSelector {
|
||||
public:
|
||||
static HeaterController *get_controller(HeaterClass heater_class) {
|
||||
switch (heater_class) {
|
||||
case HeaterClass::HEATER_AA_55_ENCRYPTED:
|
||||
return new HeaterController_AA55_E();
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace diesel_heater_ble
|
||||
} // namespace esphome
|
@ -100,6 +100,14 @@ bool DieselHeaterBLE::ble_register_for_notify(esp_gatt_if_t gattc_if, esp_bd_add
|
||||
|
||||
void DieselHeaterBLE::on_notification_received(const std::vector<uint8_t> &data) {
|
||||
// ESP_LOGD(TAG, "Notification received: %s", format_hex_pretty(data).c_str());
|
||||
if (this->controller_ == nullptr) {
|
||||
this->controller_ = ControllerSelector::get_controller(ResponseParser::detect_heater_class(data));
|
||||
if (this->controller_ == nullptr) {
|
||||
ESP_LOGD(TAG, "Failed to get controller.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool ret = ResponseParser::parse(data, this->state_);
|
||||
if (!ret) {
|
||||
ESP_LOGD(TAG, "Failed to parse response.");
|
||||
@ -212,22 +220,46 @@ void DieselHeaterBLE::update_sensors(const HeaterState &new_state) {
|
||||
}
|
||||
}
|
||||
|
||||
void DieselHeaterBLE::set_power_level_action(float value) {
|
||||
if (this->get_state().runningmode == 2) {
|
||||
this->sent_request(SetRunningModeRequest(1).toBytes());
|
||||
}
|
||||
this->sent_request(SetLevelRequest(value + 1).toBytes());
|
||||
void DieselHeaterBLE::on_power_level_number(float value) {
|
||||
this->sent_requests(
|
||||
this->controller_->gen_level_command(this->state_, value)
|
||||
);
|
||||
}
|
||||
|
||||
void DieselHeaterBLE::set_temp_number_action(float value) {
|
||||
if (this->get_state().runningmode == 1) {
|
||||
this->sent_request(SetRunningModeRequest(2).toBytes());
|
||||
}
|
||||
this->sent_request(SetTemperatureRequest(value).toBytes());
|
||||
void DieselHeaterBLE::on_temp_number(float value) {
|
||||
this->sent_requests(
|
||||
this->controller_->gen_temp_command(this->state_, value)
|
||||
);
|
||||
}
|
||||
|
||||
void DieselHeaterBLE::set_power_switch_action(bool state) {
|
||||
this->sent_request(SetPowerRequest(state).toBytes());
|
||||
void DieselHeaterBLE::on_power_switch(bool state) {
|
||||
this->sent_requests(
|
||||
this->controller_->gen_power_command(this->state_, state)
|
||||
);
|
||||
}
|
||||
|
||||
void DieselHeaterBLE::on_level_up_button_press() {
|
||||
this->sent_requests(
|
||||
this->controller_->gen_level_up_command(this->state_)
|
||||
);
|
||||
}
|
||||
|
||||
void DieselHeaterBLE::on_level_down_button_press() {
|
||||
this->sent_requests(
|
||||
this->controller_->gen_level_down_command(this->state_)
|
||||
);
|
||||
}
|
||||
|
||||
void DieselHeaterBLE::on_temp_up_button_press() {
|
||||
this->sent_requests(
|
||||
this->controller_->gen_temp_up_command(this->state_)
|
||||
);
|
||||
}
|
||||
|
||||
void DieselHeaterBLE::on_temp_down_button_press() {
|
||||
this->sent_requests(
|
||||
this->controller_->gen_temp_down_command(this->state_)
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace diesel_heater_ble
|
||||
|
@ -10,11 +10,13 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/number/number.h"
|
||||
#include "esphome/components/switch/switch.h"
|
||||
#include "esphome/components/button/button.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include "messages.h"
|
||||
#include "state.h"
|
||||
#include "controllers.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace diesel_heater_ble {
|
||||
@ -33,6 +35,12 @@ class DieselHeaterBLE : public Component, public ble_client::BLEClientNode {
|
||||
this->ble_write_chr(this->parent()->get_gattc_if(), this->parent()->get_remote_bda(), this->handle_, data_.data(), data.size());
|
||||
}
|
||||
|
||||
void sent_requests(const std::vector<Request> &requests) {
|
||||
for (const auto &request : requests) {
|
||||
this->sent_request(request.toBytes());
|
||||
}
|
||||
}
|
||||
|
||||
bool ble_write_chr(esp_gatt_if_t gattc_if, esp_bd_addr_t remote_bda, uint16_t handle, uint8_t *data, uint16_t len);
|
||||
bool ble_read_chr(esp_gatt_if_t gattc_if, esp_bd_addr_t remote_bda, uint16_t handle);
|
||||
bool ble_register_for_notify(esp_gatt_if_t gattc_if, esp_bd_addr_t remote_bda);
|
||||
@ -63,17 +71,28 @@ class DieselHeaterBLE : public Component, public ble_client::BLEClientNode {
|
||||
void set_temp_unit(sensor::Sensor *sensor) { temp_unit_ = sensor; }
|
||||
void set_altitude_unit(sensor::Sensor *sensor) { altitude_unit_ = sensor; }
|
||||
void set_automatic_heating(sensor::Sensor *sensor) { automatic_heating_ = sensor; }
|
||||
|
||||
|
||||
// Button setters
|
||||
void set_level_up_button(button::Button *button) { level_up_button_ = button; }
|
||||
void set_level_down_button(button::Button *button) { level_down_button_ = button; }
|
||||
void set_temp_up_button(button::Button *button) { temp_up_button_ = button; }
|
||||
void set_temp_down_button(button::Button *button) { temp_down_button_ = button; }
|
||||
|
||||
void on_level_up_button_press();
|
||||
void on_level_down_button_press();
|
||||
void on_temp_up_button_press();
|
||||
void on_temp_down_button_press();
|
||||
|
||||
// Number setters
|
||||
void set_power_level_number(number::Number *number) { power_level_number_ = number; }
|
||||
void set_power_level_action(float value);
|
||||
void on_power_level_number(float value);
|
||||
|
||||
void set_set_temp_number(number::Number *number) { set_temp_number_ = number; }
|
||||
void set_temp_number_action(float value);
|
||||
void on_temp_number(float value);
|
||||
|
||||
// Switch setter
|
||||
void set_power_switch(switch_::Switch *sw) { power_switch_ = sw; }
|
||||
void set_power_switch_action(bool state);
|
||||
void on_power_switch(bool state);
|
||||
|
||||
|
||||
HeaterState get_state() {
|
||||
@ -86,6 +105,7 @@ class DieselHeaterBLE : public Component, public ble_client::BLEClientNode {
|
||||
esp32_ble_tracker::ESPBTUUID characteristic_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw("0000ffe1-0000-1000-8000-00805f9b34fb");
|
||||
|
||||
HeaterState state_;
|
||||
HeaterController *controller_{};
|
||||
|
||||
bool response_received_{false};
|
||||
uint32_t last_request_{0};
|
||||
@ -115,6 +135,11 @@ class DieselHeaterBLE : public Component, public ble_client::BLEClientNode {
|
||||
sensor::Sensor *altitude_unit_{};
|
||||
sensor::Sensor *automatic_heating_{};
|
||||
|
||||
button::Button *level_up_button_{};
|
||||
button::Button *level_down_button_{};
|
||||
button::Button *temp_up_button_{};
|
||||
button::Button *temp_down_button_{};
|
||||
|
||||
number::Number *power_level_number_{};
|
||||
number::Number *set_temp_number_{};
|
||||
|
||||
|
@ -33,19 +33,15 @@ public:
|
||||
}
|
||||
|
||||
static HeaterClass detect_heater_class(const std::vector<uint8_t> &raw) {
|
||||
if(raw[0] == 0xAA) {
|
||||
return raw[1] == 0x55 ? HeaterClass::HEATER_AA_55 : HeaterClass::HEATER_AA_66;
|
||||
} else if (raw[0] == 0xDA) {
|
||||
std::vector<uint8_t> decrypted = ResponseParser::decrypt(raw);
|
||||
if (decrypted[1] == 0x55) {
|
||||
switch (raw[1]) {
|
||||
case 0x55:
|
||||
return HeaterClass::HEATER_AA_55;
|
||||
case 0x66:
|
||||
return HeaterClass::HEATER_AA_66;
|
||||
case 0x07:
|
||||
return HeaterClass::HEATER_AA_55_ENCRYPTED;
|
||||
} else if (decrypted[1] == 0x66) {
|
||||
return HeaterClass::HEATER_AA_66_ENCRYPTED;
|
||||
} else {
|
||||
default:
|
||||
return HeaterClass::HEATER_CLASS_UNKNOWN;
|
||||
}
|
||||
} else {
|
||||
return HeaterClass::HEATER_CLASS_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ class PowerLevelNumber : public number::Number, public Parented<DieselHeaterBLE>
|
||||
|
||||
protected:
|
||||
void control(float value) override {
|
||||
this->parent_->set_power_level_action(value);
|
||||
this->parent_->on_power_level_number(value);
|
||||
}
|
||||
};
|
||||
|
||||
@ -24,7 +24,7 @@ class SetTempNumber : public number::Number, public Parented<DieselHeaterBLE> {
|
||||
|
||||
protected:
|
||||
void control(float value) override {
|
||||
this->parent_->set_temp_number_action(value);
|
||||
this->parent_->on_temp_number(value);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -14,7 +14,7 @@ class PowerSwitch : public switch_::Switch, public Parented<DieselHeaterBLE> {
|
||||
|
||||
protected:
|
||||
void write_state(bool state) override {
|
||||
this->parent_->set_power_switch_action(state);
|
||||
this->parent_->on_power_switch(state);
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user