Skip to content

Commit

Permalink
Merge pull request #11 from abichinger/hv
Browse files Browse the repository at this point in the history
Remove sensors.yaml and inputs.yaml
  • Loading branch information
nliaudat authored Feb 7, 2024
2 parents 11386e0 + dec4b25 commit f2c4973
Show file tree
Hide file tree
Showing 31 changed files with 486 additions and 57 deletions.
32 changes: 29 additions & 3 deletions esphome/components/toptronic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.components.canbus import CanbusComponent
from enum import Enum

CONF_TT_ID = "toptronic_id"
CONF_CANBUS_ID = "canbus_id"
Expand All @@ -28,6 +29,24 @@
"S64": TT_TYPE.S64,
}

class DeviceType(Enum):
WEZ = 0
SOL = 64
PS = 128
FW = 192
HK = 256
MWA = 384
GLT = 448
HV = 512
BM = 1024
GW = 1153

_device_types = {t.name: t.value for t in DeviceType}

def get_device_type(t: str) -> int:
if t not in _device_types:
raise f'device type "{t}" not found'
return _device_types.get(t)

CONF_DEVICE_TYPE = "device_type"
CONF_DEVICE_ADDR = "device_addr"
Expand All @@ -39,8 +58,8 @@

CONFIG_SCHEMA_BASE = cv.Schema(
{
cv.Optional(CONF_DEVICE_TYPE, 0): cv.uint8_t,
cv.Optional(CONF_DEVICE_ADDR, 0): cv.uint8_t,
cv.Required(CONF_DEVICE_TYPE): cv.string,
cv.Required(CONF_DEVICE_ADDR): cv.uint8_t,

cv.Required(CONF_FUNCTION_GROUP): cv.uint8_t,
cv.Required(CONF_FUNCTION_NUMBER): cv.uint8_t,
Expand All @@ -53,6 +72,8 @@
{
cv.GenerateID(): cv.declare_id(TopTronicComponent),
cv.GenerateID(CONF_CANBUS_ID): cv.use_id(CanbusComponent),
cv.Optional(CONF_DEVICE_TYPE, 'GW'): cv.string,
cv.Optional(CONF_DEVICE_ADDR, 1): cv.uint8_t,
}
)
.extend(cv.COMPONENT_SCHEMA)
Expand All @@ -61,4 +82,9 @@
async def to_code(config):
cbus = await cg.get_variable(config[CONF_CANBUS_ID])
var = cg.new_Pvariable(config[CONF_ID], cbus)
await cg.register_component(var, config)
await cg.register_component(var, config)

device_type = get_device_type(config[CONF_DEVICE_TYPE])
cg.add(var.set_device_type(device_type))
cg.add(var.set_device_addr(config[CONF_DEVICE_ADDR]))

8 changes: 4 additions & 4 deletions esphome/components/toptronic/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
CONF_DATAPOINT,
TT_TYPE_OPTIONS,
CONF_DECIMAL,
get_device_type,
)

TopTronicNumber = toptronic.class_(
Expand All @@ -33,7 +34,6 @@

CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(CONF_TT_ID): cv.use_id(TopTronicComponent),
cv.GenerateID(CONF_CANBUS_ID): cv.use_id(CanbusComponent),
cv.Required(CONF_TYPE): cv.enum(TT_TYPE_OPTIONS),
cv.Required(CONF_MAX_VALUE): cv.float_,
cv.Required(CONF_MIN_VALUE): cv.float_,
Expand All @@ -44,8 +44,7 @@
)).extend(CONFIG_SCHEMA_BASE)

async def new_number(config, *, min_value: float, max_value: float, step: float):
cbus = await cg.get_variable(config[CONF_CANBUS_ID])
var = cg.new_Pvariable(config[CONF_ID], cbus)
var = cg.new_Pvariable(config[CONF_ID])
await number.register_number(
var, config, min_value=min_value, max_value=max_value, step=step
)
Expand All @@ -61,7 +60,8 @@ async def to_code(config):
step=config[CONF_STEP] / divider,
)

cg.add(var.set_device_type(config[CONF_DEVICE_TYPE]))
device_type = get_device_type(config[CONF_DEVICE_TYPE])
cg.add(var.set_device_type(device_type))
cg.add(var.set_device_addr(config[CONF_DEVICE_ADDR]))
cg.add(var.set_function_group(config[CONF_FUNCTION_GROUP]))
cg.add(var.set_function_number(config[CONF_FUNCTION_NUMBER]))
Expand Down
8 changes: 4 additions & 4 deletions esphome/components/toptronic/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
CONF_FUNCTION_NUMBER,
CONF_DATAPOINT,
CONF_VALUES,
get_device_type,
)

TopTronicSelect = toptronic.class_(
Expand All @@ -28,7 +29,6 @@

CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(CONF_TT_ID): cv.use_id(TopTronicComponent),
cv.GenerateID(CONF_CANBUS_ID): cv.use_id(CanbusComponent),
cv.Required(CONF_OPTIONS): cv.All(
cv.ensure_list(cv.string_strict), cv.Length(min=1)
),
Expand All @@ -40,16 +40,16 @@
)).extend(CONFIG_SCHEMA_BASE)

async def new_select(config, *, options: list[str]):
cbus = await cg.get_variable(config[CONF_CANBUS_ID])
var = cg.new_Pvariable(config[CONF_ID], cbus)
var = cg.new_Pvariable(config[CONF_ID])
await select.register_select(var, config, options=options)
return var

async def to_code(config):
tt = await cg.get_variable(config[CONF_TT_ID])
var = await new_select(config, options=config[CONF_OPTIONS])

cg.add(var.set_device_type(config[CONF_DEVICE_TYPE]))
device_type = get_device_type(config[CONF_DEVICE_TYPE])
cg.add(var.set_device_type(device_type))
cg.add(var.set_device_addr(config[CONF_DEVICE_ADDR]))
cg.add(var.set_function_group(config[CONF_FUNCTION_GROUP]))
cg.add(var.set_function_number(config[CONF_FUNCTION_NUMBER]))
Expand Down
6 changes: 4 additions & 2 deletions esphome/components/toptronic/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
CONF_FUNCTION_GROUP,
CONF_FUNCTION_NUMBER,
CONF_DATAPOINT,
TT_TYPE_OPTIONS
TT_TYPE_OPTIONS,
get_device_type
)

TopTronicSensor = toptronic.class_(
Expand All @@ -36,7 +37,8 @@ async def to_code(config):
sens = await sensor.new_sensor(config)
await cg.register_component(sens, config)

cg.add(sens.set_device_type(config[CONF_DEVICE_TYPE]))
device_type = get_device_type(config[CONF_DEVICE_TYPE])
cg.add(sens.set_device_type(device_type))
cg.add(sens.set_device_addr(config[CONF_DEVICE_ADDR]))
cg.add(sens.set_function_group(config[CONF_FUNCTION_GROUP]))
cg.add(sens.set_function_number(config[CONF_FUNCTION_NUMBER]))
Expand Down
4 changes: 3 additions & 1 deletion esphome/components/toptronic/text_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
CONF_FUNCTION_NUMBER,
CONF_DATAPOINT,
CONF_VALUES,
get_device_type,
)

TopTronicTextSensor = toptronic.class_(
Expand All @@ -42,7 +43,8 @@ async def to_code(config):
sens = await text_sensor.new_text_sensor(config)
await cg.register_component(sens, config)

cg.add(sens.set_device_type(config[CONF_DEVICE_TYPE]))
device_type = get_device_type(config[CONF_DEVICE_TYPE])
cg.add(sens.set_device_type(device_type))
cg.add(sens.set_device_addr(config[CONF_DEVICE_ADDR]))
cg.add(sens.set_function_group(config[CONF_FUNCTION_GROUP]))
cg.add(sens.set_function_number(config[CONF_FUNCTION_NUMBER]))
Expand Down
43 changes: 28 additions & 15 deletions esphome/components/toptronic/toptronic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,11 @@ std::string hex_str(const uint8_t *data, int len)
}

uint32_t TopTronicBase::get_device_id() {
// ignore device id
return 0;
// return (device_type_ << 8) | device_addr_;
return device_type_ | device_addr_;
}

uint32_t build_can_id(uint8_t message_id, uint8_t priority, uint8_t device_type, uint8_t device_id) {
return (message_id << 24) | (priority << 16) | (device_type << 8) | device_id;
uint32_t build_can_id(uint16_t sender_id, uint16_t receiver_mask) {
return (0x7F << 22) | (sender_id << 11) | receiver_mask;
}

std::vector<uint8_t> build_get_request(uint8_t function_group, uint8_t function_number, uint32_t datapoint) {
Expand Down Expand Up @@ -73,6 +71,10 @@ std::vector<uint8_t> TopTronicBase::get_request_data() {
return build_get_request(function_group_, function_number_, datapoint_);
}

void TopTronicBase::add_on_set_callback(std::function<void(std::vector<uint8_t>)> &&callback) {
this->set_callback_.add(std::move(callback));
}

void TopTronicBase::add_on_update_callback(std::function<void()> &&callback) {
this->update_callback_.add(std::move(callback));
}
Expand Down Expand Up @@ -176,9 +178,8 @@ void TopTronicNumber::control(float value) {
float v = multiplier_ * value;
std::vector<uint8_t> bytes = floatToBytes(v, type_);

uint32_t can_id = 0xF1E40801;
std::vector<uint8_t> data = build_set_request(function_group_, function_number_, datapoint_, bytes);
canbus_->send_data(can_id, true, data);
set_callback_.call(data);

ESP_LOGI(TAG, "[SET] %s: %f, Data: 0x%s", get_name().c_str(), v, hex_str(&data[0], data.size()).c_str());
}
Expand All @@ -191,9 +192,8 @@ std::string TopTronicTextSensor::parse_value(std::vector<uint8_t> value) {
void TopTronicSelect::control(const std::string &text) {
uint8_t value = toValue_[text];

uint32_t can_id = 0xF1E40801;
std::vector<uint8_t> data = build_set_request(function_group_, function_number_, datapoint_, {value});
canbus_->send_data(can_id, true, data);
set_callback_.call(data);

ESP_LOGI(TAG, "[SET] %s: %s, Data: 0x%s", get_name().c_str(), text.c_str(), hex_str(&data[0], data.size()).c_str());
}
Expand Down Expand Up @@ -221,11 +221,9 @@ void TopTronic::register_sensor_callbacks() {
for (const auto &s : device->sensors) {
auto sensor = s.second;
auto canbus = canbus_;
uint32_t can_id = build_can_id(device_type_ | device_addr_, sensor->get_device_id());

sensor->add_on_update_callback([canbus, sensor]() -> void {
// TODO: resolve dirty hack to get room temperature from control module
// It looks like the can_id has to end with 0x412 = can_id & 0x7FF
uint32_t can_id = sensor->get_function_group() == 83 ? 0x1FE00C12 : 0xF1E40801;
sensor->add_on_update_callback([canbus, sensor, can_id]() -> void {
auto data = sensor->get_request_data();
canbus->send_data(can_id, true, data);

Expand All @@ -235,6 +233,21 @@ void TopTronic::register_sensor_callbacks() {
}
}

void TopTronic::register_input_callbacks() {
for (const auto &d : devices_) {
auto device = d.second;
for (const auto &i : device->inputs) {
auto input = i.second;
auto canbus = canbus_;
uint32_t can_id = build_can_id(device_type_ | device_addr_, input->get_device_id());

input->add_on_set_callback([canbus, input, can_id](std::vector<uint8_t> data) -> void {
canbus->send_data(can_id, true, data);
});
}
}
}

TopTronicBase* TopTronic::get_sensor(uint32_t device_id, uint32_t sensor_id) {
if (devices_.count(device_id) == 0) {
return NULL;
Expand Down Expand Up @@ -277,6 +290,7 @@ void TopTronic::link_inputs() {
void TopTronic::setup() {
link_inputs();
register_sensor_callbacks();
register_input_callbacks();
}

void TopTronic::loop() {
Expand Down Expand Up @@ -308,8 +322,7 @@ void TopTronic::parse_frame(std::vector<uint8_t> data, uint32_t can_id, bool rem
return;
}

// uint32_t device_id = can_id & 0xFFFF;
uint32_t device_id = 0;
uint32_t device_id = (can_id >> 11) & 0x7FF;

if (devices_.count(device_id) <= 0) {
return;
Expand Down
25 changes: 13 additions & 12 deletions esphome/components/toptronic/toptronic.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ enum SensorType {
TEXTSENSOR,
};

uint32_t build_can_id(uint8_t message_id, uint8_t priority, uint8_t device_type, uint8_t device_id);
uint32_t build_can_id(uint16_t sender_id, uint16_t receiver_mask);
std::vector<uint8_t> build_get_request(uint8_t function_group, uint8_t function_number, uint32_t datapoint);
std::vector<uint8_t> build_set_request(uint8_t function_group, uint8_t function_number, uint32_t datapoint, std::vector<uint8_t> value);

class TopTronicBase: public PollingComponent {
public:
void set_device_type(uint8_t device_type) { device_type_ = device_type; }
void set_device_type(uint16_t device_type) { device_type_ = device_type; }
void set_device_addr(uint8_t device_addr) { device_addr_ = device_addr; }

void set_function_group(uint8_t function_group) { function_group_ = function_group; }
Expand All @@ -43,22 +43,23 @@ class TopTronicBase: public PollingComponent {
uint32_t get_id();
uint32_t get_device_id();
std::vector<uint8_t> get_request_data();
uint8_t get_function_group() { return function_group_; }

virtual SensorType type() = 0;

void update() override;
void add_on_update_callback(std::function<void()> &&callback);
void add_on_set_callback(std::function<void(std::vector<uint8_t>)> &&callback);

protected:
uint8_t device_type_;
uint16_t device_type_;
uint8_t device_addr_;

uint8_t function_group_;
uint8_t function_number_;
uint16_t datapoint_;

CallbackManager<void()> update_callback_;
CallbackManager<void()> update_callback_;
CallbackManager<void(std::vector<uint8_t>)> set_callback_;
};

class TopTronicSensor: public sensor::Sensor, public TopTronicBase {
Expand All @@ -73,17 +74,14 @@ class TopTronicSensor: public sensor::Sensor, public TopTronicBase {
};

class TopTronicNumber: public number::Number, public TopTronicBase {
public:
explicit TopTronicNumber(canbus::Canbus *canbus): canbus_(canbus){};

public:
void set_type(TypeName type) { type_ = type; }
void set_multiplier(float multiplier) { multiplier_ = multiplier; }
float get_multiplier() { return multiplier_; }
SensorType type() override { return SENSOR; };
void control(float value) override;

protected:
canbus::Canbus *canbus_;
TypeName type_;
float multiplier_ = 1;
};
Expand All @@ -105,8 +103,6 @@ class TopTronicTextSensor: public text_sensor::TextSensor, public TopTronicBase

class TopTronicSelect: public select::Select, public TopTronicBase {
public:
explicit TopTronicSelect(canbus::Canbus *canbus): canbus_(canbus){};

SensorType type() override { return TEXTSENSOR; };

void add_option(uint8_t value, std::string text) {
Expand All @@ -115,7 +111,6 @@ class TopTronicSelect: public select::Select, public TopTronicBase {
}

protected:
canbus::Canbus *canbus_;
std::map<uint8_t, std::string> toText_;
std::map<std::string, uint8_t> toValue_;

Expand All @@ -136,6 +131,9 @@ class TopTronic : public Component {
void add_input(TopTronicBase *input);
void parse_frame(std::vector<uint8_t> data, uint32_t can_id, bool remote_transmission_request);
void register_sensor_callbacks();
void register_input_callbacks();
void set_device_type(uint16_t device_type) { device_type_ = device_type; }
void set_device_addr(uint8_t device_addr) { device_addr_ = device_addr; }

void setup() override;
void loop() override;
Expand All @@ -148,6 +146,9 @@ class TopTronic : public Component {

canbus::Canbus *canbus_;
std::map<uint32_t, TopTronicDevice*> devices_;

uint16_t device_type_;
uint8_t device_addr_;
};

} // namespace toptronic
Expand Down
9 changes: 4 additions & 5 deletions esphome/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ substitutions:
### canbus
can_tx_pin: "GPIO22" #GPIO5
can_rx_pin: "GPIO21" #GPIO4
TTE_HV_can_id: "8" #hoval homevent can_id (you can find it in room control unit (toptronic) under maintenance
TTE_BM_can_id: "8" #hoval toptronic can_id (used for password reveal)
## you can get the next values by activating the code under the section "Find can_id " in canbus.yaml
hoval_homevent_can_Addr: "0x1FD047FF" # to get sensors values | 0x1f ## works, but must process all frames and cpu is heating
hoval_toptronic_can_Addr: "0x1FE04208" #to send sensors requests
TT_HV_addr: "8" #hoval homevent can_id (you can find it in room control unit (toptronic) under maintenance
TT_BM_addr: "8"
TT_WEZ_addr: "1"


external_components:
- source:
Expand Down
Loading

0 comments on commit f2c4973

Please sign in to comment.