Btw: First I created a google home audio group, but unfortunately this audio group is treated “offline” if one of the group members (one google home device) is powered off. Thus I’d like to use the say() command for each individual device.
Show how you tried to create the Group. There might be something we can do there. You can only have a Group of Items as far as I’m aware so it isn’t clear what you’ve done.
Beyond that, I think your only option is to use the REST API to search for the relevant Things. Or you can hard code them into the Rule in an arrayList or the like.
There are other potential approaches but I’d need to know more about what you’ve actually tried.
I can just say that I have multiple things (google home devices) available. Each offers different channels, like setting the volume via: chromecast:chromecast:cc41b57679381809e5927107e4ceffd8:volume
I’m using the say command in conjunction with a user-selectable AudioSink, although the selection possibilities are hard coded.
rule "SagEtwas"
when
Item SayCommand received update //user changeable string
then
var String AudioSink
switch AudioSink {
case Lautsprecher.state.toString=="Küche" : AudioSink="sonos:PLAY1:PlayKueche" // Lautsprecher is a dropdown on HABPanel
case Lautsprecher.state.toString=="Wohnzimmer" : AudioSink="sonos:PLAY1:PlayWohnzimmer"
case Lautsprecher.state.toString=="Büro" : AudioSink= "sonos:PLAY1:PlayBuero"
case Lautsprecher.state.toString=="Gästezimmer" : AudioSink= "sonos:PLAY1:PlayGaestezimmer"
default:AudioSink="sonos:PLAY1:PlayWohnzimmer"
}
say(Command.state.toString,"voicerss:deDE",AudioSink)
end
You’ve asked about a technique to solve a problem without telling us the overall problem you are trying to solve. This robs us of critical information that we can use to provide the best help possible.
Anyway, opus’s example shows you a way to get a mapping between a human friendly name and a Channel name. Another way would be to create a Map file mapping Item names or a human friendly name to the channel name.
But since you haven’t told us why you want this mapping it’s really hard to help. opus, myself and everyone else will just be throwing out ideas, hoping one will stick.
sorry for that. let me describe in more detail.
Using fritzbox binding I’d like my google home devices to tell me who’s calling my landline.
For this I read the callers name from the phonebook. This works like a charm.
Then I feed the callers name to the say() command. Works as well, but not always.
Why? In the google home app I’ve created an audiogroup (so this is NOT a group of openHAB items) but it constantly leads to problems when using in OH.Like here:
2019-03-26 03:46:44.698 [hingStatusInfoChangedEvent] - 'chromecast:audiogroup:45beba5c-5205-40b9-90ee-31c9c6d49fa6' changed from ONLINE to OFFLINE
2019-03-26 03:46:54.716 [hingStatusInfoChangedEvent] - 'chromecast:audiogroup:45beba5c-5205-40b9-90ee-31c9c6d49fa6' changed from OFFLINE to OFFLINE (COMMUNICATION_ERROR): Connection refused (Connection refused)
2019-03-26 03:51:32.279 [hingStatusInfoChangedEvent] - 'chromecast:audiogroup:45beba5c-5205-40b9-90ee-31c9c6d49fa6' changed from OFFLINE (COMMUNICATION_ERROR): Connection refused (Connection refused) to ONLINE
Thus I’d like to change this process and fire the say() command to each individual google home device.
For now I have established to raise/lower the volume whenever a call comes in. Like:
You would need to create an ArrayList which contains all your Audiosinks (hardcoded!) and use the for-each technique for that list.
Using the say command that way will result in non synchronised messages played!
Thanks: Btw: I tested this also with String items. This ways I hardcoded the thing UIDs inside the items file instead of rules file.
Then I tried using createTimer(now.plusSeconds(0) in each forEach loop, to achieve a more or less immediate output on all google home devices, unfortunately without success.
There is too much going on at the same time in OH. You will never get the audio to play synchronized by sending an individual command to each device from OH.
You might be able to get close if you use JSR223 Jython Rules as the Jython is much more effecient, but I suspect your issue will be network and the binding instead of the Rules code. Also, keep in mind that there are only two threads to run Timers so even if your approach worked, it would only work for two of the Google Homes and the rest would be out of sync.
The problem is that exactly that is not predictable.
The (each) say command is executed asynchronically, within it, the TTS service is called and the thread has to wait for that ( request via internet with unpredictable speed or via localhost to the cache), the audiosink might need to stop a task or not , openHAB has a thread for this task available ATM or not,…
My current solution to play a message / sound on ALL my google home devices is this:
say I have 4 google home devices.
I created one speaker group in google home app
I then created four audiogroup things in openhab. One for each of my google home device’s ip address like so:
Thing chromecast:audiogroup:gh_all_1 "All Google Home 1" [ ipAddress="192.168.1.200", port=42351 ]
Thing chromecast:audiogroup:gh_all_2 "All Google Home 2" [ ipAddress="192.168.1.203", port=42351 ]
Thing chromecast:audiogroup:gh_all_3 "All Google Home 3" [ ipAddress="192.168.1.208", port=42351 ]
Thing chromecast:audiogroup:gh_all_4 "All Google Home 4" [ ipAddress="192.168.1.165", port=42351 ]
Note that all these 4 GH devices belong to the same Speaker group in google home app.
Then in my code to play, I loop through each of those things, and see which one is online, and play it on the first one that is online. Sorry I’m using jython but you could probably do the same using rulesdsl
for i in range(4):
chromecast_uid = "chromecast:audiogroup:gh_all_{}".format(i+1)
if things.get(ThingUID(chromecast_uid)).status.toString() == "ONLINE":
Audio.playSound(chromecast_uid, "defaultdoorbell.mp3")
break
I do have one question, slightly off topic. I hope @rlkoshak or someone else could help. Note in my code above, I converted the things.get().status to string and comparing it to the string “ONLINE”. Is there a way to not convert it to string and compare it to just a constant ONLINE in a similar manner we do with item status e.g. items.SwitchItemName == ON ?