my SD card was almost dying so i ordered a new one and started with oH4 from a oH3.4 backup.
Almost everything started working as before, except for one rule.
This rule will be triggered by the battery level of my Apple Watch and should send me a message once the battery is over 75%.
This worked before the upgrade but stopped working with oH4 and i can´t find the problem.
The rule:
val telegramAction = getActions("telegram","telegram:telegramBot:bot")
val long bot1 = 1234 // me
val long bot2 = 5678 // wife
val String ruleId = "watch_Charging"
rule "watchMichael Charging Notification"
when
Item MichaelWatch_BatteryLevel changed
then
var BatteryMO = MichaelWatch_BatteryLevel.state.toString.split("\\.")
val LadungMO = BatteryMO.get(0)
val Voll = (MichaelWatch_BatteryLevel.state >= 75)
var watchMBcurrent = MichaelWatch_BatteryLevel.state.toString
var watchMBlast = MichaelWatch_BatteryLevel.previousState(true).state.toString
if(watchMBcurrent < watchMBlast)
{
logDebug(ruleId, "Laden nicht aktiv.")
return;
}
if((watchMBcurrent > watchMBlast) && Voll)
{
logDebug(ruleId, "Laden abgeschlossen mit " + LadungMO + "%. Benachrichtigung versendet.")
telegramAction.sendTelegram(bot1, "Deine Apple Watch ist zu " + LadungMO + "%% geladen.")
}
else
{
logDebug(ruleId, "Laden noch nicht abgeschlossen, Akku zu " + LadungMO + "% geladen.")
}
end
The item
Number MichaelWatch_BatteryLevel "Akku [%d %%]" <battery> (gPhones, gPersist) {channel="icloud:device:openhab:MichaelWatch:batteryLevel"}
The error:
2023-08-04 16:22:19.796 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'watchCharging-1' failed: Cannot invoke "org.openhab.binding.telegram.internal.action.TelegramActions.sendTelegram(java.lang.Long, String, Object[])" because "actions" is null in watchCharging
Is this a rules file or defined via UI ?
I think the UI does not support global variables ( variables outside the rule ).
Does it work when you move it into the rule definition ?
Well, it’s no good idea to define the val telegramAction outside the rule, this should be a local value.
I guess there are two of these rules? Maybe consider to use some openHAB magic
val long bot1 = 1234 // me
val long bot2 = 5678 // wife
rule "watchMichael Charging Notification"
when
Item MichaelWatch_BatteryLevel changed or
Item WifeWatch_BatteryLevel changed
then
val telegramAction = getActions("telegram","telegram:telegramBot:bot")
var nSOCnew = 0.0
if(newState instanceof Number)
nSOCnew = (newState as Number).floatValue
val bCharged = (nSOCnew >= 75)
val iSOCnew = nSOCnew.intValue
var nSOCold = 0.0
if(previousState instanceof Number)
nSOCold = (previousState as Number).floatValue
var theBot = bot1
val strName = triggeringItemName.split("_").get(0)
if(strName.contains("Wife"))
theBot = bot2
if(nSOCnew < nSOCold) {
logDebug("watch_Charging", "Laden {} nicht aktiv.",strName)
return;
}
if((nSOCnew > nSOCold) && bCharged) {
logDebug("watch_Charging", "Laden {} abgeschlossen mit {} %. Benachrichtigung versendet.",strName ,iSOCnew)
telegramAction.sendTelegram(theBot, "Deine Apple Watch ist zu %d %% geladen.",iSOCnew)
} else
logDebug("watch_Charging", "Laden {} noch nicht abgeschlossen, Akku zu {} % geladen.",strName ,iSOCnew)
end
Should do the job for both watches (of course you have to change the name of the second Item)
Awesome!
I´ll try to understand what you did to achieve the same result
My main problem is that i´m no developer, therefore i´m trying to have rules that i understand and can “maintain”.
Are the following descriptions correct? nS0Cnew is the current value of the item iS0Cnew is the current value as an integer for the message nS0Cold is the previous value of the item bCharged is the check that the current level is over 75% strName is the name of the triggereing item to check between the wifes and mine
Thank you Udo!
I´ll give it a try and wait for the first watch to exceed 75%
Atleast the VS Code openhab extension doesn´t like nSOCnew = (newState as Number).floatValue
and nSOCold = (previousState as Number).floatValue
because it shows me Type mismatch: cannot convert from float to int
openHAB also doesn´t like that rule and gives me the following error:
2023-08-04 19:57:47.404 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'watchCharging-1' failed: An error occurred during the script execution: Could not invoke method: org.eclipse.xtext.xbase.lib.IntegerExtensions.operator_greaterEqualsThan(int,int) on instance: null in watchCharging
Oh, sorry, of course when definig the vars it has to be a float value…
Change both definitions to
var nSOCnew = 0.0
var nSOCold = 0.0
I have changed the code above
You are at most right about the local values.
The main thing is, there are implicit variables when a rule is triggered, these are (here) newState contains the current state of the item which triggered the rule. previousState contains the old state of the item which triggered the rule (by trigger changed). trigeringItemName contains the name of the item which triggered the rule.
The items are of type Number, there is no reason to build a string and strip parts to get a string without decimals.
Please be aware that you can’t compare strings with greater than or less than, there is only equal or not equal openHAB won’t give an error, but also it won’t give the correct output.
This:
if(newState instanceof Number)
is a test if newState is of Type Number, so the next command will never fail:
nSOCnew = (newState as Number).floatValue
will ensure that the value is numeric without additional unit.
As I don’t have an Apple Watch, which values do you get from BatteryLevel? Maybe it’s an Integer
anyway (0 %, 1 % … 99 %, 100 % but not e.g. 77.5 %)
If it’s only integer, the rule will get even less complex.
Script execution of rule with UID 'watchCharging-1' failed: An error occurred during the script execution: Could not invoke method: java.lang.Double.intValue() on instance: 22.0 in watchCharging
The item is defined as Number and the value is always XY.0 because the decimal doesn´t change.
Edit: I´m wrong and the value ca have a lot of decimal places 21.99999988079071
The rule should be able to handle the whole stuff with Integer values:
val long bot1 = 1234 // me
val long bot2 = 5678 // wife
rule "watchMichael Charging Notification"
when
Item MichaelWatch_BatteryLevel changed or
Item WifeWatch_BatteryLevel changed
then
val telegramAction = getActions("telegram","telegram:telegramBot:bot")
var iSOCnew = 0
if(newState instanceof Number)
iSOCnew = (newState as Number).intValue
val bCharged = (iSOCnew >= 75)
var iSOCold = 0
if(previousState instanceof Number)
iSOCold = (previousState as Number).intValue
var theBot = bot2
val strName = triggeringItemName.split("_").get(0)
if(strName.contains("Michael"))
theBot = bot1
if(iSOCnew < iSOCold) {
logDebug("watch_Charging", "Laden {} nicht aktiv.",strName)
return;
}
if((iSOCnew > iSOCold) && bCharged) {
logDebug("watch_Charging", "Laden {} abgeschlossen mit {} %. Benachrichtigung versendet.",strName ,iSOCnew)
telegramAction.sendTelegram(theBot, "Deine Apple Watch ist zu %d %% geladen.",iSOCnew)
} else
logDebug("watch_Charging", "Laden {} noch nicht abgeschlossen, Akku zu {} % geladen.",strName ,iSOCnew)
end
Please be aware that you can’t test the rule by triggering it manually, it has to be triggered by a Item changed event
2023-08-05 14:32:57.315 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'watchCharging-1' failed: An error occurred during the script execution: Could not invoke method: java.lang.Double.intValue() on instance: 37.0 in watchCharging
Only the Telegram IDs of the bots and a val for the ruleId.
That´s the complete file of watchCharging.rules
val long bot1 = 1234 // me
val long bot2 = 5678 // wife
val String ruleId = "WatchCharging"
rule "watchMichael Charging Notification"
when
Item MichaelWatch_BatteryLevel changed or
Item WifeWatch_BatteryLevel changed
then
val telegramAction = getActions("telegram","telegram:telegramBot:bot")
var nCurrentLevel = 0
if(newState instanceof Number)
nCurrentLevel = (newState as Number).floatValue
val bCharged = (nCurrentLevel >= 75)
val iCurrentLevel = nCurrentLevel.intValue
var nLastLevel = 0
if(previousState instanceof Number)
nLastLevel = (previousState as Number).floatValue
var theBot = bot1
val strName = triggeringItemName.split("_").get(0)
if(strName.contains("Wife"))
theBot = bot2
if(nCurrentLevel < nLastLevel) {
logDebug(ruleId, "Laden {} nicht aktiv.",strName)
return;
}
if((nCurrentLevel > nLastLevel) && bCharged) {
logDebug(ruleId, "Laden {} abgeschlossen mit {} %. Benachrichtigung versendet.",strName ,iCurrentLevel)
telegramAction.sendTelegram(theBot, "Deine Apple Watch ist zu %d %% geladen.",iCurrentLevel)
} else
logDebug(ruleId, "Laden {} noch nicht abgeschlossen, Akku zu {} % geladen.",strName ,iCurrentLevel)
end
I did a restart and put a logInfo between every action in the rule.
It works until this part comes up where we compare the currentLevel against 75. val bCharged = (nCurrentLevel >= 75)
And this if also will be triggered
if(newState instanceof Number)
nCurrentLevel = (newState as Number).floatValue
because i modified it and put another logInfo into the if.
if(newState instanceof Number) {
nCurrentLevel = (newState as Number).floatValue
logInfo(ruleId, "03.1. Get current state as Number. Value: " + nCurrentLevel)
}
Output of the log:
2023-08-05 15:30:36.552 [INFO ] [nhab.core.model.script.WatchCharging] - 01. Start
2023-08-05 15:30:36.555 [INFO ] [nhab.core.model.script.WatchCharging] - 02. Load telegramAction. Value: org.openhab.binding.telegram.internal.action.TelegramActions@1234
2023-08-05 15:30:36.557 [INFO ] [nhab.core.model.script.WatchCharging] - 03. Create nCurrentLevel var. Value: 0
2023-08-05 15:30:36.560 [INFO ] [nhab.core.model.script.WatchCharging] - 03.1. Get current state as Number. Value: 65.0
2023-08-05 15:30:36.566 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'watchCharging-1' failed: An error occurred during the script execution: Could not invoke method: org.eclipse.xtext.xbase.lib.IntegerExtensions.operator_greaterEqualsThan(int,int) on instance: null in watchCharging
Ah. If you create a local variable without setting its type (which is totally fine and normally the best way to do it - let openHAB chose the type), you have to ensure that the type will be the correct one. here
var nCurrentLevel = 0 <-- will become Integer
nCurrentLevel = (newState as Number).floatValue <-- cannot invoke float to int
same for nLastLevel
so either type
var Number nCurrentLevel = 0 <-- will become Number
or
var nCurrentLevel = 0.0 <-- will also become Number
2023-08-05 16:04:19.573 [INFO ] [nhab.core.model.script.WatchCharging] - 01. Start
2023-08-05 16:04:19.578 [INFO ] [nhab.core.model.script.WatchCharging] - 02. Load telegramAction. Value: org.openhab.binding.telegram.internal.action.TelegramActions@1234
2023-08-05 16:04:19.580 [INFO ] [nhab.core.model.script.WatchCharging] - 03. Create nCurrentLevel var. Value: 0.0
2023-08-05 16:04:19.584 [INFO ] [nhab.core.model.script.WatchCharging] - 03.1. Get current state as Number. Value: 27.000002
2023-08-05 16:04:19.587 [INFO ] [nhab.core.model.script.WatchCharging] - 04. Check charging level. Value: false
2023-08-05 16:04:19.588 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'watchCharging-1' failed: An error occurred during the script execution: Could not invoke method: java.lang.Double.intValue() on instance: 27.000002 in watchCharging
05 would be val iCurrentLevel = nCurrentLevel.intValue
Could it be that .intValue can´t be used for nCurrentLevel because it gets loaded as (newState as Number).floatValue?
That’s the whole point.
This message doesn’t make sense at all, as .intValue is defined for Number and therefor also for Double and Float. (Number is parent to both)
Another question would be why it’s built as Double, makes also no sense.
I removed the .intValue from val iCurrentLevel = nCurrentLevel and now it´s working until if(nCurrentLevel < nLastLevel)
2023-08-05 16:24:22.102 [INFO ] [nhab.core.model.script.WatchCharging] - 09.1. Not charging
I´m currently charging to get a value over 75% and see what´s happening.
Is it worth raising a Github issue for this?
Edit:
Ok it´s not working as the telegramAction now fails because iCurrentLevel is a Number and can´t be used for the message…
nCurrentLevel = (newState as Number).floatValue
val iCurrentLevel = nCurrentLevel
telegramAction.sendTelegram(theBot, "Deine Apple Watch ist zu %d %% geladen.",iCurrentLevel)
2023-08-05 16:45:11.140 [INFO ] [nhab.core.model.script.WatchCharging] - 01. Start
2023-08-05 16:45:11.144 [INFO ] [nhab.core.model.script.WatchCharging] - 02. Load telegramAction. Value: org.openhab.binding.telegram.internal.action.TelegramActions@1234
2023-08-05 16:45:11.146 [INFO ] [nhab.core.model.script.WatchCharging] - 03. Create nCurrentLevel var. Value: 0.0
2023-08-05 16:45:11.149 [INFO ] [nhab.core.model.script.WatchCharging] - 03.1. Get current state as Number. Value: 90.93457
2023-08-05 16:45:11.153 [INFO ] [nhab.core.model.script.WatchCharging] - 04. Check charging level. Value: true
2023-08-05 16:45:11.155 [INFO ] [nhab.core.model.script.WatchCharging] - 05. Load current state as integer. Value: 90.93457
2023-08-05 16:45:11.157 [INFO ] [nhab.core.model.script.WatchCharging] - 06. Create nLastLevel var. Value: 0.0
2023-08-05 16:45:11.161 [INFO ] [nhab.core.model.script.WatchCharging] - 06.1. Get last state as Number. Value: 86.0
2023-08-05 16:45:11.163 [INFO ] [nhab.core.model.script.WatchCharging] - 07. Get bot1 ID. Value: 134757258
2023-08-05 16:45:11.166 [INFO ] [nhab.core.model.script.WatchCharging] - 08. Check who triggered the rule. Value: MichaelWatch
2023-08-05 16:45:11.167 [INFO ] [nhab.core.model.script.WatchCharging] - 09. Start comparsion
2023-08-05 16:45:11.168 [INFO ] [nhab.core.model.script.WatchCharging] - 10. Start comparsion if charging
2023-08-05 16:45:11.170 [INFO ] [nhab.core.model.script.WatchCharging] - 10.1. Charging active!
2023-08-05 16:45:11.172 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'watchCharging-1' failed: d != java.lang.String in watchCharging
Edit2:
It´s almost working!
telegramAction.sendTelegram(theBot, "Deine Apple Watch ist zu % geladen.",iCurrentLevel)
Deine Apple Watch ist zu 95,9446eladen.
Only 2 things to clear
Get the correct message with the level and %
Strip the decimal places…
Edit3:
I know it´s not the best way but i don´t care as long as it works
telegramAction.sendTelegram(theBot, "Deine Apple Watch ist zu " + iCurrentLevel + "%% geladen.")
Deine Apple Watch ist zu 89.11115% geladen.
Now i want to remove the decimal places like .11115 from that value.
Normally i would try to make this a String but i´m sure this wont work here.