Compare commits

..

7 commits

Author SHA1 Message Date
Christian Hesse
a8ba5ee13b Merge branch 'mode-button' into next 2026-07-17 11:48:22 +02:00
Christian Hesse
16cfe335c2 announce the change on mode-button, run migration 2026-07-17 11:48:22 +02:00
Christian Hesse
68dfe26198 mode-button: drop all global variables
With RouterOS 7.24 (actually 7.24beta1 I think) the mode, reset and wps
button scripts are run with limited policy. This causes global variables
not being available... So let's drop them here.

This is kind of inconvenient, but we can live with it. The second script
'mode-button-scheduler' is run from scheduler and does not suffer that
limitation.
2026-07-17 11:48:22 +02:00
Christian Hesse
198b088faa mode-button{,-scheduler}: store to and get count from scheduler's comment 2026-07-17 11:48:22 +02:00
Christian Hesse
0e5a30d946 mode-button: spilt the into two scripts 2026-07-17 10:22:25 +02:00
Christian Hesse
b3aa479515 mode-button: resolve nested conditions 2026-07-17 09:04:39 +02:00
Christian Hesse
b828989d8c check-health.d/temperature: give the cpu utilization in notification...
... to give a first hint if high load is an issue.
2026-07-16 13:41:04 +02:00
8 changed files with 105 additions and 81 deletions

View file

@ -14,6 +14,7 @@
:local FuncName [ :tostr $0 ]; :local FuncName [ :tostr $0 ];
:local ScriptName [ :tostr $1 ]; :local ScriptName [ :tostr $1 ];
:global CheckHealthCPUUtilization;
:global CheckHealthLast; :global CheckHealthLast;
:global CheckHealthTemperature; :global CheckHealthTemperature;
:global CheckHealthTemperatureDeviation; :global CheckHealthTemperatureDeviation;
@ -57,7 +58,8 @@
$SendNotification2 ({ origin=$ScriptName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \
message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ message=("The " . $Name . " on " . $Identity . " is above threshold: " . \
$Value . "\C2\B0" . "C") }); $Value . "\C2\B0C\n\n" . "The average CPU utilization is at " . \
($CheckHealthCPUUtilization / 10) . "%!") });
:set ($CheckHealthTemperatureNotified->$Name) true; :set ($CheckHealthTemperatureNotified->$Name) true;
} }
:if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \
@ -65,7 +67,8 @@
$SendNotification2 ({ origin=$ScriptName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \
message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \
$Value . "\C2\B0" . "C") }); $Value . "\C2\B0C\n\n" . "The average CPU utilization is at " . \
($CheckHealthCPUUtilization / 10) . "%!") });
:set ($CheckHealthTemperatureNotified->$Name) false; :set ($CheckHealthTemperatureNotified->$Name) false;
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Before After
Before After

View file

@ -16,7 +16,7 @@ Mode button with multiple presses
Description Description
----------- -----------
This script extend the functionality of mode button. Instead of just one These scripts extend the functionality of mode button. Instead of just one
you can trigger several actions by pressing the mode button several times. you can trigger several actions by pressing the mode button several times.
The hardware needs to have a mode button, see The hardware needs to have a mode button, see
@ -39,9 +39,9 @@ Copy this code to terminal to check:
Requirements and installation Requirements and installation
----------------------------- -----------------------------
Just install the script: Just install the scripts:
$ScriptInstallUpdate mode-button; $ScriptInstallUpdate mode-button,mode-button-scheduler;
Then configure the mode button to run `mode-button`: Then configure the mode button to run `mode-button`:

View file

@ -15,7 +15,7 @@
# Git commit id & info, expected configuration version # Git commit id & info, expected configuration version
:global CommitId "unknown"; :global CommitId "unknown";
:global CommitInfo "unknown"; :global CommitInfo "unknown";
:global ExpectedConfigVersion 143; :global ExpectedConfigVersion 144;
# global variables not to be changed by user # global variables not to be changed by user
:global GlobalFunctionsReady false; :global GlobalFunctionsReady false;

84
mode-button-scheduler.rsc Normal file
View file

@ -0,0 +1,84 @@
#!rsc by RouterOS
# RouterOS script: mode-button-scheduler
# Copyright (c) 2018-2026 Christian Hesse <mail@eworm.de>
# https://rsc.eworm.de/COPYING.md
#
# requires RouterOS, version=7.21
# requires device-mode, scheduler
#
# act on multiple mode and reset button presses
# https://rsc.eworm.de/doc/mode-button.md
:local ExitOK false;
:onerror Err {
:global GlobalConfigReady; :global GlobalFunctionsReady;
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
:local ScriptName [ :jobname ];
:global ModeButton;
:global LogPrint;
:global ModeButtonScheduler;
:global ValidateSyntax;
:local LEDInvert do={
:global ModeButtonLED;
:global IfThenElse;
:local LED [ /system/leds/find where leds=$ModeButtonLED \
!disabled type~"^(on|off)\$" interface=[] ];
:if ([ :len $LED ] = 0) do={
:return false;
}
/system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED;
}
:local Scheduler [ /system/scheduler/find where name="mode-button-scheduler" ];
:if ([ :len $Scheduler ] = 0) do={
$LogPrint error $ScriptName ("Scheduler does not exist.");
:set ExitOK true;
:error false;
}
:local Count ([ :deserialize from=json [ /system/scheduler/get $Scheduler comment ] ]->"count");
:local Code ($ModeButton->[ :tostr $Count ]);
/system/scheduler/remove $Scheduler;
:if ([ :len $Code ] = 0) do={
$LogPrint info $ScriptName ("No action defined for " . $Count . " mode-button presses.");
:set ExitOK true;
:error false;
}
:if ([ $ValidateSyntax $Code ] = false) do={
$LogPrint warning $ScriptName \
("The code for " . $Count . " mode-button presses failed syntax validation!");
:set ExitOK true;
:error false;
}
$LogPrint info $ScriptName ("Acting on " . $Count . " mode-button presses: " . $Code);
:for I from=1 to=$Count do={
$LEDInvert;
:if ([ /system/routerboard/settings/get silent-boot ] = false) do={
:beep length=200ms;
}
:delay 200ms;
$LEDInvert;
:delay 200ms;
}
:onerror Err {
[ :parse $Code ];
} do={
$LogPrint warning $ScriptName \
("The code for " . $Count . " mode-button presses failed with runtime error: " . $Err);
}
} do={
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
}

View file

@ -10,86 +10,21 @@
# https://rsc.eworm.de/doc/mode-button.md # https://rsc.eworm.de/doc/mode-button.md
:onerror Err { :onerror Err {
:global GlobalConfigReady; :global GlobalFunctionsReady;
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
:local ScriptName [ :jobname ]; :local ScriptName [ :jobname ];
:global ModeButton; :local Scheduler [ /system/scheduler/find where name="mode-button-scheduler" ];
:global LogPrint;
:set ($ModeButton->"count") ($ModeButton->"count" + 1);
:local Scheduler [ /system/scheduler/find where name="_ModeButtonScheduler" ];
:if ([ :len $Scheduler ] = 0) do={ :if ([ :len $Scheduler ] = 0) do={
$LogPrint info $ScriptName ("Creating scheduler _ModeButtonScheduler, counting presses..."); :log info ($ScriptName . ": Creating scheduler mode-button-scheduler, counting presses...");
:global ModeButtonScheduler do={ :onerror Err { /system/scheduler/add name="mode-button-scheduler" interval=3s \
:local FuncName $0; comment=[ :serialize to=json ({ count=1 }) ] \
on-event="/system/script/run mode-button-scheduler;";
:global ModeButton;
:global LogPrint;
:global ModeButtonScheduler;
:global ValidateSyntax;
:local LEDInvert do={
:global ModeButtonLED;
:global IfThenElse;
:local LED [ /system/leds/find where leds=$ModeButtonLED \
!disabled type~"^(on|off)\$" interface=[] ];
:if ([ :len $LED ] = 0) do={
:return false;
}
/system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED;
}
:local Count ($ModeButton->"count");
:local Code ($ModeButton->[ :tostr $Count ]);
:set ($ModeButton->"count") 0;
:set ModeButtonScheduler;
/system/scheduler/remove [ find where name="_ModeButtonScheduler" ];
:if ([ :len $Code ] > 0) do={
:if ([ $ValidateSyntax $Code ] = true) do={
$LogPrint info $FuncName ("Acting on " . $Count . " mode-button presses: " . $Code);
:for I from=1 to=$Count do={
$LEDInvert;
:if ([ /system/routerboard/settings/get silent-boot ] = false) do={
:beep length=200ms;
}
:delay 200ms;
$LEDInvert;
:delay 200ms;
}
:onerror Err {
[ :parse $Code ];
} do={
$LogPrint warning $FuncName \
("The code for " . $Count . " mode-button presses failed with runtime error: " . $Err);
}
} else={ } else={
$LogPrint warning $FuncName \ :log debug ($ScriptName . ": Updating scheduler mode-button-scheduler...");
("The code for " . $Count . " mode-button presses failed syntax validation!"); :local Presses (([ :deserialize from=json [ /system/scheduler/get $Scheduler comment ] ]->"count") + 1);
} /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ] \
} else={ comment=[ :serialize to=json ({ count=$Presses }) ];
$LogPrint info $FuncName ("No action defined for " . $Count . " mode-button presses.");
}
} do={
:global ExitOnError; $ExitOnError $0 $Err;
} }
/system/scheduler/add name="_ModeButtonScheduler" \
on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s;
} else={
$LogPrint debug $ScriptName ("Updating scheduler _ModeButtonScheduler...");
/system/scheduler/set $Scheduler start-time=[ /system/clock/get time ];
} }
} do={ } do={
:global ExitOnError; $ExitOnError [ :jobname ] $Err; :log error ([ :jobname ] . ": " . $Err);
} }

View file

@ -68,6 +68,7 @@
141="Introduced script 'dhcpv6-client-lease' to run several scripts on IPv6 DHCP client lease."; 141="Introduced script 'dhcpv6-client-lease' to run several scripts on IPv6 DHCP client lease.";
142="Added a setting for 'mod/notification-email' to check availability of certificate chain."; 142="Added a setting for 'mod/notification-email' to check availability of certificate chain.";
143="Made backup scripts 'backup-email' and 'backup-upload' support date & time in filenames."; 143="Made backup scripts 'backup-email' and 'backup-upload' support date & time in filenames.";
144="Split and reworked 'mode-button' for compatibility with RouterOS 7.24, configuration was updated automatically.";
}; };
# Migration steps to be applied on script updates # Migration steps to be applied on script updates
@ -79,4 +80,5 @@
132=":if ([ :len [ /system/script/find where name=\"check-health\" ] ] > 0) do={ :local Code \":local Install \\\"check-health\\\"; :if ([ :len [ /system/health/find where type=\\\"\\\" name~\\\"-state\\\\\\\$\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/state\\\"); }; :if ([ :len [ /system/health/find where type=\\\"C\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/temperature\\\"); }; :if ([ :len [ /system/health/find where type=\\\"V\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/voltage\\\"); }; :global ScriptInstallUpdate; \\\$ScriptInstallUpdate \\\$Install;\"; :global ValidateSyntax; :if ([ \$ValidateSyntax \$Code ] = true) do={ :do { [ :parse \$Code ]; } on-error={ }; }; };"; 132=":if ([ :len [ /system/script/find where name=\"check-health\" ] ] > 0) do={ :local Code \":local Install \\\"check-health\\\"; :if ([ :len [ /system/health/find where type=\\\"\\\" name~\\\"-state\\\\\\\$\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/state\\\"); }; :if ([ :len [ /system/health/find where type=\\\"C\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/temperature\\\"); }; :if ([ :len [ /system/health/find where type=\\\"V\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/voltage\\\"); }; :global ScriptInstallUpdate; \\\$ScriptInstallUpdate \\\$Install;\"; :global ValidateSyntax; :if ([ \$ValidateSyntax \$Code ] = true) do={ :do { [ :parse \$Code ]; } on-error={ }; }; };";
138="/certificate/set trusted=yes [ find where trusted=yes ];"; 138="/certificate/set trusted=yes [ find where trusted=yes ];";
140=":if ([ :len [ /system/script/find where name=\"lease-script\" ] ] > 0) do={ /system/script/set name=\"dhcpv4-server-lease\" \"lease-script\"; :global ScriptInstallUpdate; \$ScriptInstallUpdate; /ip/dhcp-server/set lease-script=\"dhcpv4-server-lease\" [ find where lease-script=\"lease-script\" ]; };"; 140=":if ([ :len [ /system/script/find where name=\"lease-script\" ] ] > 0) do={ /system/script/set name=\"dhcpv4-server-lease\" \"lease-script\"; :global ScriptInstallUpdate; \$ScriptInstallUpdate; /ip/dhcp-server/set lease-script=\"dhcpv4-server-lease\" [ find where lease-script=\"lease-script\" ]; };";
144=":if ([ :len [ /system/script/find where name=\"mode-button\" ] ] > 0) do={ :global ScriptInstallUpdate; \$ScriptInstallUpdate mode-button-scheduler; };";
}; };