add select component

This commit is contained in:
Your Name 2023-03-23 15:25:02 +01:00
parent c21653fd1e
commit 1e452c1a12
17 changed files with 391 additions and 6 deletions

View File

@ -123,6 +123,24 @@ The following `type` values are available:
- `ELECTRIC_POWER_LEVEL`
- `AIRCON_MANUAL_TEMPERATURE`
### Select
Select components support read and write.
```yaml
select:
- platform: truma_inetbox
name: "Fan Mode"
type: HEATER_FAN_MODE_COMBI
```
The following `type` values are available:
- `HEATER_FAN_MODE_COMBI`
- `HEATER_FAN_MODE_VARIO_HEAT`
- `HEATER_ENERGY_MIX_GAS`
- `HEATER_ENERGY_MIX_DIESEL`
### Sensor
Sensors are read-only.

View File

@ -316,8 +316,6 @@ const u_int8_t *TrumaiNetBoxApp::lin_multiframe_recieved(const u_int8_t *message
// BB.00.1F.00.1E.00.00.22.FF.FF.FF.54.01.0C.0B.00.7C.03.02.01.00.01.0C.00.01.02.01.00.00
auto device = statusFrame->inner.device;
this->init_recieved_ = micros();
ESP_LOGD(TAG, "StatusFrameDevice %d/%d - %d.%02d.%02d %04X.%02X (%02X %02X)", device.device_id + 1,
device.device_count, device.software_revision[0], device.software_revision[1], device.software_revision[2],
device.hardware_revision_major, device.hardware_revision_minor, device.unknown_2, device.unknown_3);
@ -348,6 +346,15 @@ const u_int8_t *TrumaiNetBoxApp::lin_multiframe_recieved(const u_int8_t *message
this->aircon_device_ = TRUMA_DEVICE::AIRCON_DEVICE;
}
if (device.device_count == 2 && this->heater_device_ != TRUMA_DEVICE::UNKNOWN) {
// Assumption 2 devices mean CP Plus and Heater.
this->init_recieved_ = micros();
} else if (device.device_count == 3 && this->heater_device_ != TRUMA_DEVICE::UNKNOWN &&
this->aircon_device_ != TRUMA_DEVICE::UNKNOWN) {
// Assumption 3 devices mean CP Plus, Heater and Aircon.
this->init_recieved_ = micros();
}
return response;
} else {
ESP_LOGW(TAG, "Unknown message type %02X", header->message_type);

View File

@ -0,0 +1,162 @@
#include "TrumaHeaterSelect.h"
#include "esphome/core/log.h"
#include "esphome/components/truma_inetbox/helpers.h"
namespace esphome {
namespace truma_inetbox {
static const char *const TAG = "truma_inetbox.heater_select";
void TrumaHeaterSelect::setup() {
this->parent_->get_heater()->add_on_message_callback([this](const StatusFrameHeater *status) {
switch (this->type_) {
case TRUMA_SELECT_TYPE::HEATER_FAN_MODE:
switch (status->heating_mode) {
case HeatingMode::HEATING_MODE_ECO:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_FAN_MODE::ECO).value());
break;
case HeatingMode::HEATING_MODE_VARIO_HEAT_NIGHT:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_FAN_MODE::VARIO_HEAT_NIGHT).value());
break;
case HeatingMode::HEATING_MODE_HIGH:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_FAN_MODE::COMBI_HIGH).value());
break;
case HeatingMode::HEATING_MODE_VARIO_HEAT_AUTO:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_FAN_MODE::VARIO_HEAT_AUTO).value());
break;
case HeatingMode::HEATING_MODE_BOOST:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_FAN_MODE::BOOST).value());
break;
default:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_FAN_MODE::OFF).value());
break;
}
break;
case TRUMA_SELECT_TYPE::HEATER_ENERGY_MIX:
switch (status->energy_mix_a) {
case EnergyMix::ENERGY_MIX_GAS:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::GAS).value());
break;
case EnergyMix::ENERGY_MIX_MIX:
switch (status->el_power_level_a) {
case ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::MIX_1).value());
break;
case ElectricPowerLevel::ELECTRIC_POWER_LEVEL_1800:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::MIX_2).value());
break;
default:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::GAS).value());
break;
}
break;
case EnergyMix::ENERGY_MIX_ELECTRICITY:
switch (status->el_power_level_a) {
case ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::ELECTRIC_1).value());
break;
case ElectricPowerLevel::ELECTRIC_POWER_LEVEL_1800:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::ELECTRIC_2).value());
break;
default:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::GAS).value());
break;
}
break;
default:
this->publish_state(this->at((size_t) TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::GAS).value());
break;
}
break;
default:
break;
}
});
}
void TrumaHeaterSelect::control(const std::string &value) {
auto index = this->index_of(value);
if (!index.has_value()) {
return;
}
auto heater_device = this->parent_->get_heater_device();
auto status_heater = this->parent_->get_heater()->get_status();
float temp = temp_code_to_decimal(status_heater->target_temp_room, 0);
if (index.value() > 0 && temp < 5) {
temp = 5;
}
switch (this->type_) {
case TRUMA_SELECT_TYPE::HEATER_FAN_MODE:
switch ((TRUMA_SELECT_TYPE_HEATER_FAN_MODE) index.value()) {
case TRUMA_SELECT_TYPE_HEATER_FAN_MODE::ECO:
// case TRUMA_SELECT_TYPE_HEATER_FAN_MODE::VARIO_HEAT_NIGHT:
if (heater_device == TRUMA_DEVICE::CPPLUS_VARIO) {
this->parent_->get_heater()->action_heater_room(static_cast<u_int8_t>(temp),
HeatingMode::HEATING_MODE_VARIO_HEAT_NIGHT);
} else {
this->parent_->get_heater()->action_heater_room(static_cast<u_int8_t>(temp), HeatingMode::HEATING_MODE_ECO);
}
break;
case TRUMA_SELECT_TYPE_HEATER_FAN_MODE::COMBI_HIGH:
// case TRUMA_SELECT_TYPE_HEATER_FAN_MODE::VARIO_HEAT_AUTO:
if (heater_device == TRUMA_DEVICE::CPPLUS_VARIO) {
this->parent_->get_heater()->action_heater_room(static_cast<u_int8_t>(temp),
HeatingMode::HEATING_MODE_VARIO_HEAT_AUTO);
} else {
this->parent_->get_heater()->action_heater_room(static_cast<u_int8_t>(temp), HeatingMode::HEATING_MODE_HIGH);
}
break;
case TRUMA_SELECT_TYPE_HEATER_FAN_MODE::BOOST:
this->parent_->get_heater()->action_heater_room(static_cast<u_int8_t>(temp), HeatingMode::HEATING_MODE_BOOST);
break;
default:
this->parent_->get_heater()->action_heater_room(0, HeatingMode::HEATING_MODE_OFF);
break;
}
break;
case TRUMA_SELECT_TYPE::HEATER_ENERGY_MIX:
switch ((TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX) index.value()) {
case TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::GAS:
this->parent_->get_heater()->action_heater_energy_mix(EnergyMix::ENERGY_MIX_GAS);
break;
case TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::MIX_1:
this->parent_->get_heater()->action_heater_energy_mix(EnergyMix::ENERGY_MIX_MIX,
ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900);
break;
case TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::MIX_2:
this->parent_->get_heater()->action_heater_energy_mix(EnergyMix::ENERGY_MIX_MIX,
ElectricPowerLevel::ELECTRIC_POWER_LEVEL_1800);
break;
case TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::ELECTRIC_1:
this->parent_->get_heater()->action_heater_energy_mix(EnergyMix::ENERGY_MIX_ELECTRICITY,
ElectricPowerLevel::ELECTRIC_POWER_LEVEL_900);
break;
case TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX::ELECTRIC_2:
this->parent_->get_heater()->action_heater_energy_mix(EnergyMix::ENERGY_MIX_ELECTRICITY,
ElectricPowerLevel::ELECTRIC_POWER_LEVEL_1800);
break;
default:
break;
}
break;
default:
break;
}
}
void TrumaHeaterSelect::dump_config() {
LOG_SELECT("", "Truma Heater Select", this);
ESP_LOGCONFIG(TAG, " Type '%s'", enum_to_c_str(this->type_));
ESP_LOGCONFIG(TAG, " Options are:");
// auto options = this->traits.get_options();
// for (auto i = 0; i < this->mappings_.size(); i++) {
// ESP_LOGCONFIG(TAG, " %i: %s", this->mappings_.at(i), options.at(i).c_str());
// }
}
} // namespace truma_inetbox
} // namespace esphome

View File

@ -0,0 +1,26 @@
#pragma once
#include "enum.h"
#include "esphome/components/select/select.h"
#include "esphome/components/truma_inetbox/TrumaiNetBoxApp.h"
namespace esphome {
namespace truma_inetbox {
class TrumaHeaterSelect : public Component, public select::Select, public Parented<TrumaiNetBoxApp> {
public:
void setup() override;
void dump_config() override;
void set_type(TRUMA_SELECT_TYPE val) { this->type_ = val; }
protected:
TRUMA_SELECT_TYPE type_;
void control(const std::string &value) override;
private:
};
} // namespace truma_inetbox
} // namespace esphome

View File

@ -0,0 +1,89 @@
from esphome.components import select
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import (
CONF_ID,
CONF_TYPE,
CONF_ICON,
CONF_OPTIONS,
ICON_THERMOMETER,
)
from .. import truma_inetbox_ns, CONF_TRUMA_INETBOX_ID, TrumaINetBoxApp
DEPENDENCIES = ["truma_inetbox"]
CODEOWNERS = ["@Fabian-Schmidt"]
CONF_CLASS = "class"
TrumaSelect = truma_inetbox_ns.class_(
"TrumaSelect", select.Select, cg.Component)
# `TRUMA_SELECT_TYPE` is a enum class and not a namespace but it works.
TRUMA_SELECT_TYPE_dummy_ns = truma_inetbox_ns.namespace("TRUMA_SELECT_TYPE")
CONF_SUPPORTED_TYPE = {
"HEATER_FAN_MODE_COMBI": {
CONF_CLASS: truma_inetbox_ns.class_("TrumaHeaterSelect", select.Select, cg.Component),
CONF_TYPE: TRUMA_SELECT_TYPE_dummy_ns.HEATER_FAN_MODE,
CONF_ICON: ICON_THERMOMETER,
CONF_OPTIONS: ("Off", "Eco", "High", "Boost"),
},
"HEATER_FAN_MODE_VARIO_HEAT": {
CONF_CLASS: truma_inetbox_ns.class_("TrumaHeaterSelect", select.Select, cg.Component),
CONF_TYPE: TRUMA_SELECT_TYPE_dummy_ns.HEATER_FAN_MODE,
CONF_ICON: ICON_THERMOMETER,
CONF_OPTIONS: ("Off", "Night", "Auto", "Boost"),
},
"HEATER_ENERGY_MIX_GAS": {
CONF_CLASS: truma_inetbox_ns.class_("TrumaHeaterSelect", select.Select, cg.Component),
CONF_TYPE: TRUMA_SELECT_TYPE_dummy_ns.HEATER_ENERGY_MIX,
CONF_ICON: ICON_THERMOMETER,
CONF_OPTIONS: ("Gas", "Mix 1", "Mix 2", "Electric 1", "Electric 2"),
},
"HEATER_ENERGY_MIX_DIESEL": {
CONF_CLASS: truma_inetbox_ns.class_("TrumaHeaterSelect", select.Select, cg.Component),
CONF_TYPE: TRUMA_SELECT_TYPE_dummy_ns.HEATER_ENERGY_MIX,
CONF_ICON: ICON_THERMOMETER,
CONF_OPTIONS: ("Diesel", "Mix 1", "Mix 2", "Electric 1", "Electric 2"),
},
}
def set_default_based_on_type():
def set_defaults_(config):
# update the class
config[CONF_ID].type = CONF_SUPPORTED_TYPE[config[CONF_TYPE]][CONF_CLASS]
# set defaults based on sensor type:
if CONF_ICON not in config:
config[CONF_ICON] = CONF_SUPPORTED_TYPE[config[CONF_TYPE]][CONF_ICON]
if CONF_OPTIONS not in config:
config[CONF_OPTIONS] = CONF_SUPPORTED_TYPE[config[CONF_TYPE]][CONF_OPTIONS]
return config
return set_defaults_
CONFIG_SCHEMA = select.SELECT_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(TrumaSelect),
cv.GenerateID(CONF_TRUMA_INETBOX_ID): cv.use_id(TrumaINetBoxApp),
cv.Required(CONF_TYPE): cv.enum(CONF_SUPPORTED_TYPE, upper=True),
cv.Optional(CONF_OPTIONS): cv.All(
cv.ensure_list(cv.string_strict), cv.Length(min=1)
),
}
).extend(cv.COMPONENT_SCHEMA)
FINAL_VALIDATE_SCHEMA = set_default_based_on_type()
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await select.register_select(
var,
config,
options=config[CONF_OPTIONS]
)
await cg.register_parented(var, config[CONF_TRUMA_INETBOX_ID])
cg.add(var.set_type(CONF_SUPPORTED_TYPE[config[CONF_TYPE]][CONF_TYPE]))

View File

@ -0,0 +1,50 @@
#pragma once
#include "esphome/core/log.h"
namespace esphome {
namespace truma_inetbox {
enum class TRUMA_SELECT_TYPE {
UNKNOWN,
HEATER_FAN_MODE,
HEATER_ENERGY_MIX,
};
enum class TRUMA_SELECT_TYPE_HEATER_FAN_MODE {
OFF = 0,
ECO = 1,
VARIO_HEAT_NIGHT = 1,
COMBI_HIGH = 2,
VARIO_HEAT_AUTO = 2,
BOOST = 3,
};
enum class TRUMA_SELECT_TYPE_HEATER_ENERGY_MIX {
GAS = 0,
MIX_1 = 1,
MIX_2 = 2,
ELECTRIC_1 = 3,
ELECTRIC_2 = 4,
};
#ifdef ESPHOME_LOG_HAS_CONFIG
static const char *enum_to_c_str(const TRUMA_SELECT_TYPE val) {
switch (val) {
case TRUMA_SELECT_TYPE::HEATER_FAN_MODE:
return "HEATER_FAN_MODE";
break;
case TRUMA_SELECT_TYPE::HEATER_ENERGY_MIX:
return "HEATER_ENERGY_MIX";
break;
default:
return "";
break;
}
}
#endif // ESPHOME_LOG_HAS_CONFIG
} // namespace truma_inetbox
} // namespace esphome

View File

@ -57,3 +57,8 @@ sensor:
- platform: truma_inetbox
name: "Current Water Temperature"
type: CURRENT_WATER_TEMPERATURE
select:
- platform: truma_inetbox
name: "Fan Mode"
type: HEATER_FAN_MODE_COMBI

View File

@ -58,7 +58,15 @@ sensor:
name: "Current Water Temperature"
type: CURRENT_WATER_TEMPERATURE
number:
select:
- platform: truma_inetbox
name: "electric power level"
type: ELECTRIC_POWER_LEVEL
name: "Fan Mode"
type: HEATER_FAN_MODE_COMBI
# Combi 4E / 6E:
- platform: truma_inetbox
name: "Energy Mix"
type: HEATER_ENERGY_MIX_GAS
# Combi 4DE / 6DE:
- platform: truma_inetbox
name: "Energy Mix"
type: HEATER_ENERGY_MIX_DIESEL

View File

@ -0,0 +1,12 @@
- platform: truma_inetbox
name: "Fan Mode Combi"
type: HEATER_FAN_MODE_COMBI
- platform: truma_inetbox
name: "Fan Mode Vario Heat"
type: HEATER_FAN_MODE_VARIO_HEAT
- platform: truma_inetbox
name: "Energy Mix Gas"
type: HEATER_ENERGY_MIX_GAS
- platform: truma_inetbox
name: "Energy Mix Diesel"
type: HEATER_ENERGY_MIX_DIESEL

View File

@ -30,5 +30,6 @@ binary_sensor: !include test.common.binary_sensor.yaml
button: !include test.common.button.yaml
climate: !include test.common.climate.yaml
number: !include test.common.number.yaml
select: !include test.common.select.yaml
sensor: !include test.common.sensor.yaml
switch: !include test.common.switch.yaml

View File

@ -37,5 +37,6 @@ binary_sensor: !include test.common.binary_sensor.yaml
button: !include test.common.button.yaml
climate: !include test.common.climate.yaml
number: !include test.common.number.yaml
select: !include test.common.select.yaml
sensor: !include test.common.sensor.yaml
switch: !include test.common.switch.yaml

View File

@ -24,5 +24,6 @@ binary_sensor: !include test.common.binary_sensor.yaml
button: !include test.common.button.yaml
climate: !include test.common.climate.yaml
number: !include test.common.number.yaml
select: !include test.common.select.yaml
sensor: !include test.common.sensor.yaml
switch: !include test.common.switch.yaml

View File

@ -34,5 +34,6 @@ binary_sensor: !include test.common.binary_sensor.yaml
button: !include test.common.button.yaml
climate: !include test.common.climate.yaml
number: !include test.common.number.yaml
select: !include test.common.select.yaml
sensor: !include test.common.sensor.yaml
switch: !include test.common.switch.yaml

View File

@ -37,5 +37,6 @@ binary_sensor: !include test.common.binary_sensor.yaml
button: !include test.common.button.yaml
climate: !include test.common.climate.yaml
number: !include test.common.number.yaml
select: !include test.common.select.yaml
sensor: !include test.common.sensor.yaml
switch: !include test.common.switch.yaml

View File

@ -34,5 +34,6 @@ binary_sensor: !include test.common.binary_sensor.yaml
button: !include test.common.button.yaml
climate: !include test.common.climate.yaml
number: !include test.common.number.yaml
select: !include test.common.select.yaml
sensor: !include test.common.sensor.yaml
switch: !include test.common.switch.yaml

View File

@ -37,5 +37,6 @@ binary_sensor: !include test.common.binary_sensor.yaml
button: !include test.common.button.yaml
climate: !include test.common.climate.yaml
number: !include test.common.number.yaml
select: !include test.common.select.yaml
sensor: !include test.common.sensor.yaml
switch: !include test.common.switch.yaml

View File

@ -34,5 +34,6 @@ binary_sensor: !include test.common.binary_sensor.yaml
button: !include test.common.button.yaml
climate: !include test.common.climate.yaml
number: !include test.common.number.yaml
select: !include test.common.select.yaml
sensor: !include test.common.sensor.yaml
switch: !include test.common.switch.yaml