Array Loop question

I read the address of my phone from openstreetmap using the geolocation.
the result is a json string and contains strings and numbers like: Road, housenumber, suburb, town, city, state, postcode, …).

Sometimes the json response doe not contain one or the other and I get the entire json string back (not null as expected).

Anyway, what I do is i check for this issue like this:

    if(result.contains("town")) {
		town = transform("JSONPATH", "$.address.town", result)
	}
	else {
		town = "-"
	}

Now I would like to use a loop to concat these string items if they are NOT “-” like:
road, house_number, suburb, town, state.

I am sure there is a way to do it without checking each single string for beeing “-”, because I need to size down my number of code lines. :slight_smile:

(with the same approach I could create a list of open contacts on my windows or active devices in my home (coffee machine, lights, …).

You could do that at the same time you check your json:

    var String fullAddress = ""
    if(result.contains("town")) {
        town = transform("JSONPATH", "$.address.town", result)
        fullAddress = fullAddress + ", " + town
    } else {
        town = "-"
    }

Good idea.
However - if possible - I would like to handle the information in the full address depending if it’s in my home town (just street and suburb) instead of the full address including state and country.

Again, in the same rule:

    var String fullAddress = ""
    if(result.contains("state")) {
        state = transform("JSONPATH", "$.address.state", result)
        if (state != "mystate") {
            fullAddress = fullAddress + ", " + town
        }
    } else {
        state = "-"
    }

You’re fast.
Thanks, I will try that.
I hoped there is a more generic approach
to cover the other use cases mentioned.

Anyway, this will help to get my code more streamlined.
Thanks a lot!

In this case is probably the easiest way to do it. What are your other cases. There are as many solutions to as many problems and the best way to solve your other use cases may be very different.

Thanks, I really appreciate your help.
Will post the other case soon :slight_smile:

This is one of the other cases.
I assume there is a smarter / shorter way to do this!!?

rule "Open Windows / Door Check"
when
Item G_Melder changed
//    or Time cron "24 0/7 * * * ?"
then
	if(G_Melder.state == ON) {
		var String open_Contacts_tmp = ""
		if(Abus_ENG_Sw.state == ON) {
			if(open_Contacts_tmp == "") {
				open_Contacts_tmp = "Eingang "
			}
			else {
				open_Contacts_tmp = open_Contacts_tmp + "/ Eingang "
			}
			logInfo("abus.rules", "open_Contacts_tmp set to: " + open_Contacts_tmp)	
		}
		if(Abus_BLK_Sw.state == ON) {
			if(open_Contacts_tmp == "") {
				open_Contacts_tmp = "Balkon "
			}
			else {
				open_Contacts_tmp = open_Contacts_tmp + "/ Balkon "
			}
			logInfo("abus.rules", "open_Contacts_tmp set to: " + open_Contacts_tmp)	
		}
		if(Abus_OBL_Sw.state == ON) {
			if(open_Contacts_tmp == "") {
				open_Contacts_tmp = "Oberlicht "
			}
			else {
				open_Contacts_tmp = open_Contacts_tmp + "/ Oberlicht "
			}
			logInfo("abus.rules", "open_Contacts_tmp set to: " + open_Contacts_tmp)	
		}
		if(Z_Bath_W_Sw.state == ON) {
			if(open_Contacts_tmp == "") {
				open_Contacts_tmp = "Badfenster "
			}
			else {
				open_Contacts_tmp = open_Contacts_tmp + "/ Badfenster "
			}
			logInfo("abus.rules", "open_Contacts_tmp set to: " + open_Contacts_tmp)	
		}
		open_Contacts.postUpdate(open_Contacts_tmp)
		logInfo("abus.rules", "open_Contacts updated to " + open_Contacts.state)
	}
	else {
		if(G_Melder.state == OFF) {
			open_Contacts.postUpdate("Keine")
			logInfo("abus.rules", "open_Contacts updated: " + open_Contacts.state)
		}
	}
end

If the items are in a group named gContacts, then you can do this…

val String open_Contacts_tmp = gContacts.members.filter [ i | i.state == ON ].map[ label ].reduce[ s, label | s + ", " + label ]
2 Likes

that would be awsome to replace everything with this approach.
I will try is asap

Thanks a lot!!

thank you so much.
It works like a charm - for another use case as well (active devices).
For both rules, I was able to reduce the code from approx. 70 lines to 10 :slight_smile:

1 Like

I love it!
Thanks again.
I replaced 5 rules around 70-90 lines to 10 each.
You are my hero.
Hope to find some more for this approach :slight_smile:

1 Like

Are your rules parsing times getting any better? I know that is what prompted this lines of code reduction path you are heading down in the first place.

I did not check it in detail, but it should.
I have eliminated most of my sleeps (as you recommend in your code design suggestions (avoid long running rules).

That really opened my eyes.

However, I striggle with some minor issues (these were the reason to use sleep in the first place).

One is this:
I have some rules which are triggered by xx received command.
within this rule I check for triggered by ON or OFF.
This was not working consistently, so I used sleep to wait for the command to settle (??).
Anyway, this worked in all cases with a sleep of 2 seconds.

Now I have started to split these rules mentioned above into “received command ON” and received command OFF (without sleep of course).
This seems to work much better.

Again, instead of expand my code with new stuff, I started to streamline it after I found your design strategy hints.
So thanks a lot for that!

There is still a way to go though. :slight_smile:

When using the ‘received command’ trigger, the item’s state has not yet been changed. To get around this, there is an implicit variable that you can use to get the command that was received for the item… receivedCommand. You can use this instead of the item’s state, as this is what the item’s state will be changing to. No sleep required!

rule "Test"
when
    Item Test_Switch_1 received command
then
    if (receivedCommand == ON) {
        //do stuff
    }
    else if (receivedCommand == OFF) {
        //do other stuff
    }
end

Hey, that’s great.
I did not even know “receivedCommand == ON” exists.
(I guess I should read some more documentation in my spare time).

Thanks for the hint.

I guess there is no disadvantage if I use separate rules for received command ON / OFF in the meantime?

No. It is limited to the scope of the rule instance, just like any other local variable. Meaning you can use it (and the other implicit variables) in multiple rules without issue.

Hi,

I tried to use this in multiple cases to get rid of the issue with the delay between command and the final change of the item.

However, I use this and the command is received in events.log, but the rule is not triggered.

rule "Abus_Guardmode command exec"
when
	Item Abus_Guardmode received command
then
	if(receivedCommand == OFF) {
		executeCommandLine("curl http://xxx/setparam.cgi?event_i0_enable=0", 3000)
		logInfo("abus.rules: ", "Abus_Guardmode received command OFF")
	}
	else if(receivedCommand == ON) {
		executeCommandLine("curl http://xxx/setparam.cgi?event_i0_enable=1", 3000)
		logInfo("abus.rules: ", "Abus_Guardmode received command ON")
	}
end

Any idea?

Anything in the logs?

The openHAB.log does not show anything - (no debug mode yet).

But actually deleting cache and temp file obviously helped.

So, it seems that the change was too big - changing lots of rules from receivedCommand ON / OFF to the setup with if(receivedCommand == ON).

Thanks for your quick response.
I will keep a close eye on it.