"Hopefully" improved comms on sthome canbus.

This commit is contained in:
Chris Stuurman 2025-09-04 21:35:47 +02:00
parent d28a51602a
commit 28e1253fc0
3 changed files with 328 additions and 215 deletions

View File

@ -20,23 +20,6 @@ substitutions:
CB_BATTERY_MANUFACTURER: 0x35E
# sthome messages
# can also use CB_GEYSER_TEMPERATURES: !lambda "return esphome::solar::cbf_sthome::CB_GEYSER_TEMPERATURES;", but will fail is assigned to non-templateable config option in .yaml config file
CB_GEYSER_TEMPERATURES: 0x400
CB_GEYSER_HEATING: 0x401
CB_GEYSER_ACTIVE_SCHEDULE: 0x402
CB_POWER_MAINS: 0x403
CB_POWER_INVERTER: 0x404
CB_POWER_PLUGS: 0x405
CB_POWER_LIGHTS: 0x406
CB_POWER_GEYSER: 0x407
CB_POWER_POOL: 0x408
CB_POWER_GENERATED: 0x409
CB_ENERGY_MAINS: 0x40A
CB_ENERGY_GEYSER: 0x40B
CB_ENERGY_POOL: 0x40C
CB_ENERGY_PLUGS: 0x40D
CB_ENERGY_LIGHTS: 0x40E
CB_ENERGY_HOUSE: 0x40F
CB_ENERGY_GENERATED: 0x410
CB_ENERGY_LOSS: 0x411
CB_CONTROLLER_STATES: 0x412
CB_MAX_RETRANSMISSIONS: 10
CB_RETRANSMISSION_INTERVAL: 1000ms

View File

@ -23,21 +23,13 @@ globals:
type: char[1 + ${DD_MAX_YEARS} * 5]
restore_value: yes
# initial_value: "{2022\n2023\n2024\n2025\n2026}"
- id: g_geyser_heating_on
type: bool
restore_value: no
initial_value: '0'
- id: g_utility_on
type: bool
restore_value: no
initial_value: '0'
# CAN BUS
- id: can_msgctr
type: int
restore_value: no
- id: g_cb_cache
type: solar::cbf_cache
restore_value: no
restore_value: no
esphome:
name: "${name}"
@ -56,6 +48,7 @@ esphome:
then:
- lambda: |-
id(can_msgctr) = 0;
id(update_heating_display).execute(false);
esp32:
board: esp32-s3-devkitc-1
@ -101,8 +94,8 @@ time:
- platform: homeassistant
id: time_source
update_interval: 360min # Change sync interval from default 5min to 6 hours
on_time_sync:
then:
# on_time_sync:
# then:
# - if: # Publish the time the device was last restarted, but only once.
# condition:
# lambda: 'return id(device_last_restart).state == "";'
@ -110,15 +103,13 @@ time:
# - text_sensor.template.publish:
# id: device_last_restart
# state: !lambda 'return id(time_source).now().strftime("%a %d %b %Y - %I:%M:%S %p");'
- script.execute: ind_heating_update
# - script.execute: time_update
# - script.execute: init_calendar
on_time:
- minutes: '*'
seconds: '*'
then:
- script.execute: ind_heating_update
# on_time:
# - minutes: '*'
# seconds: '*'
# then:
# - script.execute: time_update
# - lambda: |-
# id(get_calendar_days_state).execute("T");
@ -207,6 +198,9 @@ interval:
- interval: 30s
then:
- script.execute: send_info_request
- interval: 500ms
then:
- script.execute: send_quick_update_request
spi:
- id: spi_bus0
@ -247,27 +241,60 @@ canbus:
auto cbitem = cbf_store_pylon(id(can_msgctr), can_id, x, remote_transmission_request, time_obj.timestamp);
bool publish = id(g_cb_cache).additem(cbitem);
if(publish) {
ESP_LOGI(cbitem.tag().c_str(), "%s", cbitem.to_string().c_str());
//ESP_LOGI(cbitem.tag().c_str(), "%s", cbitem.to_string().c_str());
switch (can_id) {
case cbf_pylon::CB_BATTERY_STATE:
{
uint soc = static_cast<uint16_t>((x[1] << 8) + x[0]);
uint soh = static_cast<uint16_t>((x[3] << 8) + x[2]);
ESP_LOGI(cbitem.tag().c_str(), "SOC= %d%% SOH= %d%%", soc, soh);
}
}
}
}
else if(can_id >= 0x400 && can_id <= 0x580) {
auto cbitem = cbf_store_sthome(id(can_msgctr), can_id, x, remote_transmission_request, time_obj.timestamp);
bool publish = id(g_cb_cache).additem(cbitem);
//ESP_LOGI(cbitem.tag().c_str(), "%s P[%s]", cbitem.to_string().c_str(), publish ? "Y" : "N");
if(publish) {
ESP_LOGI(cbitem.tag().c_str(), "%s", cbitem.to_string().c_str());
//ESP_LOGI(cbitem.tag().c_str(), "%s", cbitem.to_string().c_str());
switch (can_id) {
case cbf_sthome::CB_CONTROLLER_STATES:
if(x[1] & 0x80 == 0)
lv_obj_add_flag(id(ind_geyser_on), LV_OBJ_FLAG_HIDDEN);
else
lv_obj_clear_flag(id(ind_geyser_on), LV_OBJ_FLAG_HIDDEN);
if(x[1] & 0x10 == 0)
lv_obj_add_flag(id(ind_utility_on), LV_OBJ_FLAG_HIDDEN);
else
lv_obj_clear_flag(id(ind_utility_on), LV_OBJ_FLAG_HIDDEN);
{
uint8_t alarms = x[0];
uint8_t states = x[1];
uint8_t modes = x[2];
id(update_heating_display).execute(states & 0x80 != 0);
//if(states & 0x40 == 0) {
// lv_obj_add_flag(id(ind_geyser_relay_on), LV_OBJ_FLAG_HIDDEN);
//}
//else {
// lv_obj_clear_flag(id(ind_geyser_relay_on), LV_OBJ_FLAG_HIDDEN);
//}
if(states & 0x20 == 0) {
lv_obj_add_flag(id(ind_utility_on), LV_OBJ_FLAG_HIDDEN);
}
else {
lv_obj_clear_flag(id(ind_utility_on), LV_OBJ_FLAG_HIDDEN);
}
}
break;
case cbf_sthome::CB_GEYSER_TEMPERATURE_TOP:
{
double temperature = (x[1] == 0xFF && x[0] == 0xFF) ? std::numeric_limits<double>::quiet_NaN() : (double) static_cast<int16_t>(256 * x[1] + x[0]) / 256;
if(!isnan(temperature)) {
id(update_temp_display).execute(temperature, rect_gtoptemp, ind_utility_on, lbl_gtoptemp);
}
}
break;
case cbf_sthome::CB_GEYSER_TEMPERATURE_BOTTOM:
{
double temperature = (x[1] == 0xFF && x[0] == 0xFF) ? std::numeric_limits<double>::quiet_NaN() : (double) static_cast<int16_t>(256 * x[1] + x[0]) / 256;
if(!isnan(temperature)) {
id(update_temp_display).execute(temperature, rect_gbottemp, ind_geyser_heating_on, lbl_gbottemp);
}
}
break;
case cbf_sthome::CB_GEYSER_TEMPERATURES:
id(update_temperature_display).execute(x);
}
}
}
@ -455,7 +482,7 @@ lvgl:
scrollbar_mode: "OFF"
widgets:
- image:
id: ind_geyser_on
id: ind_geyser_heating_on
align: CENTER #BOTTOM_RIGHT #TOP_RIGHT
src: icon_fire
image_recolor: RED
@ -1179,46 +1206,38 @@ sensor:
#
script:
- id: send_info_request
then:
- script.execute: send_request_block
- delay: 100ms
- script.execute: send_request_block
- delay: 100ms
- script.execute: send_request_block
- delay: 100ms
- script.execute: send_request_block
- delay: 100ms
- script.execute: send_request_block
- id: send_request_block
then:
- lambda: |-
using namespace solar;
id(g_cb_cache).send_request(id(canbus_sthome), cbf_sthome::CB_GEYSER_TEMPERATURES);
id(g_cb_cache).send_request(id(canbus_sthome), cbf_sthome::CB_CONTROLLER_STATES);
- id: update_temperature_display
parameters:
x: std::vector<uint8_t>&
- id: send_quick_update_request
then:
- lambda: |-
using namespace solar;
double temp_top = (x[1] == 0xFF && x[0] == 0xFF) ? std::numeric_limits<double>::quiet_NaN() : (double) static_cast<int16_t>(256 * x[1] + x[0]) / 256;
double temp_bot = (x[3] == 0xFF && x[2] == 0xFF) ? std::numeric_limits<double>::quiet_NaN() : (double) static_cast<int16_t>(256 * x[3] + x[2]) / 256;
double temp_amb = (x[5] == 0xFF && x[4] == 0xFF) ? std::numeric_limits<double>::quiet_NaN() : (double) static_cast<int16_t>(256 * x[5] + x[4]) / 256;
if(isnan(temp_top) || isnan(temp_bot)) {
// immediately request another can frame
id(g_cb_cache).send_request(id(canbus_sthome), cbf_sthome::CB_GEYSER_TEMPERATURES);
for(int i = 0; i < ${CB_MAX_RETRANSMISSIONS}; i++) {
id(send_request_block1).execute();
}
//ESP_LOGI("REC: ", "Geyser Temperatures: Top %.4f°C Bottom %.4f°C Ambient %.4f°C", temp_top, temp_bot, temp_amb);
if(!isnan(temp_top))
id(update_temp_display).execute(temp_top, rect_gtoptemp, ind_utility_on, lbl_gtoptemp);
if(!isnan(temp_bot))
id(update_temp_display).execute(temp_bot, rect_gbottemp, ind_geyser_on, lbl_gbottemp);
- id: send_info_request
then:
- lambda: |-
for(int i = 0; i < ${CB_MAX_RETRANSMISSIONS}; i++) {
id(send_request_block2).execute();
}
- id: send_request_block1
mode: queued
then:
- lambda: "id(g_cb_cache).send_request(id(canbus_sthome), solar::cbf_sthome::CB_CONTROLLER_STATES);"
- delay: 20ms
- id: send_request_block2
mode: queued
then:
- lambda: "id(g_cb_cache).send_request(id(canbus_sthome), solar::cbf_pylon::CB_BATTERY_STATE);"
- delay: 50ms
- lambda: "id(g_cb_cache).send_request(id(canbus_sthome), solar::cbf_sthome::CB_GEYSER_TEMPERATURE_TOP);"
- delay: 50ms
- lambda: "id(g_cb_cache).send_request(id(canbus_sthome), solar::cbf_sthome::CB_GEYSER_TEMPERATURE_BOTTOM);"
- delay: 50ms
- id: update_temp_display
mode: queued
parameters:
value: double
rect: lv_obj_t*
@ -1250,6 +1269,14 @@ script:
else
lv_label_set_text(label, buffer);
- id: update_heating_display
parameters:
heat_on: bool
then:
- lvgl.widget.update:
id: ind_geyser_heating_on
hidden: !lambda 'return !heat_on;'
# - id: time_update
# then:
# - lvgl.indicator.update:
@ -1286,12 +1313,6 @@ script:
# auto time_obj = id(time_source).now();
# return time_obj.strftime("%H:%M");
- id: ind_heating_update
then:
- lvgl.widget.update:
id: ind_geyser_on
hidden: !lambda return !id(g_geyser_heating_on);
# - id: init_calendar
# then:
# - lambda: |-

View File

@ -32,6 +32,7 @@ esphome:
id(timer_start) = 0;
id(can1_msgctr) = 0;
id(can2_msgctr) = 0;
id(g_cb_request_queue) = std::queue< std::set<uint32_t> >();
id(time_synched) = false;
id(init_fixed_public_holidays).execute();
id(init_schedule).execute();
@ -165,7 +166,11 @@ globals:
restore_value: no
- id: g_cb_cache # the cache is used to only accept a frame after it has been received a specified number of times within a specified period. this hopefully will iron out spurious corrupted frames
type: solar::cbf_cache
restore_value: no
restore_value: no
- id: g_cb_request_queue
type: std::queue< std::set<uint32_t> >
restore_value: no
esp32:
board: esp32dev
@ -361,111 +366,158 @@ time:
return time_obj.strftime("%Y-%m-%d %H:%M:%S");
interval:
- interval: 10s
- interval: 100ms
then:
lambda: |-
using namespace solar;
bool success = false;
if(!id(g_cb_request_queue).empty()) {
auto canid_set = id(g_cb_request_queue).front();
std::set<uint32_t> unhandled_set, failed_set;
for(auto& can_id : canid_set) {
switch(can_id) {
// pylon ids
case cbf_pylon::CB_BATTERY_LIMITS:
id(canbus_send_battery_limits).execute();
break;
case cbf_pylon::CB_BATTERY_STATE:
id(canbus_send_battery_state).execute();
break;
case cbf_pylon::CB_BATTERY_STATUS:
id(canbus_send_battery_status).execute();
break;
case cbf_pylon::CB_BATTERY_FAULT:
id(canbus_send_battery_fault).execute();
break;
case cbf_pylon::CB_BATTERY_REQUEST_FLAGS:
id(canbus_send_battery_request_flags).execute();
break;
case cbf_pylon::CB_BATTERY_MANUFACTURER:
id(canbus_send_battery_manufacturer).execute();
break;
// sthome ids
case cbf_sthome::CB_POWER_MAINS:
id(canbus_send_power_mains).execute();
break;
case cbf_sthome::CB_POWER_INVERTER:
id(canbus_send_power_inverter).execute();
break;
case cbf_sthome::CB_POWER_PLUGS:
id(canbus_send_power_plugs).execute();
break;
case cbf_sthome::CB_POWER_LIGHTS:
id(canbus_send_power_lights).execute();
break;
case cbf_sthome::CB_POWER_GEYSER:
id(canbus_send_power_geyser).execute();
break;
//case cbf_sthome::CB_POWER_POOL:
// id(canbus_send_power_pool).execute();
// break;
case cbf_sthome::CB_POWER_GENERATED:
id(canbus_send_power_generated).execute();
break;
case cbf_sthome::CB_ENERGY_MAINS:
id(canbus_send_energy_mains).execute();
break;
case cbf_sthome::CB_ENERGY_GEYSER:
id(canbus_send_energy_geyser).execute();
break;
//case cbf_sthome::CB_ENERGY_POOL:
// id(canbus_send_energy_pool).execute();
// break;
case cbf_sthome::CB_ENERGY_PLUGS:
id(canbus_send_energy_plugs).execute();
break;
case cbf_sthome::CB_ENERGY_LIGHTS:
id(canbus_send_energy_lights).execute();
break;
case cbf_sthome::CB_ENERGY_HOUSE:
id(canbus_send_energy_house).execute();
break;
case cbf_sthome::CB_ENERGY_GENERATED:
id(canbus_send_energy_generated).execute();
break;
case cbf_sthome::CB_ENERGY_LOSS:
id(canbus_send_energy_loss).execute();
break;
case cbf_sthome::CB_GEYSER_TEMPERATURE_TOP:
id(canbus_send_temperature_top).execute(success);
if(!success) {
failed_set.insert(can_id);
}
break;
case cbf_sthome::CB_GEYSER_TEMPERATURE_BOTTOM:
id(canbus_send_temperature_bottom).execute(success);
if(!success) {
failed_set.insert(can_id);
}
break;
case cbf_sthome::CB_GEYSER_TEMPERATURE_AMBIENT:
id(canbus_send_temperature_ambient).execute(success);
if(!success) {
failed_set.insert(can_id);
}
break;
case cbf_sthome::CB_CANBUS_ID08:
id(canbus_send_heartbeat).execute();
break;
default:
unhandled_set.insert(can_id);
}
}
id(g_cb_request_queue).pop(); // remove from queue
// do remaining can_ids, if any
bool time_isvalid = id(time_source).now().is_valid();
if(time_isvalid) {
for(auto& can_id : unhandled_set) {
switch(can_id) {
case cbf_sthome::CB_CONTROLLER_STATES:
id(canbus_send_controller_states).execute();
break;
case cbf_sthome::CB_GEYSER_HEATING:
id(canbus_send_geyser_heating).execute();
break;
case cbf_sthome::CB_GEYSER_ACTIVE_SCHEDULE:
id(canbus_send_geyser_active_schedule).execute();
break;
default:
ESP_LOGW("Unknown CAN_ID", "CAN_ID: 0x%X. Remote transmission request ignored!", can_id);
break;
}
}
}
else {
// re-insert unhandled can-ids to the back of the queue
id(canbus_add_to_queue).execute(unhandled_set, 5);
}
id(canbus_add_to_queue).execute(failed_set, 5);
}
- interval: ${CB_RETRANSMISSION_INTERVAL}
then:
lambda: |-
using namespace solar;
// we use the cache to handle recently received remote transmission requests. this allows for ironing out invalid (non-repeated) frames
ESP_LOGI("processing RTRs ", "%d publishable request(s) in cache", std::count_if(id(g_cb_cache).cache_map.begin(), id(g_cb_cache).cache_map.end(), [](auto& it) { auto& store = it.second.get_store(); return store.rtr && store.getpublish(); }));
// we have an outer loop to send 5 blocks of the requested frames to ensure delivery
for(int i = 0; i < 5; i++) {
// we have an outer loop to queue 5 blocks of the requested frames to ensure delivery
for(int i = 0; i < ${CB_MAX_RETRANMISSIONS}; i++) {
std::set<uint32_t> canid_set;
for(auto& kvp : id(g_cb_cache).cache_map) {
const auto& item = kvp.second;
auto& store = item.get_store();
if(store.rtr) {
//ESP_LOGI(store.tag().c_str(), "%s", store.to_string().c_str());
if(store.getpublish()) {
if(i == 4) {
ESP_LOGI(store.tag().c_str(), "%s", store.to_string().c_str()); // we display once using opportunity at end of sequence (when publish flag is reset)
canid_set.insert(store.can_id);
if(i == ${CB_MAX_RETRANMISSIONS} - 1) {
ESP_LOGI(store.tag().c_str(), "%s", store.to_string().c_str()); // we display once, using opportunity at end of sequence (when publish flag is reset)
store.setpublish(false);
}
switch(store.can_id) {
case cbf_sthome::CB_CANBUS_ID08:
ESP_LOGI("RTR", "HEARTBEAT");
id(canbus_send_heartbeat).execute();
break;
case cbf_sthome::CB_GEYSER_TEMPERATURES:
id(canbus_send_temperatures).execute();
break;
case cbf_sthome::CB_GEYSER_HEATING:
id(canbus_send_geyser_heating).execute();
break;
case cbf_sthome::CB_GEYSER_ACTIVE_SCHEDULE:
id(canbus_send_geyser_active_schedule).execute();
break;
case cbf_sthome::CB_POWER_MAINS:
id(canbus_send_power_mains).execute();
break;
case cbf_sthome::CB_POWER_INVERTER:
id(canbus_send_power_inverter).execute();
break;
case cbf_sthome::CB_POWER_PLUGS:
id(canbus_send_power_plugs).execute();
break;
case cbf_sthome::CB_POWER_LIGHTS:
id(canbus_send_power_lights).execute();
break;
case cbf_sthome::CB_POWER_GEYSER:
id(canbus_send_power_geyser).execute();
break;
//case cbf_sthome::CB_POWER_POOL:
// id(canbus_send_power_pool).execute();
// break;
case cbf_sthome::CB_POWER_GENERATED:
id(canbus_send_power_generated).execute();
break;
case cbf_sthome::CB_CONTROLLER_STATES:
id(canbus_send_controller_states).execute();
break;
case cbf_sthome::CB_ENERGY_MAINS:
id(canbus_send_energy_mains).execute();
break;
case cbf_sthome::CB_ENERGY_GEYSER:
id(canbus_send_energy_geyser).execute();
break;
//case cbf_sthome::CB_ENERGY_POOL:
// id(canbus_send_energy_pool).execute();
// break;
case cbf_sthome::CB_ENERGY_PLUGS:
id(canbus_send_energy_plugs).execute();
break;
case cbf_sthome::CB_ENERGY_LIGHTS:
id(canbus_send_energy_lights).execute();
break;
case cbf_sthome::CB_ENERGY_HOUSE:
id(canbus_send_energy_house).execute();
break;
case cbf_sthome::CB_ENERGY_GENERATED:
id(canbus_send_energy_generated).execute();
break;
case cbf_sthome::CB_ENERGY_LOSS:
id(canbus_send_energy_loss).execute();
break;
case cbf_pylon::CB_BATTERY_LIMITS:
id(canbus_send_battery_limits).execute();
break;
case cbf_pylon::CB_BATTERY_STATE:
id(canbus_send_battery_state).execute();
break;
case cbf_pylon::CB_BATTERY_STATUS:
id(canbus_send_battery_status).execute();
break;
case cbf_pylon::CB_BATTERY_FAULT:
id(canbus_send_battery_fault).execute();
break;
case cbf_pylon::CB_BATTERY_REQUEST_FLAGS:
id(canbus_send_battery_request_flags).execute();
break;
case cbf_pylon::CB_BATTERY_MANUFACTURER:
id(canbus_send_battery_manufacturer).execute();
break;
default:
ESP_LOGW(store.tag().c_str(), "Unhandled remote transmission request recieved!");
break;
}
}
}
}
id(g_cb_request_queue).push(canid_set);
}
canbus:
@ -484,12 +536,24 @@ canbus:
id(can2_msgctr)++;
using namespace solar;
auto time_obj = id(time_source).now();
if(time_obj.is_valid()) {
auto cbitem = cbf_store_sthome(id(can2_msgctr), can_id, x, remote_transmission_request, time_obj.timestamp);
bool publish = id(g_cb_cache).additem(cbitem);
if(publish) {
ESP_LOGI(cbitem.tag().c_str(), "%s", cbitem.to_string().c_str());
if(time_obj.is_valid()) {
if(can_id >= 0x350 && can_id < 0x380) {
auto cbitem = cbf_store_pylon(id(can2_msgctr), can_id, x, remote_transmission_request, time_obj.timestamp);
bool publish = id(g_cb_cache).additem(cbitem);
//if(publish) {
// ESP_LOGI(cbitem.tag().c_str(), "%s", cbitem.to_string().c_str());
//}
}
else if(can_id >= 0x400 && can_id <= 0x580) {
auto cbitem = cbf_store_sthome(id(can2_msgctr), can_id, x, remote_transmission_request, time_obj.timestamp);
bool publish = id(g_cb_cache).additem(cbitem);
//if(publish) {
// ESP_LOGI(cbitem.tag().c_str(), "%s", cbitem.to_string().c_str());
//}
}
else {
ESP_LOGI("WARN", "Request within unhandled range CAN_ID: 0x%X. Request ignored!", can_id);
}
}
- platform: mcp2515
@ -2725,31 +2789,43 @@ script:
j++;
}
- id: canbus_send_all_data
- id: canbus_add_to_queue
parameters:
can_id_set: std::set<uint32_t>&
max_requests: int
then:
- script.execute: canbus_send_temperatures
- script.execute: canbus_send_power_mains
- script.execute: canbus_send_power_inverter
- script.execute: canbus_send_power_plugs
- script.execute: canbus_send_power_lights
- script.execute: canbus_send_power_geyser
- script.execute: canbus_send_power_generated
- script.execute: canbus_send_energy_mains
- script.execute: canbus_send_energy_geyser
#- script.execute: canbus_send_energy_pool
- script.execute: canbus_send_energy_plugs
- script.execute: canbus_send_energy_lights
- script.execute: canbus_send_energy_house
- script.execute: canbus_send_energy_generated
- script.execute: canbus_send_energy_loss
# do date/time dependent values next
- if:
condition:
lambda: "return id(time_source).now().is_valid();"
then:
- script.execute: canbus_send_controller_states
- script.execute: canbus_send_geyser_heating
- script.execute: canbus_send_geyser_active_schedule
lambda: |-
if(!can_id_set.empty()) {
// check how many times can_ids are queued already
auto qcpy = id(g_cb_request_queue);
std::map<uint32_t, int> request_counts;
while (!qcpy.empty()) {
auto& cid_set = qcpy.front();
for(auto& can_id : can_id_set) {
if(cid_set.contains(can_id)) {
const auto& ret = request_counts.emplace(can_id, 1);
if(!ret.second) {
auto& kvp = *ret.first;
kvp.second++;
}
}
}
qcpy.pop();
}
std::set<uint32_t> newset;
// re-insert only those can-ids into newset that are queued less than max_requests times
for(const auto& kvp : request_counts) {
const auto& count = kvp.second;
if(count <= max_requests) {
newset.insert(kvp.first);
}
//else {
// ESP_LOGI("request_counts", "CAN_ID 0x%X, COUNT: %d not inserted!", kvp.first, count);
//}
}
// insert newset at the back of the queue with can_id request counts < max_requests
id(g_cb_request_queue).push(newset);
}
- id: canbus_send_heartbeat
then:
@ -2758,13 +2834,46 @@ script:
std::vector<uint8_t> x(cbf_sthome::heartbeat.begin(), cbf_sthome::heartbeat.end());
id(g_cb_cache).send_frame(id(canbus_sthome), cbf_sthome::CB_CANBUS_ID08, x);
- id: canbus_send_temperatures
# this one has a success output parameter, which will determine whether the frame should be resent later
- id: canbus_send_temperature_top
parameters:
success: bool&
then:
lambda: |-
using namespace solar;
if(!isnan(id(geyser_top_temperature).raw_state) || !isnan(id(geyser_bottom_temperature).raw_state) || !isnan(id(ambient_temperature).raw_state)) {
auto x = cb_frame::get_byte_stream(id(geyser_top_temperature).raw_state, -256, id(geyser_bottom_temperature).raw_state, -256, id(ambient_temperature).raw_state, -256);
id(g_cb_cache).send_frame(id(canbus_sthome), cbf_sthome::CB_GEYSER_TEMPERATURES, x);
auto temperature = id(geyser_top_temperature).raw_state;
success = !isnan(temperature);
if(success) {
auto x = cb_frame::get_byte_stream(temperature, -256);
id(g_cb_cache).send_frame(id(canbus_sthome), cbf_sthome::CB_GEYSER_TEMPERATURE_TOP, x);
}
# this one has a success output parameter, which will determine whether the frame should be resent later
- id: canbus_send_temperature_bottom
parameters:
success: bool&
then:
lambda: |-
using namespace solar;
auto temperature = id(geyser_bottom_temperature).raw_state;
success = !isnan(temperature);
if(success) {
auto x = cb_frame::get_byte_stream(temperature, -256);
id(g_cb_cache).send_frame(id(canbus_sthome), cbf_sthome::CB_GEYSER_TEMPERATURE_BOTTOM, x);
}
# this one has a success output parameter, which will determine whether the frame should be resent later
- id: canbus_send_temperature_ambient
parameters:
success: bool&
then:
lambda: |-
using namespace solar;
auto temperature = id(ambient_temperature).raw_state;
success = !isnan(temperature);
if(success) {
auto x = cb_frame::get_byte_stream(temperature, -256);
id(g_cb_cache).send_frame(id(canbus_sthome), cbf_sthome::CB_GEYSER_TEMPERATURE_AMBIENT, x);
}
- id: canbus_send_geyser_heating
@ -2836,14 +2945,14 @@ script:
then:
lambda: |-
using namespace solar;
std::vector<uint8_t> byte_stream(8, 0);
std::vector<uint8_t> byte_stream(3, 0);
uint8_t& alarms = byte_stream[0];
uint8_t& states = byte_stream[1];
uint8_t& modes = byte_stream[2];
int geysermode = 0;
id(get_geyser_mode).execute(geysermode);
alarms = ((id(inverter_1_battery).state) ? 0x80 : 0) | ((id(inverter_2_battery).state) ? 0x10 : 0) | ((id(inverter1_2_overload).state) ? 0x08 : 0);
states = ((id(geyser_heating).state) ? 0x80 : 0) | ((id(mains_supply).state) ? 0x20 : 0) | ((id(battery_charging).state) ? 0x08 : 0);
states = ((id(geyser_heating).state) ? 0x80 : 0) | ((id(geyser_relay).state) ? 0x40 : 0) | ((id(mains_supply).state) ? 0x20 : 0) | ((id(battery_charging).state) ? 0x08 : 0);
modes = ((id(vacation_mode).state) ? 0x80 : 0) | ((geysermode << 4) & 0x70);
id(g_cb_cache).send_frame(id(canbus_sthome), cbf_sthome::CB_CONTROLLER_STATES, byte_stream);