StrokesPlus.net
Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Options
Go to last post Go to first unread
randomConstant  
#1 Posted : Saturday, November 27, 2021 6:49:31 PM(UTC)
randomConstant

Rank: Advanced Member

Reputation:

Groups: Translators, Approved
Joined: 7/17/2021(UTC)
Posts: 135

Thanks: 35 times
Was thanked: 18 time(s) in 15 post(s)
Hi all,

I'm using a vbs script I got online to get an alert whenever my laptop's charging hits 94% or more, since Windows only alerts on low battery and not on full battery, I use this script to unplug the charger when my laptop is sufficiently charged. It's just a .vbs file which I run with Windows startup and its code is:

Code:
set oLocator = CreateObject("WbemScripting.SWbemLocator")
set oServices = oLocator.ConnectServer(".","root\wmi")
set oResults = oServices.ExecQuery("select * from batteryfullchargedcapacity")
for each oResult in oResults
iFull = oResult.FullChargedCapacity
next

while (1)
set oResults = oServices.ExecQuery("select * from batterystatus")
for each oResult in oResults
iRemaining = oResult.RemainingCapacity
bCharging = oResult.Charging
next
iPercent = ((iRemaining / iFull) * 100) mod 100
if bCharging and (iPercent > 94) Then msgbox "Laptop is charged now...", vbMsgBoxSetForeground
wscript.sleep 30000 ' 5 minutes
wend


It takes about 1.8 MB of Memory and idle CPU usage most of the time and shows a small pop up window when laptop is in charging status and its level is above or below the threshold(s) (94% in my case)

I was wondering if there is a way to achieve this goal using S+ (timers maybe) and if so what would the performance be like compared to .vbs script assuming we just show a pop up and do nothing fancy.

Any ideas and solutions are much appreciated.
Thanks
Rob  
#2 Posted : Sunday, November 28, 2021 3:36:51 PM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 1,349
United States
Location: Tampa, FL

Thanks: 28 times
Was thanked: 416 time(s) in 354 post(s)
S+ is already loading so many things that I would say if you have S+ running already, you should just move all of your automations into it.

The same would apply for any other app, really. Once you have one engine that can handle automation, you're just wasting resources by loading a separate one!

I haven't tested the actual timer and functionality, only tested the type/API binding and direct call to see that the values are coming back.

Global Actions > Load/Unload > Load Script
Code:
// only create the types once
if(!NativeModules.PowerStatus)
{
    var ByteT = host.typeOf(System.Byte);
    var UintT = host.typeOf(System.UInt32);
    var BooleanT = host.typeOf(System.Boolean);

    var typesTB = sp.NativeModule().CreateType("PowerStatusTypes", "Class,Public,SequentialLayout,Serializable");

    typesTB.DefineNestedStruct("SYSTEM_POWER_STATUS", 
                               "ACLineStatus,BatteryFlag,BatteryLifePercent,SystemStatusFlag,BatteryLifeTime,BatteryFullLifeTime", 
                               [ByteT,ByteT,ByteT,ByteT,UintT,UintT]).Create();

	
    var PowerStatusTB = sp.NativeModule().DefineType("PowerStatus", "Class,Public,SequentialLayout,Serializable");
	
    var SYSTEM_POWER_STATUS_refT = host.typeOf(NativeModules.PowerStatusTypes.SYSTEM_POWER_STATUS).MakeByRefType();

	//Define the platform invoke calls
	//From: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getsystempowerstatus
	PowerStatusTB.DefinePInvokeMethod("GetSystemPowerStatus",
								 "kernel32.dll",
								 [SYSTEM_POWER_STATUS_refT], 
								 BooleanT, 
								 "PreserveSig");	

	//Create the type (finalize, now made an official C# class)					 
    PowerStatusTB.Create();								 
}

//Create timer to check battery
StrokesPlus.Timer.New("Battery", 
                      0, 
                      30000, 
                      `var SYSTEM_POWER_STATUS = host.newVar(NativeModules.PowerStatusTypes.SYSTEM_POWER_STATUS);
                       NativeModules.PowerStatus.GetSystemPowerStatus(SYSTEM_POWER_STATUS.ref);
                       if(SYSTEM_POWER_STATUS.ACLineStatus == 1) {
                          // Plugged in, check battery
                          // If 94% or more and message hasn't been shown, show message
                          if(SYSTEM_POWER_STATUS.BatteryLifePercent >= 94) {
                             if(!StrokesPlus.StoredValues.Booleans.Get("BatteryMessageShown")) {
                                StrokesPlus.UI.Alert("Battery at " + SYSTEM_POWER_STATUS.BatteryLifePercent + "%", "Battery Level");
                                StrokesPlus.StoredValues.Booleans.Set("BatteryMessageShown", true);
                             }
                          } 
                       } else {
                          // Not plugged in, clear var
                          StrokesPlus.StoredValues.Booleans.Dispose("BatteryMessageShown");
                       }
                      `);



Example/testing code, logs to User tab in Console window
Code:
//Create type to receive data from API call
var SYSTEM_POWER_STATUS = host.newVar(NativeModules.PowerStatusTypes.SYSTEM_POWER_STATUS);
//Call API
var result = NativeModules.PowerStatus.GetSystemPowerStatus(SYSTEM_POWER_STATUS.ref);

//Show result: True = successfully called API
StrokesPlus.Console.Log(result); 

// See https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-system_power_status

//AC power status: 1 = Plugged in, 0 = not plugged in
StrokesPlus.Console.Log(SYSTEM_POWER_STATUS.ACLineStatus);

//Current battery percentage
StrokesPlus.Console.Log(SYSTEM_POWER_STATUS.BatteryLifePercent);

Edited by user Sunday, November 28, 2021 10:52:33 PM(UTC)  | Reason: Not specified

randomConstant  
#3 Posted : Sunday, November 28, 2021 7:42:20 PM(UTC)
randomConstant

Rank: Advanced Member

Reputation:

Groups: Translators, Approved
Joined: 7/17/2021(UTC)
Posts: 135

Thanks: 35 times
Was thanked: 18 time(s) in 15 post(s)
Yup! Thanks for the quick reply Rob, I'm trying to do as many things as I can using S+ while not hindering it's performance via bad logics.

So I tried copying the code but it gave me an error.

This is the code I place in console script:
Code:
// only create the types once
if(!NativeModules.PowerStatus)
{
    var ByteT = host.typeOf(System.Byte);
    var UintT = host.typeOf(System.UInt32);
    var BooleanT = host.typeOf(System.Boolean);

    var typesTB = sp.NativeModule().CreateType("PowerStatusTypes", "Class,Public,SequentialLayout,Serializable");

    typesTB.DefineNestedStruct("SYSTEM_POWER_STATUS", 
                               "ACLineStatus,BatteryFlag,BatteryLifePercent,SystemStatusFlag,BatteryLifeTime,BatteryFullLifeTime", 
                               [ByteT,ByteT,ByteT,ByteT,UintT,UintT]).Create();

	
    var PowerStatusTB = sp.NativeModule().DefineType("PowerStatus", "Class,Public,SequentialLayout,Serializable");
	
    var SYSTEM_POWER_STATUS_refT = host.typeOf(NativeModules.PowerStatusTypes.SYSTEM_POWER_STATUS).MakeByRefType();

	//Define the platform invoke calls
	//From: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getsystempowerstatus
	PowerStatusTB.DefinePInvokeMethod("GetSystemPowerStatus",
								 "kernel32.dll",
								 [SYSTEM_POWER_STATUS_refT], 
								 BooleanT, 
								 "PreserveSig");	

	//Create the type (finalize, now made an official C# class)					 
    PowerStatusTB.Create();								 
}

//Create type to receive data from API call
var SYSTEM_POWER_STATUS = host.newVar(NativeModules.PowerTypes.SYSTEM_POWER_STATUS);


and that is the error logged:
Code:
TypeError: Cannot read property 'SYSTEM_POWER_STATUS' of undefined
    at Script [113]:32:64 -> var SYSTEM_POWER_STATUS = host.newVar(NativeModules.PowerTypes.SYSTEM_POWER_STATUS);


When I put the Load Script code (provided by Rob along with the timer as it is) into Global Actions > Load/Unload > Load Script I get following error repeatedly:
Code:
[ScriptEngine.Execute() - ScriptEngineException] TypeError: Cannot read property 'SYSTEM_POWER_STATUS' of undefined
    at Script [6]:1:64 -> var SYSTEM_POWER_STATUS = host.newVar(NativeModules.PowerTypes.SYSTEM_POWER_STATUS);
[ScriptEngine.Execute() - ScriptEngineException] TypeError: Cannot read property 'SYSTEM_POWER_STATUS' of undefined
    at Script [6]:1:64 -> var SYSTEM_POWER_STATUS = host.newVar(NativeModules.PowerTypes.SYSTEM_POWER_STATUS);


I honestly do not understand the code much so I can not tell whether it's a typo or some logic error. Any help will be useful.
Thanks
Rob  
#4 Posted : Sunday, November 28, 2021 7:59:36 PM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 1,349
United States
Location: Tampa, FL

Thanks: 28 times
Was thanked: 416 time(s) in 354 post(s)
Bah, I made some naming changes and didn't test it again.

Change PowerTypes to PowerStatusTypes, there are a couple spots.
randomConstant  
#5 Posted : Sunday, November 28, 2021 11:28:58 PM(UTC)
randomConstant

Rank: Advanced Member

Reputation:

Groups: Translators, Approved
Joined: 7/17/2021(UTC)
Posts: 135

Thanks: 35 times
Was thanked: 18 time(s) in 15 post(s)
Thanks a lot Rob!

It is working perfectly fine after the naming correction, I changed it slightly to show a DisplayText instead of MessageBox for neatness but overall it is working great.

I imagine one can even fire some notification sound or even adjust the timer interval dynamically depending on battery level (such as it runs timers every 20 minutes when level is <50%, every 10 minutes when level is <75%, every 3 minutes when level is <83% and so on..) not sure how useful it will be in lessoning load of the timer calls but glad to know we have the option.

From rough estimates S+ is consuming around +3.5 MB of Memory and around 0.7% of CPU (when it displays text), which is acceptable compared to 1.8 MB of Memory from .vbs script. In fact trading those 2 MBs or so for all the functionality of S+ is worth every bit Laugh

Hopefully it benefits someone in coming future. A quick tip, you may want to remove BatteryMessageShown flag if you are forgetful like myself and need constant reminders about the level until you unplug the machine.
Thanks.
Rob  
#6 Posted : Monday, November 29, 2021 3:26:18 AM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 1,349
United States
Location: Tampa, FL

Thanks: 28 times
Was thanked: 416 time(s) in 354 post(s)
Sure, could even have it spoken to you :)
Code:
var speech = new System.Speech.Synthesis.SpeechSynthesizer();
speech.SelectVoiceByHints(System.Speech.Synthesis.VoiceGender.Female);
speech.Rate = 3; // -10 for slow, 10 for fast
speech.Speak("94%");
randomConstant  
#7 Posted : Monday, November 29, 2021 12:12:05 PM(UTC)
randomConstant

Rank: Advanced Member

Reputation:

Groups: Translators, Approved
Joined: 7/17/2021(UTC)
Posts: 135

Thanks: 35 times
Was thanked: 18 time(s) in 15 post(s)
Wow, thanks Rob! Laugh
Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.