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
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 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.
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)
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