Array Variables / Expressions

Hi all! I’m new to Sharptools and am looking for some pointers.

I would like to create a role that rotates the color/hue of an LED light through 4 different hues that represent Red Blue Green and Orange. There is no way that I can tell to define a variable that is an array of integers via the “Manage Variables” feature. So in my rule I set a variable like this:

Variable: $colorArray
Expression: [$colorHueBlue, $colorHueGreen, $colorHueOrange, $colorHueRed ]

And it does successfully evaluate to : [71,33,11,0]

Now to cycle through these values I have an incrementing counter ($cylingCounter) that I then apply a modulus to give me a value between 0 and 3 to pick the color.

Here is where I can’t seem to get the expression correct… any suggestions?

Variable: $colorHueValue
Expression: $colorArray[ $cyclingCounter % 4 ] <=== doesn’t work

It seems like it doesn’t recognize $colorArray as an array…even count($colorArray) doesn’t work

Is there a better approach?

Thanks!

What is the type of the $colorArray variable? I suspect it was created as a Text variable, so the expression is ultimately getting implicitly serialized to a string.

You can also explicitly serialize and deserialize data to a string. If the variable type is Text, then values will implicitly be serialized to a string, but it will stay a string after being written to a Text variable. If you want to parse it back into array/object format for use within an expression, you must do that explicitly within the expression.

Serialize/Deserialize

Under the General String Manipulation section of the General Functions help article, you’ll find the functions stringify() and parseJson() which you can use to explicitly serialize and deserialize object data to/from a string.

So you could do something like the following if you want to explicitly serialize the data (though the implicit serialization may be fine for your needs):

  • Set Variable $colorArray to expression:
    stringify([$colorHueBlue, $colorHueGreen, $colorHueOrange, $colorHueRed])
    

Or if you know the values you want in the array, just write it directly into the string as it sounds like the deserializing the data back to an array is the main part you need (eg. Set Variable $colorArray to static value [71,33,11,0])

Then you could deserialize the string into an array and grab the item you want out of it:

  • Set Variable $colorHue to expression:
    hues = jsonParse($colorArray)
    hues[ $cyclingCounter % 4 ]
    

This is using a trick that creates a hyper-local variable called hues within the expression evaluation just to make it easier to reference things. Since your $colorArray will already have the value set, you should be able to Tap to Evaluate the expression and see the result to make sure your syntax is right.

:information_source: Make sure your $colorHue variable is a Numeric type if you want to use it in commands that expect a numeric argument.

Random Value

If you wanted a random value from the array rather than to sequentially iterate through the colors, you could use the pickRandom([item1, item2, ... itemN]) function also documented in the help article linked above:

  • Set Variable $colorHue to expression:
    pickRandom(parseJson($colorArray))
    

What is the type of the $colorArray variable? I suspect it was created as a Text variable, so the expression is ultimately getting implicitly serialized to a string.

It is defined as a number, but you cannot specify that it is an array type.

Setting the $colorHueValue (numeric variable) expression to

[$colorHueBlue, $colorHueGreen, $colorHueOrange, $colorHueRed ][$outsideLightCyclingCounter % 4]

works as well.

I’ll review your suggestions to see what works best for me visually.

Thank you for your help!

Thanks for the update. In that case, the ‘Tap to Evaluate’ is capable of evaluating the expression and returns the raw result… but since the expression ultimately tries to save an Array to a Number, the implicit conversion fails and it would get saved to the variable as null/NaN (‘Not a Number’) when the rule actually runs.

If you don’t have any need for the $colorHueXXX variables individually, either deleting and recreating the $colorHueArray as a string and setting the value manually, or even just statically entering the array into the expression for setting the $colorHueValue could work for you (or the random() approach if you want some randomness in the order items are picked).

  • Set $colorHueValue to expression
    [71,33,11,0][ $cyclingCounter % 4 ]
    

I suppose that’s the neat thing with expressions - they provide lots of flexibility in how you implement things depending on your needs!

Thanks Josh, and since I’m still talking about the same rule, I get this error:

Rule has exceeded the rate limit. Execution is stopped.

The cycling of lights is set to every 20 seconds. At what rate should I set the repeat pattern to not trigger the limit?

The rate limit is 200 executions within 10 minutes, so I would double check your rule configuration and logs to make sure its executing as expected.

Thanks, and for clarity sake, what counts as an ‘execution’ ?

Basically anytime the rule flow is told to run (valid trigger or manual execution).

Ok thank you. That comes out to a rate of every 3 seconds. I’ll set my rule back to include a 10 second delay and we’ll see what happens. If it fails again with that error condition I’ll contact support and hopefully they’ll be able to see what’s going on.

Sounds good. :slight_smile: Feel free to post a screenshot of your rule logic (and potentially the logs) and we can take a look. Often times the community has creative ways to help you optimize your rule flow!

1 Like

While we’re talking about arrays, if a user is trying to filter an existing array for values that don’t match a given value, should they write the expression in this form:
filter ([1,2,3], x<>3)
or this form:
filter ([1,2,3], not(x=3))

My end goal is to use filter() in this way as a makeshift remove(). May need get even more creative in the absence of min, max, first, last, push, pop, etc. functions.

Either approach would work, but the correct syntax would be:

filter ([1,2,3], x != 3)

or

filter([1,2,3], not(x == 3))

In the second case, the single = is an assignment operator rather than an equality comparison == and in the first case, the ‘not equals’ comparison operator would be !=

Edit: I would note that min(), max() and similar math functions exist. You can get the first and last indexes from an array based on the index position. I’ll double check on the math functions as they might be missing from the docs.

min([8,2,3]) #// yields 2 as the result
1 Like

Perfect and just the info that I was looking (in the Docs) for. Thanks!