diff --git a/.gitignore b/.gitignore index d4cbcd5a0..13f63f326 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,7 @@ interface/src/i18n/i18n-util.async.ts .scannerwork/ sonar/ build_wrapper_output_directory/ + +# other build files +dump_entities.csv +dump_entities.xls* diff --git a/Makefile b/Makefile index 636cc1d99..195b0e318 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,9 @@ CXX_STANDARD := -std=c++11 #---------------------------------------------------------------------- # Defined Symbols #---------------------------------------------------------------------- -DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_PROGMEM=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0 -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_USE_SERIAL +DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_PROGMEM=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0 +DEFINES += -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_USE_SERIAL +DEFINES += $(ARGS) DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.5.0b11\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" diff --git a/scripts/dump_entities.py b/scripts/dump_entities.py new file mode 100644 index 000000000..7efc0fe0c --- /dev/null +++ b/scripts/dump_entities.py @@ -0,0 +1,14 @@ +# use like +# make clean; make ARGS=-DEMSESP_STANDALONE_DUMP; echo "test dump" | ./emsesp | python3 ./scripts/dump_entities.py + +import fileinput +with fileinput.input() as f_input: + inRecordingMode = False + for line in f_input: + if not inRecordingMode: + if line.startswith('---- CSV START ----'): + inRecordingMode = True + elif line.startswith('---- CSV END ----'): + inRecordingMode = False + else: + print(line, end="") diff --git a/scripts/dump_entities.sh b/scripts/dump_entities.sh new file mode 100644 index 000000000..76c7fb824 --- /dev/null +++ b/scripts/dump_entities.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +# creates an CSV file called "dump_entities.cvs" with all devices and their entities +# run from top folder like `sh ./scripts/dump_entities.sh` +make clean; make ARGS=-DEMSESP_STANDALONE_DUMP; echo "test dump" | ./emsesp | python3 ./scripts/dump_entities.py > dump_entities.csv diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 6f9e280e1..c02841e77 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -443,20 +443,23 @@ void EMSdevice::add_device_value(uint8_t tag, } // initialize the device value depending on it's type + // ignoring DeviceValueType::CMD and DeviceValueType::TIME if (type == DeviceValueType::STRING) { *(char *)(value_p) = {'\0'}; // this is important for string functions like strlen() to work later } else if (type == DeviceValueType::INT) { - *(int8_t *)(value_p) = EMS_VALUE_INT_NOTSET; + *(int8_t *)(value_p) = EMS_VALUE_DEFAULT_INT; + } else if (type == DeviceValueType::UINT) { + *(uint8_t *)(value_p) = EMS_VALUE_DEFAULT_UINT; } else if (type == DeviceValueType::SHORT) { - *(int16_t *)(value_p) = EMS_VALUE_SHORT_NOTSET; + *(int16_t *)(value_p) = EMS_VALUE_DEFAULT_SHORT; } else if (type == DeviceValueType::USHORT) { - *(uint16_t *)(value_p) = EMS_VALUE_USHORT_NOTSET; + *(uint16_t *)(value_p) = EMS_VALUE_DEFAULT_USHORT; } else if ((type == DeviceValueType::ULONG) || (type == DeviceValueType::TIME)) { - *(uint32_t *)(value_p) = EMS_VALUE_ULONG_NOTSET; + *(uint32_t *)(value_p) = EMS_VALUE_DEFAULT_ULONG; } else if (type == DeviceValueType::BOOL) { - *(int8_t *)(value_p) = EMS_VALUE_BOOL_NOTSET; // bool is uint8_t, but other initial value - } else { - *(uint8_t *)(value_p) = EMS_VALUE_UINT_NOTSET; // enums behave as uint8_t + *(int8_t *)(value_p) = EMS_VALUE_DEFAULT_BOOL; // bool is uint8_t, but other initial value + } else if (type == DeviceValueType::ENUM) { + *(uint8_t *)(value_p) = EMS_VALUE_DEFAULT_ENUM; // enums behave as uint8_t } // determine state @@ -1059,6 +1062,117 @@ void EMSdevice::getCustomEntities(std::vector & entity_ids) { } } +#if defined(EMSESP_STANDALONE_DUMP) +// device name, device type, shortname, fullname, type [(enum values) | (min/max)], uom, readable, writeable, visible +void EMSdevice::dump_value_info() { + for (auto & dv : devicevalues_) { + Serial.print(name_); + Serial.print(','); + Serial.print(device_type_name().c_str()); + Serial.print(','); + + Serial.print(dv.short_name); + Serial.print(','); + Serial.print(dv.get_fullname().c_str()); + Serial.print(','); + + // type and optional enum values and min/max + switch (dv.type) { + case DeviceValueType::ENUM: { + Serial.print("enum"); + Serial.print(" ("); + for (uint8_t i = 0; i < dv.options_size; i++) { + Serial.print(Helpers::translated_word(dv.options[i])); + if (i < dv.options_size - 1) { + Serial.print('|'); + } + } + Serial.print(')'); + break; + } + + case DeviceValueType::CMD: { + Serial.print("cmd"); + Serial.print(" ("); + for (uint8_t i = 0; i < dv.options_size; i++) { + Serial.print(Helpers::translated_word(dv.options[i])); + if (i < dv.options_size - 1) { + Serial.print('|'); + } + } + Serial.print(')'); + break; + } + + case DeviceValueType::USHORT: + Serial.print("ushort"); + break; + + case DeviceValueType::UINT: + Serial.print("uint"); + break; + + case DeviceValueType::SHORT: + Serial.print("short"); + break; + + case DeviceValueType::INT: + Serial.print("int"); + break; + + case DeviceValueType::ULONG: + Serial.print("ulong"); + break; + + case DeviceValueType::BOOL: + Serial.print("boolean"); + break; + + case DeviceValueType::TIME: + Serial.print("time"); + break; + + case DeviceValueType::STRING: + Serial.print("string"); + break; + + default: + break; + } + + // min/max range + int16_t dv_set_min; + uint16_t dv_set_max; + if (dv.get_min_max(dv_set_min, dv_set_max)) { + Serial.print(" (>="); + Serial.print(dv_set_min); + Serial.print("<="); + Serial.print(dv_set_max); + Serial.print(")"); + } + + Serial.print(","); + + // uom + if (dv.uom == DeviceValue::DeviceValueUOM::DEGREES || dv.uom == DeviceValue::DeviceValueUOM::DEGREES_R) { + Serial.print('C'); // the degrees symbol doesn't print nicely in XLS + } else { + Serial.print(DeviceValue::DeviceValueUOM_s[dv.uom]); + } + Serial.print(","); + + // readable, writeable, visible flags + Serial.print(!dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE) ? "true" : "false"); + Serial.print(","); + Serial.print((dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY)) ? "true" : "false"); + Serial.print(","); + Serial.print(!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) ? "true" : "false"); + + Serial.println(); + } +} +#endif + // builds json for a specific device value / entity // cmd is the endpoint or name of the device entity // returns false if failed, otherwise true diff --git a/src/emsdevice.h b/src/emsdevice.h index a826e9383..ee8a447b6 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -201,6 +201,8 @@ class EMSdevice { bool get_value_info(JsonObject & root, const char * cmd, const int8_t id); void get_dv_info(JsonObject & json); + void dump_value_info(); + enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API_SHORTNAMES, MQTT, CONSOLE }; bool generate_values(JsonObject & output, const uint8_t tag_filter, const bool nested, const uint8_t output_target); void generate_values_web(JsonObject & output); diff --git a/src/emsdevicevalue.cpp b/src/emsdevicevalue.cpp index 97e4a15c4..efa0b7ec1 100644 --- a/src/emsdevicevalue.cpp +++ b/src/emsdevicevalue.cpp @@ -63,6 +63,7 @@ DeviceValue::DeviceValue(uint8_t device_type, // set the min/max set_custom_minmax(); +/* #ifdef EMSESP_STANDALONE // only added for debugging Serial.print(COLOR_BRIGHT_RED_BACKGROUND); @@ -98,6 +99,7 @@ DeviceValue::DeviceValue(uint8_t device_type, } Serial.println(COLOR_RESET); #endif +*/ } // mapping of UOM, to match order in DeviceValueUOM enum emsdevicevalue.h diff --git a/src/emsesp.cpp b/src/emsesp.cpp index d4cc7a02f..b14eab24b 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -307,6 +307,29 @@ void EMSESP::show_ems(uuid::console::Shell & shell) { shell.println(); } +// Dump all entities to Serial out +// this is intended to run within the OS with lots of available memory! +#if defined(EMSESP_STANDALONE_DUMP) +void EMSESP::dump_all_values(uuid::console::Shell & shell) { + Serial.println("---- CSV START ----"); // marker use by py script + // add header for CSV + Serial.print("device name,device type,shortname,fullname,type [(enum values) | (min/max)],uom,readable,writeable,visible"); + Serial.println(); + + for (const auto & device_class : EMSFactory::device_handlers()) { + // go through each device type so they are sorted + for (const auto & device : device_library_) { + if (device_class.first == device.device_type) { + emsdevices.push_back(EMSFactory::add(device.device_type, 0, device.product_id, "1.0", device.name, device.flags, EMSdevice::Brand::NO_BRAND)); + emsdevices.back()->dump_value_info(); // dump all the entity information + } + } + } + + Serial.println("---- CSV END ----"); // marker use by py script +} +#endif + // show EMS device values to the shell console void EMSESP::show_device_values(uuid::console::Shell & shell) { if (emsdevices.empty()) { diff --git a/src/emsesp.h b/src/emsesp.h index 876bdd795..82ce58c5a 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -140,6 +140,7 @@ class EMSESP { static void show_device_values(uuid::console::Shell & shell); static void show_sensor_values(uuid::console::Shell & shell); + static void dump_all_values(uuid::console::Shell & shell); static void show_devices(uuid::console::Shell & shell); static void show_ems(uuid::console::Shell & shell); diff --git a/src/telegram.h b/src/telegram.h index 6c0cb5a69..9de740d09 100644 --- a/src/telegram.h +++ b/src/telegram.h @@ -52,6 +52,24 @@ static constexpr uint32_t EMS_VALUE_ULLONG_NOTSET = 0xFFFFFFFF; // for 4-byte lo static constexpr uint8_t EMS_MAX_TELEGRAM_LENGTH = 32; // max length of a complete EMS telegram static constexpr uint8_t EMS_MAX_TELEGRAM_MESSAGE_LENGTH = 27; // max length of message block, assuming EMS1.0 +#if defined(EMSESP_STANDALONE_DUMP) +#define EMS_VALUE_DEFAULT_INT 11 +#define EMS_VALUE_DEFAULT_UINT -12 +#define EMS_VALUE_DEFAULT_SHORT -1234 +#define EMS_VALUE_DEFAULT_USHORT 1234 +#define EMS_VALUE_DEFAULT_ULONG 12356 +#define EMS_VALUE_DEFAULT_BOOL 1 +#define EMS_VALUE_DEFAULT_ENUM 1 +#else +#define EMS_VALUE_DEFAULT_INT EMS_VALUE_INT_NOTSET +#define EMS_VALUE_DEFAULT_UINT EMS_VALUE_UINT_NOTSET +#define EMS_VALUE_DEFAULT_SHORT EMS_VALUE_SHORT_NOTSET +#define EMS_VALUE_DEFAULT_USHORT EMS_VALUE_USHORT_NOTSET +#define EMS_VALUE_DEFAULT_ULONG EMS_VALUE_ULONG_NOTSET +#define EMS_VALUE_DEFAULT_BOOL EMS_VALUE_BOOL_NOTSET +#define EMS_VALUE_DEFAULT_ENUM EMS_VALUE_UINT_NOTSET +#endif + namespace emsesp { class Telegram { diff --git a/src/test/test.cpp b/src/test/test.cpp index 1e6452263..cd61bd5c6 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -29,7 +29,6 @@ bool Test::run_test(const char * command, int8_t id) { return false; } - if (strcmp(command, "general") == 0) { EMSESP::logger().info("Testing general. Adding a Boiler and Thermostat"); @@ -245,6 +244,13 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const command = cmd; } +#if defined(EMSESP_STANDALONE_DUMP) + if (command == "dump") { + shell.printfln("Adding all devices and entities..."); + EMSESP::dump_all_values(shell); + } +#endif + if (command == "general") { shell.printfln("Testing adding a general boiler & thermostat..."); run_test("general"); diff --git a/src/test/test.h b/src/test/test.h index 5abd892bc..5f2b6beea 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -35,7 +35,7 @@ namespace emsesp { // #define EMSESP_DEBUG_DEFAULT "boiler" // #define EMSESP_DEBUG_DEFAULT "mqtt2" // #define EMSESP_DEBUG_DEFAULT "mqtt_nested" -#define EMSESP_DEBUG_DEFAULT "ha" +// #define EMSESP_DEBUG_DEFAULT "ha" // #define EMSESP_DEBUG_DEFAULT "masked" // #define EMSESP_DEBUG_DEFAULT "board_profile" // #define EMSESP_DEBUG_DEFAULT "shower_alert" @@ -52,6 +52,7 @@ namespace emsesp { // #define EMSESP_DEBUG_DEFAULT "mqtt_post" // #define EMSESP_DEBUG_DEFAULT "api_wwmode" // #define EMSESP_DEBUG_DEFAULT "custom" +#define EMSESP_DEBUG_DEFAULT "dump" class Test { public: