342 lines
17 KiB
C++
342 lines
17 KiB
C++
#include "cbf_sthome.h"
|
|
|
|
namespace solar
|
|
{
|
|
// see common.h for definition of publish_spec_t
|
|
// publish_spec_t(int on_count, int interval, int timeout)
|
|
const publish_spec_t cbf_sthome::publish_spec = publish_spec_t(3, 15, 30); // default publish spec
|
|
const publish_spec_t cbf_sthome::rtr_publish_spec = publish_spec_t(2, 10, 40); // for remote transmission requests
|
|
|
|
const std::string cbf_sthome::heartbeat = "HELLO\0\0\0"; // must be exactly 8 bytes including null terminators
|
|
|
|
//cbf_sthome::cbf_sthome(int msg_id, uint32_t can_id, const byte_vector& frame, bool rtr)
|
|
// : cb_frame(msg_id, can_id, frame, rtr)
|
|
// {
|
|
// }
|
|
cbf_sthome& cbf_sthome::operator=(cbf_sthome&& src)
|
|
{
|
|
if (this != &src) {
|
|
cb_frame::operator=(std::move(src));
|
|
src.clear();
|
|
//ESP_LOGI(tag("pylon MOASS").c_str(), "%-20s %s", "Assigned pylon", this->to_string().c_str());
|
|
}
|
|
return *this;
|
|
}
|
|
void cbf_sthome::clear()
|
|
{
|
|
cb_frame::clear();
|
|
}
|
|
|
|
bool cbf_sthome::verify_heartbeat() const
|
|
{
|
|
const auto& x = this->frame;
|
|
std::string hb(reinterpret_cast<const char*>(x.data()), x.size());
|
|
hb.erase(std::find_if(hb.rbegin(), hb.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), hb.end());
|
|
return hb == heartbeat;
|
|
}
|
|
// float cbf_sthome::_get_battery_charge_voltage_limit() const
|
|
// {
|
|
// const auto& x = this->frame;
|
|
// return 0.1 * (float)((x[1] << 8) + x[0]);
|
|
// }
|
|
|
|
// Function to build a message from the pylon canbus frame
|
|
std::string cbf_sthome::to_string() const
|
|
{
|
|
char buffer[128];
|
|
const auto& x = this->frame;
|
|
switch (can_id)
|
|
{
|
|
case CB_CANBUS_ID01:
|
|
return rtr ? "Request for sthome-ut1 heartbeat" : verify_heartbeat() ? "sthome-ut1 alive" : "";
|
|
case CB_CANBUS_ID02:
|
|
return rtr ? "Request for sthome-ut2 heartbeat" : verify_heartbeat() ? "sthome-ut2 alive" : "";
|
|
case CB_CANBUS_ID03:
|
|
return rtr ? "Request for sthome-u3 heartbeat" : verify_heartbeat() ? "sthome-ut3 alive " : "";
|
|
case CB_CANBUS_ID04:
|
|
return rtr ? "Request for sthome-ut4 heartbeat" : verify_heartbeat() ? "sthome-ut4 alive" : "";
|
|
case CB_CANBUS_ID05:
|
|
return rtr ? "Request for sthome-ut5 heartbeat" : verify_heartbeat() ? "sthome-ut5 alive" : "";
|
|
case CB_CANBUS_ID06:
|
|
return rtr ? "Request for sthome-ut6 heartbeat" : verify_heartbeat() ? "sthome-ut6 alive" : "";
|
|
case CB_CANBUS_ID07:
|
|
return rtr ? "Request for sthome-ut7 heartbeat" : verify_heartbeat() ? "sthome-ut7 alive" : "";
|
|
case CB_CANBUS_ID08:
|
|
return rtr ? "Request for sthome-ut8 heartbeat" : verify_heartbeat() ? "sthome-ut8 alive" : "";
|
|
case CB_CANBUS_ID09:
|
|
return rtr ? "Request for sthome-ut9 heartbeat" : verify_heartbeat() ? "sthome-ut9 alive" : "";
|
|
case CB_CANBUS_ID10:
|
|
return rtr ? "Request for sthome-ut10 heartbeat" : verify_heartbeat() ? "sthome-ut10 alive" : "";
|
|
case CB_GEYSER_TEMPERATURE_TOP:
|
|
{
|
|
if(rtr) {
|
|
return "Request for geyser top temp";
|
|
}
|
|
double temp_top = get_double(x[0], x[1], 256, true);
|
|
snprintf (buffer, sizeof(buffer), "GEYSER TOP: %.2f°C", temp_top);
|
|
return buffer;
|
|
}
|
|
case CB_GEYSER_TEMPERATURE_BOTTOM:
|
|
{
|
|
if(rtr) {
|
|
return "Request for geyser bottom temp";
|
|
}
|
|
double temp_bot = get_double(x[0], x[1], 256, true);
|
|
snprintf (buffer, sizeof(buffer), "GEYSER BOT: %.2f°C", temp_bot);
|
|
return buffer;
|
|
}
|
|
case CB_GEYSER_TEMPERATURE_AMBIENT:
|
|
{
|
|
if(rtr) {
|
|
return "Request for geyser ambient temp";
|
|
}
|
|
double temp_amb = get_double(x[0], x[1], 256, true);
|
|
snprintf (buffer, sizeof(buffer), "GEYSER AMB: %.2f°C", temp_amb);
|
|
return buffer;
|
|
}
|
|
case CB_GEYSER_HEATING:
|
|
{
|
|
if(rtr) {
|
|
return "Request for geyser heating";
|
|
}
|
|
double heating_loss = get_double(x[0], x[1], 64, true); // -512W to 512W
|
|
double heat_gained = get_double(x[2], x[3], 128); // 0 to 512W
|
|
double calculated_heat_loss = get_double(x[4], x[5], 128); // 0 to 512W
|
|
unsigned int est_heating_time = (unsigned int) static_cast<uint16_t>(256 * x[7] + x[6]); // 0 to 65536 seconds
|
|
snprintf (buffer, sizeof(buffer), "Heat: loss %.3fW, gain %.3fW, calc loss %.3fW, est. heat time %ds", heating_loss, heat_gained, calculated_heat_loss, est_heating_time);
|
|
return buffer;
|
|
}
|
|
case CB_GEYSER_ACTIVE_SCHEDULE:
|
|
{
|
|
if(rtr) {
|
|
return "Request for geyser schedule";
|
|
}
|
|
double active_schedule_temp = get_double(x[0], x[1], 256, true); // -128 to 128°C
|
|
int active_heating_time = static_cast<int16_t>(256 * x[3] + x[2]); // -32768 to 32768s
|
|
double heating_overshoot_time = get_double(x[4], x[5], -64); // -512 to 512s
|
|
int active_schedule_day = static_cast<uint8_t>(x[6]);
|
|
snprintf (buffer, sizeof(buffer), "Geyser Schedule: target %.2f°C, heating time %ds, overshoot %.1fs, day %d", active_schedule_temp, active_heating_time, heating_overshoot_time, active_schedule_day);
|
|
return buffer;
|
|
}
|
|
case CB_POWER_MAINS:
|
|
{
|
|
if(rtr) {
|
|
return "Request for power mains";
|
|
}
|
|
double power = get_double(x[0], x[1], 2048); // 0 to 32kW
|
|
double voltage = get_double(x[2], x[3], 128); // 0 to 512V
|
|
double current = get_double(x[4], x[5], 512); // 0 to 128A
|
|
snprintf (buffer, sizeof(buffer), "Mains : %.3fV, %.3fA, %.3fkW", voltage, current, power);
|
|
return buffer;
|
|
}
|
|
case CB_POWER_INVERTER:
|
|
{
|
|
if(rtr) {
|
|
return "Request for power inverter";
|
|
}
|
|
double power = get_double(x[0], x[1], 2048); // 0 to 32kW
|
|
double voltage = get_double(x[2], x[3], 128); // 0 to 512V
|
|
double current = get_double(x[4], x[5], 512); // 0 to 128A
|
|
snprintf (buffer, sizeof(buffer), "InvOut: %.3fV, %.3fA, %.3fkW", voltage, current, power);
|
|
return buffer;
|
|
}
|
|
case CB_POWER_PLUGS:
|
|
{
|
|
if(rtr) {
|
|
return "Request for power plugs";
|
|
}
|
|
double power = get_double(x[0], x[1], 2048); // 0 to 32kW
|
|
double voltage = get_double(x[2], x[3], 128); // 0 to 512V
|
|
double current = get_double(x[4], x[5], 512); // 0 to 128A
|
|
snprintf (buffer, sizeof(buffer), "Plugs : %.3fV, %.3fA, %.3fkW", voltage, current, power);
|
|
return buffer;
|
|
}
|
|
case CB_POWER_LIGHTS:
|
|
{
|
|
if(rtr) {
|
|
return "Request for power lights";
|
|
}
|
|
double power = get_double(x[0], x[1], 2048); // 0 to 32kW
|
|
double voltage = get_double(x[2], x[3], 128); // 0 to 512V
|
|
double current = get_double(x[4], x[5], 512); // 0 to 128A
|
|
snprintf (buffer, sizeof(buffer), "Lights: %.3fV, %.3fA, %.3fkW", voltage, current, power);
|
|
return buffer;
|
|
}
|
|
case CB_POWER_GEYSER:
|
|
{
|
|
if(rtr) {
|
|
return "Request for power geyser";
|
|
}
|
|
double power = get_double(x[0], x[1], 2048); // 0 to 32kW
|
|
double voltage = get_double(x[2], x[3], 128); // 0 to 512V
|
|
double current = get_double(x[4], x[5], 512); // 0 to 128A
|
|
snprintf (buffer, sizeof(buffer), "Geyser: %.3fV, %.3fA, %.3fkW", voltage, current, power);
|
|
return buffer;
|
|
}
|
|
case CB_POWER_POOL:
|
|
{
|
|
if(rtr) {
|
|
return "Request for power pool";
|
|
}
|
|
double power = get_double(x[0], x[1], 2048); // 0 to 32kW
|
|
double voltage = get_double(x[2], x[3], 128); // 0 to 512V
|
|
double current = get_double(x[4], x[5], 512); // 0 to 128A
|
|
snprintf (buffer, sizeof(buffer), "Pool : %.3fV, %.3fA, %.3fkW", voltage, current, power);
|
|
return buffer;
|
|
}
|
|
case CB_POWER_GENERATED:
|
|
{
|
|
if(rtr) {
|
|
return "Request for power generated";
|
|
}
|
|
double power_generated = get_double(x[0], x[1], 2048); // 0 to 32kW
|
|
double power_loss = get_double(x[2], x[3], 2048); // 0 to 32kW
|
|
snprintf (buffer, sizeof(buffer), "Power : Generated %.3fkW, Loss %.3fkW", power_generated, power_loss);
|
|
return buffer;
|
|
}
|
|
case CB_ENERGY_MAINS:
|
|
{
|
|
if(rtr) {
|
|
return "Request for energy mains";
|
|
}
|
|
double energy_daily = get_double(x[0], x[1], 512); // 0 to 128kWh
|
|
double energy_monthly = get_double(x[2], x[3], 32); // 0 to 2048kWh
|
|
double energy_yearly = get_double(x[4], x[5], 2); // 0 to 32768kWh
|
|
double energy_lifetime = 0.01 * ((x[7] << 8) + x[6]); // 0 to 655MWh
|
|
snprintf (buffer, sizeof(buffer), "Mains Energy: day %.3fkWh, month %.3fkWh, year %.1fkWh, lifetime %.2fMWh", energy_daily, energy_monthly, energy_yearly, energy_lifetime);
|
|
return buffer;
|
|
}
|
|
case CB_ENERGY_GEYSER:
|
|
{
|
|
if(rtr) {
|
|
return "Request for energy geyser";
|
|
}
|
|
double energy_daily = get_double(x[0], x[1], 512); // 0 to 128kWh
|
|
double energy_monthly = get_double(x[2], x[3], 32); // 0 to 2048kWh
|
|
double energy_yearly = get_double(x[4], x[5], 2); // 0 to 32768kWh
|
|
double energy_lifetime = 0.01 * ((x[7] << 8) + x[6]); // 0 to 655MWh
|
|
snprintf (buffer, sizeof(buffer), "Geyser Energy day %.3fkWh, month %.3fkWh, year %.1fkWh, lifetime %.2fMWh", energy_daily, energy_monthly, energy_yearly, energy_lifetime);
|
|
return buffer;
|
|
}
|
|
case CB_ENERGY_POOL:
|
|
{
|
|
if(rtr) {
|
|
return "Request for energy pool";
|
|
}
|
|
double energy_daily = get_double(x[0], x[1], 512); // 0 to 128kWh
|
|
double energy_monthly = get_double(x[2], x[3], 32); // 0 to 2048kWh
|
|
double energy_yearly = get_double(x[4], x[5], 2); // 0 to 32768kWh
|
|
double energy_lifetime = 0.01 * ((x[7] << 8) + x[6]); // 0 to 655MWh
|
|
snprintf (buffer, sizeof(buffer), "Pool Energy: day %.3fkWh, month %.3fkWh, year %.1fkWh, lifetime %.2fMWh", energy_daily, energy_monthly, energy_yearly, energy_lifetime);
|
|
return buffer;
|
|
}
|
|
case CB_ENERGY_PLUGS:
|
|
{
|
|
if(rtr) {
|
|
return "Request for energy plugs";
|
|
}
|
|
double energy_daily = get_double(x[0], x[1], 512); // 0 to 128kWh
|
|
double energy_monthly = get_double(x[2], x[3], 32); // 0 to 2048kWh
|
|
double energy_yearly = get_double(x[4], x[5], 2); // 0 to 32768kWh
|
|
double energy_lifetime = 0.01 * ((x[7] << 8) + x[6]); // 0 to 655MWh
|
|
snprintf (buffer, sizeof(buffer), "Plugs Energy: day %.3fkWh, month %.3fkWh, year %.1fkWh, lifetime %.2fMWh", energy_daily, energy_monthly, energy_yearly, energy_lifetime);
|
|
return buffer;
|
|
}
|
|
case CB_ENERGY_LIGHTS:
|
|
{
|
|
if(rtr) {
|
|
return "Request for energy lights";
|
|
}
|
|
double energy_daily = get_double(x[0], x[1], 512); // 0 to 128kWh
|
|
double energy_monthly = get_double(x[2], x[3], 32); // 0 to 2048kWh
|
|
double energy_yearly = get_double(x[4], x[5], 2); // 0 to 32768kWh
|
|
double energy_lifetime = 0.01 * ((x[7] << 8) + x[6]); // 0 to 655MWh
|
|
snprintf (buffer, sizeof(buffer), "Lights Energy: day %.3fkWh, month %.3fkWh, year %.1fkWh, lifetime %.2fMWh", energy_daily, energy_monthly, energy_yearly, energy_lifetime);
|
|
return buffer;
|
|
}
|
|
case CB_ENERGY_HOUSE:
|
|
{
|
|
if(rtr) {
|
|
return "Request for energy house";
|
|
}
|
|
double energy_daily = get_double(x[0], x[1], 512); // 0 to 128kWh
|
|
double energy_monthly = get_double(x[2], x[3], 32); // 0 to 2048kWh
|
|
double energy_yearly = get_double(x[4], x[5], 2); // 0 to 32768kWh
|
|
double energy_lifetime = 0.01 * ((x[7] << 8) + x[6]); // 0 to 655MWh
|
|
snprintf (buffer, sizeof(buffer), "House Energy: day %.3fkWh, month %.3fkWh, year %.1fkWh, lifetime %.2fMWh", energy_daily, energy_monthly, energy_yearly, energy_lifetime);
|
|
return buffer;
|
|
}
|
|
case CB_ENERGY_GENERATED:
|
|
{
|
|
if(rtr) {
|
|
return "Request for energy generated";
|
|
}
|
|
double energy_daily = get_double(x[0], x[1], 512); // 0 to 128kWh
|
|
double energy_monthly = get_double(x[2], x[3], 32); // 0 to 2048kWh
|
|
double energy_yearly = get_double(x[4], x[5], 2); // 0 to 32768kWh
|
|
double energy_lifetime = 0.01 * ((x[7] << 8) + x[6]); // 0 to 655MWh
|
|
snprintf (buffer, sizeof(buffer), "Generated Energy: day %.3fkWh, month %.3fkWh, year %.1fkWh, lifetime %.2fMWh", energy_daily, energy_monthly, energy_yearly, energy_lifetime);
|
|
return buffer;
|
|
}
|
|
case CB_ENERGY_LOSS:
|
|
{
|
|
if(rtr) {
|
|
return "Request for energy loss";
|
|
}
|
|
double energy_daily = get_double(x[0], x[1], 512); // 0 to 128kWh
|
|
double energy_monthly = get_double(x[2], x[3], 32); // 0 to 2048kWh
|
|
double energy_yearly = get_double(x[4], x[5], 2); // 0 to 32768kWh
|
|
double energy_lifetime = 0.01 * ((x[7] << 8) + x[6]); // 0 to 655MWh
|
|
snprintf (buffer, sizeof(buffer), "Energy Loss: day %.3fkWh, month %.3fkWh, year %.1fkWh, lifetime %.2fMWh", energy_daily, energy_monthly, energy_yearly, energy_lifetime);
|
|
return buffer;
|
|
}
|
|
case CB_CONTROLLER_STATES:
|
|
{
|
|
if(rtr) {
|
|
return "Request for controller states";
|
|
}
|
|
uint8_t alarms = x[0];
|
|
uint8_t states = x[1];
|
|
uint8_t modes = x[2];
|
|
bool inverter_1_battery_low = alarms & 0x80;
|
|
bool inverter_2_battery_low = alarms & 0x10;
|
|
bool inverter_overload = alarms & 0x08;
|
|
bool geyser_heating = states & 0x80;
|
|
bool geyser_energised = states & 0x40;
|
|
bool mains_supply_present = states & 0x20;
|
|
bool battery_charging = states & 0x08;
|
|
bool vacation_mode = modes & 0x80; // nobody at home
|
|
std::string mode = "";
|
|
int geysermode = (modes & 0x70) >> 4;
|
|
switch (geysermode) {
|
|
case GM_SUNDAY:
|
|
mode = "SUN";
|
|
break;
|
|
case GM_WORKDAY:
|
|
mode = "WRK";
|
|
break;
|
|
case GM_SATURDAY:
|
|
mode = "SAT";
|
|
break;
|
|
case GM_PUBLIC_HOLIDAY:
|
|
mode = "PUB";
|
|
break;
|
|
case GM_SCHOOL_HOLIDAY:
|
|
mode = "SCH";
|
|
break;
|
|
default:
|
|
mode = "UNK";
|
|
break;
|
|
}
|
|
snprintf(buffer, sizeof(buffer), "STATES: %s%s%s%s MODE: %s%s INV: %s%s%s", geyser_heating ? "HEAT " : "", geyser_energised ? "GEYSER " : "", mains_supply_present ? "MAINS " : "", battery_charging ? "BATCHG " : "", vacation_mode ? "VACA ": "", mode.c_str(), inverter_1_battery_low ? "INV LOBAT " : "", inverter_2_battery_low ? "INV2 LOBAT " : "", inverter_overload ? "INV OVL " : "");
|
|
return buffer;
|
|
}
|
|
|
|
}
|
|
if(rtr) {
|
|
return "Request for unknown sthome CAN ID";
|
|
}
|
|
return "Unknown CAN ID";
|
|
}
|
|
|
|
} // namespace solar
|