mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 00:39:50 +03:00
Merge branch 'v2' of https://github.com/proddy/EMS-ESP into v2
This commit is contained in:
@@ -56,7 +56,8 @@ void EMSESPShell::stopped() {
|
|||||||
|
|
||||||
// remove all custom contexts
|
// remove all custom contexts
|
||||||
commands->remove_all_commands();
|
commands->remove_all_commands();
|
||||||
_console_commands_loaded = false; // make sure they got loaded next time a console is opened
|
|
||||||
|
_console_commands_loaded = false; // make sure they get reloaded next time a console is opened
|
||||||
}
|
}
|
||||||
|
|
||||||
// show welcome banner
|
// show welcome banner
|
||||||
@@ -74,7 +75,7 @@ void EMSESPShell::display_banner() {
|
|||||||
printfln(F("│ │"));
|
printfln(F("│ │"));
|
||||||
|
|
||||||
if (System::safe_mode()) {
|
if (System::safe_mode()) {
|
||||||
printfln(F("│ %sIN SAFE MODE. EMS BUS IS DISABLED%s │"), COLOR_BRIGHT_RED_BACKGROUND, COLOR_RESET);
|
printfln(F("│ %sIN SAFE MODE. EMS BUS IS DISABLED%s │"), COLOR_BRIGHT_RED_BACKGROUND, COLOR_RESET);
|
||||||
#ifdef EMSESP_SAFE_MODE
|
#ifdef EMSESP_SAFE_MODE
|
||||||
printfln(F("│ %s!FORCED AT COMPILE TIME!%s │"), COLOR_BRIGHT_RED, COLOR_RESET);
|
printfln(F("│ %s!FORCED AT COMPILE TIME!%s │"), COLOR_BRIGHT_RED, COLOR_RESET);
|
||||||
#endif
|
#endif
|
||||||
@@ -101,7 +102,7 @@ void EMSESPShell::add_console_commands() {
|
|||||||
// just in case, remove everything
|
// just in case, remove everything
|
||||||
// commands->remove_context_commands(ShellContext::MAIN);
|
// commands->remove_context_commands(ShellContext::MAIN);
|
||||||
commands->remove_all_commands();
|
commands->remove_all_commands();
|
||||||
|
|
||||||
commands->add_command(ShellContext::MAIN,
|
commands->add_command(ShellContext::MAIN,
|
||||||
CommandFlags::USER,
|
CommandFlags::USER,
|
||||||
flash_string_vector{F_(refresh)},
|
flash_string_vector{F_(refresh)},
|
||||||
|
|||||||
@@ -340,19 +340,25 @@ void Boiler::show_values(uuid::console::Shell & shell) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
print_value(shell, 2, F("Warm Water activated"), wWActivated_, nullptr, EMS_VALUE_BOOL);
|
print_value(shell, 2, F("Warm Water activated"), wWActivated_, nullptr, EMS_VALUE_BOOL);
|
||||||
print_value(shell, 2, F("Warm Water charging type"), wWCircPumpType_ ? F("3-way valve") : F("charge pump"));
|
if (Helpers::hasValue(wWCircPumpType_, true)) {
|
||||||
print_value(shell, 2, F("Warm Water circulation pump available"), wWCircPump_, nullptr, EMS_VALUE_BOOL);
|
print_value(shell, 2, F("Warm Water charging type"), wWCircPumpType_ ? F("3-way valve") : F("charge pump"));
|
||||||
if (wWCircPumpMode_ == 7) {
|
|
||||||
print_value(shell, 2, F("Warm Water circulation pump freq"), F("continuous"));
|
|
||||||
} else {
|
|
||||||
char s[7];
|
|
||||||
char buffer[2];
|
|
||||||
buffer[0] = (wWCircPumpMode_ % 10) + '0';
|
|
||||||
buffer[1] = '\0';
|
|
||||||
strlcpy(s, buffer, 7);
|
|
||||||
strlcat(s, "x3min", 7);
|
|
||||||
print_value(shell, 2, F("Warm Water circulation pump freq"), s);
|
|
||||||
}
|
}
|
||||||
|
print_value(shell, 2, F("Warm Water circulation pump available"), wWCircPump_, nullptr, EMS_VALUE_BOOL);
|
||||||
|
|
||||||
|
if (Helpers::hasValue(wWCircPumpMode_)) {
|
||||||
|
if (wWCircPumpMode_ == 7) {
|
||||||
|
print_value(shell, 2, F("Warm Water circulation pump freq"), F("continuous"));
|
||||||
|
} else {
|
||||||
|
char s[7];
|
||||||
|
char buffer[2];
|
||||||
|
buffer[0] = (wWCircPumpMode_ % 10) + '0';
|
||||||
|
buffer[1] = '\0';
|
||||||
|
strlcpy(s, buffer, 7);
|
||||||
|
strlcat(s, "x3min", 7);
|
||||||
|
print_value(shell, 2, F("Warm Water circulation pump freq"), s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
print_value(shell, 2, F("Warm Water circulation active"), wWCirc_, nullptr, EMS_VALUE_BOOL);
|
print_value(shell, 2, F("Warm Water circulation active"), wWCirc_, nullptr, EMS_VALUE_BOOL);
|
||||||
|
|
||||||
if (wWComfort_ == 0x00) {
|
if (wWComfort_ == 0x00) {
|
||||||
@@ -697,6 +703,8 @@ void Boiler::set_warmwater_mode(const uint8_t comfort) {
|
|||||||
} else if (comfort == 3) {
|
} else if (comfort == 3) {
|
||||||
LOG_INFO(F("Setting boiler warm water to intelligent"));
|
LOG_INFO(F("Setting boiler warm water to intelligent"));
|
||||||
set = 2;
|
set = 2;
|
||||||
|
} else {
|
||||||
|
return; // do nothing
|
||||||
}
|
}
|
||||||
write_command(EMS_TYPE_UBAParameterWW, 9, comfort);
|
write_command(EMS_TYPE_UBAParameterWW, 9, comfort);
|
||||||
// some boilers do not have this setting, than it's done by thermostat
|
// some boilers do not have this setting, than it's done by thermostat
|
||||||
|
|||||||
@@ -27,14 +27,13 @@ REGISTER_FACTORY(Controller, EMSdevice::DeviceType::CONTROLLER);
|
|||||||
MAKE_PSTR(logger_name, "controller")
|
MAKE_PSTR(logger_name, "controller")
|
||||||
uuid::log::Logger Controller::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
uuid::log::Logger Controller::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
||||||
|
|
||||||
Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string &version, const std::string &name, uint8_t flags, uint8_t brand)
|
Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
// telegram handlers
|
// telegram handlers
|
||||||
// register_telegram_type(EMS_TYPE_XX, "XX", false, std::bind(&Controller::process_XX, this, _1));
|
// register_telegram_type(EMS_TYPE_XX, "XX", false, std::bind(&Controller::process_XX, this, _1));
|
||||||
|
|
||||||
// MQTT callbacks
|
// MQTT callbacks
|
||||||
// register_mqtt_topic("cmd", std::bind(&Controller::cmd, this, _1));
|
// register_mqtt_topic("cmd", std::bind(&Controller::cmd, this, _1));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::add_context_menu() {
|
void Controller::add_context_menu() {
|
||||||
|
|||||||
@@ -155,14 +155,14 @@ void Mixing::process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> tel
|
|||||||
// e.g. A0 00 FF 00 00 0C 01 00 00 00 00 00 54
|
// e.g. A0 00 FF 00 00 0C 01 00 00 00 00 00 54
|
||||||
// A1 00 FF 00 00 0C 02 04 00 01 1D 00 82
|
// A1 00 FF 00 00 0C 02 04 00 01 1D 00 82
|
||||||
void Mixing::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
void Mixing::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
||||||
type_ = Type::HC;
|
type_ = Type::HC;
|
||||||
hc_ = device_id() - 0x20 + 1;
|
hc_ = device_id() - 0x20 + 1;
|
||||||
uint8_t ismixed = 0;
|
uint8_t ismixed = 0;
|
||||||
telegram->read_value(ismixed, 0); // check if circuit is active, 0-off, 1-unmixed, 2-mixed
|
telegram->read_value(ismixed, 0); // check if circuit is active, 0-off, 1-unmixed, 2-mixed
|
||||||
if (ismixed == 0) {
|
if (ismixed == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ismixed == 2) { // we have a mixed circuit
|
if (ismixed == 2) { // we have a mixed circuit
|
||||||
telegram->read_value(flowTemp_, 3); // is * 10
|
telegram->read_value(flowTemp_, 3); // is * 10
|
||||||
telegram->read_value(flowSetTemp_, 5);
|
telegram->read_value(flowSetTemp_, 5);
|
||||||
telegram->read_value(status_, 2); // valve status
|
telegram->read_value(status_, 2); // valve status
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ void Solar::process_SM100Status(std::shared_ptr<const Telegram> telegram) {
|
|||||||
uint8_t pumpmod = pumpModulation_;
|
uint8_t pumpmod = pumpModulation_;
|
||||||
telegram->read_value(pumpModulation_, 9);
|
telegram->read_value(pumpModulation_, 9);
|
||||||
if (pumpmod == 0 && pumpModulation_ == 100) { // mask out boosts
|
if (pumpmod == 0 && pumpModulation_ == 100) { // mask out boosts
|
||||||
pumpModulation_ = 15; // set to minimum,
|
pumpModulation_ = 15; // set to minimum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,10 +214,10 @@ void Solar::process_SM100Energy(std::shared_ptr<const Telegram> telegram) {
|
|||||||
* e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0
|
* e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0
|
||||||
*/
|
*/
|
||||||
void Solar::process_ISM1StatusMessage(std::shared_ptr<const Telegram> telegram) {
|
void Solar::process_ISM1StatusMessage(std::shared_ptr<const Telegram> telegram) {
|
||||||
telegram->read_value(collectorTemp_, 4); // Collector Temperature
|
telegram->read_value(collectorTemp_, 4); // Collector Temperature
|
||||||
telegram->read_value(bottomTemp_, 6); // Temperature Bottom of Solar Boiler
|
telegram->read_value(bottomTemp_, 6); // Temperature Bottom of Solar Boiler
|
||||||
uint16_t Wh = 0xFFFF;
|
uint16_t Wh = 0xFFFF;
|
||||||
telegram->read_value(Wh, 2); // Solar Energy produced in last hour only ushort, is not * 10
|
telegram->read_value(Wh, 2); // Solar Energy produced in last hour only ushort, is not * 10
|
||||||
if (Wh != 0xFFFF) {
|
if (Wh != 0xFFFF) {
|
||||||
energyLastHour_ = Wh * 10; // set to *10
|
energyLastHour_ = Wh * 10; // set to *10
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1042,9 +1042,12 @@ void Thermostat::process_IBASettings(std::shared_ptr<const Telegram> telegram) {
|
|||||||
|
|
||||||
// type 0x6F - FR10/FR50/FR100 Junkers
|
// type 0x6F - FR10/FR50/FR100 Junkers
|
||||||
void Thermostat::process_JunkersMonitor(std::shared_ptr<const Telegram> telegram) {
|
void Thermostat::process_JunkersMonitor(std::shared_ptr<const Telegram> telegram) {
|
||||||
if (telegram->message_length <= 1) {
|
|
||||||
|
// ignore single byte telegram messages
|
||||||
|
if (telegram->message_length <= 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||||
|
|
||||||
telegram->read_value(hc->curr_roomTemp, 4); // value is * 10
|
telegram->read_value(hc->curr_roomTemp, 4); // value is * 10
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace emsesp {
|
|||||||
|
|
||||||
uuid::log::Logger EMSdevice::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
uuid::log::Logger EMSdevice::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
||||||
|
|
||||||
std::string EMSdevice::brand() const {
|
std::string EMSdevice::brand_to_string() const {
|
||||||
switch (brand_) {
|
switch (brand_) {
|
||||||
case EMSdevice::Brand::BOSCH:
|
case EMSdevice::Brand::BOSCH:
|
||||||
return read_flash_string(F("Bosch"));
|
return read_flash_string(F("Bosch"));
|
||||||
@@ -143,7 +143,7 @@ std::string EMSdevice::to_string() const {
|
|||||||
snprintf_P(&str[0],
|
snprintf_P(&str[0],
|
||||||
str.capacity() + 1,
|
str.capacity() + 1,
|
||||||
PSTR("%s %s (DeviceID:0x%02X ProductID:%d, Version:%s)"),
|
PSTR("%s %s (DeviceID:0x%02X ProductID:%d, Version:%s)"),
|
||||||
brand().c_str(),
|
brand_to_string().c_str(),
|
||||||
name_.c_str(),
|
name_.c_str(),
|
||||||
device_id_,
|
device_id_,
|
||||||
product_id_,
|
product_id_,
|
||||||
|
|||||||
@@ -86,11 +86,15 @@ class EMSdevice {
|
|||||||
brand_ = brand;
|
brand_ = brand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint8_t brand() const {
|
||||||
|
return brand_;
|
||||||
|
}
|
||||||
|
|
||||||
inline void name(const std::string & name) {
|
inline void name(const std::string & name) {
|
||||||
name_ = name;
|
name_ = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string brand() const;
|
std::string brand_to_string() const;
|
||||||
static uint8_t decode_brand(uint8_t value);
|
static uint8_t decode_brand(uint8_t value);
|
||||||
|
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
@@ -171,8 +175,8 @@ class EMSdevice {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// device IDs
|
// device IDs
|
||||||
static constexpr uint16_t EMS_DEVICE_ID_BOILER = 0x08; // fixed device_id for Master Boiler/UBA
|
static constexpr uint8_t EMS_DEVICE_ID_BOILER = 0x08; // fixed device_id for Master Boiler/UBA
|
||||||
static constexpr uint16_t EMS_DEVICE_ID_MODEM = 0x48; // gateways like the KM200
|
static constexpr uint8_t EMS_DEVICE_ID_MODEM = 0x48; // gateways like the KM200
|
||||||
|
|
||||||
// type IDs
|
// type IDs
|
||||||
static constexpr uint16_t EMS_TYPE_VERSION = 0x02; // type ID for Version information. Generic across all EMS devices.
|
static constexpr uint16_t EMS_TYPE_VERSION = 0x02; // type ID for Version information. Generic across all EMS devices.
|
||||||
|
|||||||
@@ -497,10 +497,10 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the EMS device to our list of devices
|
// add a new or update existing EMS device to our list of active EMS devices
|
||||||
// if its not in our database, we don't add it
|
// if its not in our database, we don't add it
|
||||||
bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, std::string & version, const uint8_t brand) {
|
bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, std::string & version, const uint8_t brand) {
|
||||||
// don't add ourselves
|
// don't add ourselves!
|
||||||
if (device_id == rxservice_.ems_bus_id()) {
|
if (device_id == rxservice_.ems_bus_id()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -509,10 +509,13 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, std::
|
|||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if (emsdevice) {
|
if (emsdevice) {
|
||||||
if (emsdevice->is_device_id(device_id)) {
|
if (emsdevice->is_device_id(device_id)) {
|
||||||
LOG_DEBUG(F("Updating details for already existing device with ID 0x%02X"), device_id);
|
LOG_DEBUG(F("Updating details to already existing device ID 0x%02X"), device_id);
|
||||||
emsdevice->product_id(product_id);
|
emsdevice->product_id(product_id);
|
||||||
emsdevice->version(version);
|
emsdevice->version(version);
|
||||||
emsdevice->brand(brand);
|
// only set brand if it doesn't already exist
|
||||||
|
if (emsdevice->brand() == EMSdevice::Brand::NO_BRAND) {
|
||||||
|
emsdevice->brand(brand);
|
||||||
|
}
|
||||||
// find the name and flags in our database
|
// find the name and flags in our database
|
||||||
for (const auto & device : device_library_) {
|
for (const auto & device : device_library_) {
|
||||||
if (device.product_id == product_id) {
|
if (device.product_id == product_id) {
|
||||||
@@ -521,28 +524,37 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, std::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true; // finish
|
return true; // finish up
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// look up the rest of the details using the product_id and create the new device object
|
// look up the rest of the details using the product_id and create the new device object
|
||||||
// then send a request to the device to get the version and any other info we may have
|
Device_record * device_p = nullptr;
|
||||||
bool found = false;
|
for (auto & device : device_library_) {
|
||||||
for (const auto & device : device_library_) {
|
|
||||||
if (device.product_id == product_id) {
|
if (device.product_id == product_id) {
|
||||||
emsdevices.push_back(
|
// sometimes boilers share the same product id as controllers
|
||||||
EMSFactory::add(device.device_type, device_id, device.product_id, version, uuid::read_flash_string(device.name), device.flags, brand));
|
// so only add boilers if the device_id is 0x08, which is fixed for EMS
|
||||||
found = true;
|
if (device.device_type == DeviceType::BOILER) {
|
||||||
break;
|
if (device_id == EMSdevice::EMS_DEVICE_ID_BOILER) {
|
||||||
|
device_p = &device;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// it's not a boiler, but we have a match
|
||||||
|
device_p = &device;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we don't recognize the product ID report it, but don't add it.
|
// if we don't recognize the product ID report it, but don't add it.
|
||||||
if (!found) {
|
if (device_p == nullptr) {
|
||||||
LOG_NOTICE(F("Unrecognized EMS device with device ID 0x%02X with product ID %d. Please report on GitHub."), device_id, product_id);
|
LOG_NOTICE(F("Unrecognized EMS device with device ID 0x%02X with product ID %d. Please report on GitHub."), device_id, product_id);
|
||||||
return false; // not found
|
return false; // not found
|
||||||
} else {
|
} else {
|
||||||
|
emsdevices.push_back(
|
||||||
|
EMSFactory::add(device_p->device_type, device_id, device_p->product_id, version, uuid::read_flash_string(device_p->name), device_p->flags, brand));
|
||||||
LOG_DEBUG(F("Adding new device with device ID 0x%02X with product ID %d and version %s"), device_id, product_id, version.c_str());
|
LOG_DEBUG(F("Adding new device with device ID 0x%02X with product ID %d and version %s"), device_id, product_id, version.c_str());
|
||||||
// go and fetch its data,
|
// go and fetch its data,
|
||||||
fetch_device_values(device_id);
|
fetch_device_values(device_id);
|
||||||
@@ -572,7 +584,9 @@ void EMSESP::send_write_request(const uint16_t type_id,
|
|||||||
// we check if its a complete telegram or just a single byte (which could be a poll or a return status)
|
// we check if its a complete telegram or just a single byte (which could be a poll or a return status)
|
||||||
// the CRC check is not done here, only when it's added to the Rx queue with add()
|
// the CRC check is not done here, only when it's added to the Rx queue with add()
|
||||||
void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
||||||
|
#ifdef EMSESP_DEBUG
|
||||||
static uint32_t tx_time_ = 0;
|
static uint32_t tx_time_ = 0;
|
||||||
|
#endif
|
||||||
// check first for echo
|
// check first for echo
|
||||||
uint8_t first_value = data[0];
|
uint8_t first_value = data[0];
|
||||||
if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) {
|
if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) {
|
||||||
@@ -632,7 +646,9 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
|||||||
// if ht3 poll must be ems_bus_id else if Buderus poll must be (ems_bus_id | 0x80)
|
// if ht3 poll must be ems_bus_id else if Buderus poll must be (ems_bus_id | 0x80)
|
||||||
if ((first_value ^ 0x80 ^ rxservice_.ems_mask()) == txservice_.ems_bus_id()) {
|
if ((first_value ^ 0x80 ^ rxservice_.ems_mask()) == txservice_.ems_bus_id()) {
|
||||||
EMSbus::last_bus_activity(uuid::get_uptime()); // set the flag indication the EMS bus is active
|
EMSbus::last_bus_activity(uuid::get_uptime()); // set the flag indication the EMS bus is active
|
||||||
tx_time_ = ::millis(); // get_uptime is only updated once per loop, does not give the right time
|
#ifdef EMSESP_DEBUG
|
||||||
|
tx_time_ = ::millis(); // get_uptime is only updated once per loop, does not give the right time
|
||||||
|
#endif
|
||||||
txservice_.send();
|
txservice_.send();
|
||||||
}
|
}
|
||||||
// send remote room temperature if active
|
// send remote room temperature if active
|
||||||
|
|||||||
@@ -61,7 +61,13 @@ uint8_t EMSbus::calculate_crc(const uint8_t * data, const uint8_t length) {
|
|||||||
|
|
||||||
// creates a telegram object
|
// creates a telegram object
|
||||||
// stores header in separate member objects and the rest in the message_data block
|
// stores header in separate member objects and the rest in the message_data block
|
||||||
Telegram::Telegram(uint8_t operation, uint8_t src, uint8_t dest, uint16_t type_id, uint8_t offset, uint8_t * data, uint8_t message_length)
|
Telegram::Telegram(const uint8_t operation,
|
||||||
|
const uint8_t src,
|
||||||
|
const uint8_t dest,
|
||||||
|
const uint16_t type_id,
|
||||||
|
const uint8_t offset,
|
||||||
|
const uint8_t * data,
|
||||||
|
const uint8_t message_length)
|
||||||
: operation(operation)
|
: operation(operation)
|
||||||
, src(src)
|
, src(src)
|
||||||
, dest(dest)
|
, dest(dest)
|
||||||
@@ -113,7 +119,6 @@ void RxService::flush_rx_queue() {
|
|||||||
// Rx loop, run as many times as you can
|
// Rx loop, run as many times as you can
|
||||||
// processes all telegrams on the queue. Assumes there are valid (i.e. CRC checked)
|
// processes all telegrams on the queue. Assumes there are valid (i.e. CRC checked)
|
||||||
void RxService::loop() {
|
void RxService::loop() {
|
||||||
|
|
||||||
while (!rx_telegrams_.empty()) {
|
while (!rx_telegrams_.empty()) {
|
||||||
auto telegram = rx_telegrams_.front().telegram_;
|
auto telegram = rx_telegrams_.front().telegram_;
|
||||||
|
|
||||||
@@ -300,8 +305,8 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
|
|||||||
}
|
}
|
||||||
telegram_raw[1] = dest;
|
telegram_raw[1] = dest;
|
||||||
|
|
||||||
uint8_t message_p = 0; // this is the position in the telegram where we want to put our message data
|
uint8_t message_p = 0; // this is the position in the telegram where we want to put our message data
|
||||||
uint8_t message_p0 = 0; // this is the position of start of message data
|
bool copy_data = true; // true if we want to copy over the data message block to the end of the telegram header
|
||||||
|
|
||||||
if (telegram->type_id > 0xFF) {
|
if (telegram->type_id > 0xFF) {
|
||||||
// it's EMS 2.0/+
|
// it's EMS 2.0/+
|
||||||
@@ -320,7 +325,7 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
|
|||||||
telegram_raw[5] = (telegram->type_id >> 8) - 1; // type, 1st byte, high-byte, subtract 0x100
|
telegram_raw[5] = (telegram->type_id >> 8) - 1; // type, 1st byte, high-byte, subtract 0x100
|
||||||
telegram_raw[6] = telegram->type_id & 0xFF; // type, 2nd byte, low-byte
|
telegram_raw[6] = telegram->type_id & 0xFF; // type, 2nd byte, low-byte
|
||||||
message_p = 7;
|
message_p = 7;
|
||||||
message_p0 = 1; // data[0] is in raw[4]
|
copy_data = false; // there are no more data values after the type_id when reading on EMS+
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// EMS 1.0
|
// EMS 1.0
|
||||||
@@ -329,13 +334,15 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
|
|||||||
message_p = 4;
|
message_p = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the data to send to to the end of the header
|
if (copy_data) {
|
||||||
if (telegram->message_length > EMS_MAX_TELEGRAM_MESSAGE_LENGTH) {
|
if (telegram->message_length > EMS_MAX_TELEGRAM_MESSAGE_LENGTH) {
|
||||||
return; // too big
|
return; // too big
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t i = message_p0; i < telegram->message_length; i++) {
|
// add the data to send to to the end of the header
|
||||||
telegram_raw[message_p++] = telegram->message_data[i];
|
for (uint8_t i = 0; i < telegram->message_length; i++) {
|
||||||
|
telegram_raw[message_p++] = telegram->message_data[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t length = message_p;
|
uint8_t length = message_p;
|
||||||
@@ -346,16 +353,16 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
|
|||||||
|
|
||||||
length++; // add one since we want to now include the CRC
|
length++; // add one since we want to now include the CRC
|
||||||
|
|
||||||
LOG_DEBUG(F("Sending %s Tx [#%d], telegram: %s"),
|
LOG_DEBUG(F("Sending %s Tx [#%d], telegram: %s"),
|
||||||
(telegram->operation == Telegram::Operation::TX_WRITE) ? F("write") : F("read"),
|
(telegram->operation == Telegram::Operation::TX_WRITE) ? F("write") : F("read"),
|
||||||
tx_telegram.id_,
|
tx_telegram.id_,
|
||||||
telegram->to_string(telegram_raw, length).c_str());
|
telegram->to_string(telegram_raw, length).c_str());
|
||||||
|
|
||||||
#ifdef EMSESP_DEBUG
|
#ifdef EMSESP_DEBUG
|
||||||
// if watching in 'raw' mode
|
// if watching in 'raw' mode
|
||||||
if (EMSESP::watch() == EMSESP::Watch::WATCH_RAW) {
|
if (EMSESP::watch() == EMSESP::Watch::WATCH_RAW) {
|
||||||
LOG_NOTICE(F("[DEBUG] Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str());
|
LOG_NOTICE(F("[DEBUG] Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// send the telegram to the UART Tx
|
// send the telegram to the UART Tx
|
||||||
@@ -412,19 +419,19 @@ void TxService::add(const uint8_t operation, const uint8_t dest, const uint16_t
|
|||||||
// builds a Tx telegram and adds to queue
|
// builds a Tx telegram and adds to queue
|
||||||
// this is used by the retry() function to put the last failed Tx back into the queue
|
// this is used by the retry() function to put the last failed Tx back into the queue
|
||||||
// format is EMS 1.0 (src, dest, type_id, offset, data)
|
// format is EMS 1.0 (src, dest, type_id, offset, data)
|
||||||
// length is the length of the whole telegram data
|
// length is the length of the whole telegram data, excluding the CRC
|
||||||
void TxService::add(uint8_t operation, uint8_t * data, const uint8_t length) {
|
void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t length) {
|
||||||
// build header. src, dest and offset have fixed positions
|
// build header. src, dest and offset have fixed positions
|
||||||
uint8_t src = data[0];
|
uint8_t src = data[0];
|
||||||
uint8_t dest = data[1];
|
uint8_t dest = data[1];
|
||||||
uint8_t offset = data[3];
|
uint8_t offset = data[3];
|
||||||
|
|
||||||
uint16_t type_id;
|
uint16_t type_id;
|
||||||
uint8_t * message_data; // where the message block starts
|
const uint8_t * message_data; // where the message block starts
|
||||||
uint8_t message_length; // length of the message block, excluding CRC
|
uint8_t message_length; // length of the message block, excluding CRC
|
||||||
|
|
||||||
// work out depending on the type, where the data message block starts and the message length
|
// work out depending on the type, where the data message block starts and the message length
|
||||||
// same logic as in RxService::add()
|
// same logic as in RxService::add(), but adjusted for no appended CRC
|
||||||
if (data[2] < 0xF0) {
|
if (data[2] < 0xF0) {
|
||||||
// EMS 1.0
|
// EMS 1.0
|
||||||
type_id = data[2];
|
type_id = data[2];
|
||||||
@@ -520,7 +527,6 @@ void TxService::send_raw(const char * telegram_data) {
|
|||||||
// add last Tx to tx queue and increment count
|
// add last Tx to tx queue and increment count
|
||||||
// returns retry count, or 0 if all done
|
// returns retry count, or 0 if all done
|
||||||
void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const uint8_t length) {
|
void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const uint8_t length) {
|
||||||
|
|
||||||
// have we reached the limit? if so, reset count and give up
|
// have we reached the limit? if so, reset count and give up
|
||||||
if (++retry_count_ > MAXIMUM_TX_RETRIES) {
|
if (++retry_count_ > MAXIMUM_TX_RETRIES) {
|
||||||
reset_retry_count(); // give up
|
reset_retry_count(); // give up
|
||||||
|
|||||||
@@ -57,7 +57,13 @@ namespace emsesp {
|
|||||||
// from Rx (receiving one) or Tx for preparing one for sending
|
// from Rx (receiving one) or Tx for preparing one for sending
|
||||||
class Telegram {
|
class Telegram {
|
||||||
public:
|
public:
|
||||||
Telegram(uint8_t operation, uint8_t src, uint8_t dest, uint16_t type_id, uint8_t offset, uint8_t * message_data, uint8_t message_length);
|
Telegram(const uint8_t operation,
|
||||||
|
const uint8_t src,
|
||||||
|
const uint8_t dest,
|
||||||
|
const uint16_t type_id,
|
||||||
|
const uint8_t offset,
|
||||||
|
const uint8_t * message_data,
|
||||||
|
const uint8_t message_length);
|
||||||
~Telegram() = default;
|
~Telegram() = default;
|
||||||
|
|
||||||
const uint8_t operation; // is Operation mode
|
const uint8_t operation; // is Operation mode
|
||||||
@@ -81,8 +87,8 @@ class Telegram {
|
|||||||
|
|
||||||
// reads a bit value from a given telegram position
|
// reads a bit value from a given telegram position
|
||||||
void read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const {
|
void read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const {
|
||||||
uint8_t abs_index = (index - offset);
|
uint8_t abs_index = (index - offset);
|
||||||
if(abs_index >= message_length) {
|
if (abs_index >= message_length) {
|
||||||
return; // out of bounds
|
return; // out of bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,7 +271,7 @@ class TxService : public EMSbus {
|
|||||||
void send();
|
void send();
|
||||||
|
|
||||||
void add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length);
|
void add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length);
|
||||||
void add(const uint8_t operation, uint8_t * data, const uint8_t length);
|
void add(const uint8_t operation, const uint8_t * data, const uint8_t length);
|
||||||
|
|
||||||
void read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset = 0);
|
void read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset = 0);
|
||||||
|
|
||||||
|
|||||||
@@ -134,14 +134,25 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
|||||||
EMSESP::add_device(0x08, 123, version, EMSdevice::Brand::BUDERUS); // Nefit Trendline
|
EMSESP::add_device(0x08, 123, version, EMSdevice::Brand::BUDERUS); // Nefit Trendline
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command == "unknown") {
|
// unknown device -
|
||||||
|
if ((command == "unknown") || (command == "u")) {
|
||||||
// question: do we need to set the mask?
|
// question: do we need to set the mask?
|
||||||
std::string version("1.2.3");
|
std::string version("1.2.3");
|
||||||
EMSESP::add_device(0x09, 89, version, EMSdevice::Brand::BUDERUS);
|
|
||||||
|
// add boiler
|
||||||
|
EMSESP::add_device(0x08, 84, version, EMSdevice::Brand::BUDERUS);
|
||||||
|
EMSESP::rxservice_.loop();
|
||||||
|
|
||||||
|
// add Controller - BC10 GB142 - but using the same device_id to see what happens
|
||||||
|
EMSESP::add_device(0x09, 84, version, EMSdevice::Brand::BUDERUS);
|
||||||
EMSESP::rxservice_.loop();
|
EMSESP::rxservice_.loop();
|
||||||
|
|
||||||
// simulate getting version information back from an unknown device
|
// simulate getting version information back from an unknown device
|
||||||
rx_telegram({0x09, 0x0B, 0x02, 0x00, 0x59, 0x01, 0x02});
|
// note there is no brand (byte 9)
|
||||||
|
rx_telegram({0x09, 0x0B, 0x02, 0x00, 0x59, 0x09, 0x0a});
|
||||||
|
|
||||||
|
shell.loop_all();
|
||||||
|
EMSESP::show_values(shell);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command == "unknown2") {
|
if (command == "unknown2") {
|
||||||
@@ -282,7 +293,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
|||||||
uart_telegram_withCRC("90 0B FF 00 01 A5 80 00 01 26 15 00 26 2A 05 A0 03 03 03 05 A0 05 A0 00 00 11 01 03 FF FF 00 FE");
|
uart_telegram_withCRC("90 0B FF 00 01 A5 80 00 01 26 15 00 26 2A 05 A0 03 03 03 05 A0 05 A0 00 00 11 01 03 FF FF 00 FE");
|
||||||
uart_telegram_withCRC("90 00 FF 19 01 A5 01 04 00 00 00 00 FF 64 2A 00 3C 01 FF 92");
|
uart_telegram_withCRC("90 00 FF 19 01 A5 01 04 00 00 00 00 FF 64 2A 00 3C 01 FF 92");
|
||||||
|
|
||||||
|
|
||||||
EMSESP::show_emsbus(shell);
|
EMSESP::show_emsbus(shell);
|
||||||
EMSESP::rxservice_.loop();
|
EMSESP::rxservice_.loop();
|
||||||
EMSESP::show_values(shell);
|
EMSESP::show_values(shell);
|
||||||
@@ -395,26 +405,39 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
|||||||
EMSESP::txservice_.flush_tx_queue();
|
EMSESP::txservice_.flush_tx_queue();
|
||||||
|
|
||||||
// TX queue example - Me -> Thermostat, (0x91), telegram: 0B 17 91 05 44 45 46 47 (#data=4)
|
// TX queue example - Me -> Thermostat, (0x91), telegram: 0B 17 91 05 44 45 46 47 (#data=4)
|
||||||
// uint8_t t11[] = {0x44, 0x45, 0x46, 0x47};
|
uint8_t t11[] = {0x44, 0x45, 0x46, 0x47};
|
||||||
// EMSESP::txservice_.add(Telegram::Operation::TX_RAW, 0x17, 0x91, 0x05, t11, sizeof(t11));
|
EMSESP::txservice_.add(Telegram::Operation::TX_RAW, 0x17, 0x91, 0x05, t11, sizeof(t11));
|
||||||
|
|
||||||
// TX - raw example test
|
// TX - raw example test
|
||||||
// uint8_t t12[] = {0x10, 0x08, 0x63, 0x04, 0x64};
|
uint8_t t12[] = {0x10, 0x08, 0x63, 0x04, 0x64};
|
||||||
// EMSESP::txservice_.add(t12, sizeof(t12));
|
EMSESP::txservice_.add(Telegram::Operation::TX_RAW, t12, sizeof(t12));
|
||||||
|
|
||||||
// TX - sending raw string
|
// TX - sending raw string
|
||||||
// EMSESP::txservice_.send_raw("10 08 63 03 64 65 66");
|
EMSESP::txservice_.send_raw("10 08 63 03 64 65 66");
|
||||||
|
|
||||||
// TX - send a read request
|
// TX - send a read request
|
||||||
EMSESP::send_read_request(0x18, 0x08);
|
EMSESP::send_read_request(0x18, 0x08);
|
||||||
|
|
||||||
// TX - send a write request
|
// TX - send a write request
|
||||||
// uint8_t t18[] = {0x52, 0x79};
|
uint8_t t18[] = {0x52, 0x79};
|
||||||
// send_write_request(0x91, 0x17, 0x00, t18, sizeof(t18));
|
EMSESP::send_write_request(0x91, 0x17, 0x00, t18, sizeof(t18), 0x00);
|
||||||
|
|
||||||
|
// TX - send EMS+
|
||||||
|
const uint8_t t13[] = {0x90, 0x0B, 0xFF, 00, 01, 0xBA, 00, 0x2E, 0x2A, 0x26, 0x1E, 0x03,
|
||||||
|
00, 0xFF, 0xFF, 05, 0x2A, 01, 0xE1, 0x20, 0x01, 0x0F, 05, 0x2A};
|
||||||
|
EMSESP::txservice_.add(Telegram::Operation::TX_RAW, t13, sizeof(t13));
|
||||||
|
|
||||||
|
// EMS+ Junkers read request
|
||||||
|
EMSESP::send_read_request(0x16F, 0x10);
|
||||||
|
|
||||||
|
EMSESP::show_emsbus(shell);
|
||||||
|
|
||||||
|
// process whole Tx queue
|
||||||
|
for (uint8_t i = 0; i < 10; i++) {
|
||||||
|
EMSESP::txservice_.send(); // send it to UART
|
||||||
|
}
|
||||||
|
|
||||||
shell.loop_all();
|
shell.loop_all();
|
||||||
EMSESP::show_emsbus(shell);
|
|
||||||
EMSESP::txservice_.send(); // send it to UART
|
|
||||||
|
|
||||||
EMSESP::txservice_.flush_tx_queue();
|
EMSESP::txservice_.flush_tx_queue();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "2.0.0a27"
|
#define EMSESP_APP_VERSION "2.0.0a28"
|
||||||
|
|||||||
Reference in New Issue
Block a user