It is currently September 20th, 2021, 6:27 pm

How to initiate an action on a timer but only if the timer is not running already?

Get help with installing and using Rainmeter.
jn_meter
Posts: 90
Joined: December 27th, 2016, 12:04 pm

How to initiate an action on a timer but only if the timer is not running already?

Post by jn_meter »

I have Rainmeter set to show, when and only total CPU use is above a threshold, the process using the most CPU. This works. However, often the displayed process disappears too quickly - namely, when the global CPU usage exceeds the threshold only briefly. So, I thought I would do the following when the global CPU goes below the threshold. Start a timer - unless such a timer is running already - to hide the display of the process (hide its meter and indeed disable its measure) after a delay. But implementing this has proved rather difficult. Does anyone have any ideas for an implementation? The simpler the better!

Thanks!
User avatar
jsmorley
Developer
Posts: 22286
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: How to initiate an action on a timer but only if the timer is not running already?

Post by jsmorley »

So something like this?

Code: Select all

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1

[MeasureCPUAvg]
Measure=Plugin
Plugin=UsageMonitor
Alias=CPU
Index=0
IfCondition=MeasureCPUAvg >= 2
IfTrueAction=[!EnableMeasure MeasureTopProcess][!UpdateMeasure MeasureTopProcess][!ShowMeter MeterTopProcess][!UpdateMeter *][!Redraw]
IfFalseAction=[!Delay 10000][!HideMeter MeterTopProcess][!DisableMeasure MeasureTopProcess][!UpdateMeter *][!Redraw]

[MeasureTopProcess]
Measure=Plugin
Plugin=UsageMonitor
Alias=CPU
Blacklist=_Total|Idle|dwm|wmpnetwk|csrss|svchost|lsass|services|System|system|WmiPrvSE
Index=1
RegexpSubstitute=1
Substitute="^$":"Idle"

[MeterCPUPercent]
Meter=String
MeasureName=MeasureCPUAvg
FontSize=12
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
DynamicVariables=1
Text=[MeasureCPUAvg:1]%

[MeterTopProcess]
Meter=String
MeasureName=MeasureTopProcess
X=5R
FontSize=12
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
Hidden=1
The problem with this thinking is that if the IfCondition remains "true", but the name of the top process changes, it's going to change the name of the top process, but that isn't going to in any way "start over" any "timer" on how long it is displayed. So it's still going to be kinda jerky in my opinion. I just don't think I like this disconnect between the CPU percent and the Top Process.
User avatar
jsmorley
Developer
Posts: 22286
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: How to initiate an action on a timer but only if the timer is not running already?

Post by jsmorley »

I'd be tempted to disconnect the top process name and the top process percent usage at the point it exceeds the limit from the always-changing current CPU usage. Something like:

Code: Select all

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1

[MeasureCPUAvg]
Measure=Plugin
Plugin=UsageMonitor
Alias=CPU
Index=0
IfCondition=MeasureCPUAvg >= 2
IfTrueAction=[!EnableMeasure MeasureTopProcess][!UpdateMeasure MeasureTopProcess][!SetOption MeterTopPercent Text "Top: [MeasureTopProcess:1]%"][!SetOption MeterTopProcess Text "[MeasureTopProcess]"][!ShowMeterGroup TopStuff][!UpdateMeter *][!Redraw]
IfFalseAction=[!Delay 5000][!HideMeterGroup TopStuff][!DisableMeasure MeasureTopProcess][!UpdateMeter *][!Redraw]

[MeasureTopProcess]
Measure=Plugin
Plugin=UsageMonitor
Alias=CPU
Blacklist=_Total|Idle|dwm|wmpnetwk|csrss|svchost|lsass|services|System|system|WmiPrvSE
Index=1
RegexpSubstitute=1
Substitute="^$":"Idle"
Disabled=1

[MeterCPUPercent]
Meter=String
MeasureName=MeasureCPUAvg
FontSize=12
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
DynamicVariables=1
Text=Current: [MeasureCPUAvg:1]%

[MeterTopPercent]
Meter=String
Group=TopStuff
Y=5R
FontSize=12
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
Hidden=1

[MeterTopProcess]
Meter=String
Group=TopStuff
MeasureName=MeasureTopProcess
X=5R
Y=0r
FontSize=12
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
Hidden=1
Of course this has its own downside, since if the CPU usage remains above the limit, but the top process names changes, that won't be reflected until after the !Delay timer runs out. Not sure I see a real graceful way to do this.
jn_meter
Posts: 90
Joined: December 27th, 2016, 12:04 pm

Re: How to initiate an action on a timer but only if the timer is not running already?

Post by jn_meter »

Thank you, Morley.

Matters are complicated by this: I switch off the display of the top process, not only if the global CPU goes below a certain value, but also if the top process is using less than a certain value.

Here is the code that I have. I modified it response to your first suggestion, and preliminary testing suggests that it works well enough. (I hope I give you all the relevant code; the whole script is too large to usefully post here - because it does all sorts of other stuff that is unrelated to the functionality at issue.)

Code: Select all

[Rainmeter]
AccurateText=1
Update=1000

[Variables]

; ** CPU & TOP-PROCESS **
processTop_threshold=10
; But display of top process is controlled also by global CPU use - see measure_cpu_usage

; ** DYNAMIC VARIABLES **

var_meterProcessTopText=""

; ** ACTIONS **

action_processTop_enableThenDisable=[!log "enable-then-disable"] [!EnableMeasure measure_processTop] [!UpdateMeasure measure_processTop] [!UpdateMeter meter_processTop] [!ShowMeter meter_processTop] #action_processTop_disable#

action_processTop_enable=[!log "enabling"] [!EnableMeasure measure_processTop] [!UpdateMeasure measure_processTop] [!UpdateMeter meter_processTop] [!ShowMeter meter_processTop]

action_processTop_disable=[!log "disabling"] [!Delay 5000] [!DisableMeasure measure_processTop] [!HideMeter meter_processTop] [!SetVariable var_meterProcessTopText ""]


action_cpu_usage_lowest=[!SetOption meter_value_cpuUsage BarColor #col_green_light#] [!UpdateMeter meter_value_cpuUsage] #action_processTop_disable#

action_cpu_usage_low=[!SetOption meter_value_cpuUsage BarColor #col_green_light#] [!UpdateMeter meter_value_cpuUsage] #action_processTop_enable#

action_cpu_usage_medium= [!SetOption meter_value_cpuUsage BarColor #col_green_dark#] [!UpdateMeter meter_value_cpuUsage] #action_processTop_enable#

action_cpu_usage_high=[!SetOption meter_value_cpuUsage BarColor #col_yellow#] [!UpdateMeter meter_value_cpuUsage] #action_processTop_enable#

action_cpu_usage_highest=[!SetOption meter_value_cpuUsage BarColor #col_orange_red#] [!UpdateMeter meter_value_cpuUsage] #action_processTop_enable#


; ========
; MEASURES
; ========


; -----------------
; CPU & TOP PROCESS
; ------------------

[measure_cpu_usage]
; Do NOT need 'DynamicVariables=1'.
; If set, the measure value will be an average of the specified number of past actual values. This can be useful to create a smoother transition on some graphical meters.
AverageSize=2
Measure=CPU
Processor=0
IfCondition=(measure_cpu_usage < 20)
IfTrueAction=#action_cpu_usage_lowest#
IfCondition2=(measure_cpu_usage > 19) && ( measure_cpu_usage < 50 )
IfTrueAction2= #action_cpu_usage_low#
IfCondition3=(measure_cpu_usage > 49) && ( measure_cpu_usage < 80 )
IfTrueAction3=#action_cpu_usage_medium#
IfCondition4=(measure_cpu_usage > 79) && ( measure_cpu_usage < 90 )
IfTrueAction4=#action_cpu_usage_high#
IfCondition5=(measure_cpu_usage > 89)
IfTrueAction5=#action_cpu_usage_highest#

[measure_processTop]
; DO need 'DynamicVariables=1'
; Runs in separate thread every second (unalterably). UpdateDivider sets how often the IfCondition is executed.
; The measure gets toggled by measure_cpu_usage.
Blacklist=_Total|Idle|dwm|wmpnetwk|csrss|svchost|lsass|System|system|Memory Compression|wininit|RemindersServer|spoolsv|IpOverUsbSvc
Category=Process
Counter=% Processor Time
;Disabled=1
DynamicVariables=1
Formula=measure_processTop
IfCondition=measure_processTop > #processTop_threshold#
IfConditionMode=1
IfTrueAction=[!SetVariable var_meterProcessTopText "[measure_processTop] ([measure_processTop:1]%)"]
IfFalseAction=[!SetVariable var_meterProcessTopText ""]
Index=1
Measure=Plugin
Percent=1
Plugin=UsageMonitor
UpdateDivider=3
Disabled=1


; ======
; METERS
; ======

; -----------
; Top-process
; -----------

[meter_processTop]
; We DO need 'DynamicVariables=1'
DynamicVariables=1
Hidden=1
; MeasureName=measure_processTop
Meter=String
Text=#var_meterProcessTopText#


; EOF
jn_meter
Posts: 90
Joined: December 27th, 2016, 12:04 pm

Re: How to initiate an action on a timer but only if the timer is not running already?

Post by jn_meter »

NB: what I have just posted does not use my #action_processTop_enable# (though it does use a !Delay elsewhere).