diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 03cca966b..22ca3e11f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,11 +27,15 @@ jobs: - uses: actions/setup-python@v7 with: python-version: '3.13' + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + version: "latest" + enable-cache: false - name: Build documentation run: | cd docs sudo apt install imagemagick zip - pip install uv uv pip install --system -r requirements.txt python ./builds_overview.py make html @@ -50,9 +54,13 @@ jobs: - uses: actions/setup-python@v7 with: python-version: '3.13' + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + version: "latest" + enable-cache: false - id: set-matrix run: | - pip install uv uv pip install --system pioarduino python tools/ci/generate-matrix.py @@ -66,24 +74,24 @@ jobs: - uses: actions/setup-python@v7 with: python-version: '3.13' - - name: Dependencies + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + version: "latest" + enable-cache: false + - name: Install dependencies run: | - sudo apt-get update - sudo apt install binutils build-essential libffi-dev libgit2-dev - pip install uv - uv pip install --system -r requirements.txt - pio pkg update -e ${{ matrix.env }} + uv pip install --system pioarduino + uv pip install --system pygit2>=1.10.1 - name: Get current date id: date run: | echo "builddate=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT - - name: Build and archive - id: build-and-archive + - name: Run PlatformIO env: - CHIP: ${{ matrix.chip }} - ENV: ${{ matrix.env }} - run: | - python tools/ci/build-and-archive.py + PYTHONIOENCODING: utf-8 + PYTHONUTF8: '1' + run: platformio run -e ${{ matrix.env }} - id: string uses: Entepotenz/change-string-case-action-min-dependencies@v1 with: @@ -93,7 +101,7 @@ jobs: # FIXME Workaround to (temporarily) not use # in the artifact name, see https://github.com/actions/upload-artifact/issues/473 name: Bin-${{ steps.string.outputs.uppercase }}-${{ matrix.env }}-${{ steps.date.outputs.builddate }}_PR_${{ github.event.number }}_${{ github.run_id }} # Sort by ESP type path: | - bin + ./build_output/bin if-no-files-found: ignore # Package all ESP82xx and ESP32 into a single ESPEasy-all-Binaries-_PR#_.zip diff --git a/platformio_special_envs.ini b/platformio_special_envs.ini index 75538698c..98b1d40d5 100644 --- a/platformio_special_envs.ini +++ b/platformio_special_envs.ini @@ -5,10 +5,10 @@ [debug_pio] build_type = debug -;check_tool = clangtidy -check_tool = pvs-studio +check_tool = clangtidy +;check_tool = pvs-studio check_flags = - pvs-studio: --analysis-mode=4 --errors-off=V532,V586,V795,V1042 --lic-file=../pvs_studio.lic +; pvs-studio: --analysis-mode=4 --errors-off=V532,V586,V795,V1042 --lic-file=../pvs_studio.lic build_flags = ${compiler_warnings.build_flags} diff --git a/requirements.txt b/requirements.txt index 777e2035b..7dcd69fcc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -pioarduino==6.1.19 +pioarduino==6.2.0 pygit2>=1.10.1 cryptography==50.0.0 setuptools>=75.8 diff --git a/src/src/DataStructs/ValueStruct.cpp b/src/src/DataStructs/ValueStruct.cpp index a0fd71085..fdb7fbf08 100644 --- a/src/src/DataStructs/ValueStruct.cpp +++ b/src/src/DataStructs/ValueStruct.cpp @@ -41,6 +41,20 @@ ValueStruct ValueStruct::makeHexFormatted(uint64_t val, uint8_t minNrDigits) return res; } +ValueStruct ValueStruct::makeHexDecimalFormatted(uint64_t val, + uint8_t minNrDigits) +{ + ValueStruct res(val); + + // TODO TD-er: Add factor option for decimal formatted, like in String formatToHex_decimal(uint32_t value, uint32_t factor) + // Or maybe just a flag to make it 'human readable' and maybe whether the factor should be 1000 or 1024. + + res.setPreferredFormat(PreferredFormat::Hex_Dec); + res.setMinNrDigits(minNrDigits); + res.setCaseFormat(CaseFormat::ToUpper); + return res; +} + ValueStruct ValueStruct::makeBinFormatted(uint64_t val, uint8_t minNrDigits) { ValueStruct res(val); @@ -685,8 +699,14 @@ size_t ValueStruct::print(Print& out, ValueType& valueType, bool unformatted) co return out.print(concat(F("0b"), ull2String(u64_val, BIN, _minNrDigits))); } - if (format == PreferredFormat::Hex) { - return out.print(concat(F("0x"), ull2String(u64_val, HEX, _minNrDigits, '\0', getCaseFormat(unformatted) == CaseFormat::ToUpper))); + if ((format == PreferredFormat::Hex) || (format == PreferredFormat::Hex_Dec)) { + String str = concat(F("0x"), ull2String(u64_val, HEX, _minNrDigits, '\0', getCaseFormat(unformatted) == CaseFormat::ToUpper)); + + if (format == PreferredFormat::Hex_Dec) { + // Old implementation: formatToHex_decimal + str += strformat(F(" (%s)"), ull2String(u64_val, DEC /*, _minNrDigits*/).c_str()); + } + return out.print(std::move(str)); } if ((_size > 32) || _minNrDigits) { diff --git a/src/src/DataStructs/ValueStruct.h b/src/src/DataStructs/ValueStruct.h index 4da33a349..0d60a4f9e 100644 --- a/src/src/DataStructs/ValueStruct.h +++ b/src/src/DataStructs/ValueStruct.h @@ -46,7 +46,8 @@ public: enum class PreferredFormat : uint8_t { Default = 0, Bin, - Hex + Hex, + Hex_Dec // for example: "0x1234 (4660)" }; @@ -103,6 +104,8 @@ public: static ValueStruct makeHexFormatted(uint64_t val, uint8_t minNrDigits); + static ValueStruct makeHexDecimalFormatted(uint64_t val, + uint8_t minNrDigits); static ValueStruct makeBinFormatted(uint64_t val, uint8_t minNrDigits); @@ -118,7 +121,8 @@ public: void setInt(size_t val); #endif - void setIPAddress(const IPAddress& ip, bool includeZone = false); + void setIPAddress(const IPAddress& ip, + bool includeZone = false); ValueStruct::ValueType getValueType() const { diff --git a/src/src/Helpers/Dallas1WireHelper.cpp b/src/src/Helpers/Dallas1WireHelper.cpp index 60bc9652f..eb2c2372f 100644 --- a/src/src/Helpers/Dallas1WireHelper.cpp +++ b/src/src/Helpers/Dallas1WireHelper.cpp @@ -34,6 +34,12 @@ # endif // ifdef ESP32 +# ifndef DALLAS_RESET_RETRIES + +// Reset may fail if a +# define DALLAS_RESET_RETRIES 3 +# endif // ifndef DALLAS_RESET_RETRIES + # include unsigned char ROM_NO[8]{ 0 }; @@ -45,7 +51,6 @@ int32_t usec_release{}; int32_t presence_start{}; int32_t presence_end{}; - void DALLAS_IRAM_ATTR Dallas_pinModeInput(uint32_t gpio_pin_rx, uint32_t gpio_pin_tx) { if (gpio_pin_rx == gpio_pin_tx) { @@ -132,7 +137,8 @@ int Dallas_measure_rise_time(int8_t gpio_pin_rx, int8_t gpio_pin_tx) // http://owfs.sourceforge.net/simple_family.html // https://github.com/owfs/owfs-doc/wiki/1Wire-Device-List const __FlashStringHelper* Dallas_getModel(uint8_t family, const bool hasFixedResolution) { - switch (family) { + switch (family) + { case 0x28: return F("DS18B20"); case 0x3b: return hasFixedResolution ? F("MAX31826") : F("DS1825"); case 0x22: return F("DS1822"); @@ -271,13 +277,14 @@ void Dallas_addr_selector_webform_load(taskIndex_t TaskIndex, int8_t gpio_pin_rx } const bool selected = (memcmp(tmpAddress, savedAddress, 8) == 0); - addSelector_Item(option, index, selected); + addSelector_Item_index64(option, scan_res[index], selected); } addSelector_Foot(); } } # ifndef LIMIT_BUILD_SIZE + void Dallas_show_sensor_stats_webform_load(const Dallas_SensorData& sensor_data) { if (sensor_data.addr == 0) { @@ -338,10 +345,10 @@ void Dallas_addr_selector_webform_save(taskIndex_t TaskIndex, int8_t gpio_pin_rx uint8_t addr[8]{}; for (uint8_t var_index = 0; var_index < nrVariables; ++var_index) { - const int selection = getFormItemInt(concat(F("dallas_addr"), static_cast(var_index)), -1); + const uint64_t selection = getFormItemUInt64(concat(F("dallas_addr"), static_cast(var_index)), 0); - if (selection != -1) { - Dallas_scan(selection, addr, gpio_pin_rx, gpio_pin_tx); + if (selection != 0) { + Dallas_uint64_to_addr(selection, addr); Dallas_plugin_set_addr(addr, TaskIndex, var_index); } } @@ -411,6 +418,7 @@ uint8_t Dallas_scan(uint8_t getDeviceROM, uint8_t *ROM, int8_t gpio_pin_rx, int8 // read power supply # ifndef LIMIT_BUILD_SIZE + bool Dallas_is_parasite(const uint8_t ROM[8], int8_t gpio_pin_rx, int8_t gpio_pin_tx, bool& isParasitePowered) { if (!Dallas_address_ROM(ROM, gpio_pin_rx, gpio_pin_tx)) { @@ -435,6 +443,7 @@ bool Dallas_is_parasite(const uint8_t ROM[8], int8_t gpio_pin_rx, int8_t gpio_pi Dallas_write(0x44, gpio_pin_rx, gpio_pin_tx); } */ + /*********************************************************************************************\ * Dallas Read temperature from scratchpad \*********************************************************************************************/ @@ -535,6 +544,7 @@ Dallas_read_result Dallas_readTemp(const uint8_t ROM[8], float *value, int8_t gp } # ifdef USES_P080 + bool Dallas_readiButton(const uint8_t addr[8], int8_t gpio_pin_rx, int8_t gpio_pin_tx, int8_t lastState) { // maybe this is needed to trigger the reading @@ -783,113 +793,117 @@ bool Dallas_setResolution(const uint8_t ROM[8], uint8_t res, int8_t gpio_pin_rx, \*********************************************************************************************/ uint8_t Dallas_reset(int8_t gpio_pin_rx, int8_t gpio_pin_tx) { - presence_start = 0; - presence_end = 0; + for (uint8_t attempt = 0; attempt < DALLAS_RESET_RETRIES; ++attempt) { + presence_start = 0; + presence_end = 0; - // Keep track of usec_release as it is an indicator for the recovery time - usec_release = Dallas_measure_rise_time(gpio_pin_rx, gpio_pin_tx); - delayMicroseconds(10); + // Keep track of usec_release as it is an indicator for the recovery time + // Only call ISR_noInterrupts(); after this Dallas_measure_rise_time as it also disables interrupts. + usec_release = Dallas_measure_rise_time(gpio_pin_rx, gpio_pin_tx); + delayMicroseconds(10); - ISR_noInterrupts(); + ISR_noInterrupts(); -# ifdef DEBUG_LOGIC_ANALYZER_PIN - - // DEBUG code using logic analyzer for timings - DIRECT_pinWrite(DEBUG_LOGIC_ANALYZER_PIN, 1); -# endif // ifdef DEBUG_LOGIC_ANALYZER_PIN - - Dallas_pinInput; - -# ifdef DEBUG_LOGIC_ANALYZER_PIN - - // DEBUG code using logic analyzer for timings - DIRECT_pinWrite(DEBUG_LOGIC_ANALYZER_PIN, 0); -# endif // ifdef DEBUG_LOGIC_ANALYZER_PIN - - // wait until the wire is high... just in case - if (Dallas_waitForPinHigh(gpio_pin_rx, micros(), 250)) { # ifdef DEBUG_LOGIC_ANALYZER_PIN // DEBUG code using logic analyzer for timings DIRECT_pinWrite(DEBUG_LOGIC_ANALYZER_PIN, 1); # endif // ifdef DEBUG_LOGIC_ANALYZER_PIN - - // The master starts a transmission with a reset pulse, - // which pulls the wire to 0 volts for at least 480 µs. - // This resets communication of every slave device on the bus. - Dallas_pinLow; - - delayMicroseconds(480); // t_RSTL 480 ... 960 usec - - // puling pin high will be very fast, so start measurement before pulling high - const uint32_t start = micros(); - Dallas_pinHigh; - - // digitalWrite(gpio_pin_tx, 1); - delayMicroseconds(1); - - - // Set to 'input', state will be pulled high by pull-up resistor - // Or will be kept pulled low by sensor - Dallas_pinInput; + { + Dallas_pinInput; # ifdef DEBUG_LOGIC_ANALYZER_PIN - // DEBUG code using logic analyzer for timings - DIRECT_pinWrite(DEBUG_LOGIC_ANALYZER_PIN, 0); + // DEBUG code using logic analyzer for timings + DIRECT_pinWrite(DEBUG_LOGIC_ANALYZER_PIN, 0); +# endif // ifdef DEBUG_LOGIC_ANALYZER_PIN + + // wait until the wire is high... just in case + if (Dallas_waitForPinHigh(gpio_pin_rx, micros(), 250)) { +# ifdef DEBUG_LOGIC_ANALYZER_PIN + + // DEBUG code using logic analyzer for timings + DIRECT_pinWrite(DEBUG_LOGIC_ANALYZER_PIN, 1); +# endif // ifdef DEBUG_LOGIC_ANALYZER_PIN + + // The master starts a transmission with a reset pulse, + // which pulls the wire to 0 volts for at least 480 µs. + // This resets communication of every slave device on the bus. + Dallas_pinLow; + + delayMicroseconds(480); // t_RSTL 480 ... 960 usec + + // puling pin high will be very fast, so start measurement before pulling high + const uint32_t start = micros(); + Dallas_pinHigh; + + // digitalWrite(gpio_pin_tx, 1); + delayMicroseconds(1); + + + // Set to 'input', state will be pulled high by pull-up resistor + // Or will be kept pulled low by sensor + Dallas_pinInput; + +# ifdef DEBUG_LOGIC_ANALYZER_PIN + + // DEBUG code using logic analyzer for timings + DIRECT_pinWrite(DEBUG_LOGIC_ANALYZER_PIN, 0); # endif // ifdef DEBUG_LOGIC_ANALYZER_PIN - // After that, any slave device, if present, shows that it exists with a "presence" pulse: - // it holds the bus low for at least 60 µs after the master releases the bus. - // This may take about 25 usec after release for present sensors to pull the line low. - // Sequence: - // - Release => pin high (typ: 1 usec as it was actively pulled high by GPIO) - // - Presence condition start (typ: 25 usec after release) - // - Presence condition end (minimal duration 60 usec, typ: 110 usec) - // - Wait till 480 usec after release. + // After that, any slave device, if present, shows that it exists with a "presence" pulse: + // it holds the bus low for at least 60 µs after the master releases the bus. + // This may take about 25 usec after release for present sensors to pull the line low. + // Sequence: + // - Release => pin high (typ: 1 usec as it was actively pulled high by GPIO) + // - Presence condition start (typ: 25 usec after release) + // - Presence condition end (minimal duration 60 usec, typ: 110 usec) + // - Wait till 480 usec after release. - // First check will only be to make sure the pin isn't pulled down for whatever reason - // Since we set the pin to high, this should return immediately - if (Dallas_waitForPinHigh(gpio_pin_rx, start, 15)) { - // Signal fall time will be quite fast, so no correction needed - presence_start = Dallas_measureWaitForPinLow(gpio_pin_rx, start, 60); + // First check will only be to make sure the pin isn't pulled down for whatever reason + // Since we set the pin to high, this should return immediately + if (Dallas_waitForPinHigh(gpio_pin_rx, start, 15)) { + // Signal fall time will be quite fast, so no correction needed + presence_start = Dallas_measureWaitForPinLow(gpio_pin_rx, start, 60); - if (presence_start > 15) { - // t_PDH 15 ... 60 usec - // t_PDL 60 ... 240 usec + if (presence_start > 15) { + // t_PDH 15 ... 60 usec + // t_PDL 60 ... 240 usec - // Signal will rise only due to pull-up resistor - // Meaning measured duration may be off by usec_release (too int32_t) - presence_end = Dallas_measureWaitForPinHigh(gpio_pin_rx, start, 60 + 240); + // Signal will rise only due to pull-up resistor + // Meaning measured duration may be off by usec_release (too int32_t) + presence_end = Dallas_measureWaitForPinHigh(gpio_pin_rx, start, 60 + 240); - // Set the pin high, just in case we have a (single) parasitic powered sensor - Dallas_pinHigh; + // Set the pin high, just in case we have a (single) parasitic powered sensor + Dallas_pinHigh; - // Enable interrupts again as soon as timing-critical section is done - ISR_interrupts(); + // Enable interrupts again as soon as timing-critical section is done + ISR_interrupts(); - const int32_t presence_duration = presence_end - presence_start; + const int32_t presence_duration = presence_end - presence_start; - if ((presence_duration >= 60) && (presence_duration < (240 /* + usec_release*/))) { - // t_RSTH = 480 usec - const int32_t timeLeft = 480 - usecPassedSince_fast(start); + if ((presence_duration >= 60) && (presence_duration < (240 /* + usec_release*/))) { + // t_RSTH = 480 usec + const int32_t timeLeft = 480 - usecPassedSince_fast(start); - if (timeLeft > 0) { - delayMicroseconds(timeLeft); + if (timeLeft > 0) { + delayMicroseconds(timeLeft); + } + + return 1; + } } - - return 1; } - return 0; } + + // Set the pin high, just in case we have a (single) parasitic powered sensor + Dallas_pinHigh; + + ISR_interrupts(); } } - // Set the pin high, just in case we have a (single) parasitic powered sensor - Dallas_pinHigh; - - ISR_interrupts(); return 0; } @@ -1176,7 +1190,7 @@ void Dallas_write_bit(uint8_t v, int8_t gpio_pin_rx, int8_t gpio_pin_tx) // High time is based on the recovery time, which is detected during reset const int32_t low_time = (v & 1) ? 7 : 60; const int32_t high_time = (v & 1) ? (40 + usec_release) : (2 * usec_release + 20); // Recovery time - uint32_t start = 0; + uint32_t start = 0; Dallas_write_bit_ISR(v, gpio_pin_rx, gpio_pin_tx, low_time, high_time, start); @@ -1191,8 +1205,8 @@ void Dallas_write_bit(uint8_t v, int8_t gpio_pin_rx, int8_t gpio_pin_tx) void DALLAS_IRAM_ATTR Dallas_write_bit_ISR(uint8_t v, int8_t gpio_pin_rx, int8_t gpio_pin_tx, - int32_t low_time, - int32_t high_time, + int32_t low_time, + int32_t high_time, uint32_t& start) { ISR_noInterrupts(); @@ -1345,7 +1359,8 @@ bool Dallas_SensorData::collect_value(int8_t gpio_rx, int8_t gpio_tx) { --nrRetries; Dallas_read_result res = Dallas_readTemp(tmpaddr, &value, gpio_rx, gpio_tx); - switch (res) { + switch (res) + { case Dallas_read_result::OK: ++read_success; lastReadError = false; diff --git a/src/src/WebServer/Markup.cpp b/src/src/WebServer/Markup.cpp index 5eb476359..c266ffe77 100644 --- a/src/src/WebServer/Markup.cpp +++ b/src/src/WebServer/Markup.cpp @@ -276,6 +276,24 @@ void addSelector_Item(const __FlashStringHelper *option, int index, bool sele } void addSelector_Item(const String& option, int index, bool selected, bool disabled, const String& attr) +{ + addSelector_Item(option, String(index), selected, disabled, attr); +} + +void addSelector_Item_index64(const String& option, + uint64_t index, + bool selected, + bool disabled, + const String& attr) +{ + addSelector_Item(option, ull2String(index), selected, disabled, attr); +} + +void addSelector_Item(const String& option, + const String& index, + bool selected, + bool disabled, + const String& attr) { addHtml(F("