This commit is contained in:
MichaelDvP
2020-06-25 16:32:06 +02:00
13 changed files with 154 additions and 88 deletions

View File

@@ -56,7 +56,8 @@ void EMSESPShell::stopped() {
// remove all custom contexts
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

View File

@@ -340,8 +340,12 @@ void Boiler::show_values(uuid::console::Shell & shell) {
}
print_value(shell, 2, F("Warm Water activated"), wWActivated_, nullptr, EMS_VALUE_BOOL);
if (Helpers::hasValue(wWCircPumpType_, true)) {
print_value(shell, 2, F("Warm Water charging type"), wWCircPumpType_ ? F("3-way valve") : F("charge pump"));
}
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 {
@@ -353,6 +357,8 @@ void Boiler::show_values(uuid::console::Shell & shell) {
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);
if (wWComfort_ == 0x00) {
@@ -697,6 +703,8 @@ void Boiler::set_warmwater_mode(const uint8_t comfort) {
} else if (comfort == 3) {
LOG_INFO(F("Setting boiler warm water to intelligent"));
set = 2;
} else {
return; // do nothing
}
write_command(EMS_TYPE_UBAParameterWW, 9, comfort);
// some boilers do not have this setting, than it's done by thermostat

View File

@@ -27,14 +27,13 @@ REGISTER_FACTORY(Controller, EMSdevice::DeviceType::CONTROLLER);
MAKE_PSTR(logger_name, "controller")
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) {
// telegram handlers
// register_telegram_type(EMS_TYPE_XX, "XX", false, std::bind(&Controller::process_XX, this, _1));
// MQTT callbacks
// register_mqtt_topic("cmd", std::bind(&Controller::cmd, this, _1));
}
void Controller::add_context_menu() {

View File

@@ -184,7 +184,7 @@ void Solar::process_SM100Status(std::shared_ptr<const Telegram> telegram) {
uint8_t pumpmod = pumpModulation_;
telegram->read_value(pumpModulation_, 9);
if (pumpmod == 0 && pumpModulation_ == 100) { // mask out boosts
pumpModulation_ = 15; // set to minimum,
pumpModulation_ = 15; // set to minimum
}
}

View File

@@ -1042,9 +1042,12 @@ void Thermostat::process_IBASettings(std::shared_ptr<const Telegram> telegram) {
// type 0x6F - FR10/FR50/FR100 Junkers
void Thermostat::process_JunkersMonitor(std::shared_ptr<const Telegram> telegram) {
// ignore single byte telegram messages
if (telegram->message_length <= 1) {
return;
}
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->curr_roomTemp, 4); // value is * 10

View File

@@ -26,7 +26,7 @@ namespace emsesp {
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_) {
case EMSdevice::Brand::BOSCH:
return read_flash_string(F("Bosch"));
@@ -143,7 +143,7 @@ std::string EMSdevice::to_string() const {
snprintf_P(&str[0],
str.capacity() + 1,
PSTR("%s %s (DeviceID:0x%02X ProductID:%d, Version:%s)"),
brand().c_str(),
brand_to_string().c_str(),
name_.c_str(),
device_id_,
product_id_,

View File

@@ -86,11 +86,15 @@ class EMSdevice {
brand_ = brand;
}
inline uint8_t brand() const {
return brand_;
}
inline void name(const std::string & name) {
name_ = name;
}
std::string brand() const;
std::string brand_to_string() const;
static uint8_t decode_brand(uint8_t value);
std::string to_string() const;
@@ -171,8 +175,8 @@ class EMSdevice {
};
// device IDs
static constexpr uint16_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_BOILER = 0x08; // fixed device_id for Master Boiler/UBA
static constexpr uint8_t EMS_DEVICE_ID_MODEM = 0x48; // gateways like the KM200
// type IDs
static constexpr uint16_t EMS_TYPE_VERSION = 0x02; // type ID for Version information. Generic across all EMS devices.

View File

@@ -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
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()) {
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) {
if (emsdevice) {
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->version(version);
// 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
for (const auto & device : device_library_) {
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
// then send a request to the device to get the version and any other info we may have
bool found = false;
for (const auto & device : device_library_) {
Device_record * device_p = nullptr;
for (auto & device : device_library_) {
if (device.product_id == product_id) {
emsdevices.push_back(
EMSFactory::add(device.device_type, device_id, device.product_id, version, uuid::read_flash_string(device.name), device.flags, brand));
found = true;
// sometimes boilers share the same product id as controllers
// so only add boilers if the device_id is 0x08, which is fixed for EMS
if (device.device_type == DeviceType::BOILER) {
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 (!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);
return false; // not found
} 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());
// go and fetch its data,
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)
// 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) {
#ifdef EMSESP_DEBUG
static uint32_t tx_time_ = 0;
#endif
// check first for echo
uint8_t first_value = data[0];
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 ((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
#ifdef EMSESP_DEBUG
tx_time_ = ::millis(); // get_uptime is only updated once per loop, does not give the right time
#endif
txservice_.send();
}
// send remote room temperature if active

View File

@@ -61,7 +61,13 @@ uint8_t EMSbus::calculate_crc(const uint8_t * data, const uint8_t length) {
// creates a telegram object
// 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)
, src(src)
, dest(dest)
@@ -113,7 +119,6 @@ void RxService::flush_rx_queue() {
// Rx loop, run as many times as you can
// processes all telegrams on the queue. Assumes there are valid (i.e. CRC checked)
void RxService::loop() {
while (!rx_telegrams_.empty()) {
auto telegram = rx_telegrams_.front().telegram_;
@@ -301,7 +306,7 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
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_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) {
// 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[6] = telegram->type_id & 0xFF; // type, 2nd byte, low-byte
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 {
// EMS 1.0
@@ -329,14 +334,16 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
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) {
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
for (uint8_t i = 0; i < telegram->message_length; i++) {
telegram_raw[message_p++] = telegram->message_data[i];
}
}
uint8_t length = message_p;
@@ -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
// 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)
// length is the length of the whole telegram data
void TxService::add(uint8_t operation, uint8_t * data, const uint8_t length) {
// length is the length of the whole telegram data, excluding the CRC
void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t length) {
// build header. src, dest and offset have fixed positions
uint8_t src = data[0];
uint8_t dest = data[1];
uint8_t offset = data[3];
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
// 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) {
// EMS 1.0
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
// returns retry count, or 0 if all done
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
if (++retry_count_ > MAXIMUM_TX_RETRIES) {
reset_retry_count(); // give up

View File

@@ -57,7 +57,13 @@ namespace emsesp {
// from Rx (receiving one) or Tx for preparing one for sending
class Telegram {
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;
const uint8_t operation; // is Operation mode
@@ -82,7 +88,7 @@ class Telegram {
// reads a bit value from a given telegram position
void read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const {
uint8_t abs_index = (index - offset);
if(abs_index >= message_length) {
if (abs_index >= message_length) {
return; // out of bounds
}
@@ -265,7 +271,7 @@ class TxService : public EMSbus {
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, 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);

View File

@@ -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
}
if (command == "unknown") {
// unknown device -
if ((command == "unknown") || (command == "u")) {
// question: do we need to set the mask?
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();
// 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") {
@@ -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 00 FF 19 01 A5 01 04 00 00 00 00 FF 64 2A 00 3C 01 FF 92");
EMSESP::show_emsbus(shell);
EMSESP::rxservice_.loop();
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();
// TX queue example - Me -> Thermostat, (0x91), telegram: 0B 17 91 05 44 45 46 47 (#data=4)
// uint8_t t11[] = {0x44, 0x45, 0x46, 0x47};
// EMSESP::txservice_.add(Telegram::Operation::TX_RAW, 0x17, 0x91, 0x05, t11, sizeof(t11));
uint8_t t11[] = {0x44, 0x45, 0x46, 0x47};
EMSESP::txservice_.add(Telegram::Operation::TX_RAW, 0x17, 0x91, 0x05, t11, sizeof(t11));
// TX - raw example test
// uint8_t t12[] = {0x10, 0x08, 0x63, 0x04, 0x64};
// EMSESP::txservice_.add(t12, sizeof(t12));
uint8_t t12[] = {0x10, 0x08, 0x63, 0x04, 0x64};
EMSESP::txservice_.add(Telegram::Operation::TX_RAW, t12, sizeof(t12));
// 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
EMSESP::send_read_request(0x18, 0x08);
// TX - send a write request
// uint8_t t18[] = {0x52, 0x79};
// send_write_request(0x91, 0x17, 0x00, t18, sizeof(t18));
uint8_t t18[] = {0x52, 0x79};
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();
EMSESP::show_emsbus(shell);
EMSESP::txservice_.send(); // send it to UART
EMSESP::txservice_.flush_tx_queue();
}

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "2.0.0a27"
#define EMSESP_APP_VERSION "2.0.0a28"