Is there a way to create or mimic Array Variables?

So, I have a number of scripts in RM 4.1 using TTS and sound file playback. Iā€™m converting to new versions using RM because I will want to continue using and modifying them over the long future. Of course, I could just re-write the code, but Iā€™m trying to find ways to make it better as I go. Which gets me to my question.

I have a collection of sound files on my hub, with their addresses saved into Hub Variables. Basically, different variables like SND01, SND02, SND03, etcā€¦. That way, when I want to change the a sound file, I just change the hub variable and everything else tracks through. I have separate rules that call other rules to route sound playback around the house as required, usually with an announce rule that saves information into hub variables which are referenced further down the command chainā€¦

What this means is that I need a bunch of hub variables, a bunch of IF/ENDIF statements, and a bunch of rules, which I currently have in 4.1. It works okay, butā€¦.

I would love to have an Array Variable like ā€œSounds(1)ā€, where the address of each sound is available inside of the array, and I can just choose the sound by calling something like: %Sounds(%countVariable%)% (Like you might in another programming language). If I could do this, I could probably condense work that is done across 12 different rules and a bunch of IF/ENDIF statements down to 1 or 2 rules.

Yes, there are user installed apps available that mostly do what I am doing right here, and Iā€™ve tried many of them. However, I actually like the solutions Iā€™ve created and want to keep with that idea. Just want to see if there is a way to streamline my work a little better.

I am open to ideas about how to create this functionality.

There are no array types in Rule Machine variables or in hub variables. There are some string operations you can do, like splitting based on a delimiter, which you might be able to use to simulate indexing in an array. Whether that's actually easier or not, I don't know. :slight_smile: Here is an example of how that works:

You might also be able to just build the URL using a local variable in the rule by concatenating your desired number--from the variable value--with the rest of the (presumably fixed) URL string, but it's hard to say anything specific without seeing what you're really doing.

Probably not important for this, but a technical note: if you're using hub variables, you're probably not using Rule 4.1 (unless you made connectors and are using those devices, which you can do in any app that works with the device type). Hub variables replaced the functionality of global variables in Rule 5.0, new in hub firmware 2.2.8.

These sort of needs border on the need to use Groovy and to write a small app that would handle it with ease. You can expose commands within your app that can be called from RM

2 Likes

Many months ago I was playing with an idea that I never fully developed, but left a small device driver that can be used as named variable storage.

https://raw.githubusercontent.com/thebearmay/hubitat/main/dynAttribute.groovy

Using it with RM (or webCoRE, Event Engine, etc.) you could set up a series of named values like Sound1, Sound2, etc and iterate through them.

Not a great piece of work but useful on occasion. Feel free to use, modfiy, rejectā€¦

I'm probably with @bertabcd1234, we may need to know a little more about the rules / processes you are trying to use this list for.

I have recently started storing a list of image URLs in a local json file, but the method to get the json text into the file requires a rule and two variables, which is not ideal. That said, Bruce did make it clear they were sitting back and assessing how people want to use the local files, before looking at expanding the options for using them, which is fair enough. Not really sure whether this would suit your situation at all....

Thanks to everyone for your support. Sorry I wasn't clear in my first post about the variables. In 4.1, I am using global variables. I am replacing them with Hub variables in RM 5. I will checked out the String delimiter idea. I had found that post when I was looking for options and it is bouncing around in my head. It might work. I am aware that I am getting close to the needs of moving over to Groovy, which will be a bit of a learning curve for me. However, I get the feeling that if I take that step, it will all become easier for me.

@thebearmay, thank you for the device driver. I will check it out. That may work out perfect. Also may be a good place for me to get my groovy feet wet. I'll post one of the child apps next to give you a clue of what I'm doing. It's actually pretty simple, just very repetitive.

Okay here is the stuff from my announce rules in 4.1. I am basically mimicking the functionality of some available User-defined apps that I used to use when I first started with Habitat. Since they never really did what I needed exactly, I decided to write my own rules, which work pretty well. Like many of us, I make minor changes over time as I have new ideas. This is basically a way to send announcements around the house for various reasons, with a variety of triggers.

btw, I use prefixes for my variables: GBL = Global, LCL = Local.

#1) I have a rule that sets up my global variables, which include an AnnounceMessage, AnnounceSound (Sound file to play before the TTS), and AnnounceSpeaker (numbered Google Nest Minis around the house). These are the rules I am constantly writing and changing.

#2) That first rule then triggers another the master announce rule, which uses the AnnounceSpeaker variable to figure out where to send the message. This is a repetitive code that looks like this:

Master PlayTrack Code

IF (Variable AnnounceSpeakerA(1) = 1(T) [TRUE]) THEN
Run Actions: * PlayTrack-01-Kitchen
END-IF
IF (Variable AnnounceSpeakerA(1) = 2(F) [FALSE]) THEN
Run Actions: * PlayTrack-02-LivingRoom
END-IF
IF (Variable AnnounceSpeakerA(1) = 3(F) [FALSE]) THEN
Run Actions: * PlayTrack-03-Downstairs
END-IF
IF (Variable AnnounceSpeakerA(1) = 4(F) [FALSE]) THEN
Run Actions: * PlayTrack-04-Master
END-IF
IF (Variable AnnounceSpeakerA(1) = 5(F) [FALSE]) THEN
Run Actions: * PlayTrack-05-Chloe
END-IF
IF (Variable AnnounceSpeakerA(1) = 6(F) [FALSE]) THEN
Run Actions: * PlayTrack-06-Cian
END-IF

#3) Using the above code, the appropriate child rule is played, which plays the selected sound, waits a designated time for that sound, then plays the TTS to the designated speaker. I basically have multiple copies of this rule for each speaker. See below:

PlayTrack-04 Mom Speaker Code

Set LCL-RestoreVol to Mom speaker volume
Set Volume on Mom speaker to 50
IF (Variable AnnounceSound(0) = 1(F) [FALSE]) THEN
playTrack('GBL-SND-01(http://192.168.86.230/local/Relax_BeautyBells.mp3)') on Mom speaker
Delay GBL-SndTime-01(2) seconds
END-IF
IF (Variable AnnounceSound(0) = 2(F) [FALSE]) THEN
playTrack('GBL-SND-02(http://192.168.86.230/local/smb_Pause.mp3)') on Mom speaker
Delay GBL-SndTime-02(2) seconds
END-IF
IF (Variable AnnounceSound(0) = 3(F) [FALSE]) THEN
playTrack('GBL-SND-03(http://192.168.86.230/local/smb_Coin.mp3)') on Mom speaker
Delay GBL-SndTime-03(2) seconds
END-IF
IF (Variable AnnounceSound(0) = 4(F) [FALSE]) THEN
playTrack('GBL-SND-04(http://192.168.86.230/local/smb_Powerup.mp3)') on Mom speaker
Delay GBL-SndTime-04(2) seconds
END-IF
IF (Variable AnnounceSound(0) = 5(F) [FALSE]) THEN
playTrack('GBL-SND-05(http://192.168.86.230/local/smb_Kick.mp3)') on Mom speaker
Delay GBL-SndTime-05(2) seconds
END-IF
IF (Variable AnnounceSound(0) = 6(F) [FALSE]) THEN
playTrack('GBL-SND-06(http://192.168.86.230/local/Relax_Varimba.mp3)') on Mom speaker
Delay GBL-SndTime-06(3) seconds
END-IF
IF (Variable AnnounceSound(0) = 7(F) [FALSE]) THEN
playTrack('GBL-SND-07(http://192.168.86.230/local/Relax_WaterMusic.mp3)') on Mom speaker
Delay GBL-SndTime-07(4) seconds
END-IF
IF (Variable AnnounceSound(0) = 8(F) [FALSE]) THEN
playTrack('GBL-SND-08(ā€œā€)') on Mom speaker
Delay GBL-SndTime-08(0) seconds
END-IF
IF (Variable AnnounceSound(0) = 9(F) [FALSE]) THEN
playTrack('GBL-SND-09(ā€œā€)') on Mom speaker
Delay GBL-SndTime-09(0) seconds
END-IF
IF (Variable AnnounceSound(0) = 10(F) [FALSE]) THEN
playTrack('GBL-SND-10(ā€œā€)') on Mom speaker
Delay GBL-SndTime-10(0) seconds
END-IF
Speak on Mom speaker: '%AnnounceMessage%'
Delay 0:00:15
Set Volume on Mom speaker to LCL-RestoreVol(40)

What would be awesome, is if I had something like array variables to load with the sound file address, and maybe even array variables to load the speaker locations, I could have the code auto grab the appropriate data from the original variables in the first rule, and not have to copy the same code over and over again for multiple sound files and multiple speakers.

Once again, my current (copied a lot) system does work. Just looking to streamline. I may dive into Groovy more as well, I'm just not at that point yet. However, I thought the habitat hive mind might have some ideas, and as always, you all do! Thank you!