Expression 'IF' statement or looping through an Array?

So transitioning from WebCore since support from SmartThings will be removed anytime (story of everyone’s lift at this point I’m sure…).

One thing I do is during Night mode, do a variety of checks to report back. For example, I check the status of my ecobee thermostat in my SHOP. If the thermostat is not in ‘OFF’ mode, it’ll add that to a variable to report on. If then checks my smart outlet I have for my truck’s block heater. If it is on, it will report that too. Basically letting me know the things that I may have left on while working out there for the day.

In order to format the message properly and only add a ’ ; ’ to split the devices up when I have multiple warnings coming back for each check, I need to check the RIGHT most value of the current variable. So example

vSTRShopCheckMessage = ‘SHOP(’ – Would set the starting variable
– Shop’s thermostate is not OFF so need to add it as a warning
IF RIGHT(vSTRShopCheckMessage , 1) != ‘(’ – Check if the right most character is ( and if it isn’t, I know I have another device already started and need to include a ; to separate
THEN vSTRShopCheckMessage = vSTRShopCheckMessage + ’ ; truckblockheater@ON ’

If it does equal (, I know nothing has been put there yet so this would be the first and wouldn’t need to include the ;. I know it is petty but helps my message be formatted very nicely.

So just curious if there is a LEFT/RIGHT functionality to pull a value and check what it is so I know what to do. In WebCore, I was able to do this within the expression code itself. Not sure if it is doable in Sharp Tools or if I would have to actually build out the IF block everytime.

One more quick question that may help me do it a little differently with less code… Arrays.

Can I populate an array with the devices that need to be reported on during NIGHT mode? Then at the end of the checks for ‘SHOP’, I could count the values in the array. If 0, no need to do anything. If I have at least one, anyway to loop through and build out the message?

@Array = { ‘truckblockheater@ON’ , 'tstat@ON } – This would be built and a new array value added for each check (dynamically)

If @Array[count] > 0
For i = 0 to @Array[count]
$ShopMessage = $ShopMessage + @Array[i]
Loop

Just using the syntax above as a generalization to get my point across.

Thanks!

left() and right() string functions

There are left() and right() type of methods within expressions. You can find documentation on the available general purpose functions in the documentation:

That being said, you can’t access device state directly in expressions, so you would either need to temporarily store the device state in a variable for use in your expression or you could use IF Conditions (potentially along with the expressions for advanced concatenation).

Array Basics

Sort of. We don’t have an official ‘array’ or ‘object’ variable type for storing values, but they can be used within expressions. And if you want to store an array/object in a variable you can use the parseJson() and stringify() methods mentioned in the documentation above to encode it into a string.

You can find some examples that use these methods for encoding array data into a string variable in the following posts:

Conditional Expressions (Ternary Operator)

You can also use ternary operators for conditions. The format is:

condition ? trueExpression : falseExpression

So a simple example might be:

myNumber = 12
myNumber >= 10 ? "It's 10 or bigger" : "It's less than 10"

Example with String Concatenation

Combining some of the above, you might have something like:

  • Set variable $truckBlockHeater to Truck Block Heater - switch.
  • Set variable $shopThermostat to Shop Thermostat - mode.
  • Set variable $reportString to expression:
truckBlockHeater = "on"
shopThermostat  = "heat"

tempString = ""

equalText(truckBlockHeater, "on") ? tempString = concat(tempString, "The truck heater is on;") : ""

equalText(shopThermostat, "off") ? tempString = concat(tempString, "The thermostat is off;") : ""

tempString

In this example, I’m using ternary operators to check the string with an equalText() method on the left side of the ternary. Then only if it’s true, I concat() the existing tempString along with whatever addition I want. In the else block, I’m just using an empty string (since we’re not actually assigning it, it’s basically just doing nothing).

A key part here is to make sure to return the tempString as the last line. The way the expression system works is it returns whatever the last line is. So we want to make sure the fully contatenated string with the expression variable is the last thing we return.

You could of course have other logic in here like returning a default string (instead of an empty string) if no strings were concatenated on.

Array Example

You could do this with an array too, but I didn’t see how it would help this particular situation as you would need to build up the array anyway. Here’s some array type features though in case you had something else in mind and you were looking for inspiration.

truckBlockHeater = "on"
shopThermostat  = "off"

myArray = []

equalText(truckBlockHeater, "on") ? myArray = concat(myArray, ["The truck heater is on"]) : ""

equalText(shopThermostat, "off") ? myArray = concat(myArray, ["The thermostat is off"]) : ""

join(myArray, "; ")

The key difference in this approach, is we use the concat() method to merge two arrays together. So you have to make sure both inputs to the method are arrays – basically just wrap the string on the right side in an array. This is the closest approximation to an array ‘push’ type of concept.

Then the last piece that’s near is using the join() method, but one thing to keep in mind is this will only add the join character/string between items in the array. So if it’s a single item in the array, there’s no ; at all, if there’s 2 items, there’s just a single ; between them, and so on. You may have to adapt or use a different approach if you wanted the ; ending each line, but the join() is cool for a lot of use cases, so it’s worth mentioning.

Truck is on
Truck is on; Heater is off
Truck is on; Heater is off; Light is on

Also note that I just used the join() method as the last line here since the result of that method is the output we wanted. Writing it to a local tempString type of variable would have been superfluous here, so we just returned the joined string directly.

1 Like

Josh,

Appreciate the detailed response! This helps greatly. I tried finding some of this but had some trouble. I did bookmark the link above and added to some of the others I found (such as working with dates). I needed to work with dates to offset the now functionality by my time zone adjustment.

I think with this data, I should easily be able to do exactly what I need! I’m trying to get it all done before trail is over so I know for sure I’m good with Sharp Tools and purchase the yearly membership. Or if I end up going to Hubitat (from Smart Things) and stick with WebCore. But so far, it seems like the functionality you all provide is on par with what I needed from WebCore.

Appreciate it!

1 Like

So, I got this working using the array as suggested above and its great!

Then, I tried to get fancy and set a custom message if the array was empty. :frowning:

What I tried to do that does not work is check to see if the array was equal to “blank” and if so, concat “blank” with a specific message…my logic is flawed somewhere – likely multiple places:

equalText(myArray,"") ? myArray = concat(myArray, ["There are no alarms set for tomorrow."]) : myArray

The code that does work is:

myArray = []
equalText($AlarmMasterVariable, "on") ? myArray = concat(myArray, [concat("Master: ",$AlarmMasterTime)]) : ""
equalText($AlarmLilyVariable, "on") ? myArray = concat(myArray, [concat("Lily: ",$AlarmLilyTime)]) : ""
equalText($AlarmElizabethVariable, "on") ? myArray = concat(myArray, [concat("Elizabeth: ",$AlarmElizabethTime)]) : ""
join(myArray,", ")

If it’s literally checking an empty array, then that wouldn’t work as that expression is trying to compare an empty array to an empty string which are not directly comparable.

  • Empty Array: []
  • Empty String: ''

I would probably recommend just using the isEmpty() method if you want some flexibility in checking to see if the input data is ‘empty’. You can find it in the Content Checks section of the General Functions in Rule Expressions documentation.

The nice thing about this method is it covers a variety of ‘blank’ scenarios. It covers each of the following concepts.

  • String that is null or ''
  • Array with no items []
  • Number that is 0
  • Object property that is undefined
    (or matches one of the above type comparisons)

Edit: There’s a few examples showing this in the following threads:

Argh…I should have gotten that one…thanks for the help!

If anyone comes across this later on, here’s the completed and working snippet:

myArray = []
equalText($AlarmMasterVariable, "on") ? myArray = concat(myArray, [concat("Master: ",$AlarmMasterTime)]) : ""
equalText($AlarmLilyVariable, "on") ? myArray = concat(myArray, [concat("Lily: ",$AlarmLilyTime)]) : ""
equalText($AlarmElizabethVariable, "on") ? myArray = concat(myArray, [concat("Elizabeth: ",$AlarmElizabethTime)]) : ""
myArray = isEmpty(myArray) ? "No alarms are set." : join(myArray,", ")