there is a Thing Status API sample code in the docs.
I try to get this code to work. My aim is to get a list of all things and show this list in my log-file.
I have changed the code the way I think it should be right, but I get the following error:
2019-04-22 10:15:22.022 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model '18_ThingsCheck.rules'
2019-04-22 10:16:12.737 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'rTestThingStatusAPI': The name 'thingRegistry' cannot be resolved to an item or type; line 86, column 20, length 13
This error refers to line 86 which is MyThings = thingRegistry.getAll()
At the moment my rule looks like this
rule "rTestThingStatusAPI" // test the code sample from https://www.openhab.org/docs/concepts/things.html#thing-status-api
when
Time cron "0 */1 * ? * *" // Only for testing! Every minute.
then
// first prepare the log entry
val String MyLogFile = "MySeparateLogFile" // if 'MySeparateLogFile' does not exist, logging goes into openhab.log (to create a separate logfile see https://www.openhab.org/docs/administration/logging.html#logging-into-separate-file)
val DateTime MyLogDate = now
val StringBuilder MyLogMessage = new StringBuilder
MyLogMessage.append( "\n" + "\n" + " ---------- " + MyLogDate.toString("HH:mm") + " rTestThingStatusAPI v001 ----------" + "\n" + "\n" )
// second create values we can work with
MyThings = thingRegistry.getAll()
// for each thing check status
for (MyThings : things) {
ThingStatusInfo statusInfo = thing.getStatusInfo()
switch (statusInfo.getStatus()) {
case "ONLINE":
{
MyLogMessage.append( "Thing is online" + "\n" )
break
}
case "OFFLINE":
{
MyLogMessage.append( "Thing is offline" + "\n" )
break
}
default:
{
MyLogMessage.append( "Thing is in state " + statusInfo.getStatus() + "\n" )
break
}
}
MyLogMessage.append( "Thing status detail: " + statusInfo.getStatusDetail() + "\n" )
MyLogMessage.append( "Thing status description: " + statusInfo.getDescription() + "\n" )
}
// finally, write the log-entry into the log-file
MyLogMessage.append( "\n" + " ---------- End Of Rule ----------" + "\n" + "\n" )
logInfo( MyLogFile, MyLogMessage.toString )
end // EndOfRule rTestThingStatusAPI
Can someone help me solving this problem? Do I need some imports?
I have had this before but have changed it because using val I get additional info variable MyThings is not used.
val MyThings = thingRegistry.getAll()
leads to this messages
2019-04-23 02:50:14.052 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model '18_ThingsCheck.rules', using it anyway:
The value of the local variable MyThings is not used
2019-04-23 02:50:14.304 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model '18_ThingsCheck.rules'
2019-04-23 02:51:11.108 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'rTestThingStatusAPI': The name 'thingRegistry' cannot be resolved to an item or type; line 91, column 24, length 13
2019-04-23 02:52:00.040 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'rTestThingStatusAPI': The name 'thingRegistry' cannot be resolved to an item or type; line 91, column 24, length 13
I also tried this
val MyThings = thingsRegistry.getAll()
with this messages
2019-04-23 02:54:20.355 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model '18_ThingsCheck.rules', using it anyway:
The value of the local variable MyThings is not used
2019-04-23 02:54:20.616 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model '18_ThingsCheck.rules'
2019-04-23 02:55:11.515 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'rTestThingStatusAPI': The name 'thingsRegistry' cannot be resolved to an item or type; line 91, column 24, length 14
2019-04-23 02:56:00.039 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'rTestThingStatusAPI': The name 'thingsRegistry' cannot be resolved to an item or type; line 91, column 24, length 14
Ok, but that’s progress. You’ve gone from it complaining that something that does exist not existing, to it complaining that a variable that you’ve created isn’t used.
This points to a syntax error.
I’m pretty sure that the example in the docs had an error in that it is missing the val or var. But it is also including the type that gets returned in the example and your coffee is not.
val Collection<Thing> MyThings = ...
I also see that your for loop is wrong which explains the “not being used” warning. If you look at the example in the docs it uses:
I strongly suggest using VSCode with the openHAB extension which should help with solving syntax errors like these. I’m on my phone and have no experience working with Things in Rules.
Always consider the actual line of code the error refers to. It appears to be referring to the for.
I searched for examples to learn the syntax of Collection and for ... case , but didn’t find anything that was useful to me. D o you know useful links?
That’s odd because it is the same thing that generates the error in openhab.log as what syntax checks the code.
Wait, that example code isn’t Rules code, it’s binding code. You can’t write code like this as a Rule. The switch statement syntax is different for Rules. You don’t use breaks in Rules for one.
I don’t know if code like this is even possible in Rules DSL. But it certainly wont work as written here.
As I needed to dump all things status to log due to debugging purposes, found your code inspirative. However was not easy to make it working. But, finally, here is working code:
import org.eclipse.smarthome.model.script.ScriptServiceUtil
rule "dump all things after system started (or rules reloaded)"
when
System started
then
logInfo("SYSTEM started:", "system started (or rules reloaded), dumping things status")
// first prepare the log entry
val String MyLogFile = "MySeparateLogFile" // if 'MySeparateLogFile' does not exist, logging goes into openhab.log (to create a separate logfile see https://www.openhab.org/docs/administration/logging.html#logging-into-separate-file)
val DateTime MyLogDate = now
val StringBuilder MyLogMessage = new StringBuilder
MyLogMessage.append( "\n" + "\n" + " ---------- " + MyLogDate.toString("HH:mm") + " DumpAllThings v.RKA.20200503 ----------" + "\n" + "\n" )
val things = ScriptServiceUtil.getInstance.thingRegistry.getAll()
things.forEach[ thing |
MyLogMessage.append( "Thing Bridge UID: " + thing.getBridgeUID() + "\n" )
MyLogMessage.append( "Thing UID: " + thing.getUID() + "\n" )
MyLogMessage.append( "Thing Label: " + thing.getLabel() + "\n" )
val statusInfo = thing.getStatusInfo()
if (statusInfo.getStatus().toString() == 'ONLINE') {
MyLogMessage.append( "Thing status: online" + "\n" )
}
else if (statusInfo.getStatus().toString() == 'OFFLINE') {
MyLogMessage.append( "Thing status: OFFLINE" + "\n" )
}
else {
MyLogMessage.append( "Thing state: " + statusInfo.getStatus() + "\n" )
}
MyLogMessage.append( "Thing status detail: " + statusInfo.getStatusDetail() + "\n" )
MyLogMessage.append( "Thing status description: " + statusInfo.getDescription() + "\n" )
]
// finally, write the log-entry into the log-file
MyLogMessage.append( "\n" + " ---------- End Of Rule ----------" + "\n" + "\n" )
logInfo( MyLogFile, MyLogMessage.toString )
end
All Thing status changes get logged out to events.log by default. What is missing from that, that you need to log?
2020-05-03 04:44:14.985 [hingStatusInfoChangedEvent] - 'mqtt:broker:spare' changed from OFFLINE (COMMUNICATION_ERROR): io.netty.channel.AbstractChannel$AnnotatedNoRouteToHostException: No route to host: spare.koshak.net/10.10.1.167:1883 to OFFLINE
2020-05-03 04:44:18.182 [hingStatusInfoChangedEvent] - 'mqtt:broker:spare' changed from OFFLINE to OFFLINE (COMMUNICATION_ERROR): io.netty.channel.AbstractChannel$AnnotatedNoRouteToHostException: No route to host: spare.koshak.net/10.10.1.167:1883
2020-05-03 05:00:20.331 [hingStatusInfoChangedEvent] - 'chromecast:chromecast:ba707f086019e93c9e9bcc4dee240c26' changed from OFFLINE to ONLINE
2020-05-03 16:23:53.332 [hingStatusInfoChangedEvent] - 'mqtt:broker:spare' changed from OFFLINE (COMMUNICATION_ERROR): io.netty.channel.AbstractChannel$AnnotatedNoRouteToHostException: No route to host: spare.koshak.net/10.10.1.167:1883 to UNINITIALIZED
2020-05-03 16:23:53.336 [hingStatusInfoChangedEvent] - 'mqtt:broker:spare' changed from UNINITIALIZED to OFFLINE
The above are just a few random Thing status updates.
I dont know if its this feature your trying to get to work. But I´m using this rather simple code to notify me if a thing goes on or offline. The only bad issue is, it needs to be done to every thing. You cant group things, as far as I know. Having tons of things, is a time killer doing this rule.
rule "Zwave Node3 status"
when
Thing "zwave:device:zstick:node3" changed
then
var thingStatusInfo = getThingStatusInfo("zwave:device:zstick:node3")
if ((thingStatusInfo !== null) && (thingStatusInfo.getStatus().toString() == "ONLINE")) {
logInfo("ThingStatus", "ZwaveNode3 is online.")
ZWaveNode3_status.postUpdate(ON)
} else {
logError("ThingStatus", "ZwaveNode3 is offline or doesn't exist.")
ZWaveNode3_status.postUpdate(OFF)
}
end
You cannot make a Group of Things to listen out for in a rule, but you can have a (NGRE) rule listen to all Thing status changes. That rule can then filter out certain classes of Things and/or events.
A practical example exploiting Yannick’s method to listen to Modbus poller type things only. Because I wasn’t very comfortable with writing NGRE, it actually transmits events to a DSL rule for further action.
Another approach that would also work for Rules DSL would be to use the Log Reader binding to watch events.log for the hingStatusInfoChangedEvent lines to trigger a Rule to send the alert.