From daeb6a6878e0ba667817262a3a58b472c828bde5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 10:43:43 +0000 Subject: [PATCH 01/12] Bump softprops/action-gh-release in the all-actions group Bumps the all-actions group with 1 update: [softprops/action-gh-release](https://github.com/softprops/action-gh-release). Updates `softprops/action-gh-release` from 2.6.1 to 3.0.0 - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2.6.1...v3.0.0) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: 3.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: all-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/Create-NewReleases.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Create-NewReleases.yml b/.github/workflows/Create-NewReleases.yml index bb9b258..ce63171 100644 --- a/.github/workflows/Create-NewReleases.yml +++ b/.github/workflows/Create-NewReleases.yml @@ -97,7 +97,7 @@ jobs: # 7--- Publish a GitHub Release with auto-generated notes - name: Create Release with Automated Release Notes - uses: softprops/action-gh-release@v2.6.1 + uses: softprops/action-gh-release@v3.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} tag_name: ${{ steps.nextver.outputs.tag }} From f477526bf976e25039953134e2210c2ce47e290c Mon Sep 17 00:00:00 2001 From: Martinski4GitHub <119833648+Martinski4GitHub@users.noreply.github.com> Date: Wed, 15 Apr 2026 09:09:58 -0700 Subject: [PATCH 02/12] Code Improvement Modified code to ensure that the F/W built-in hook scripts used by the add-on have executable permissions. --- README.md | 4 +-- spdmerlin.sh | 78 +++++++++++++++++++++++++++++++--------------------- 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index f5f6d77..24b36ab 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # spdMerlin -## v4.4.19 -### Updated on 2026-Apr-11 +## v4.4.20 +### Updated on 2026-Apr-15 ## About spdMerlin is an internet speedtest and monitoring tool for AsusWRT Merlin with charts for daily, weekly and monthly summaries. It tracks download/upload bandwidth as well as latency, jitter and packet loss. diff --git a/spdmerlin.sh b/spdmerlin.sh index e847936..1c7eb18 100644 --- a/spdmerlin.sh +++ b/spdmerlin.sh @@ -14,7 +14,7 @@ ## Forked from https://github.com/jackyaz/spdMerlin ## ## ## ############################################################## -# Last Modified: 2026-Apr-11 +# Last Modified: 2026-Apr-15 #------------------------------------------------------------- ############## Shellcheck directives ############# @@ -38,8 +38,8 @@ ### Start of script variables ### readonly SCRIPT_NAME="spdMerlin" readonly SCRIPT_NAME_LOWER="$(echo "$SCRIPT_NAME" | tr 'A-Z' 'a-z')" -readonly SCRIPT_VERSION="v4.4.19" -readonly SCRIPT_VERSTAG="26041103" +readonly SCRIPT_VERSION="v4.4.20" +readonly SCRIPT_VERSTAG="26041500" SCRIPT_BRANCH="develop" SCRIPT_REPO="https://raw.githubusercontent.com/AMTM-OSR/$SCRIPT_NAME/$SCRIPT_BRANCH" readonly SCRIPT_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d" @@ -1058,7 +1058,7 @@ Conf_Exists() { local AUTOMATEDopt delCRON=false - if [ -f "$SCRIPT_CONF" ] + if [ -s "$SCRIPT_CONF" ] then dos2unix "$SCRIPT_CONF" chmod 0644 "$SCRIPT_CONF" @@ -1248,7 +1248,7 @@ Auto_ServiceEvent() local theScriptFilePath="/jffs/scripts/$SCRIPT_NAME_LOWER" case $1 in create) - if [ -f /jffs/scripts/service-event ] + if [ -s /jffs/scripts/service-event ] then STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/service-event)" STARTUPLINECOUNTEX="$(grep -cx 'if echo "$2" | /bin/grep -qE "('"$SCRIPT_NAME_LOWER"'|vpnclient)" ; then { '"$theScriptFilePath"' service_event "$@" & }; fi # '"$SCRIPT_NAME" /jffs/scripts/service-event)" @@ -1269,14 +1269,15 @@ Auto_ServiceEvent() echo 'if echo "$2" | /bin/grep -qE "('"$SCRIPT_NAME_LOWER"'|vpnclient)" ; then { '"$theScriptFilePath"' service_event "$@" & }; fi # '"$SCRIPT_NAME" echo } > /jffs/scripts/service-event - chmod 0755 /jffs/scripts/service-event fi + chmod 0755 /jffs/scripts/service-event ;; delete) - if [ -f /jffs/scripts/service-event ] + if [ -s /jffs/scripts/service-event ] then STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/service-event)" - if [ "$STARTUPLINECOUNT" -gt 0 ]; then + if [ "$STARTUPLINECOUNT" -gt 0 ] + then sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/service-event fi fi @@ -1318,9 +1319,11 @@ Auto_OpenVPN_Event() case $1 in create) # Check if any OpenVPN Client is set up/available in NVRAM # - if ! _CheckForOpenVPN_ClientsAvailable_ ; then return 1 ; fi + if ! _CheckForOpenVPN_ClientsAvailable_ + then return 1 + fi - if [ -f /jffs/scripts/openvpn-event ] + if [ -s /jffs/scripts/openvpn-event ] then STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/openvpn-event)" STARTUPLINECOUNTEX="$(grep -cx '\[ -x '"$theScriptFilePath"' \] && '"$theScriptFilePath"' openvpn_event "$1" "$script_type" & # '"$SCRIPT_NAME" /jffs/scripts/openvpn-event)" @@ -1341,14 +1344,15 @@ Auto_OpenVPN_Event() echo '[ -x '"$theScriptFilePath"' ] && '"$theScriptFilePath"' openvpn_event "$1" "$script_type" & # '"$SCRIPT_NAME" echo } > /jffs/scripts/openvpn-event - chmod 0755 /jffs/scripts/openvpn-event fi + chmod 0755 /jffs/scripts/openvpn-event ;; delete) - if [ -f /jffs/scripts/openvpn-event ] + if [ -s /jffs/scripts/openvpn-event ] then STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/openvpn-event)" - if [ "$STARTUPLINECOUNT" -gt 0 ]; then + if [ "$STARTUPLINECOUNT" -gt 0 ] + then sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/openvpn-event fi fi @@ -1396,12 +1400,14 @@ Auto_WG_ClientEvent() case $1 in create) # Check if any WireGuard Client is set up/available in NVRAM # - if ! _CheckForWireGuard_ClientsAvailable_ ; then return 1 ; fi + if ! _CheckForWireGuard_ClientsAvailable_ + then return 1 + fi for wgClientEvent in stop start do wgClientFilePath="/jffs/scripts/wgclient-$wgClientEvent" - if [ -f "$wgClientFilePath" ] + if [ -s "$wgClientFilePath" ] then STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" "$wgClientFilePath")" STARTUPLINECOUNTEX="$(grep -cx '\[ -x '"$theScriptFilePath"' \] && '"$theScriptFilePath"' wgclient_event '"$wgClientEvent"' "$@" & # '"$SCRIPT_NAME" "$wgClientFilePath")" @@ -1422,18 +1428,19 @@ Auto_WG_ClientEvent() echo '[ -x '"$theScriptFilePath"' ] && '"$theScriptFilePath"' wgclient_event '"$wgClientEvent"' "$@" & # '"$SCRIPT_NAME" echo } > "$wgClientFilePath" - chmod 0755 "$wgClientFilePath" fi + chmod 0755 "$wgClientFilePath" done ;; delete) for wgClientEvent in stop start do wgClientFilePath="/jffs/scripts/wgclient-$wgClientEvent" - if [ -f "$wgClientFilePath" ] + if [ -s "$wgClientFilePath" ] then STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" "$wgClientFilePath")" - if [ "$STARTUPLINECOUNT" -gt 0 ]; then + if [ "$STARTUPLINECOUNT" -gt 0 ] + then sed -i -e '/# '"$SCRIPT_NAME"'/d' "$wgClientFilePath" fi fi @@ -1450,14 +1457,15 @@ Auto_Startup() local theScriptFilePath="/jffs/scripts/$SCRIPT_NAME_LOWER" case $1 in create) - if [ -f /jffs/scripts/services-start ] + if [ -s /jffs/scripts/services-start ] then STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/services-start)" - if [ "$STARTUPLINECOUNT" -gt 0 ]; then + if [ "$STARTUPLINECOUNT" -gt 0 ] + then sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/services-start fi fi - if [ -f /jffs/scripts/post-mount ] + if [ -s /jffs/scripts/post-mount ] then STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/post-mount)" STARTUPLINECOUNTEX="$(grep -cx '\[ -x "${1}/entware/bin/opkg" \] && \[ -x '"$theScriptFilePath"' \] && '"$theScriptFilePath"' startup "$@" & # '"$SCRIPT_NAME" /jffs/scripts/post-mount)" @@ -1479,21 +1487,23 @@ Auto_Startup() echo '[ -x "${1}/entware/bin/opkg" ] && [ -x '"$theScriptFilePath"' ] && '"$theScriptFilePath"' startup "$@" & # '"$SCRIPT_NAME" echo } > /jffs/scripts/post-mount - chmod 0755 /jffs/scripts/post-mount fi + chmod 0755 /jffs/scripts/post-mount ;; delete) - if [ -f /jffs/scripts/services-start ] + if [ -s /jffs/scripts/services-start ] then STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/services-start)" - if [ "$STARTUPLINECOUNT" -gt 0 ]; then + if [ "$STARTUPLINECOUNT" -gt 0 ] + then sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/services-start fi fi - if [ -f /jffs/scripts/post-mount ] + if [ -s /jffs/scripts/post-mount ] then STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/post-mount)" - if [ "$STARTUPLINECOUNT" -gt 0 ]; then + if [ "$STARTUPLINECOUNT" -gt 0 ] + then sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/post-mount fi fi @@ -1510,9 +1520,11 @@ Auto_Cron() case $1 in create) STARTUPLINECOUNT="$(cru l | grep -c "#${SCRIPT_NAME}#")" - if [ "$STARTUPLINECOUNT" -gt 0 ]; then + if [ "$STARTUPLINECOUNT" -gt 0 ] + then cru d "${SCRIPT_NAME}" fi + STARTUPLINECOUNTGEN="$(cru l | grep -c "${SCRIPT_NAME}_generate")" CRU_SCHHOUR="$(_GetConfigParam_ SCHHOURS '*')" CRU_SCHMINS="$(_GetConfigParam_ SCHMINS '12,42')" @@ -1535,21 +1547,25 @@ Auto_Cron() cru d "${SCRIPT_NAME}_trimDB" STARTUPLINECOUNTTRIM="$(cru l | grep -c "${SCRIPT_NAME}_trimDB")" fi - if [ "$STARTUPLINECOUNTTRIM" -eq 0 ]; then + if [ "$STARTUPLINECOUNTTRIM" -eq 0 ] + then cru a "${SCRIPT_NAME}_trimDB" "$defTrimDB_Mins $defTrimDB_Hour * * * $theScriptFilePath trimdb" fi ;; delete) STARTUPLINECOUNT="$(cru l | grep -c "#${SCRIPT_NAME}#")" - if [ "$STARTUPLINECOUNT" -gt 0 ]; then + if [ "$STARTUPLINECOUNT" -gt 0 ] + then cru d "$SCRIPT_NAME" fi STARTUPLINECOUNTGEN="$(cru l | grep -c "#${SCRIPT_NAME}_generate#")" - if [ "$STARTUPLINECOUNTGEN" -gt 0 ]; then + if [ "$STARTUPLINECOUNTGEN" -gt 0 ] + then cru d "${SCRIPT_NAME}_generate" fi STARTUPLINECOUNTTRIM="$(cru l | grep -c "#${SCRIPT_NAME}_trimDB#")" - if [ "$STARTUPLINECOUNTTRIM" -gt 0 ]; then + if [ "$STARTUPLINECOUNTTRIM" -gt 0 ] + then cru d "${SCRIPT_NAME}_trimDB" fi ;; From 5b76cb6a6ed03dd45efc53dd6cd4409c38bbc71a Mon Sep 17 00:00:00 2001 From: ExtremeFiretop Date: Sun, 3 May 2026 08:33:39 -0400 Subject: [PATCH 03/12] Update Templates Update Templates --- .github/ISSUE_TEMPLATE/bug-report.md | 1 + .github/ISSUE_TEMPLATE/feature-request.md | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 318ea84..6832063 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -3,6 +3,7 @@ name: Bug Report about: Create a report to help us improve title: "[BUG] - " labels: bug +assignees: ExtremeFiretop, Martinski4GitHub, jumpsmm7 --- diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index 0bd7dea..ea6c725 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -3,10 +3,11 @@ name: Feature Request about: Suggest an idea for this project title: "[REQ] - " labels: enhancement +assignees: ExtremeFiretop, Martinski4GitHub, jumpsmm7 --- -⚠️ @AMTM-OSR/triagers — please help triage this request. +⚠️ @AMTM-OSR/maintainers — please help triage this request. **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. [Ex. Link to existing bug report...] From 1a6a374ab0d924e8697a539f7ed64798b436b1aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 09:53:55 +0000 Subject: [PATCH 04/12] Bump actions/checkout from 6.0.2 to 6.0.3 in the all-actions group Bumps the all-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 6.0.2 to 6.0.3 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6.0.2...v6.0.3) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/Create-NewReleases.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Create-NewReleases.yml b/.github/workflows/Create-NewReleases.yml index ce63171..404f8ea 100644 --- a/.github/workflows/Create-NewReleases.yml +++ b/.github/workflows/Create-NewReleases.yml @@ -19,7 +19,7 @@ jobs: steps: # 1--- Check out master so we tag the exact merge commit - name: Checkout source code - uses: actions/checkout@v6.0.2 + uses: actions/checkout@v6.0.3 with: fetch-depth: 0 ref: 'master' From 3774e17d341f62943c5209f940dba054b243bae4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 09:53:25 +0000 Subject: [PATCH 05/12] Bump the all-actions group with 2 updates Bumps the all-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [softprops/action-gh-release](https://github.com/softprops/action-gh-release). Updates `actions/checkout` from 6.0.3 to 7.0.0 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6.0.3...v7.0.0) Updates `softprops/action-gh-release` from 3.0.0 to 3.0.1 - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v3.0.0...v3.0.1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: all-actions - dependency-name: softprops/action-gh-release dependency-version: 3.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/Create-NewReleases.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Create-NewReleases.yml b/.github/workflows/Create-NewReleases.yml index 404f8ea..a82630c 100644 --- a/.github/workflows/Create-NewReleases.yml +++ b/.github/workflows/Create-NewReleases.yml @@ -19,7 +19,7 @@ jobs: steps: # 1--- Check out master so we tag the exact merge commit - name: Checkout source code - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 with: fetch-depth: 0 ref: 'master' @@ -97,7 +97,7 @@ jobs: # 7--- Publish a GitHub Release with auto-generated notes - name: Create Release with Automated Release Notes - uses: softprops/action-gh-release@v3.0.0 + uses: softprops/action-gh-release@v3.0.1 with: token: ${{ secrets.GITHUB_TOKEN }} tag_name: ${{ steps.nextver.outputs.tag }} From 8b601bfc271730a6dc4225fb51d85e1477a638c1 Mon Sep 17 00:00:00 2001 From: Martinski4GitHub <119833648+Martinski4GitHub@users.noreply.github.com> Date: Wed, 24 Jun 2026 06:59:32 -0700 Subject: [PATCH 06/12] Fix for Missing "cookie" Helper Functions Fix for compatibility issue with latest AsusWRT6 routers, such as the GT-BE19000AI, running 3006.102.8 F/W version, where the webpage generates errors due to missing "cookie" helper functions previously defined in the 'state.js' file (Ported from Unbound Stats WebUI ASP fix supplied by @ExtremeFiretop). --- README.md | 2 +- spdmerlin.sh | 4 ++-- spdstats_www.asp | 8 ++++---- spdstats_www.js | 31 ++++++++++++++++++++++++++++++- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 24b36ab..1aa3b74 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # spdMerlin ## v4.4.20 -### Updated on 2026-Apr-15 +### Updated on 2026-Jun-24 ## About spdMerlin is an internet speedtest and monitoring tool for AsusWRT Merlin with charts for daily, weekly and monthly summaries. It tracks download/upload bandwidth as well as latency, jitter and packet loss. diff --git a/spdmerlin.sh b/spdmerlin.sh index 1c7eb18..bc98fb4 100644 --- a/spdmerlin.sh +++ b/spdmerlin.sh @@ -14,7 +14,7 @@ ## Forked from https://github.com/jackyaz/spdMerlin ## ## ## ############################################################## -# Last Modified: 2026-Apr-15 +# Last Modified: 2026-Jun-24 #------------------------------------------------------------- ############## Shellcheck directives ############# @@ -39,7 +39,7 @@ readonly SCRIPT_NAME="spdMerlin" readonly SCRIPT_NAME_LOWER="$(echo "$SCRIPT_NAME" | tr 'A-Z' 'a-z')" readonly SCRIPT_VERSION="v4.4.20" -readonly SCRIPT_VERSTAG="26041500" +readonly SCRIPT_VERSTAG="26062400" SCRIPT_BRANCH="develop" SCRIPT_REPO="https://raw.githubusercontent.com/AMTM-OSR/$SCRIPT_NAME/$SCRIPT_BRANCH" readonly SCRIPT_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d" diff --git a/spdstats_www.asp b/spdstats_www.asp index 0da58e4..a6467bd 100644 --- a/spdstats_www.asp +++ b/spdstats_www.asp @@ -30,9 +30,9 @@ p{font-weight:bolder;}thead.collapsible-jquery{color:white;padding:0;width:100%; diff --git a/spdstats_www.js b/spdstats_www.js index 219690e..59bbb0e 100644 --- a/spdstats_www.js +++ b/spdstats_www.js @@ -1,5 +1,5 @@ /**----------------------------**/ -/** Last Modified: 2025-Oct-14 **/ +/** Last Modified: 2026-Jun-24 **/ /**----------------------------**/ var daysofweek = ['Mon','Tues','Wed','Thurs','Fri','Sat','Sun']; @@ -814,6 +814,35 @@ function getTimeFormat(value,format){ return timeformat; } +/**----------------------------------------------------------------** + ** Compatibility layer for the latest AsusWRT6 routers, such as + ** the GT-BE19000AI, where the previous global 'cookie' helper + ** functions defined in the 'state.js' file are now removed in + ** favour of using the "window.localStorage" property. + **----------------------------------------------------------------**/ +if (typeof window.cookie === "undefined" || + typeof window.cookie.get !== "function" || + typeof window.cookie.set !== "function") +{ + window.cookie = { + get: function (key) { + return window.localStorage.getItem(key); + }, + + /** In the previous 'cookie' function a 3rd argument was given for 'days' **/ + /** Here, we ignore the value because there is no expiration date anymore **/ + set: function (key, value, days) { + window.localStorage.setItem(key, String(value)); + }, + + unset: function (key) { + window.localStorage.removeItem(key); + } + }; + + console.log("Installed localStorage compatibility for cookie API."); +} + function GetCookie(cookiename,returntype){ if(cookie.get('spd_'+cookiename) != null){ return cookie.get('spd_'+cookiename); From 1309301a19be942a30c506acafb7f198c91cf4ed Mon Sep 17 00:00:00 2001 From: Martinski4GitHub <119833648+Martinski4GitHub@users.noreply.github.com> Date: Wed, 8 Jul 2026 20:52:36 -0700 Subject: [PATCH 07/12] Conditional Requirement for SWAP Modified code to make SWAP a conditional requirement based on the total physical RAM. The SWAP will be required only if the router has less than 512MB RAM. --- README.md | 2 +- spdmerlin.sh | 113 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 67 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 1aa3b74..d84979a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # spdMerlin ## v4.4.20 -### Updated on 2026-Jun-24 +### Updated on 2026-Jul-08 ## About spdMerlin is an internet speedtest and monitoring tool for AsusWRT Merlin with charts for daily, weekly and monthly summaries. It tracks download/upload bandwidth as well as latency, jitter and packet loss. diff --git a/spdmerlin.sh b/spdmerlin.sh index bc98fb4..3f42894 100644 --- a/spdmerlin.sh +++ b/spdmerlin.sh @@ -14,7 +14,7 @@ ## Forked from https://github.com/jackyaz/spdMerlin ## ## ## ############################################################## -# Last Modified: 2026-Jun-24 +# Last Modified: 2026-Jul-08 #------------------------------------------------------------- ############## Shellcheck directives ############# @@ -39,7 +39,7 @@ readonly SCRIPT_NAME="spdMerlin" readonly SCRIPT_NAME_LOWER="$(echo "$SCRIPT_NAME" | tr 'A-Z' 'a-z')" readonly SCRIPT_VERSION="v4.4.20" -readonly SCRIPT_VERSTAG="26062400" +readonly SCRIPT_VERSTAG="26070806" SCRIPT_BRANCH="develop" SCRIPT_REPO="https://raw.githubusercontent.com/AMTM-OSR/$SCRIPT_NAME/$SCRIPT_BRANCH" readonly SCRIPT_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d" @@ -229,8 +229,25 @@ Clear_Lock() return 0 } -Check_Swap(){ - if [ "$(wc -l < /proc/swaps)" -ge 2 ]; then return 0; else return 1; fi +##-------------------------------------## +## Added by Martinski W. [2026-Jul-08] ## +##-------------------------------------## +_HasRouterMoreThan256MBtotalRAM_() +{ + local totalRAM_KB + totalRAM_KB="$(awk -F ' ' '/^MemTotal:/{print $2}' /proc/meminfo)" + if [ -n "$totalRAM_KB" ] && [ "$totalRAM_KB" -gt 262144 ] + then return 0 + else return 1 + fi +} + +Check_Swap() +{ + if [ "$(wc -l < /proc/swaps)" -ge 2 ] + then return 0 + else return 1 + fi } ##----------------------------------------## @@ -3232,7 +3249,7 @@ _Trim_Database_() } ##----------------------------------------## -## Modified by Martinski W. [2025-Oct-30] ## +## Modified by Martinski W. [2026-Jul-08] ## ##----------------------------------------## Run_Speedtest() { @@ -3242,7 +3259,8 @@ Run_Speedtest() opkg update opkg install findutils fi - if [ -n "$PPID" ]; then + if [ -n "$PPID" ] + then ps | grep -v grep | grep -v $$ | grep -v "$PPID" | grep -i "$SCRIPT_NAME_LOWER" | grep generate | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 else ps | grep -v grep | grep -v $$ | grep -i "$SCRIPT_NAME_LOWER" | grep generate | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 @@ -3311,37 +3329,45 @@ Run_Speedtest() spdTestDBGFile="/tmp/${SCRIPT_NAME}.DEBUG.txt" rm -f "$tmpfile" "$resultfile" "$spdTestLogFile" - if [ -n "$(pidof "$PROC_NAME")" ]; then - killall -q "$PROC_NAME" + if [ -n "$(pidof "$PROC_NAME")" ] + then killall -q "$PROC_NAME" fi - if Check_Swap + if ! _HasRouterMoreThan256MBtotalRAM_ && ! Check_Swap + then + echo 'var spdteststatus = "NoSwap";' > /tmp/detect_spdtest.js + Print_Output true "Total RAM is less than 512MB and SWAP file NOT detected. Exiting" "$CRIT" + Clear_Lock + return 1 + fi + + IFACELIST="" + if [ -z "$specificiface" ] then - IFACELIST="" - if [ -z "$specificiface" ] - then while IFS='' read -r line || [ -n "$line" ] do - if [ "$(echo "$line" | grep -c "#")" -eq 0 ]; then + if [ "$(echo "$line" | grep -c "#")" -eq 0 ] + then IFACELIST="$IFACELIST $(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')" fi done < "$SCRIPT_INTERFACES_USER" IFACELIST="$(echo "$IFACELIST" | cut -c2-)" - elif [ "$specificiface" = "All" ] - then + elif [ "$specificiface" = "All" ] + then while IFS='' read -r line || [ -n "$line" ] do - if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ]; then + if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ] + then IFACELIST="$IFACELIST $(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')" fi done < "$SCRIPT_INTERFACES_USER" IFACELIST="$(echo "$IFACELIST" | cut -c2-)" - else + else IFACELIST="$specificiface" - fi + fi - if [ "$IFACELIST" != "" ] - then + if [ -n "$IFACELIST" ] + then stoppedQoS=false if [ "$(ExcludeFromQoS check)" = "true" ] then @@ -3719,18 +3745,11 @@ Run_Speedtest() rm -f "$tmpfile" /tmp/spdstatstitle.txt Clear_Lock - else + else echo 'var spdteststatus = "Error";' > /tmp/detect_spdtest.js - Print_Output true "No interfaces enabled, exiting" "$CRIT" + Print_Output true "No interfaces enabled. Exiting" "$CRIT" Clear_Lock return 1 - fi - Clear_Lock - else - echo 'var spdteststatus = "NoSwap";' > /tmp/detect_spdtest.js - Print_Output true "Swap file not active, exiting" "$CRIT" - Clear_Lock - return 1 fi } @@ -4817,9 +4836,12 @@ MainMenu() MainMenu } +##----------------------------------------## +## Modified by Martinski W. [2026-Jul-08] ## +##----------------------------------------## Check_Requirements() { - CHECKSFAILED="false" + local CHECKSFAILED=false if [ "$(nvram get jffs2_scripts)" -ne 1 ] then @@ -4828,37 +4850,34 @@ Check_Requirements() Print_Output true "Custom JFFS Scripts enabled" "$WARN" fi - if ! Check_Swap + if ! _HasRouterMoreThan256MBtotalRAM_ && ! Check_Swap then - Print_Output false "No Swap file detected!" "$ERR" - CHECKSFAILED="true" + Print_Output false "Total RAM is less than 512MB and SWAP file NOT detected!" "$ERR" + CHECKSFAILED=true fi if [ ! -f /opt/bin/opkg ] then Print_Output false "Entware NOT detected!" "$CRIT" - CHECKSFAILED="true" + CHECKSFAILED=true fi if ! Firmware_Version_Check then Print_Output false "Unsupported firmware version detected" "$CRIT" Print_Output false "$SCRIPT_NAME requires Merlin 384.15/384.13_4 or Fork 43E5 (or later)" "$ERR" - CHECKSFAILED="true" + CHECKSFAILED=true fi - if [ "$CHECKSFAILED" = "false" ] - then - Print_Output false "Installing required packages from Entware" "$PASS" - opkg update - opkg install sqlite3-cli - opkg install jq - opkg install p7zip - opkg install findutils - return 0 - else - return 1 - fi + "$CHECKSFAILED" && return 1 + + Print_Output false "Installing required packages from Entware" "$PASS" + opkg update + opkg install sqlite3-cli + opkg install jq + opkg install p7zip + opkg install findutils + return 0 } ##----------------------------------------## From f0ca0e7107f9549056a0768a1212695137112b00 Mon Sep 17 00:00:00 2001 From: Martinski4GitHub <119833648+Martinski4GitHub@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:18:57 -0700 Subject: [PATCH 08/12] Fixes and Improvements. - Modified code to be able to run the built-in Ookla binaries installed on the latest 3006.102.8.0 F/W version using the newer configuration URL. - Modified CLI Menu toggle option to clarify what the 'built-in' and 'external' binaries refer to. - Miscellaneous code improvements and fine-tuning. --- README.md | 2 +- spdmerlin.sh | 308 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 190 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index d84979a..3e89eff 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # spdMerlin ## v4.4.20 -### Updated on 2026-Jul-08 +### Updated on 2026-Jul-12 ## About spdMerlin is an internet speedtest and monitoring tool for AsusWRT Merlin with charts for daily, weekly and monthly summaries. It tracks download/upload bandwidth as well as latency, jitter and packet loss. diff --git a/spdmerlin.sh b/spdmerlin.sh index 3f42894..89ec987 100644 --- a/spdmerlin.sh +++ b/spdmerlin.sh @@ -14,7 +14,7 @@ ## Forked from https://github.com/jackyaz/spdMerlin ## ## ## ############################################################## -# Last Modified: 2026-Jul-08 +# Last Modified: 2026-Jul-12 #------------------------------------------------------------- ############## Shellcheck directives ############# @@ -39,7 +39,7 @@ readonly SCRIPT_NAME="spdMerlin" readonly SCRIPT_NAME_LOWER="$(echo "$SCRIPT_NAME" | tr 'A-Z' 'a-z')" readonly SCRIPT_VERSION="v4.4.20" -readonly SCRIPT_VERSTAG="26070806" +readonly SCRIPT_VERSTAG="26071209" SCRIPT_BRANCH="develop" SCRIPT_REPO="https://raw.githubusercontent.com/AMTM-OSR/$SCRIPT_NAME/$SCRIPT_BRANCH" readonly SCRIPT_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d" @@ -49,11 +49,21 @@ readonly SHARED_DIR="/jffs/addons/shared-jy" readonly SHARED_REPO="https://raw.githubusercontent.com/AMTM-OSR/shared-jy/master" readonly SHARED_WEB_DIR="$SCRIPT_WEBPAGE_DIR/shared-jy" readonly TEMP_MENU_TREE="/tmp/menuTree.js" - readonly HOME_DIR="/home/root" -readonly OOKLA_DIR="$SCRIPT_DIR/ookla" -readonly OOKLA_LICENSE_DIR="$SCRIPT_DIR/ooklalicense" -readonly OOKLA_HOME_DIR="$HOME_DIR/.config/ookla" + +# For F/W built-in Ookla CLI Speed Test Binaries # +readonly BUILTIN_OOKLA_PROC="ookla" +readonly BUILTIN_OOKLA_BINARY="/usr/sbin/$BUILTIN_OOKLA_PROC" +readonly BUILTIN_OOKLA_CONFIG1="https://www.speedtest.net/api/embed/vz0azjarf5enop8a/config" +readonly BUILTIN_OOKLA_CONFIG2="https://config.speedtest.net/v1/embed/4tiouex6gsnzq55o/config" + +# For external Ookla CLI Speed Test Binaries # +readonly OOKLA_DIR="${SCRIPT_DIR}/ookla" +readonly OOKLA_HOME_DIR="${HOME_DIR}/.config/ookla" +readonly OOKLA_LICENSE_DIR="${SCRIPT_DIR}/ooklalicense" +readonly EXTERNL_OOKLA_PROC="speedtest" +readonly EXTERNL_OOKLA_BINARY="${OOKLA_DIR}/$EXTERNL_OOKLA_PROC" + readonly FULL_IFACELIST="WAN VPNC1 VPNC2 VPNC3 VPNC4 VPNC5 WGVPN1 WGVPN2 WGVPN3 WGVPN4 WGVPN5" [ -z "$(nvram get odmpid)" ] && ROUTER_MODEL="$(nvram get productid)" || ROUTER_MODEL="$(nvram get odmpid)" @@ -75,6 +85,14 @@ readonly branchxStr_TAG="[Branch: $SCRIPT_BRANCH]" readonly versionDev_TAG="${SCRIPT_VERSION}_${SCRIPT_VERSTAG}" readonly versionMod_TAG="$SCRIPT_VERSION on $ROUTER_MODEL" +##-------------------------------------## +## Added by Martinski W. [2026-Jul-12] ## +##-------------------------------------## +readonly fwInstalledBaseVers="$(nvram get firmver | sed 's/\.//g')" +readonly fwInstalledBuildVers="$(nvram get buildno)" +readonly fwInstalledBuildLong="${fwInstalledBaseVers}.$fwInstalledBuildVers" +readonly fwInstalledBuildShrt="${fwInstalledBaseVers}.$(echo "$fwInstalledBuildVers" | awk -F'.' '{print $1}')" + # To support automatic script updates from AMTM # doScriptUpdateFromAMTM=true @@ -106,7 +124,8 @@ unset LD_LIBRARY_PATH # Give priority to built-in binaries # export PATH="/bin:/usr/bin:/sbin:/usr/sbin:$PATH" -if [ "$(uname -m)" = "aarch64" ]; then +if [ "$(uname -m)" = "aarch64" ] +then ARCH="aarch64" else /bin/grep -Eq 'Features\s*:.*\s+v?fp\s+' /proc/cpuinfo && ARCH="arm" || ARCH="armel" @@ -427,19 +446,55 @@ ScriptUpdateFromAMTM() ##-------------------------------------## ## Added by Martinski W. [2025-Jun-11] ## ##-------------------------------------## -_GetSpeedtestBinaryVersion_() +_GetExternalSpeedTestBinVersion_() { - if [ ! -x "$OOKLA_DIR/speedtest" ] ; then echo "[N/A]" ; return 1 ; fi + if [ ! -x "$EXTERNL_OOKLA_BINARY" ] + then echo "[N/A]" ; return 1 + fi local verLine verStr="[N/A]" - verLine="$("$OOKLA_DIR"/speedtest -V | grep -E '^Speedtest by Ookla [1-9]+[.].*')" + verLine="$($EXTERNL_OOKLA_BINARY -V | grep -E '^Speedtest by Ookla [1-9]+[.].*')" if [ -n "$verLine" ] - then - verStr="$(echo "$verLine" | awk -F ' ' '{print $4}')" + then verStr="$(echo "$verLine" | awk -F ' ' '{print $4}')" fi echo "$verStr" } +##-------------------------------------## +## Added by Martinski W. [2026-Jul-12] ## +##-------------------------------------## +_GetBuiltInSpeedTestBinVersion_() +{ + if [ ! -x "$BUILTIN_OOKLA_BINARY" ] + then echo "[N/A]" ; return 1 + fi + local verLine verStr="[N/A]" + + verLine="$($BUILTIN_OOKLA_BINARY -V | grep -E '^ookla [1-9]+[.].*')" + if [ -n "$verLine" ] + then verStr="$(echo "$verLine" | awk -F ' ' '{print $2}')" + fi + echo "$verStr" +} + +_FWVersionStrToNum_() +{ echo "$1" | awk -F '.' '{ printf ("%d%03d%02d%02d\n", $1,$2,$3,$4); }' ; } + +##-------------------------------------## +## Added by Martinski W. [2026-Jul-12] ## +##-------------------------------------## +_GetBuiltInSpeedTestConfigURL_() +{ + local configURL="$BUILTIN_OOKLA_CONFIG1" + + if [ "$fwInstalledBuildShrt" = "3006.102" ] && \ + [ "$(_FWVersionStrToNum_ "$fwInstalledBuildLong")" -ge "$(_FWVersionStrToNum_ "3006.102.8")" ] + then + configURL="$BUILTIN_OOKLA_CONFIG2" + fi + echo "$configURL" +} + ##-------------------------------------## ## Added by Martinski W. [2025-Jun-19] ## ##-------------------------------------## @@ -454,21 +509,21 @@ Update_File() if [ "$1" = "$ARCH.tar.gz" ] then tmpfile="/tmp/$1" - Download_File "$SCRIPT_REPO/$1" "$tmpfile" + Download_File "${SCRIPT_REPO}/$1" "$tmpfile" tar -xzf "$tmpfile" -C "/tmp" rm -f "$tmpfile" - localmd5="$(md5sum "$OOKLA_DIR/speedtest" | awk '{print $1}')" + localmd5="$(md5sum "$EXTERNL_OOKLA_BINARY" | awk '{print $1}')" tmpmd5="$(md5sum /tmp/speedtest | awk '{print $1}')" if [ "$localmd5" != "$tmpmd5" ] then - rm -f "$OOKLA_DIR"/* - Download_File "$SCRIPT_REPO/$1" "$OOKLA_DIR/$1" - tar -xzf "$OOKLA_DIR/$1" -C "$OOKLA_DIR" - rm -f "$OOKLA_DIR/$1" - chmod 0755 "$OOKLA_DIR/speedtest" - chown "${theUserName}:root" "$OOKLA_DIR"/* - spdTestVer="$(_GetSpeedtestBinaryVersion_)" - Print_Output true "Speedtest CLI $spdTestVer version was downloaded." "$PASS" + rm -f "${OOKLA_DIR}"/* + Download_File "${SCRIPT_REPO}/$1" "${OOKLA_DIR}/$1" + tar -xzf "${OOKLA_DIR}/$1" -C "$OOKLA_DIR" + rm -f "${OOKLA_DIR}/$1" + chmod 0755 "$EXTERNL_OOKLA_BINARY" + chown "${theUserName}:root" "${OOKLA_DIR}"/* + spdTestVer="$(_GetExternalSpeedTestBinVersion_)" + Print_Output true "Ookla Speedtest CLI $spdTestVer version was downloaded." "$PASS" fi rm -f /tmp/speedtest* elif [ "$1" = "spdstats_www.asp" ] @@ -476,19 +531,19 @@ Update_File() tmpfile="/tmp/$1" if [ -f "$SCRIPT_DIR/$1" ] then - Download_File "$SCRIPT_REPO/$1" "$tmpfile" + Download_File "${SCRIPT_REPO}/$1" "$tmpfile" if ! diff -q "$tmpfile" "$SCRIPT_DIR/$1" >/dev/null 2>&1 then Get_WebUI_Page "$SCRIPT_DIR/$1" sed -i "\\~$MyWebPage~d" "$TEMP_MENU_TREE" rm -f "$SCRIPT_WEBPAGE_DIR/$MyWebPage" 2>/dev/null - Download_File "$SCRIPT_REPO/$1" "$SCRIPT_DIR/$1" + Download_File "${SCRIPT_REPO}/$1" "$SCRIPT_DIR/$1" Print_Output true "New version of $1 downloaded" "$PASS" Mount_WebUI fi rm -f "$tmpfile" else - Download_File "$SCRIPT_REPO/$1" "$SCRIPT_DIR/$1" + Download_File "${SCRIPT_REPO}/$1" "$SCRIPT_DIR/$1" Print_Output true "New version of $1 downloaded" "$PASS" Mount_WebUI fi @@ -1033,7 +1088,7 @@ Interfaces_FromSettings() ##-------------------------------------## _GetDefaultSpeedTestBinary_() { - if [ -f /usr/sbin/ookla ] + if [ -x "$BUILTIN_OOKLA_BINARY" ] then echo "builtin" else echo "external" fi @@ -2125,21 +2180,21 @@ SpeedtestBinary() case "$1" in builtin) - if [ -f /usr/sbin/ookla ] + if [ -x "$BUILTIN_OOKLA_BINARY" ] then sed -i 's/^SPEEDTESTBINARY=.*$/SPEEDTESTBINARY=builtin/' "$SCRIPT_CONF" else retCode=1 - Print_Output true "The built-in Speedtest binary is NOT found." "$ERR" + Print_Output true "The F/W built-in Ookla speedtest binary is NOT found." "$ERR" fi ;; external) - if [ -f "$OOKLA_DIR/speedtest" ] + if [ -x "$EXTERNL_OOKLA_BINARY" ] then sed -i 's/^SPEEDTESTBINARY=.*$/SPEEDTESTBINARY=external/' "$SCRIPT_CONF" else retCode=1 - Print_Output true "The external Speedtest binary is NOT found." "$ERR" + Print_Output true "The external Ookla Speedtest binary is NOT found." "$ERR" fi ;; check) @@ -2420,6 +2475,7 @@ WriteStats_ToJS() GenerateServerList() { local serverMsgStr maxServerCount serverCount serverIndx COUNTER + local errorLogFile="/tmp/${SCRIPT_NAME}.DEBUG.Servers.LOG" if [ ! -f /opt/bin/jq ] && [ -x /opt/bin/opkg ] then @@ -2430,31 +2486,36 @@ GenerateServerList() then promptforservername="" else promptforservername="$2" fi + rm -f "$errorLogFile" printf " Generating list of closest servers for ${GRNct}${1}${CLRct} interface.\n" printf " Please wait...\n\n" + CONFIG_STRING="" - LICENSE_STRING="--accept-license --accept-gdpr" + LICENSE_STRING="" SPEEDTEST_BINARY="" if [ "$(SpeedtestBinary check)" = "builtin" ] then - SPEEDTEST_BINARY="/usr/sbin/ookla" + SPEEDTEST_BINARY="$BUILTIN_OOKLA_BINARY" + CONFIG_STRING="-c $(_GetBuiltInSpeedTestConfigURL_)" elif [ "$(SpeedtestBinary check)" = "external" ] then - SPEEDTEST_BINARY="$OOKLA_DIR/speedtest" - fi - if [ "$SPEEDTEST_BINARY" = "/usr/sbin/ookla" ] - then - CONFIG_STRING="-c http://www.speedtest.net/api/embed/vz0azjarf5enop8a/config" - LICENSE_STRING="" + SPEEDTEST_BINARY="$EXTERNL_OOKLA_BINARY" + LICENSE_STRING="--accept-license --accept-gdpr" fi - serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$1")" --servers --format="json" $LICENSE_STRING)" 2>/dev/null + + serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$1")" --servers --format="json" $LICENSE_STRING)" 2>"$errorLogFile" if [ -z "$serverList" ] then - Print_Output true "Error retrieving server list for $1 interface" "$CRIT" + Print_Output true "ERROR retrieving server list for $1 interface" "$CRIT" serverNum="ERROR" + if [ -s "$errorLogFile" ] + then cat "$errorLogFile" ; echo + fi + rm -f "$errorLogFile" return 1 fi + serverCount="$(echo "$serverList" | jq '.servers | length')" COUNTER=1 until [ "$COUNTER" -gt "${serverCount:=0}" ] @@ -2570,22 +2631,19 @@ GenerateServerList_WebUI() serverlistfile="$2" rm -f "/tmp/${serverlistfile}.txt" rm -f "/tmp/${serverlistfile}.tmp" - rm -f "$SCRIPT_WEB_DIR/${serverlistfile}.htm" + rm -f "${SCRIPT_WEB_DIR}/${serverlistfile}.htm" + CONFIG_STRING="" + LICENSE_STRING="" SPEEDTEST_BINARY="" if [ "$(SpeedtestBinary check)" = "builtin" ] then - SPEEDTEST_BINARY="/usr/sbin/ookla" + SPEEDTEST_BINARY="$BUILTIN_OOKLA_BINARY" + CONFIG_STRING="-c $(_GetBuiltInSpeedTestConfigURL_)" elif [ "$(SpeedtestBinary check)" = "external" ] then - SPEEDTEST_BINARY="$OOKLA_DIR/speedtest" - fi - CONFIG_STRING="" - LICENSE_STRING="--accept-license --accept-gdpr" - if [ "$SPEEDTEST_BINARY" = "/usr/sbin/ookla" ] - then - CONFIG_STRING="-c http://www.speedtest.net/api/embed/vz0azjarf5enop8a/config" - LICENSE_STRING="" + SPEEDTEST_BINARY="$EXTERNL_OOKLA_BINARY" + LICENSE_STRING="--accept-license --accept-gdpr" fi if [ ! -f /opt/bin/jq ] && [ -x /opt/bin/opkg ] @@ -2618,7 +2676,7 @@ GenerateServerList_WebUI() serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$IFACE_NAME")" --servers --format="json" $LICENSE_STRING)" 2>/dev/null if [ -z "$serverList" ] then - Print_Output true "Error retrieving server list for $IFACE_NAME interface" "$CRIT" + Print_Output true "ERROR retrieving server list for $IFACE_NAME interface" "$CRIT" { echo "0|**ERROR**: Unable to retrieve server list." ; echo "-----" } >> "/tmp/${serverlistfile}.tmp" @@ -2640,7 +2698,7 @@ GenerateServerList_WebUI() serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$spdifacename")" --servers --format="json" $LICENSE_STRING)" 2>/dev/null if [ -z "$serverList" ] then - Print_Output true "Error retrieving server list for $spdifacename interface" "$CRIT" + Print_Output true "ERROR retrieving server list for $spdifacename interface" "$CRIT" serverCount=0 else serverCount="$(echo "$serverList" | jq '.servers | length')" @@ -3249,7 +3307,7 @@ _Trim_Database_() } ##----------------------------------------## -## Modified by Martinski W. [2026-Jul-08] ## +## Modified by Martinski W. [2026-Jul-12] ## ##----------------------------------------## Run_Speedtest() { @@ -3269,10 +3327,10 @@ Run_Speedtest() Conf_Exists if [ "$(SpeedtestBinary check)" = "builtin" ] then - echo "/usr/sbin/ookla" > /tmp/spdmerlin-binary + echo "$BUILTIN_OOKLA_BINARY" > /tmp/spdmerlin-binary elif [ "$(SpeedtestBinary check)" = "external" ] then - echo "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary + echo "$EXTERNL_OOKLA_BINARY" > /tmp/spdmerlin-binary fi Auto_Startup create 2>/dev/null if AutomaticMode check @@ -3303,24 +3361,21 @@ Run_Speedtest() then verboseNUM=0 fi + PROC_NAME="" CONFIG_STRING="" - LICENSE_STRING="--accept-license --accept-gdpr" - PROC_NAME="speedtest" + LICENSE_STRING="" SPEEDTEST_BINARY="" if [ "$(SpeedtestBinary check)" = "builtin" ] then - SPEEDTEST_BINARY="/usr/sbin/ookla" + PROC_NAME="$BUILTIN_OOKLA_PROC" + SPEEDTEST_BINARY="$BUILTIN_OOKLA_BINARY" + CONFIG_STRING="-c $(_GetBuiltInSpeedTestConfigURL_)" elif [ "$(SpeedtestBinary check)" = "external" ] then - SPEEDTEST_BINARY="$OOKLA_DIR/speedtest" + PROC_NAME="$EXTERNL_OOKLA_PROC" + SPEEDTEST_BINARY="$EXTERNL_OOKLA_BINARY" + LICENSE_STRING="--accept-license --accept-gdpr" fi - if [ "$SPEEDTEST_BINARY" = "/usr/sbin/ookla" ] - then - CONFIG_STRING="-c http://www.speedtest.net/api/embed/vz0azjarf5enop8a/config" - LICENSE_STRING="" - PROC_NAME="ookla" - fi - echo 'var spdteststatus = "InProgress";' > /tmp/detect_spdtest.js tmpfile=/tmp/spd-stats.txt @@ -3476,8 +3531,8 @@ Run_Speedtest() if [ "$mode" = "auto" ] then - Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME interface. Please wait..." "$PASS" - "$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING 2>"$spdTestLogFile" | tee "$tmpfile" & + Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME [$IFACE] interface. Please wait..." "$PASS" + ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$spdTestLogFile" & sleep 2 speedTestSecs=0 while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] @@ -3486,16 +3541,18 @@ Run_Speedtest() done if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ] then - Print_Output true "Speedtest for $IFACE_NAME hung (> 2 mins), killing process" "$CRIT" + Print_Output true "Speedtest for $IFACE_NAME [$IFACE] hung (> 2 mins), killing process" "$CRIT" killall -q "$PROC_NAME" - if [ -s "$spdTestLogFile" ] ; then echo ; cat "$spdTestLogFile" ; echo ; fi + if [ -s "$spdTestLogFile" ] + then cat "$spdTestLogFile" ; echo + fi continue fi else if [ "$speedtestServerIDx" -ne 0 ] then - Print_Output true "Starting speedtest using $speedtestServerName for $IFACE_NAME interface. Please wait..." "$PASS" - "$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --server-id="$speedtestServerIDx" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING 2>"$spdTestLogFile" | tee "$tmpfile" & + Print_Output true "Starting speedtest using $speedtestServerName for $IFACE_NAME [$IFACE] interface. Please wait..." "$PASS" + ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --server-id="$speedtestServerIDx" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$spdTestLogFile" & sleep 2 speedTestSecs=0 while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] @@ -3504,14 +3561,16 @@ Run_Speedtest() done if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ] then - Print_Output true "Speedtest for $IFACE_NAME hung (> 2 mins), killing process" "$CRIT" + Print_Output true "Speedtest for $IFACE_NAME [$IFACE] hung (> 2 mins), killing process" "$CRIT" killall -q "$PROC_NAME" - if [ -s "$spdTestLogFile" ] ; then echo ; cat "$spdTestLogFile" ; echo ; fi + if [ -s "$spdTestLogFile" ] + then cat "$spdTestLogFile" ; echo + fi continue fi else - Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME interface. Please wait..." "$PASS" - "$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING 2>"$spdTestLogFile" | tee "$tmpfile" & + Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME [$IFACE] interface. Please wait..." "$PASS" + ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$spdTestLogFile" & sleep 2 speedTestSecs=0 while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] @@ -3520,9 +3579,11 @@ Run_Speedtest() done if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ] then - Print_Output true "Speedtest for $IFACE_NAME hung (> 2 mins), killing process" "$CRIT" + Print_Output true "Speedtest for $IFACE_NAME [$IFACE] hung (> 2 mins), killing process" "$CRIT" killall -q "$PROC_NAME" - if [ -s "$spdTestLogFile" ] ; then echo ; cat "$spdTestLogFile" ; echo ; fi + if [ -s "$spdTestLogFile" ] + then cat "$spdTestLogFile" ; echo + fi continue fi fi @@ -3530,8 +3591,10 @@ Run_Speedtest() if [ ! -s "$tmpfile" ] || [ -z "$(cat "$tmpfile")" ] || [ "$(grep -c 'FAILED' "$tmpfile")" -gt 0 ] then - Print_Output true "ERROR running speedtest for $IFACE_NAME [No Results]" "$CRIT" - if [ -s "$spdTestLogFile" ] ; then echo ; cat "$spdTestLogFile" ; echo ; fi + Print_Output true "ERROR running speedtest for $IFACE_NAME [$IFACE] [No Results]" "$CRIT" + if [ -s "$spdTestLogFile" ] + then cat "$spdTestLogFile" ; echo + fi continue fi @@ -3548,7 +3611,7 @@ Run_Speedtest() serverName="$(echo "$serverLine" | sed 's/^Server: *//' | sed 's/ *(id[: =]\+ [0-9]\+)$//')" serverIDno="$(echo "$serverLine" | grep -Eo '[(]id(:| =)[[:blank:]]+[0-9]+[)]' | awk -F' ' '{print $NF}' | tr -d ')')" - ## if-then-else block added to with ookla output when buffer bloat has been added to the human readable output ## + ## if-then-else block added to with Ookla output when buffer bloat has been added to the human readable output ## BUFFBLOAT="$(grep "Idle Latency:" "$tmpfile")" if [ -n "$BUFFBLOAT" ] then @@ -3586,7 +3649,9 @@ Run_Speedtest() then cp -fp "$tmpfile" "$spdTestDBGFile" Print_Output true "ERROR running speedtest for $IFACE_NAME [Empty or Bad Values]" "$CRIT" - if [ -s "$spdTestLogFile" ] ; then echo ; cat "$spdTestLogFile" ; echo ; fi + if [ -s "$spdTestLogFile" ] + then cat "$spdTestLogFile" ; echo + fi continue fi @@ -3847,16 +3912,16 @@ Process_Upgrade() { local foundError foundLocked resultStr doUpdateDB=false - if [ ! -f "$OOKLA_DIR/speedtest" ] + if [ ! -x "$EXTERNL_OOKLA_BINARY" ] then - rm -f "$OOKLA_DIR"/* - Download_File "$SCRIPT_REPO/$ARCH.tar.gz" "$OOKLA_DIR/$ARCH.tar.gz" - tar -xzf "$OOKLA_DIR/$ARCH.tar.gz" -C "$OOKLA_DIR" - rm -f "$OOKLA_DIR/$ARCH.tar.gz" - chmod 0755 "$OOKLA_DIR/speedtest" - chown "${theUserName}:root" "$OOKLA_DIR"/* - spdTestVer="$(_GetSpeedtestBinaryVersion_)" - Print_Output true "Speedtest CLI $spdTestVer version was downloaded." "$PASS" + rm -f "${OOKLA_DIR}"/* + Download_File "${SCRIPT_REPO}/$ARCH.tar.gz" "${OOKLA_DIR}/$ARCH.tar.gz" + tar -xzf "${OOKLA_DIR}/$ARCH.tar.gz" -C "$OOKLA_DIR" + rm -f "${OOKLA_DIR}/$ARCH.tar.gz" + chmod 0755 "$EXTERNL_OOKLA_BINARY" + chown "${theUserName}:root" "${OOKLA_DIR}"/* + spdTestVer="$(_GetExternalSpeedTestBinVersion_)" + Print_Output true "Ookla Speedtest CLI $spdTestVer version was downloaded." "$PASS" fi rm -f "$SCRIPT_STORAGE_DIR/spdjs.js" rm -f "$SCRIPT_STORAGE_DIR/.tableupgraded"* @@ -4482,11 +4547,11 @@ _HandleInvalidMenuOption_() } ##----------------------------------------## -## Modified by Martinski W. [2026-Jan-05] ## +## Modified by Martinski W. [2026-Jul-12] ## ##----------------------------------------## _Menu_SpeedTestOptions_() { - local menuOption exitMenu=false + local menuOption exitMenu=false speedTestBinaryType="[N/A]" local OPTION_FOR_QOS TEST_SCHED_LINE TEST_SCHED_DAYS local TEST_SCHED_MENU CRON_SCHED_DAYS CRON_SCHED_HOUR CRON_SCHED_MINS @@ -4495,6 +4560,12 @@ _Menu_SpeedTestOptions_() else OPTION_FOR_QOS="included in" fi + if [ "$(SpeedtestBinary check)" = "builtin" ] + then speedTestBinaryType="F/W ${SETTING}built-in${CLRct} Ookla speedtest binary" + elif [ "$(SpeedtestBinary check)" = "external" ] + then speedTestBinaryType="${SETTING}external${CLRct} Ookla binary installed by $SCRIPT_NAME" + fi + TEST_SCHED_LINE="$(CronTestSchedule check)" CRON_SCHED_DAYS="$(echo "$TEST_SCHED_LINE" | cut -f1 -d'|')" CRON_SCHED_HOUR="$(echo "$TEST_SCHED_LINE" | cut -f2 -d'|')" @@ -4512,7 +4583,7 @@ _Menu_SpeedTestOptions_() printf " ${GRNct}2${CLRct}. Set schedule for automatic speed tests\n" printf " Currently: ${SETTING}%s - %s${CLRct}\n\n" "$TEST_SCHED_MENU" "$TEST_SCHED_DAYS" printf " ${GRNct}3${CLRct}. Toggle between built-in Ookla speedtest and speedtest-cli\n" - printf " Currently: ${SETTING}%s${CLRct} binary will be used for speed tests${CLRct}\n\n" "$(SpeedtestBinary check)" + printf " [The ${speedTestBinaryType} will be used${CLRct}]\n\n" printf " ${GRNct}q${CLRct}. Toggle exclusion of %s speed tests from QoS\n" "$SCRIPT_NAME" printf " Currently: %s speed tests are ${SETTING}%s${CLRct} QoS\n\n" "$SCRIPT_NAME" "$OPTION_FOR_QOS" printf " ${GRNct}c${CLRct}. Customise list of interfaces for automatic speed tests\n" @@ -4920,24 +4991,24 @@ Menu_Install() Conf_Exists if [ "$(SpeedtestBinary check)" = "builtin" ] then - echo "/usr/sbin/ookla" > /tmp/spdmerlin-binary + echo "$BUILTIN_OOKLA_BINARY" > /tmp/spdmerlin-binary elif [ "$(SpeedtestBinary check)" = "external" ] then - echo "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary + echo "$EXTERNL_OOKLA_BINARY" > /tmp/spdmerlin-binary fi Set_Version_Custom_Settings local "$SCRIPT_VERSION" Set_Version_Custom_Settings server "$SCRIPT_VERSION" ScriptStorageLocation load Create_Symlinks - rm -f "$OOKLA_DIR"/* - Download_File "$SCRIPT_REPO/$ARCH.tar.gz" "$OOKLA_DIR/$ARCH.tar.gz" - tar -xzf "$OOKLA_DIR/$ARCH.tar.gz" -C "$OOKLA_DIR" - rm -f "$OOKLA_DIR/$ARCH.tar.gz" - chmod 0755 "$OOKLA_DIR/speedtest" - chown "${theUserName}:root" "$OOKLA_DIR"/* - spdTestVer="$(_GetSpeedtestBinaryVersion_)" - Print_Output true "Speedtest CLI $spdTestVer version was downloaded." "$PASS" + rm -f "${OOKLA_DIR}"/* + Download_File "${SCRIPT_REPO}/$ARCH.tar.gz" "${OOKLA_DIR}/$ARCH.tar.gz" + tar -xzf "${OOKLA_DIR}/$ARCH.tar.gz" -C "$OOKLA_DIR" + rm -f "${OOKLA_DIR}/$ARCH.tar.gz" + chmod 0755 "$EXTERNL_OOKLA_BINARY" + chown "${theUserName}:root" "${OOKLA_DIR}"/* + spdTestVer="$(_GetExternalSpeedTestBinVersion_)" + Print_Output true "Ookla Speedtest CLI $spdTestVer version was downloaded." "$PASS" Update_File README.md Update_File spdstats_www.asp @@ -5015,10 +5086,10 @@ Menu_Startup() Conf_Exists if [ "$(SpeedtestBinary check)" = "builtin" ] then - echo "/usr/sbin/ookla" > /tmp/spdmerlin-binary + echo "$BUILTIN_OOKLA_BINARY" > /tmp/spdmerlin-binary elif [ "$(SpeedtestBinary check)" = "external" ] then - echo "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary + echo "$EXTERNL_OOKLA_BINARY" > /tmp/spdmerlin-binary fi ScriptStorageLocation load true Auto_Startup create 2>/dev/null @@ -6603,21 +6674,20 @@ Menu_Uninstall() ps | grep -v grep | grep -v $$ | grep -i "$SCRIPT_NAME_LOWER" | grep generate | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 fi + PROC_NAME="" SPEEDTEST_BINARY="" if [ "$(SpeedtestBinary check)" = "builtin" ] then - SPEEDTEST_BINARY="/usr/sbin/ookla" + PROC_NAME="$BUILTIN_OOKLA_PROC" + SPEEDTEST_BINARY="$BUILTIN_OOKLA_BINARY" elif [ "$(SpeedtestBinary check)" = "external" ] then - SPEEDTEST_BINARY="$OOKLA_DIR/speedtest" - fi - PROC_NAME="speedtest" - if [ "$SPEEDTEST_BINARY" = "/usr/sbin/ookla" ] - then - PROC_NAME="ookla" + PROC_NAME="$EXTERNL_OOKLA_PROC" + SPEEDTEST_BINARY="$EXTERNL_OOKLA_BINARY" fi - if [ -n "$(pidof "$PROC_NAME")" ]; then - killall -q "$PROC_NAME" + + if [ -n "$(pidof "$PROC_NAME")" ] + then killall -q "$PROC_NAME" fi Print_Output true "Removing $SCRIPT_NAME..." "$PASS" Auto_Startup delete 2>/dev/null @@ -6850,10 +6920,10 @@ then Conf_Exists if [ "$(SpeedtestBinary check)" = "builtin" ] then - echo "/usr/sbin/ookla" > /tmp/spdmerlin-binary + echo "$BUILTIN_OOKLA_BINARY" > /tmp/spdmerlin-binary elif [ "$(SpeedtestBinary check)" = "external" ] then - echo "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary + echo "$EXTERNL_OOKLA_BINARY" > /tmp/spdmerlin-binary fi ScriptStorageLocation load Create_Symlinks @@ -7034,10 +7104,10 @@ case "$1" in Conf_Exists if [ "$(SpeedtestBinary check)" = "builtin" ] then - echo "/usr/sbin/ookla" > /tmp/spdmerlin-binary + echo "$BUILTIN_OOKLA_BINARY" > /tmp/spdmerlin-binary elif [ "$(SpeedtestBinary check)" = "external" ] then - echo "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary + echo "$EXTERNL_OOKLA_BINARY" > /tmp/spdmerlin-binary fi ScriptStorageLocation load true Create_Symlinks From ce9ed7182c7083d2bd54267256c23357084b20bb Mon Sep 17 00:00:00 2001 From: Martinski4GitHub <119833648+Martinski4GitHub@users.noreply.github.com> Date: Wed, 15 Jul 2026 13:50:39 -0700 Subject: [PATCH 09/12] Tentative Fix and Improvements - A tentative solution for the recent speed test failures that have begun to occur all of sudden as reported by some users. This commit implements the solution only in the code that generates the list of test servers. - Some code improvements and fine-tuning. --- README.md | 2 +- spdmerlin.sh | 299 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 185 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index 3e89eff..edd461c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # spdMerlin ## v4.4.20 -### Updated on 2026-Jul-12 +### Updated on 2026-Jul-15 ## About spdMerlin is an internet speedtest and monitoring tool for AsusWRT Merlin with charts for daily, weekly and monthly summaries. It tracks download/upload bandwidth as well as latency, jitter and packet loss. diff --git a/spdmerlin.sh b/spdmerlin.sh index 89ec987..af75aba 100644 --- a/spdmerlin.sh +++ b/spdmerlin.sh @@ -14,7 +14,7 @@ ## Forked from https://github.com/jackyaz/spdMerlin ## ## ## ############################################################## -# Last Modified: 2026-Jul-12 +# Last Modified: 2026-Jul-15 #------------------------------------------------------------- ############## Shellcheck directives ############# @@ -39,7 +39,7 @@ readonly SCRIPT_NAME="spdMerlin" readonly SCRIPT_NAME_LOWER="$(echo "$SCRIPT_NAME" | tr 'A-Z' 'a-z')" readonly SCRIPT_VERSION="v4.4.20" -readonly SCRIPT_VERSTAG="26071209" +readonly SCRIPT_VERSTAG="26071512" SCRIPT_BRANCH="develop" SCRIPT_REPO="https://raw.githubusercontent.com/AMTM-OSR/$SCRIPT_NAME/$SCRIPT_BRANCH" readonly SCRIPT_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d" @@ -1644,6 +1644,30 @@ Auto_Cron() esac } +##-------------------------------------## +## Added by Martinski W. [2026-Jul-15] ## +##-------------------------------------## +_Get_Interface_IPv4address_() +{ + if [ $# -eq 0 ] || [ -z "$1" ] || \ + ! echo "$1" | grep -qE "^(wgc|tun1)[1-5]$" + then echo ; return 1 + fi + local wgcRegExp="[[:blank:]]+inet[[:blank:]]+.*[[:blank:]]+global[[:blank:]]+${1}$" + local tunRegExp="[[:blank:]]+dev[[:blank:]]+${1}[[:blank:]]+proto[[:blank:]]+.*[[:blank:]]+src[[:blank:]]+" + + if echo "$1" | grep -qE "^tun1[1-5]$" + then + ip route show | grep -E "$tunRegExp" | awk -F' ' '{print $NF}' + return 0 + fi + if echo "$1" | grep -qE "^wgc[1-5]$" + then + ip addr show "$1" | grep -E "$wgcRegExp" | awk -F' ' '{print $2}' | awk -F'/' '{print $1}' + return 0 + fi +} + ##----------------------------------------## ## Modified by Martinski W. [2025-Jun-27] ## ##----------------------------------------## @@ -2470,11 +2494,12 @@ WriteStats_ToJS() } ##----------------------------------------## -## Modified by Martinski W. [2026-Jan-05] ## +## Modified by Martinski W. [2026-Jul-15] ## ##----------------------------------------## GenerateServerList() { - local serverMsgStr maxServerCount serverCount serverIndx COUNTER + local serverMsgStr maxServerCount serverCount serverIndx + local IFACE_NAME IFACE_LOWER IFACE_IPv4A COUNTER serverList local errorLogFile="/tmp/${SCRIPT_NAME}.DEBUG.Servers.LOG" if [ ! -f /opt/bin/jq ] && [ -x /opt/bin/opkg ] @@ -2486,11 +2511,16 @@ GenerateServerList() then promptforservername="" else promptforservername="$2" fi - rm -f "$errorLogFile" - printf " Generating list of closest servers for ${GRNct}${1}${CLRct} interface.\n" + rm -f "$errorLogFile" + IFACE_NAME="$1" + IFACE_LOWER="$(Get_Interface_From_Name "$IFACE_NAME" | tr 'A-Z' 'a-z')" + IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" + + printf " Generating list of closest servers for ${GRNct}${IFACE_NAME} [$IFACE_LOWER]${CLRct} interface.\n" printf " Please wait...\n\n" + serverList="" CONFIG_STRING="" LICENSE_STRING="" SPEEDTEST_BINARY="" @@ -2504,10 +2534,14 @@ GenerateServerList() LICENSE_STRING="--accept-license --accept-gdpr" fi - serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$1")" --servers --format="json" $LICENSE_STRING)" 2>"$errorLogFile" + serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$IFACE_LOWER" --servers --format="json" $LICENSE_STRING)" 2>"$errorLogFile" + if [ -z "$serverList" ] && [ -n "$IFACE_IPv4A" ] + then + serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --ip="$IFACE_IPv4A" --servers --format="json" $LICENSE_STRING)" 2>"$errorLogFile" + fi if [ -z "$serverList" ] then - Print_Output true "ERROR retrieving server list for $1 interface" "$CRIT" + Print_Output true "ERROR retrieving server list for $IFACE_NAME [$IFACE_LOWER] interface" "$CRIT" serverNum="ERROR" if [ -s "$errorLogFile" ] then cat "$errorLogFile" ; echo @@ -2539,9 +2573,9 @@ GenerateServerList() while true do - printf "\n${BOLD}Select a %s from the list above [${GRNct}1-%d${CLRct}].${CLRct}" "$serverMsgStr" "$maxServerCount" - printf "\n${BOLD}Or press ${GRNct}C${CLRct} key to enter a known speed test server ID.${CLRct}" - printf "\n${BOLD}Enter answer:${CLRct} " + printf "\n ${BOLD}Select a %s from the list above [${GRNct}1-%d${CLRct}].${CLRct}" "$serverMsgStr" "$maxServerCount" + printf "\n ${BOLD}Or press ${GRNct}C${CLRct} key to enter a known speed test server ID.${CLRct}" + printf "\n ${BOLD}Enter answer:${CLRct} " read -r serverIndx if echo "$serverIndx" | grep -qE "^(e|E)$" @@ -2557,7 +2591,7 @@ GenerateServerList() then while true do - printf "\n${BOLD}Please enter server ID (WARNING: ID is NOT validated) or ${GRNct}e${CLRct} to go back.${CLRct} " + printf "\n ${BOLD}Please enter server ID (${MGNTct}WARNING: ID is NOT validated${CLRct}) or ${GRNct}e${CLRct} to go back.${CLRct} " read -r customserver if [ "$customserver" = "e" ] then @@ -2572,19 +2606,19 @@ GenerateServerList() then while true do - printf "\n${BOLD}Would you like to enter a name for this server? (default: Custom) (y/n)?${CLRct} " + printf "\n ${BOLD}Would you like to enter a name for this server? (default: Custom) (y/n)?${CLRct} " read -r servername_select - if [ "$servername_select" = "n" ] || [ "$servername_select" = "N" ] + if echo "$servername_select" | grep -qE '^(n|N)$' then serverName="Custom" break - elif [ "$servername_select" = "y" ] || [ "$servername_select" = "Y" ] + elif echo "$servername_select" | grep -qE '^(y|Y)$' then - printf "\n${BOLD}Please enter the name for this server:${CLRct} " + printf "\n ${BOLD}Please enter the name for this server:${CLRct} " read -r serverName - printf "\n${BOLD}%s${CLRct}\n" "$serverName" - printf "\n${BOLD}Is that correct (y/n)?${CLRct} " + printf "\n ${BOLD}${GRNct}%s${CLRct}\n" "$serverName" + printf "\n ${BOLD}Is that correct (y/n)?${CLRct} " read -r servername_confirm if [ "$servername_confirm" = "y" ] || \ [ "$servername_confirm" = "Y" ] @@ -2600,8 +2634,7 @@ GenerateServerList() else serverName="Custom" fi - printf "\n" - return 0 + echo ; return 0 fi done elif ! Validate_Number "$serverIndx" @@ -2621,11 +2654,12 @@ GenerateServerList() } ##----------------------------------------## -## Modified by Martinski W. [2025-Oct-12] ## +## Modified by Martinski W. [2026-Jul-15] ## ##----------------------------------------## GenerateServerList_WebUI() { - local setIFaceUserStatus=false + local setIFaceUserStatus=false serverList + local IFACE_NAME IFACE_LOWER IFACE_IPv4A COUNTER spdifacename="$1" serverlistfile="$2" @@ -2633,6 +2667,7 @@ GenerateServerList_WebUI() rm -f "/tmp/${serverlistfile}.tmp" rm -f "${SCRIPT_WEB_DIR}/${serverlistfile}.htm" + serverList="" CONFIG_STRING="" LICENSE_STRING="" SPEEDTEST_BINARY="" @@ -2673,10 +2708,16 @@ GenerateServerList_WebUI() for IFACE_NAME in $IFACELIST do - serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$IFACE_NAME")" --servers --format="json" $LICENSE_STRING)" 2>/dev/null + IFACE_LOWER="$(Get_Interface_From_Name "$IFACE_NAME" | tr 'A-Z' 'a-z')" + IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" + serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$IFACE_LOWER" --servers --format="json" $LICENSE_STRING)" 2>/dev/null + if [ -z "$serverList" ] && [ -n "$IFACE_IPv4A" ] + then + serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --ip="$IFACE_IPv4A" --servers --format="json" $LICENSE_STRING)" 2>/dev/null + fi if [ -z "$serverList" ] then - Print_Output true "ERROR retrieving server list for $IFACE_NAME interface" "$CRIT" + Print_Output true "ERROR retrieving server list for $IFACE_NAME [$IFACE_LOWER] interface" "$CRIT" { echo "0|**ERROR**: Unable to retrieve server list." ; echo "-----" } >> "/tmp/${serverlistfile}.tmp" @@ -2695,10 +2736,16 @@ GenerateServerList_WebUI() echo "-----" >> "/tmp/${serverlistfile}.tmp" done else - serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$spdifacename")" --servers --format="json" $LICENSE_STRING)" 2>/dev/null + IFACE_LOWER="$(Get_Interface_From_Name "$spdifacename" | tr 'A-Z' 'a-z')" + IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" + serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$IFACE_LOWER" --servers --format="json" $LICENSE_STRING)" 2>/dev/null + if [ -z "$serverList" ] && [ -n "$IFACE_IPv4A" ] + then + serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --ip="$IFACE_IPv4A" --servers --format="json" $LICENSE_STRING)" 2>/dev/null + fi if [ -z "$serverList" ] then - Print_Output true "ERROR retrieving server list for $spdifacename interface" "$CRIT" + Print_Output true "ERROR retrieving server list for $spdifacename [$IFACE_LOWER] interface" "$CRIT" serverCount=0 else serverCount="$(echo "$serverList" | jq '.servers | length')" @@ -3307,7 +3354,7 @@ _Trim_Database_() } ##----------------------------------------## -## Modified by Martinski W. [2026-Jul-12] ## +## Modified by Martinski W. [2026-Jul-15] ## ##----------------------------------------## Run_Speedtest() { @@ -3356,6 +3403,7 @@ Run_Speedtest() local stoppedQoS nvramQoSenable nvramQoStype local spdIndx spdTestOK verboseNUM verboseARG local serverLine serverIDno + local IFACE_NAME IFACE_LOWER IFACE_IPv4A verboseNUM="$(_GetConfigParam_ VERBOSE_TEST 0)" if ! echo "$verboseNUM" | grep -qE "^[0-3]$" then verboseNUM=0 @@ -3380,9 +3428,9 @@ Run_Speedtest() tmpfile=/tmp/spd-stats.txt resultfile=/tmp/spd-result.txt - spdTestLogFile="/tmp/${SCRIPT_NAME}.DEBUG.log" + errorLogFile="/tmp/${SCRIPT_NAME}.DEBUG.LOG" spdTestDBGFile="/tmp/${SCRIPT_NAME}.DEBUG.txt" - rm -f "$tmpfile" "$resultfile" "$spdTestLogFile" + rm -f "$tmpfile" "$resultfile" "$errorLogFile" if [ -n "$(pidof "$PROC_NAME")" ] then killall -q "$PROC_NAME" @@ -3396,6 +3444,15 @@ Run_Speedtest() return 1 fi + _WaitForSpeedTestProcess_() + { + sleep 2 ; speedTestSecs=0 + while [ -n "$(pidof "$PROC_NAME")" ] && \ + [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] + do speedTestSecs="$((speedTestSecs + 1))" ; sleep 1 + done + } + IFACELIST="" if [ -z "$specificiface" ] then @@ -3474,9 +3531,7 @@ Run_Speedtest() for IFACE_NAME in $IFACELIST do - IFACE="$(Get_Interface_From_Name "$IFACE_NAME")" - IFACE_LOWER="$(echo "$IFACE" | tr "A-Z" "a-z")" - + IFACE_LOWER="$(Get_Interface_From_Name "$IFACE_NAME" | tr 'A-Z' 'a-z')" interface_UP=false if echo "$IFACE_NAME" | grep -q "^WGVPN" then @@ -3489,9 +3544,10 @@ Run_Speedtest() if ! "$interface_UP" then - Print_Output true "$IFACE not up, please check. Skipping speedtest for $IFACE_NAME" "$WARN" + Print_Output true "$IFACE_LOWER is not up, please check. Skipping speedtest for $IFACE_NAME" "$WARN" continue else + IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" if [ "$mode" = "webui_user" ]; then mode="user" elif [ "$mode" = "webui_auto" ]; then @@ -3527,62 +3583,65 @@ Run_Speedtest() fi echo 'var spdteststatus = "InProgress_'"$IFACE_NAME"'";' > /tmp/detect_spdtest.js - printf '' > "$tmpfile" + printf '' > "$tmpfile" ; printf '' > "$errorLogFile" if [ "$mode" = "auto" ] then - Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME [$IFACE] interface. Please wait..." "$PASS" - ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$spdTestLogFile" & - sleep 2 - speedTestSecs=0 - while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] - do - speedTestSecs="$((speedTestSecs + 1))" ; sleep 1 - done + Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME [$IFACE_LOWER] interface. Please wait..." "$PASS" + ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE_LOWER" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" & + _WaitForSpeedTestProcess_ + + if [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] && \ + [ ! -s "$tmpfile" ] && [ -s "$errorLogFile" ] && [ -n "$IFACE_IPv4A" ] + then + : ##*TBD*## + fi if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ] then - Print_Output true "Speedtest for $IFACE_NAME [$IFACE] hung (> 2 mins), killing process" "$CRIT" + Print_Output true "Speedtest for $IFACE_NAME [$IFACE_LOWER] hung (> 2 mins), killing process" "$CRIT" killall -q "$PROC_NAME" - if [ -s "$spdTestLogFile" ] - then cat "$spdTestLogFile" ; echo + if [ -s "$errorLogFile" ] + then cat "$errorLogFile" ; echo fi continue fi else if [ "$speedtestServerIDx" -ne 0 ] then - Print_Output true "Starting speedtest using $speedtestServerName for $IFACE_NAME [$IFACE] interface. Please wait..." "$PASS" - ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --server-id="$speedtestServerIDx" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$spdTestLogFile" & - sleep 2 - speedTestSecs=0 - while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] - do - speedTestSecs="$((speedTestSecs + 1))" ; sleep 1 - done + Print_Output true "Starting speedtest using $speedtestServerName for $IFACE_NAME [$IFACE_LOWER] interface. Please wait..." "$PASS" + ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE_LOWER" --server-id="$speedtestServerIDx" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" & + _WaitForSpeedTestProcess_ + + if [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] && \ + [ ! -s "$tmpfile" ] && [ -s "$errorLogFile" ] && [ -n "$IFACE_IPv4A" ] + then + : ##*TBD*## + fi if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ] then - Print_Output true "Speedtest for $IFACE_NAME [$IFACE] hung (> 2 mins), killing process" "$CRIT" + Print_Output true "Speedtest for $IFACE_NAME [$IFACE_LOWER] hung (> 2 mins), killing process" "$CRIT" killall -q "$PROC_NAME" - if [ -s "$spdTestLogFile" ] - then cat "$spdTestLogFile" ; echo + if [ -s "$errorLogFile" ] + then cat "$errorLogFile" ; echo fi continue fi else - Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME [$IFACE] interface. Please wait..." "$PASS" - ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$spdTestLogFile" & - sleep 2 - speedTestSecs=0 - while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] - do - speedTestSecs="$((speedTestSecs + 1))" ; sleep 1 - done + Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME [$IFACE_LOWER] interface. Please wait..." "$PASS" + ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE_LOWER" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" & + _WaitForSpeedTestProcess_ + + if [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] && \ + [ ! -s "$tmpfile" ] && [ -s "$errorLogFile" ] && [ -n "$IFACE_IPv4A" ] + then + : ##*TBD*## + fi if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ] then - Print_Output true "Speedtest for $IFACE_NAME [$IFACE] hung (> 2 mins), killing process" "$CRIT" + Print_Output true "Speedtest for $IFACE_NAME [$IFACE_LOWER] hung (> 2 mins), killing process" "$CRIT" killall -q "$PROC_NAME" - if [ -s "$spdTestLogFile" ] - then cat "$spdTestLogFile" ; echo + if [ -s "$errorLogFile" ] + then cat "$errorLogFile" ; echo fi continue fi @@ -3591,9 +3650,9 @@ Run_Speedtest() if [ ! -s "$tmpfile" ] || [ -z "$(cat "$tmpfile")" ] || [ "$(grep -c 'FAILED' "$tmpfile")" -gt 0 ] then - Print_Output true "ERROR running speedtest for $IFACE_NAME [$IFACE] [No Results]" "$CRIT" - if [ -s "$spdTestLogFile" ] - then cat "$spdTestLogFile" ; echo + Print_Output true "ERROR running speedtest for $IFACE_NAME [$IFACE_LOWER] [No Results]" "$CRIT" + if [ -s "$errorLogFile" ] + then cat "$errorLogFile" ; echo fi continue fi @@ -3648,9 +3707,9 @@ Run_Speedtest() [ -z "$datadownload" ] || [ -z "$dataupload" ] then cp -fp "$tmpfile" "$spdTestDBGFile" - Print_Output true "ERROR running speedtest for $IFACE_NAME [Empty or Bad Values]" "$CRIT" - if [ -s "$spdTestLogFile" ] - then cat "$spdTestLogFile" ; echo + Print_Output true "ERROR running speedtest for $IFACE_NAME [$IFACE_LOWER] [Empty or Bad Values]" "$CRIT" + if [ -s "$errorLogFile" ] + then cat "$errorLogFile" ; echo fi continue fi @@ -4077,7 +4136,6 @@ Process_Upgrade() ##----------------------------------------## ## Modified by Martinski W. [2025-Jun-20] ## ##----------------------------------------## -#$1 IFACE Name Generate_LastXResults() { local foundError foundLocked resultStr sqlProcSuccess @@ -5133,25 +5191,28 @@ _Reset_Interface_States_() ##----------------------------------------## Menu_RunSpeedtest() { - exitmenu="" - validselection="" - useiface="" - usepreferred="" - ScriptHeader + local exitmenu="" validSelection=false ifaceCountMAX=0 + local useiface="" usepreferred="" iface_choice ifaceID + while true do - printf "Choose an interface to speedtest:\n\n" - printf "1. All\n" - COUNTER="2" - while IFS='' read -r line || [ -n "$line" ] + ScriptHeader + printf " Choose an interface to run a speed test:\n\n" + printf " ${GRNct}1${CLRct}) All\n" + COUNTER=2 + while IFS='' read -r theLINE || [ -n "$theLINE" ] do - if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ] + if [ "$(echo "$theLINE" | grep -c "interface not up")" -eq 0 ] then - printf "%s. %s\n" "$COUNTER" "$(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')" - COUNTER="$((COUNTER+1))" + ifaceID="$(echo "$theLINE" | cut -d'#' -f1 | sed 's/ *$//')" + printf " ${GRNct}%2d${CLRct}) %s\n" "$COUNTER" "$ifaceID" + COUNTER="$((COUNTER + 1))" fi done < "$SCRIPT_INTERFACES_USER" - printf "\nChoose an option (e=Exit): " + printf "\n ${GRNct}e${CLRct}) Return to Main Menu\n" + ifaceCountMAX="$((COUNTER - 1))" + + printf "\n Choose an option: " read -r iface_choice if [ "$iface_choice" = "e" ] @@ -5160,34 +5221,37 @@ Menu_RunSpeedtest() break elif ! Validate_Number "$iface_choice" then - printf "\n${ERR}Please enter a valid number [1-%s].${CLEARFORMAT}\n" "$((COUNTER-1))" - validselection="false" + validSelection=false + printf "\n${ERR}Please enter a valid number [1-%s].${CLRct}\n" "$ifaceCountMAX" + PressEnter ; continue else - if [ "$iface_choice" -lt 1 ] || [ "$iface_choice" -gt "$((COUNTER-1))" ] + if [ "$iface_choice" -lt 1 ] || [ "$iface_choice" -gt "$ifaceCountMAX" ] then - printf "\n${ERR}Please enter a number between 1 and %s.${CLEARFORMAT}\n" "$((COUNTER-1))" - validselection="false" + validSelection=false + printf "\n${ERR}Please enter a number between 1 and %s.${CLRct}\n" "$ifaceCountMAX" + PressEnter ; continue else - if [ "$iface_choice" -gt "1" ] + if [ "$iface_choice" -gt 1 ] then useiface="$(grep -v "interface not up" "$SCRIPT_INTERFACES_USER" | sed -n $((iface_choice-1))p | cut -f1 -d"#" | sed 's/ *$//')" else useiface="All" fi - validselection="true" + validSelection=true fi fi - printf "\n" + echo - if [ "$exitmenu" != "exit" ] && [ "$validselection" != "false" ] + if [ "$exitmenu" != "exit" ] && "$validSelection" then while true do - printf "What mode would you like to use?\n\n" - printf "1. Auto-select\n" - printf "2. Preferred server\n" - printf "3. Choose a server\n" - printf "\nChoose an option (e=Exit): " + printf "\n What mode would you like to use?\n\n" + printf " ${GRNct}1${CLRct}. Auto-select\n" + printf " ${GRNct}2${CLRct}. Preferred server\n" + printf " ${GRNct}3${CLRct}. Choose a server\n\n" + printf " ${GRNct}e${CLRct}. Return to Main Menu\n" + printf "\n Choose an option: " read -r usepref_choice if [ "$usepref_choice" = "e" ] @@ -5196,42 +5260,47 @@ Menu_RunSpeedtest() break elif ! Validate_Number "$usepref_choice" then - printf "\n${ERR}Please enter a valid number [1-3].${CLEARFORMAT}\n" - validselection="false" ; echo + validSelection=false + printf "\n${ERR}Please enter a valid number [1-3].${CLRct}\n" + PressEnter ; echo else if [ "$usepref_choice" -lt 1 ] || [ "$usepref_choice" -gt 3 ] then - printf "\n${ERR}Please enter a number between 1 and 3.${CLEARFORMAT}\n" - validselection="false" ; echo + validSelection=false + printf "\n${ERR}Please enter a number between 1 and 3.${CLRct}\n" + PressEnter ; echo else case "$usepref_choice" in 1) usepreferred="auto" ;; 2) usepreferred="user" ;; 3) usepreferred="onetime" ;; esac - validselection="true" ; echo + validSelection=true ; echo break fi fi done fi - if [ "$exitmenu" != "exit" ] && [ "$validselection" != "false" ] + + if [ "$exitmenu" = "exit" ] + then break ; fi + + if "$validSelection" then - if Check_Lock menu; then + if Check_Lock menu + then Run_Speedtest "$usepreferred" "$useiface" Clear_Lock fi - elif [ "$exitmenu" = "exit" ]; then - break fi - printf "\n" - PressEnter - ScriptHeader + echo ; PressEnter done if [ "$exitmenu" != "exit" ] - then return 0 - else echo ; return 1 + then + return 0 + else + echo ; return 1 fi } From d0d2ef5d61131a8b91f525ac875fd9f405b7b614 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 09:53:56 +0000 Subject: [PATCH 10/12] Bump softprops/action-gh-release in the all-actions group Bumps the all-actions group with 1 update: [softprops/action-gh-release](https://github.com/softprops/action-gh-release). Updates `softprops/action-gh-release` from 3.0.1 to 3.0.2 - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v3.0.1...v3.0.2) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: 3.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/Create-NewReleases.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Create-NewReleases.yml b/.github/workflows/Create-NewReleases.yml index a82630c..9b8f667 100644 --- a/.github/workflows/Create-NewReleases.yml +++ b/.github/workflows/Create-NewReleases.yml @@ -97,7 +97,7 @@ jobs: # 7--- Publish a GitHub Release with auto-generated notes - name: Create Release with Automated Release Notes - uses: softprops/action-gh-release@v3.0.1 + uses: softprops/action-gh-release@v3.0.2 with: token: ${{ secrets.GITHUB_TOKEN }} tag_name: ${{ steps.nextver.outputs.tag }} From 9ea224600adec1f1efb234fb953e4c33e6d1c9cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 09:53:49 +0000 Subject: [PATCH 11/12] Bump actions/checkout from 7.0.0 to 7.0.1 in the all-actions group Bumps the all-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 7.0.0 to 7.0.1 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v7.0.0...v7.0.1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/Create-NewReleases.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Create-NewReleases.yml b/.github/workflows/Create-NewReleases.yml index 9b8f667..22a07b4 100644 --- a/.github/workflows/Create-NewReleases.yml +++ b/.github/workflows/Create-NewReleases.yml @@ -19,7 +19,7 @@ jobs: steps: # 1--- Check out master so we tag the exact merge commit - name: Checkout source code - uses: actions/checkout@v7.0.0 + uses: actions/checkout@v7.0.1 with: fetch-depth: 0 ref: 'master' From 8e00d95e8c9eb9ffac728e25f34701ed13091979 Mon Sep 17 00:00:00 2001 From: Martinski4GitHub <119833648+Martinski4GitHub@users.noreply.github.com> Date: Sun, 9 Aug 2026 22:41:04 -0700 Subject: [PATCH 12/12] Disabled Tentative Solution to Speed Test Failures Disabled the tentative solution implemented for some unusual speed test failures. It does not seem to work well and reliably enough for a production release. More investigation is needed. --- README.md | 2 +- spdmerlin.sh | 40 +++++++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index edd461c..515a9fe 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # spdMerlin ## v4.4.20 -### Updated on 2026-Jul-15 +### Updated on 2026-Aug-10 ## About spdMerlin is an internet speedtest and monitoring tool for AsusWRT Merlin with charts for daily, weekly and monthly summaries. It tracks download/upload bandwidth as well as latency, jitter and packet loss. diff --git a/spdmerlin.sh b/spdmerlin.sh index af75aba..1f86b8c 100644 --- a/spdmerlin.sh +++ b/spdmerlin.sh @@ -14,7 +14,7 @@ ## Forked from https://github.com/jackyaz/spdMerlin ## ## ## ############################################################## -# Last Modified: 2026-Jul-15 +# Last Modified: 2026-Aug-09 #------------------------------------------------------------- ############## Shellcheck directives ############# @@ -39,7 +39,7 @@ readonly SCRIPT_NAME="spdMerlin" readonly SCRIPT_NAME_LOWER="$(echo "$SCRIPT_NAME" | tr 'A-Z' 'a-z')" readonly SCRIPT_VERSION="v4.4.20" -readonly SCRIPT_VERSTAG="26071512" +readonly SCRIPT_VERSTAG="26080922" SCRIPT_BRANCH="develop" SCRIPT_REPO="https://raw.githubusercontent.com/AMTM-OSR/$SCRIPT_NAME/$SCRIPT_BRANCH" readonly SCRIPT_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d" @@ -1653,17 +1653,17 @@ _Get_Interface_IPv4address_() ! echo "$1" | grep -qE "^(wgc|tun1)[1-5]$" then echo ; return 1 fi - local wgcRegExp="[[:blank:]]+inet[[:blank:]]+.*[[:blank:]]+global[[:blank:]]+${1}$" - local tunRegExp="[[:blank:]]+dev[[:blank:]]+${1}[[:blank:]]+proto[[:blank:]]+.*[[:blank:]]+src[[:blank:]]+" + local addrRegExp="[[:blank:]]+inet[[:blank:]]+.*[[:blank:]]+global[[:blank:]]+${1}$" + local routRegExp="[[:blank:]]+dev[[:blank:]]+${1}[[:blank:]]+proto[[:blank:]]+.*[[:blank:]]+src[[:blank:]]+" if echo "$1" | grep -qE "^tun1[1-5]$" then - ip route show | grep -E "$tunRegExp" | awk -F' ' '{print $NF}' + ip route show | grep -E "$routRegExp" | awk -F' ' '{print $NF}' return 0 fi if echo "$1" | grep -qE "^wgc[1-5]$" then - ip addr show "$1" | grep -E "$wgcRegExp" | awk -F' ' '{print $2}' | awk -F'/' '{print $1}' + ip addr show "$1" | grep -E "$addrRegExp" | awk -F' ' '{print $2}' | awk -F'/' '{print $1}' return 0 fi } @@ -1684,9 +1684,9 @@ Get_Interface_From_Name() elif [ "$wanProto" = "l2tp" ] || \ [ "$wanProto" = "pptp" ] || \ [ "$wanProto" = "pppoe" ] - then + then #(e.g. 'ppp0')# IFACEname="$(nvram get "${wanPrefix}_pppoe_ifname")" - else + else #(e.g. 'eth0')# IFACEname="$(nvram get "${wanPrefix}_ifname")" fi ;; @@ -2515,7 +2515,8 @@ GenerateServerList() rm -f "$errorLogFile" IFACE_NAME="$1" IFACE_LOWER="$(Get_Interface_From_Name "$IFACE_NAME" | tr 'A-Z' 'a-z')" - IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" + IFACE_IPv4A="" ##DO NOT SET## + ##OFF## IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" printf " Generating list of closest servers for ${GRNct}${IFACE_NAME} [$IFACE_LOWER]${CLRct} interface.\n" printf " Please wait...\n\n" @@ -2709,7 +2710,8 @@ GenerateServerList_WebUI() for IFACE_NAME in $IFACELIST do IFACE_LOWER="$(Get_Interface_From_Name "$IFACE_NAME" | tr 'A-Z' 'a-z')" - IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" + IFACE_IPv4A="" ##DO NOT SET## + ##OFF## IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$IFACE_LOWER" --servers --format="json" $LICENSE_STRING)" 2>/dev/null if [ -z "$serverList" ] && [ -n "$IFACE_IPv4A" ] then @@ -2737,7 +2739,8 @@ GenerateServerList_WebUI() done else IFACE_LOWER="$(Get_Interface_From_Name "$spdifacename" | tr 'A-Z' 'a-z')" - IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" + IFACE_IPv4A="" ##DO NOT SET## + ##OFF## IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$IFACE_LOWER" --servers --format="json" $LICENSE_STRING)" 2>/dev/null if [ -z "$serverList" ] && [ -n "$IFACE_IPv4A" ] then @@ -3547,7 +3550,8 @@ Run_Speedtest() Print_Output true "$IFACE_LOWER is not up, please check. Skipping speedtest for $IFACE_NAME" "$WARN" continue else - IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" + IFACE_IPv4A="" ##DO NOT SET## + ##OFF## IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")" if [ "$mode" = "webui_user" ]; then mode="user" elif [ "$mode" = "webui_auto" ]; then @@ -3594,7 +3598,9 @@ Run_Speedtest() if [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] && \ [ ! -s "$tmpfile" ] && [ -s "$errorLogFile" ] && [ -n "$IFACE_IPv4A" ] then - : ##*TBD*## + printf '' > "$errorLogFile" + ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --ip="$IFACE_IPv4A" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" & + _WaitForSpeedTestProcess_ fi if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ] then @@ -3615,7 +3621,9 @@ Run_Speedtest() if [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] && \ [ ! -s "$tmpfile" ] && [ -s "$errorLogFile" ] && [ -n "$IFACE_IPv4A" ] then - : ##*TBD*## + printf '' > "$errorLogFile" + ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --ip="$IFACE_IPv4A" --server-id="$speedtestServerIDx" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" & + _WaitForSpeedTestProcess_ fi if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ] then @@ -3634,7 +3642,9 @@ Run_Speedtest() if [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] && \ [ ! -s "$tmpfile" ] && [ -s "$errorLogFile" ] && [ -n "$IFACE_IPv4A" ] then - : ##*TBD*## + printf '' > "$errorLogFile" + ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --ip="$IFACE_IPv4A" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" & + _WaitForSpeedTestProcess_ fi if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ] then