Playing mp3 files

Hi all, I have a Xiaomi button that I want to trigger playing mp3 files from the sounds folder.
This is a project to keep my new grandchild entertained. The idea being, every time the button is pressed, it plays a file (animal sound) and next press plays the next file from the array. The output is to play on a google home mini. At the moment, I don’t have permission to put the files in the sound folder which is /etc/openhab/sounds/

Could someone please point me in the right direction?
This is my rule

var currState = 0
var sounds = newArrayList("1.mp3", "2.mp3", "3.mp3","4.mp3", "5.mp3", "6.mp3", "7.mp3", "8.mp3", "9.mp3", "10.mp3", "11.mp3", "12.mp3", "13.mp3", "14.mp3", "15.mp3", "16.mp3", "17.mp3", "18.mp3", "19.mp3", "20.mp3", "21.mp3", "22.mp3", "23.mp3", "24.mp3", "25.mp3", "26.mp3", "27.mp3"  )


rule "Animal Sounds"
when
    Channel "mihome:sensor_switch:04cf8c9783a3:158d0002f80bdc:button" triggered
    
then
    var actionName = receivedEvent
    switch(actionName) {
        case "SHORT_PRESSED": {
                
            if (currState <= 0) currState = -1
            currState = currState + 1
            val value1 = sounds.get(currState % sounds.size)
            playSound("value1")
		    playSound("chromecast:chromecast:KitchenGoogle", value1, new PercentType(50))
            
        }
        case "DOUBLE_PRESSED": {
            if (SW3_01_2.state != ON)             
                 SW3_01_2.sendCommand(ON)
             else  SW3_01_2.sendCommand(OFF) 
            //currState = currState + 1
            //val func2 = brlight.get(currState % brlight.size)
            //func2.apply()
                        
        }
        case "LONG_PRESSED": {
            if (SW3_01_1.state != ON)             
                 SW3_01_1.sendCommand(ON)
             else  SW3_01_1.sendCommand(OFF)
            
        }
        //case "LONG_RELEASED": {
        //    Bedroom_Light.sendCommand(100)
        //}
    }
end

Thank you

As which user are you trying to do that?

Your code will not work like this.
Every time you press the button, your rule starts with currState = 1 and will always play 1.mp3. You either have tobstore that value in an item or, better, in a cache variable:

var i = (cache.private.get("i") !== null) ? cache.private.get("i") * 1 : 1;
actions.Audio.playSound("chromecast:chromecast:KitchenGoogle", i.toString() + ".mp3", new PercentType(50));
cache.private.put("i", i + 1);

Please note, this is JS scripting.
You just need to add some logic to begin with 1 once i > 27

As it’s a DSL rule and is defined via rules file, currState is indeed a global var and will hold its state. You don’t need a cache for that in DSL rules (if setup via rules file).

Interesting. Are all variables then global variables in file based DSL?
This would reduce the code even more (untested, writing from mobile phone):

if (i === null)  { var i = 1 }
actions.Audio.playSound("chromecast:chromecast:KitchenGoogle", i.toString() + ".mp3", new PercentType(50));
i = i + 1

no need for sounds array, etc

It depends on where the var is defined (i.e. inside a rule → local var, outside a rule - on top of all rules → global var, but only valid for rules in this specific file)

I’ll just add that all variables declared outside the rules definition in all the rules languages are “global” to that file and exist outside the scope of any individual rule.

In managed rules, there is no outside the rule to define the variables so in that case to have a variable persist from one run to the next of a given rule or to share a variable with multiple rules the cache needs to be used.

Advantage of using the cache over global variables even in text based rules files include:

  • timers placed in the cache automatically get cancelled when all rules that use that value in the cache are reloaded, no more orphaned timers
  • you can share variables across files, not just between rules in the same file
  • you can share variables across rules languages in some cases

@JDLambert , @opus is on the right track. Assuming this is Linux based on the file path, you need to be a user with permissions to write to a folder and /etc/openhab generally only allows user openhab to write to it.

But user root can do anything. The command sudo elevates the user to root for the command that follows (e.g. sudo cp *.mp3 /etc/openhab/sounds). However, the files will likely have root’s ownership and permissions so run sudo openhab-cli fix-permissions (or something like that) to make sure user openhab can read those files.

1 Like

You missed that the OP used a modulus when declaring value1.

The next line wouldn’t work. Handing over the string “value1” instead of the value of ‘value1’ to the method ‘playSound’ is wrong.