diff --git a/src/_P126_74HC595.ino b/src/_P126_74HC595.ino index 16659b4109..3f6703dd8e 100644 --- a/src/_P126_74HC595.ino +++ b/src/_P126_74HC595.ino @@ -7,6 +7,7 @@ // ####################################################################################################### /** Changelog: + * 2026-06-30 tonhuisman: Code optimization by moving ul2stringFixed to StringConverter_Numerical * 2025-01-12 tonhuisman: Add support for MQTT AutoDiscovery (not supported for Shift registers) * 2022-02-27 tonhuisman: Rename plugin title to Output - Shift registers (74HC595) * 2022-02-25 tonhuisman: Again rename commands, now using separate prefix shiftout and the rest of the previous command as subcommand. @@ -59,19 +60,6 @@ # include "./src/PluginStructs/P126_data_struct.h" -// TODO tonhuisman: ? Move to StringConverter ? though it is a bit specific, can also be used by P129 -String P126_ul2stringFixed(uint32_t value, uint8_t base) { - uint64_t val = static_cast(value); - - val &= 0x0ffffffff; // Keep 32 bits - val |= 0x100000000; // Set bit just left of 32 bits so we will see the leading zeroes - String valStr = ull2String(val, base); - - valStr.remove(0, 1); // Delete leading 1 we added - valStr.toUpperCase(); // uppercase hex for readability - return valStr; -} - boolean Plugin_126(uint8_t function, struct EventStruct *event, String& string) { boolean success = false; @@ -286,15 +274,16 @@ boolean Plugin_126(uint8_t function, struct EventStruct *event, String& string) (P126_CONFIG_FLAGS_GET_OUTPUT_SELECTION == P126_OUTPUT_HEXBIN)) { string += '0'; string += (P126_CONFIG_FLAGS_GET_VALUES_DISPLAY ? 'b' : 'x'); - string += P126_ul2stringFixed(UserVar.getUint32(event->TaskIndex, event->idx), - # ifdef P126_SHOW_VALUES - (P126_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : - # endif // ifdef P126_SHOW_VALUES - HEX - # ifdef P126_SHOW_VALUES - ) - # endif // ifdef P126_SHOW_VALUES - ); + + string += ul2stringFixed(UserVar.getUint32(event->TaskIndex, event->idx), + # ifdef P126_SHOW_VALUES + (P126_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : + # endif // ifdef P126_SHOW_VALUES + HEX + # ifdef P126_SHOW_VALUES + ) + # endif // ifdef P126_SHOW_VALUES + , 1 == event->ParN[event->idx]); } success = true; break; @@ -308,21 +297,15 @@ boolean Plugin_126(uint8_t function, struct EventStruct *event, String& string) const String abcd = F("ABCDEFGH"); // In case anyone dares to extend // VARS_PER_TASK to 8... const uint16_t endCheck = P126_CONFIG_CHIP_COUNT + (P126_CONFIG_CHIP_COUNT == 255 ? 3 : 4); // 4(.0) = nr of bytes in an uint32_t. - const uint16_t maxVar = min(static_cast(VARS_PER_TASK), static_cast(ceil(P126_CONFIG_CHIP_COUNT / 4.0))); - uint8_t dotInsert; - uint8_t dotOffset; + const uint16_t maxVar = min(static_cast(VARS_PER_TASK), static_cast(ceilf(P126_CONFIG_CHIP_COUNT / 4.0f))); for (uint16_t varNr = 0; varNr < maxVar; ++varNr) { if (P126_CONFIG_FLAGS_GET_VALUES_DISPLAY) { label = F("Bin"); state = F("0b"); - dotInsert = 10; - dotOffset = 9; } else { label = F("Hex"); state = F("0x"); - dotInsert = 4; - dotOffset = 3; } label += strformat(F(" State_%s "), abcd.substring(varNr, varNr + 1).c_str()); @@ -331,11 +314,7 @@ boolean Plugin_126(uint8_t function, struct EventStruct *event, String& string) label += (P126_CONFIG_SHOW_OFFSET + (4 * varNr) + 1); // 4 = nr of bytes in an uint32_t. if ((P126_CONFIG_SHOW_OFFSET + (4 * varNr) + 4) <= endCheck) { // Only show if still in range - state += P126_ul2stringFixed(UserVar.getUint32(event->TaskIndex, varNr), P126_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : HEX); - - for (uint8_t i = 0; i < 3; ++i, dotInsert += dotOffset) { // Insert readability separators - state = state.substring(0, dotInsert) + '.' + state.substring(dotInsert); - } + state += ul2stringFixed(UserVar.getUint32(event->TaskIndex, varNr), P126_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : HEX, true); pluginWebformShowValue(event->TaskIndex, VARS_PER_TASK + varNr, label, state, true); } } diff --git a/src/_P129_74HC165.ino b/src/_P129_74HC165.ino index 27f54c0150..bf0b73511a 100644 --- a/src/_P129_74HC165.ino +++ b/src/_P129_74HC165.ino @@ -7,6 +7,7 @@ // ####################################################################################################### /** Changelog: + * 2026-06-30 tonhuisman: Code optimization by moving ul2stringFixed to StringConverter_Numerical * 2025-06-14 tonhuisman: Add support for Custom Value Type per task value * 2025-01-12 tonhuisman: Add support for MQTT AutoDiscovery (not supported for Shift registers) * 2023-01-04 tonhuisman: Use DIRECT_pin GPIO functions for faster GPIO handling (mostly on ESP32), string optimization @@ -43,19 +44,6 @@ # include "./src/PluginStructs/P129_data_struct.h" -// TODO tonhuisman: ? Move to StringConverter ? though it is a bit specific, can also be used by P126 -String P129_ul2stringFixed(uint32_t value, uint8_t base) { - // Set bit just left of 32 bits so we will see the leading zeroes - const uint64_t val = static_cast(value) | 0x100000000ull; - - String valStr = ull2String(val, base).substring(1); // Delete leading 1 we added - - if (base == HEX) { - valStr.toUpperCase(); // uppercase hex for readability - } - return valStr; -} - boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) { boolean success = false; @@ -146,7 +134,7 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_GET_DEVICEVALUECOUNT: { event->Par1 = min(static_cast(VARS_PER_TASK), - static_cast(ceil(P129_CONFIG_CHIP_COUNT / 4.0f))); + static_cast(ceilf(P129_CONFIG_CHIP_COUNT / 4.0f))); success = true; break; } @@ -155,7 +143,7 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) { event->sensorType = static_cast( min(static_cast(VARS_PER_TASK), - static_cast(ceil(P129_CONFIG_CHIP_COUNT / 4.0f)))); + static_cast(ceilf(P129_CONFIG_CHIP_COUNT / 4.0f)))); event->idx = 0; success = true; break; @@ -187,6 +175,7 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) F("Number of chips (Q7 → DS)"), F("chipcnt"), P129_CONFIG_CHIP_COUNT); addUnit(concat(F("Daisychained 1.."), P129_MAX_CHIP_COUNT)); # ifndef LIMIT_BUILD_SIZE + // addFormNote(F("Changing the number of chips will reload the page and update the Event configuration.")); # endif // ifndef LIMIT_BUILD_SIZE } @@ -240,12 +229,12 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) if (i % 4 == 0) { bits = PCONFIG_ULONG(i / 4) & 0x0ffffffff; off = 0; - # ifndef P129_DEBUG_LOG + # ifdef P129_DEBUG_LOG if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("74HC165 Reading from: %d, bits: %s"), i / 4, P129_ul2stringFixed(bits, BIN).c_str())); + addLog(LOG_LEVEL_INFO, strformat(F("74HC165 Reading from: %d, bits: %s"), i / 4, ul2stringFixed(bits, BIN, false).c_str())); } - # endif // ifndef P129_DEBUG_LOG + # endif // ifdef P129_DEBUG_LOG } html_TR(); addHtml(F("")); @@ -310,15 +299,15 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) } PCONFIG_ULONG(i / 4) = bits; - # ifndef P129_DEBUG_LOG + # ifdef P129_DEBUG_LOG if (loglevelActiveFor(LOG_LEVEL_INFO) && ((i % 4 == 3) || (i == P129_CONFIG_CHIP_COUNT))) { addLog(LOG_LEVEL_INFO, strformat(F("74HC165 Writing to: %d, offset: %d, bits: %s"), i / 4, off * 8, - P129_ul2stringFixed(bits, BIN).c_str())); + ul2stringFixed(bits, BIN, false).c_str())); } - # endif // ifndef P129_DEBUG_LOG + # endif // ifdef P129_DEBUG_LOG off++; } success = true; @@ -391,15 +380,16 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) (P129_CONFIG_FLAGS_GET_OUTPUT_SELECTION == P129_OUTPUT_HEXBIN)) { string += '0'; string += (P129_CONFIG_FLAGS_GET_VALUES_DISPLAY ? 'b' : 'x'); - string += P129_ul2stringFixed(UserVar.getUint32(event->TaskIndex, event->idx), - # ifdef P129_SHOW_VALUES - (P129_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : - # endif // ifdef P129_SHOW_VALUES - HEX - # ifdef P129_SHOW_VALUES - ) - # endif // ifdef P129_SHOW_VALUES - ); + + string += ul2stringFixed(UserVar.getUint32(event->TaskIndex, event->idx), + # ifdef P129_SHOW_VALUES + (P129_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : + # endif // ifdef P129_SHOW_VALUES + HEX + # ifdef P129_SHOW_VALUES + ) + # endif // ifdef P129_SHOW_VALUES + , 1 == event->ParN[event->idx]); } success = true; break; @@ -412,21 +402,15 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) state.reserve(40); const String abcd = F("ABCDEFGH"); // In case anyone dares to extend VARS_PER_TASK to 8... const uint16_t endCheck = P129_CONFIG_CHIP_COUNT + 4; // 4(.0) = nr of bytes in an uint32_t. - const uint16_t maxVar = min(static_cast(VARS_PER_TASK), static_cast(ceil(P129_CONFIG_CHIP_COUNT / 4.0f))); - uint8_t dotInsert; - uint8_t dotOffset; + const uint16_t maxVar = min(static_cast(VARS_PER_TASK), static_cast(ceilf(P129_CONFIG_CHIP_COUNT / 4.0f))); for (uint16_t varNr = 0; varNr < maxVar; ++varNr) { if (P129_CONFIG_FLAGS_GET_VALUES_DISPLAY) { label = F("Bin"); state = F("0b"); - dotInsert = 10; - dotOffset = 9; } else { label = F("Hex"); state = F("0x"); - dotInsert = 4; - dotOffset = 3; } label += strformat(F(" State_%s "), abcd.substring(varNr, varNr + 1).c_str()); @@ -435,11 +419,7 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) label += (P129_CONFIG_SHOW_OFFSET + (4 * varNr) + 1); // 4 = nr of bytes in an uint32_t. if ((P129_CONFIG_SHOW_OFFSET + (4 * varNr) + 4) <= endCheck) { // Only show if still in range - state += P129_ul2stringFixed(UserVar.getUint32(event->TaskIndex, varNr), P129_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : HEX); - - for (uint8_t i = 0; i < 3; ++i, dotInsert += dotOffset) { // Insert readability separators - state = state.substring(0, dotInsert) + '.' + state.substring(dotInsert); - } + state += ul2stringFixed(UserVar.getUint32(event->TaskIndex, varNr), P129_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : HEX, true); pluginWebformShowValue(event->TaskIndex, VARS_PER_TASK + varNr, label, state, true); } } diff --git a/src/src/Helpers/StringConverter_Numerical.cpp b/src/src/Helpers/StringConverter_Numerical.cpp index d7bd1b68a3..53b302f55c 100644 --- a/src/src/Helpers/StringConverter_Numerical.cpp +++ b/src/src/Helpers/StringConverter_Numerical.cpp @@ -95,6 +95,42 @@ String ll2String(int64_t value, uint8_t base) { } } +/** + * format an uint32_t with 0-prefixed in the provided base of 2, 16 and insert an optional dot as separator for each byte + * separator only applied for base 2 and 16 + */ +String ul2stringFixed(uint32_t value, uint8_t base, bool dotSeparator) { + // Set bit just left of 32 bits so we will see the leading zeroes + const uint64_t val = static_cast(value) | 0x100000000ull; + + String valStr = ull2String(val, base).substring(1); // Delete leading 1 we added + + if (base == HEX) { + valStr.toUpperCase(); // uppercase hex for readability + } + + if (dotSeparator) { + uint8_t dotInsert{}; + uint8_t dotOffset{}; + + if (BIN == base) { + dotInsert = 10; + dotOffset = 9; + } else + if (HEX == base) { + dotInsert += 4; + dotOffset = 3; + } + + if (dotInsert) { + for (uint8_t i = 0; i < 3; ++i, dotInsert += dotOffset) { // Insert readability separators + valStr = valStr.substring(0, dotInsert) + '.' + valStr.substring(dotInsert); + } + } + } + return valStr; +} + String trimTrailingZeros(const String& value) { String res(value); int dot_pos = res.lastIndexOf('.'); diff --git a/src/src/Helpers/StringConverter_Numerical.h b/src/src/Helpers/StringConverter_Numerical.h index e6acb300f9..e7f0c3bd1b 100644 --- a/src/src/Helpers/StringConverter_Numerical.h +++ b/src/src/Helpers/StringConverter_Numerical.h @@ -35,6 +35,11 @@ String ull2String(uint64_t value, String ll2String(int64_t value, uint8_t base = 10); +String ul2stringFixed(uint32_t value, + uint8_t base, + bool dotSeparator); + + String trimTrailingZeros(const String& value); String toStringNoZero(int64_t value); diff --git a/src/src/PluginStructs/P126_data_struct.cpp b/src/src/PluginStructs/P126_data_struct.cpp index 3aae12ad20..a08b2bb4ca 100644 --- a/src/src/PluginStructs/P126_data_struct.cpp +++ b/src/src/PluginStructs/P126_data_struct.cpp @@ -35,7 +35,7 @@ bool P126_data_struct::plugin_init(struct EventStruct *event) { } const uint16_t maxVar = min(static_cast(VARS_PER_TASK), - static_cast(ceil((P126_CONFIG_CHIP_COUNT - P126_CONFIG_SHOW_OFFSET) / 4.0))); + static_cast(ceilf((P126_CONFIG_CHIP_COUNT - P126_CONFIG_SHOW_OFFSET) / 4.0f))); uint32_t par; for (uint16_t varNr = 0; varNr < maxVar; ++varNr) { diff --git a/src/src/WebServer/JSON.cpp b/src/src/WebServer/JSON.cpp index 90eb4ed797..c9eef9f3c1 100644 --- a/src/src/WebServer/JSON.cpp +++ b/src/src/WebServer/JSON.cpp @@ -519,6 +519,29 @@ void handle_json() #endif // if FEATURE_STRING_VARIABLES uom); } + + if (Device[DeviceIndex].HasFormatUserVar) { + struct EventStruct TempEvent(TaskIndex); + + for (uint8_t x = 0; x < valueCount; x++) + { + String value; + TempEvent.idx = x; + TempEvent.ParN[x] = 1; // Get formatted version of the value + PluginCall(PLUGIN_FORMAT_USERVAR, &TempEvent, value); + + if (!value.isEmpty()) { + handle_json_stream_task_value_data(taskValueWriter.get(), + VARS_PER_TASK + x + 1, + Cache.getTaskDeviceValueName(TaskIndex, x), + 255, + value, + EMPTY_STRING, + EMPTY_STRING); + } + } + // FIXME tonhuisman: HasFormatUserVar is not really compatible with Derived Values... + } #if FEATURE_STRING_VARIABLES if (Settings.ShowDerivedTaskValues(TaskIndex)) {