If-Statement causes an error when using it with "triggeringItem"

Thx, for your hint. No I didn’t, as I thought it’s only for comparing with null. I will give it a try and inform you about the result.

Cheers,
Peter

thx, for answering.
But as the switch is just a “Dummy” for manually triggering the rule from time to time no channel is possible or do you have an idea for a Dummy-Channel ?
Cheers,
Peter

@fibu-freak

extracted from the documentation

When a binding provides such channels, you can find the needed information in the corresponding binding documentation. There is no generic list of possible values for triggerEvent , The triggerEvent (s) available depend upon the specific implementation details of the binding. If the Rule needs to know what the received event was, use the implicit variable receivedEvent to access the information.

Did you try to use receivedEvent instead triggeringEvent?

@mikaelgu
Hi Mikael,
sorry to say but your hint didn’t work. Same error as before.

I tried:

    if (triggeringItem.state === ON) {
      logInfo("sonoff.rules", "Rule was manually fired: " + triggeringItem +  " previousState: " + previousState)
    }
 

and the error:

2019-07-29 10:28:02.309 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Sonoff Tasmota Release Version': cannot invoke method public abstract org.eclipse.smarthome.core.types.State org.eclipse.smarthome.core.items.Item.getState() on null

came up again.

But anyway, thx for help.

Cheers,
Peter

@fibu-freak

the implicit variable triggeringItem is populated with the Item that caused the Rule to trigger.

You are using a combination of an item and channels, that’s why you get the error when the trigger comes from the astro channel

When the rule gets triggered by a channel, there is no implicit triggeringItem. There’s no fix for that, it’s just a logical consequence.

But the Item exists whether or not you trigger any rules by channels or anything else. The Item is always accessible by name within any rule, regardless of how it was triggered.
You can always test the state of the Item by name.

1 Like

Hi Humberto,
in another rule I just tested the event-driven way. It’s a rule based on this post from @shutterfreak.
But an error came up when I inserted the line

or Item Sonoff_Release_Refresh changed to ON

the rule:

rule "sunset check"
when
         Channel 'astro:sun:local:set#event' triggered
    or   Channel 'astro:sun:local:civilDusk#event' triggered
    or   Channel 'astro:sun:local:nauticDusk#event' triggered
    or   Channel 'astro:sun:local:astroDusk#event' triggered 
    or   Channel 'astro:sun:local:daylight#event' triggered
    or   Channel 'astro:sun:local:noon#event' triggered
    or   Channel 'astro:sun:stowing1:noon#event' triggered START 
    or   Channel 'astro:sun:stowing2:noon#event' triggered
    or   Channel 'astro:sun:stowing3:noon#event' triggered
    or   Channel 'astro:sun:local:rise#event' triggered 
    or   Channel 'astro:sun:local:morningNight#event' triggered 
    or   Channel 'astro:sun:local:astroDawn#event' triggered 
    or   Channel 'astro:sun:local:nauticDawn#event' triggered 
    or   Channel 'astro:sun:local:night#event' triggered 
    or   Item Sonoff_Release_Refresh changed to ON 
then
//    val String ruleTitle="event::getCanonicalName()"
    logInfo( "sunset Check", "INFO: receivedEvent.class.getCanonicalName() --> [{}], Event = '{}'", receivedEvent.class.getCanonicalName(), receivedEvent.getEvent() )
    logInfo( "sunset Check", "INFO: receivedEvent.channel.toString()       --> [{}], Event = '{}'", receivedEvent.channel.toString(), receivedEvent.getEvent() )
    val channelevent = receivedEvent.getEvent()
    logInfo( "sunset Check", "INFO: Channel Event = '{}'", channelevent )
    val channelname = receivedEvent.channel.toString()
    logInfo( "sunset Check", "INFO: Channel Name =  '{}'", channelname )
    val channelthingUID = receivedEvent.channel.thingUID.toString()
    logInfo( "sunset Check", "INFO: Channel UID =  '{}'", channelthingUID )
    val channelID = receivedEvent.channel.id.toString()
    logInfo( "sunset Check", "INFO: Channel ID =  '{}'", channelID )

    logInfo( "sunset Check", "INFO: receivedEvent.channel.toString()       --> [{}], Event = '{}'", receivedEvent.channel.toString(), receivedEvent)
//    logInfo( "sunset Check", "INFO: receivedEvent.channel.toString()       --> [{}], Event = '{}'", receivedEvent.getCanonicalName(), receivedEvent.getEvent() )  //geht nicht
//    logInfo( "sunset Check", "INFO: receivedEvent.channel.toString()       --> [{}], Event = '{}'", receivedEvent.class.getCanonicalName().split(".").get(5), receivedEvent.getEvent() )  // geht so nicht 
//    val channelState = receivedEvent.getStatusInfo()
//    logInfo( "sunset Check", "INFO: Channel Status =  '{}'", channelState )
    val triggerEvent_split = receivedEvent.toString
    logInfo( "sunset Check", "INFO: Trigger =  '{}'", triggerEvent_split )
	val triggerEvent_split_3 = triggerEvent_split.split(":").get(3)
    logInfo( "sunset Check", "INFO: Split_3 ID =  '{}'", triggerEvent_split_3 )

the log:

2019-07-29 10:54:05.955 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'sunset check': cannot invoke method public final native java.lang.Class java.lang.Object.getClass() on null

As I’m not very experienced in programming and that stuff, I just doing “trial and error”. But for me it seems as if those variants do not work together :thinking:, but thx for hint.
Cheers,
Peter

@fibu-freak did you import org.eclipse.smarthome.core.thing.events.ChannelTriggeredEvent?

1 Like

thx for your tip. This is the way i’m just doing :wink:. My proposal was to combine the two ways in a more general manner.
But if it’s not possible - it’s not possible, anyway :slightly_smiling_face:.
So no need to think about it anymore, as I spent hours and hours to find a solution or workaround.

:slightly_smiling_face: This is the head of the rule,I posted above:

//import org.eclipse.smarthome.core.thing.events.ChannelTriggeredEvent   // When using this import, you can see the answer next line
//                                                                          The import 'org.eclipse.smarthome.core.thing.events.ChannelTriggeredEvent' is never used.
  
rule "sunset check"
when
         Channel 'astro:sun:local:set#event' triggered
    or   Channel 'astro:sun:local:civilDusk#event' triggered
 

When using the import I just get the information that the import is never used, so I commetend it out.

Remove channel triggers from your rule and move them to a new rule to have a body to contain Sonoff_Release_Refresh.sendCommand(ON)

@fibu-freak you can also define an Item to store those astro events that you are interested on, like

DateTime Sunrise_Time { channel="astro:sun:home:rise#start" }

By doing that you can use the triggeringEvent implicit variable on you rule for all the triggers

or you can do what @mstormi suggests

umm, it doesn’t work like that. You cannot store transient events in an Item state.

What your example does is store the expected datetime of sunrise in an Item. The Astro binding will set that when it calculates the day’s events, usually at midnight, and that’s that. The Item stays set to the datetime all day until the next time it is changed. Nothing happens to it when the given time passes.

astro:sun:home:rise#start is a datetime state, a prediction.

astro:sun:local:set#event is an event. It just happens, then it is gone again until next day.

1 Like

Hi Markus,
thx for your hint, but I do not quite understand what is meant or what you try me to explain (sorry I’m bit stupid)
I don’t want to send a command to my switch. But if you mean to make two rules, one which fire when I use the switch to start and another one which starts channel based, I understand. But this was not my intension.
I just want to know if the rule is triggered by the switch or by a channel. And it works when I used a named switch(Item).
But my consideration was to use the If-Clause more general to make the Rule-Stuff a bit more “lean”.

@rossko57 thanks for your remark :+1:

@rhumbertgz and @rossko57 thx to you both.

That’s the difficult part, so my suggestion is to have two rules, rule 1 for the (virtual) switch and rule 2 for the channels. Then rule 2 sends a command to the virtual switch which is not having any physical effect but is there only to call rule 1 and do everything else in there.

1 Like

Aaaah :hugs: now I understand (der Groschen ist gefallen or the penny dropped). But a little drop of bitterness still stays. When the Channel-based rule is fired and gives the information to the “Switch-Rule” I get the information from the “manual rule” too that it is triggered. Maybe it is possible to use one Rule-File for both rules and a gobal variable which is set in the channel-based one and queried in the other one.
I will try, thx.

The specific problem is that when the Rule is triggered by the Channel events there is no triggeringItem so there is no way to have triggeringItem.state == ON. When there is no triggeringItem, you will always get an error if you try to call triggeringItem.state.

You might be able to test that it’s not null first triggeringItem != null && triggeringItem.state == ON.

=== should only be used when comparing with null.

That’s the same problem but from the other direction. When you trigger that Rule by the Item there is no receivedEvent so you will get an error when you try to call receivedEvent.class.

As with the above, you might be able to determine whether the Rule was triggered by the Item or the Channels using something like:

    if(triggeringItem !== null){
        // do Item stuff
    }
    else if(receivedEvent !== null){
        // do channel stuff
    }

This too might generate an error in which case the suggestions of splitting it into two Rules will be the only viable option.

1 Like

Hi Guys,
thx to all of you for your help finding a solution for my problem, especially to @mstormi for his attempt splitting it into two Rules and his extra Explanations for me.

I will use his idea in one of my next tests. I’m just looking for suitable example.

After a while of testing the possibilities, the way I’m looking for came from @rlkoshak , as I only want to determine wether the rule is triggered by an event or by a channel and then log this in the viewer

So now my rule looks like:

import org.eclipse.smarthome.model.script.ScriptServiceUtil
val sonoff_device_ids = newArrayList("sonoffs")
val rulename = "sonoff_firmware_info"
var Timer tSonoffFirmware = null

rule "Sonoff_firmware_info"
when
        Item Sonoff_Release_Refresh changed to ON
     or Item Dummy4 changed to ON 
     or Channel 'astro:sun:local:noon#event' triggered START 
     or Channel 'astro:sun:local:astroDusk#event' triggered START 
     or Channel 'astro:sun:local:night#event' triggered START 
     or Channel 'astro:sun:stowing1:noon#event' triggered START 

then
    var firmware = transform("REGEX", ".*([0-9].[0-9].[0-9])", Sonoff_Current_FW_Available.state.toString)
    logInfo(rulename, "Tasmota Refresh Items Firmware-Release-State in BasicUI : " + firmware + "(sonoff)")

        // is it an event based Trigger ?
    if (triggeringItem !== null) {
        // now you can do stuff like logInfo
        logInfo(rulename, "Rule fired manually by  : " + triggeringItem.name + " State: " + triggeringItem.state + " previousState: " + previousState)
        // or something other like: generic item from triggeringItem.name  "it's Just fun"
        //++++ Pointer-adresses for the dynamically generated items to get corresponding/generic item       ***thx to @5iver and @rlkoshak for help***
       var GenericItem tempTriggerItem = ScriptServiceUtil.getItemRegistry.getItem(triggeringItem.name) as  GenericItem  // 
       logInfo (rulename, "Itemname is: " + tempTriggerItem.name)
       // or this :
       if (tSonoffFirmware !== null) {
          logInfo("rulename","Timer wird gecancelled: " + tSonoffFirmware)
          tSonoffFirmware.cancel
       }
        logInfo("rulename","Timer wird initialisiert")
        tSonoffFirmware = createTimer(now.plusSeconds(3), [|
           if (triggeringItem.state == ON) {               // this is the state of the triggering Item (could also be generic Item's State)
               tempTriggerItem.postUpdate(OFF)             // update(switch Off) the triggering item via generic item (as it's the same in this case)
               logInfo("rulename","GenericItem ist" + tempTriggerItem)
               // or whatever stuff you want ;)
           }
        ])
    }
             // is it a channel based Trigger ? 
    else if (receivedEvent !== null) {
        // now you can do stuff like logInfo
        logInfo(rulename, "Rule fired by Channel: " + receivedEvent.toString )
        // and of course a lot of other stuff if you/I want ;)
   }
    for (String device_id : sonoff_device_ids) {
          publish("peter", "cmnd/" + device_id + "/status", "2")
          logInfo(rulename, "Sonoff Maintenance: " + device_id)
    }
    logInfo(rulename, "Tasmota Refresh Items Firmware-Release-State : end")
end 

even it has a bit of the idea of Markus inside the lambda (the switch back to OFF for the the triggered event, (as said just a bit :wink::wink:), as a starting point for more).
And the result in the logger shows:

2019-08-02 22:44:15.345 [INFO ] [me.model.script.sonoff_firmware_info] - Tasmota Refresh Items Firmware-Release-State in BasicUI : 6.6.0(sonoff)
2019-08-02 22:44:15.356 [INFO ] [me.model.script.sonoff_firmware_info] - Rule fired manually by  : Dummy4 State: ON previousState: OFF
2019-08-02 22:44:15.363 [INFO ] [me.model.script.sonoff_firmware_info] - Itemname is: Dummy4
2019-08-02 22:44:15.389 [INFO ] [me.model.script.sonoff_firmware_info] - Sonoff Maintenance: sonoffs
2019-08-02 22:44:15.392 [INFO ] [me.model.script.sonoff_firmware_info] - Tasmota Refresh Items Firmware-Release-State : end
//
2019-08-02 23:27:02.862 [INFO ] [me.model.script.sonoff_firmware_info] - Tasmota Refresh Items Firmware-Release-State in BasicUI : 6.6.0(sonoff)
2019-08-02 23:27:02.873 [INFO ] [me.model.script.sonoff_firmware_info] - Rule fired by Channel: astro:sun:local:night#event triggered START
2019-08-02 23:27:02.889 [INFO ] [me.model.script.sonoff_firmware_info] - Sonoff Maintenance: sonoffs
2019-08-02 23:27:02.894 [INFO ] [me.model.script.sonoff_firmware_info] - Tasmota Refresh Items Firmware-Release-State : end

BTW: My second Rule was not a very good example, as I inserted the virtuel Switch just for testing the rule if it triggeres. I changed it now to

//import org.eclipse.smarthome.core.thing.events.ChannelTriggeredEvent   // When using this import, you can see the answer next line
//                                                                          The import 'org.eclipse.smarthome.core.thing.events.ChannelTriggeredEvent' is never used.
  
rule "sunset check"
when
         Channel 'astro:sun:local:set#event' triggered
    or   Channel 'astro:sun:local:civilDusk#event' triggered
    or   Channel 'astro:sun:local:nauticDusk#event' triggered
    or   Channel 'astro:sun:local:astroDusk#event' triggered 
    or   Channel 'astro:sun:local:daylight#event' triggered
    or   Channel 'astro:sun:local:noon#event' triggered
    or   Channel 'astro:sun:stowing1:noon#event' triggered START 
    or   Channel 'astro:sun:stowing2:noon#event' triggered
    or   Channel 'astro:sun:stowing3:noon#event' triggered
    or   Channel 'astro:sun:local:rise#event' triggered 
    or   Channel 'astro:sun:local:morningNight#event' triggered 
    or   Channel 'astro:sun:local:astroDawn#event' triggered 
    or   Channel 'astro:sun:local:nauticDawn#event' triggered 
    or   Channel 'astro:sun:local:night#event' triggered 
    or   Item Sonoff_Release_Refresh changed to ON 
then
    if (triggeringItem !== null) {
    logInfo("sunset Check", "INFO: Rule was manually triggered  by =  '{}' but that's not good in this Rule, so we break off", triggeringItem.name )
    return;   // only for checking if the Rule is triggered manually by an event(item)
    }
    //    val String ruleTitle="event::getCanonicalName()"
    logInfo( "sunset Check", "INFO: receivedEvent.class.getCanonicalName() --> [{}], Event = '{}'", receivedEvent.class.getCanonicalName(), receivedEvent.getEvent() )
    logInfo( "sunset Check", "INFO: receivedEvent.channel.toString()       --> [{}], Event = '{}'", receivedEvent.channel.toString(), receivedEvent.getEvent() )
    val channelevent = receivedEvent.getEvent()
    logInfo( "sunset Check", "INFO: Channel Event = '{}'", channelevent )
    val channelname = receivedEvent.channel.toString()
    logInfo( "sunset Check", "INFO: Channel Name =  '{}'", channelname )
    val channelthingUID = receivedEvent.channel.thingUID.toString()
    logInfo( "sunset Check", "INFO: Channel UID =  '{}'", channelthingUID )
    val channelID = receivedEvent.channel.id.toString()
    logInfo( "sunset Check", "INFO: Channel ID =  '{}'", channelID )

    logInfo( "sunset Check", "INFO: receivedEvent.channel.toString() Line 35      --> [{}], receivedEvent = '{}'", receivedEvent.channel.toString(), receivedEvent)
//    logInfo( "sunset Check", "INFO: receivedEvent.channel.toString() Line 36       --> [{}], Event = '{}'", receivedEvent.class.getCanonicalName.toString().split(".").get(5), receivedEvent.getEvent() )  // geht so nicht - doesn't work either 
//    val channelState = receivedEvent.getStatusInfo  // geht so nicht - doesn't work either 
//    logInfo( "sunset Check", "INFO: Channel Status Line 38 =  '{}'", channelState )  // geht so nicht - doesn't work either 
    val triggerEvent_split = receivedEvent.toString
    logInfo( "sunset Check", "INFO: Trigger =  '{}'", triggerEvent_split )
    val triggerEvent_split_3 = triggerEvent_split.split(":").get(3)
    logInfo( "sunset Check", "INFO: Split_3 ID =  '{}'", triggerEvent_split_3 )

end

Again, thx to you all for help.

Cheers,
Peter