Concatonating strings and variables in a rule

Hoping someone can help me out here - trying to genericise this rule to cover all rooms

Have the following items that receive events:

Switch    KNXVolumeBathroomGuest
Switch    KNXVolumeBathroomMain      
Switch    KNXVolumeBedroom1        
... (10 more devices)

and want to update the volumes on the following:

Dimmer         ChromecastAudioBathroomGuestVolume       
Dimmer         ChromecastAudioBathroomMainVolume    
Dimmer         ChromecastAudioBedroom1Volme
... (10 more devices)

I had this rule working with one room but am trying to adapt to work with the corresponding room name and am stuck on the part/or basically how to concatenate strings and variables together in a rule.

var String ChromecastDeviceName.concat+=("ChromecastAudio" + room + "Volume")

Here’s the actual rule - I’m also unclear how to then subsequently correctly reference the new variable in sendCommand. Sorry for the noob questions but have been banging my head against the wall on this.

rule "KNX Volume Contol"
when
    Member of gKNXVolume received command
then
    logInfo("KNXVolumeControl","triggering Item: {}",triggeringItem.name)
    var room = triggeringItem.name.replace("KNXVolume","") 
    logInfo("KNXVolumeControl","extracted room: {}",room)
    var String ChromecastDeviceName.concat+=("ChromecastAudio" + room + "Volume")
    logInfo("KNXVolumeControl","Device to change the volume on: {}",ChromecastDeviceName)
        if (receivedCommand == OFF) {
        logInfo("KNXVolumeControl","reducing volme in {}", room)
        sendCommand({{ChromecastDeviceName}}, ((ChromecastAudioStudyVolume.state as DecimalType) - 5))
    }
    else if (receivedCommand == ON) {
        logInfo("KNXVolumeControl","increasing volme in {}", room)
        "ChromecastAudio" + roomStudyVolume.sendCommand((ChromecastAudioStudyVolume.state as DecimalType) + 5)
        sendCommand("ChromecastAudio" + {{ room }} + "Volume", ((ChromecastAudioStudyVolume.state as DecimalType) + 5))
    }
end

Example -
var String ChromecastDeviceName = "whatever " + someStringVar + " fred"

That won’t work, strings do not have a send command method.

The tools you need are here -

Thanks for the pointer. I understand that the output should be something like the example in the design pattern

postUpdate(triggeringItem.name+"_LastUpdate", now.toString)

and in my case the sendCommand will need to transform KNXVolumeBathroomGuest to ChromecastAudioBathroomGuestVolume. Which is sort of where I’m stuck. Or am I missing the point in that design pattern?

The point of the design pattern is, when given an Item’s name (e.g. the triggeringItem) you can use that Item’s name to construct the names of the associated Items. In this case you could use triggeringItem.name.repalce("KNXVolume", "ChromecastAudio") to convert from the one Item’s name to the other. But that’s only if all of these pairs of Items follow this same naming pattern.

I think that’s what I’m tying to do. So it’s more of a syntax question.

KNXVolumeBathroomGuest becomes ChromecastAudioBathroomGuestVolume
KNXVolumeBathroomMain becomes ChromecastAudioBathroomMainVolume

First work out which room we are dealing with (seems to work and room=BathroomGuest):

var room = triggeringItem.name.replace("KNXVolume","")

Build the name of the target device (doesn’t work - do I need tospecify that room is a string?)

var String ChromecastDeviceName = "ChromecastAudio " + room + " Volume"

Then call the update: (How do I speficy that “ChromecastDeviceName” is a variable?)

sendCommand(ChromecastDeviceName, ((ChromecastAudioStudyVolume.state as DecimalType) - 5))

Sorry - many dumb questions.

More please? You’ve logged it out to see what it looks like? There’s some error message?

You have got spaces in your “name builder” that I doubt you want.

You don’t, or rather you already did when you created it.
In DSL rules, “xx” will be treated as a string and xx as an object or variable.

I can say that it’s much easier if you use “_” to separate the parts of the Item name instead of camel case. But ultimately the syntax is just going to be a bunch fo String manipulation. The syntax is pretty straight forward. You can break them apart using split, regex to pull parts of the string, + to concatenate strings, replace to replace part of a String with another.

Thanks @rlkoshak and @rossko57 - making progress here:

rule "KNX Volume Contol"
when
    Member of gKNXVolume received command
then
    logInfo("KNXVolumeControl","triggering Item: {}",triggeringItem.name)
    var room = triggeringItem.name.replace("KNXVolume","") 
    logInfo("KNXVolumeControl","extracted room: {}", room)
    var String ChromecastDeviceName = "ChromecastAudio" + room + "Volume" 
    logInfo("KNXVolumeControl","Will change volume on: {}", ChromecastDeviceName)
    if (receivedCommand == OFF) {
        logInfo("KNXVolumeControl","reducing volme in {}", room)
        sendCommand(ChromecastDeviceName, (ChromecastDeviceName.state as DecimalType) - 5)
    }
    else if (receivedCommand == ON) {
        logInfo("KNXVolumeControl","increasing volme in {}", room)
        sendCommand(ChromecastDeviceName, (ChromecastDeviceName.state as DecimalType) + 5)
    }
end

results in

2021-04-16 17:13:16.387 onGroupWrite Thing 'knx:device:volume' received a GroupValueWrite telegram from '6.3.1' for destination '6/5/2'
2021-04-16 17:13:16.389 triggering Item: KNXVolumeStudy
2021-04-16 17:13:16.390 extracted room: Study 
2021-04-16 17:13:16.390 Will change volume on: ChromecastAudioStudyVolume
2021-04-16 17:13:16.391 reducing volme in Study
2021-04-16 17:13:16.392 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'knx-volumes-1' failed: 'state' is not a member of 'java.lang.String'; line 12, column 44, length 26 in knx-volumes

to test I run the following which works

sendCommand(ChromecastDeviceName, "10")

So it’s something with the converting the existing value in

        sendCommand(ChromecastDeviceName, (ChromecastDeviceName.state as DecimalType) - 5)

I’ve tried quoting it… any ideas?

Well, as rossko57 indicated above, a String is not an Item. Only Items have a .state. As documented in the Associated Items DP, if you need the state of an Item and all you have is the Item’s name as a String, you need to use the ItemRegistry to pull the Item by name so you can get the state. Alternatively you can have the Items in a Group and you can search through the Group’s members for the one with a given name.

Note this restriction is for Rules DSL. In the other rules languages there is a dict called items that contains all the states of all the Items keyed by the Item name. But you don’t have that here so you have ti import the ScriptServiceUtil and use the Item Registry.

@rlkoshak thanks - makes sense (and next time I’ll start with the Python rules). Just to wrap up, I have the following working nicely now. This enables the KNX wall buttons to control the volume in any room.

import org.openhab.core.model.script.ScriptServiceUtil
rule "KNX Volume Contol"
when
    Member of gKNXVolume received command
then
    logInfo("KNXVolumeControl","triggering Item: {}",triggeringItem.name)
    var room = triggeringItem.name.replace("KNXVolume","") 
    logInfo("KNXVolumeControl","extracted room: {}", room)
    var String ChromecastDeviceName = "ChromecastAudio" + room + "Volume" 
    logInfo("KNXVolumeControl","Will change volume on: {}", ChromecastDeviceName)
    var CurrentVolume = ScriptServiceUtil.getItemRegistry.getItem(ChromecastDeviceName).state as DecimalType
    logInfo("KNXVolumeControl","CurrentVolume: {}", CurrentVolume)
    
    if (receivedCommand == OFF) {
        sendCommand(ChromecastDeviceName , ((CurrentVolume - 5).toString()))
    }
    else if (receivedCommand == ON) {
        sendCommand(ChromecastDeviceName ,  ((CurrentVolume + 5).toString()))
    }
end

Thanks for your help @rossko57 and @rlkoshak