VoiceRSS and Sonos

Hello guys,

i hope there is somebody out there that can help me.
I am using OpenHAB 2.2.0.008-SNAPSHOT on my Synology with DSM 5.2.

I want to push notification to my sonos speakers.

What I Did so far:

  • installed the Sonos binding and checked that it is working
  • installed VoiceRSS TTS Service
  • created an account at http://www.voicerss.org/
  • put the api Key in the config (voicerss.cfg at conf\services) AND in the PaperUI at Configuration, Services (just to be sure)
  • configurated Voice Service at PaperUI - Configuration - System to use VoiceRSS and set Language to “de”

For my understanding that was everything to do for using VoiceRSS with OpenHAB.

My Item file looks like this:

//Sonos
String Speech_Out   "Speech Out"
Switch wz_sonos_play_uri_switch "Sonos WZ Welcome" (Wohnzimmer,Multimedia) {channel="sonos:One:RINCON_XXXXXXXXXXXXXXXXXXX:playuri"}
String wz_sonos_play_uri "Sonos WZ Welcome" (Wohnzimmer,Multimedia) {channel="sonos:One:RINCON_XXXXXXXXXXXXXXXX:playuri"}

rule "Sonos play uri"
when
	Item wz_sonos_play_uri_switch changed to ON
then
     sendCommand(Speech_Out.state.toString, 'zweiter test')
     say(Speech_Out.state.toString,"voicerss:deDE","sonos:One:RINCON_XXXXXXXXXXXXX")
//'http://stream01.iloveradio.de/iloveradio9.mp3' - this is working!      

end

My Sonos Speaker just says “NULL”.

At least there are some files (mp3 and txt) created at /openHAB2/userdata/voicerss/cache/
But the content of the txt file is also NULL. So i assumed a problem with the VoiceRSS service. But i tried "http://api.voicerss.org/?key=APIKEY&hl=de-de&src=Hallo!") to be sure it is working with my API Key, and it worked.

In addition to that i tried to play some mp3 radio streaming url. this worked too.

So VoiceRSS is working and streaming to Sonos is working, but its not working when trying to do it together with openhab.

I also tried Googles TTS with this Rule:

rule "Sonos play uri"
when
	Item wz_sonos_play_uri_switch changed to ON
then
	val speech = "Hello. This is a test"
	val url = "x-rincon-mp3radio://translate.google.com/translate_tts?tl=de&q=\"" + speech + "\"&client=OpenHAB"
	logInfo("Sonos Say URI","Link: " + url)
	sendCommand(wz_sonos_play_uri, url)
end

this one wokred 2-3 times. but then nothing. (no connection to TTS system anymore)

Is there anybody out there who got any idea?

Regards,

Tidle

1 Like

I use Sonos with VoiceRSS.
Using the sendCommand just before the say command is probably the reason. The item isn’t updated when the say command is referring to its state. Why don’t you use the string directly in the say command.
Your audio sink and VoiceRSS setup seems to be correct otherwise you wouldn’t hear the “Null”.

2 Likes

thank you for your answer! :slight_smile:

can you tell me how you implement it? i do not know what you mean…

you mean like this

say("Hello World","voicerss:deDE","sonos:One:RINCON_XXXXXXXXXXXXX")

But i want to do it with a variable to be more flexible.

regards

1 Like

Look in here (Sonos ... Audio Sink ... Say?) for the rule I’m using. The controls are on a habpanel (a text box for the text, a selection list for the audio sinks and a button the start it).

1 Like

okay, but isnt your command:

say(SayCommand.state.toString,"voicerss:deDE",AudioSink)

the same like mine:

sendCommand(Speech_Out.state.toString, 'zweiter test')
     say(Speech_Out.state.toString,"voicerss:deDE","sonos:One:RINCON_XXXXXXXXXXXXX")

but that your input comes from a textbox instead from a var within an rule?

my error is a little bit different now. (without changing anything) when i restart openhab and run the rule i see the files created in the voicerss cache directory. but every other run from the rule does not result in new files (even when i change the text for tts).
here a picture of my designer, because it always tells me say is undefinied.


what is going on here? ^^

Yes, the actual say command is the same as yours, however my item gets set via a GUI and NOT using a sendCommand within the rule (that command takes time and since it is run in a different thread it might not be ready yet. Hence your observed “Null”).
The new behaviour you see needs to be clearified. I would have expect that an old text would have been used (and therefor not crwate a new file). Try to put a logInfo between the sendCommand and say in order to get a feedback of the actual state.
However I see no reason for setting a new state to an item within a rule and use that state afterwards for the say command. Whatever you set the item.state to you can directly hand to the say command.

The designer is known for such false reprts!

okay, you definitely point me to the right direction.
i tried to use your habcontrol construct and it was working fine.
so i was looking for a different method to update my string and found this on which works fine:

Speech_Out.postUpdate('Was fĂĽr ein SpaĂź!')
say(Speech_Out.state.toString,"voicerss:deDE","sonos:One:RINCON_XXXXXXXXXXXXX")

Thank you for your help! =)

there is only one open point:
when i am playing music or whatever on my sonos speaker and openhab sends a notification the music is not resuming after the notification. is there a way to do that?

Hmm???
I haven’t used it recently, but during the test it was working that way.
Which binding for Sonos are you using? I’m on OH 2 1 Stable release
Which music source are you using?

Haha. You are right. I restarted my server once more and now everything is working like expected. Thank you! :slight_smile:

1 Like

You’re welcome.

The fun starts when are using that from somewhere else (via VPN for example). Imagine you have (known) visitors in your house while you are away and suddenly they are greeted by something like “You are welcome, but please clean up before you leave!”

1 Like

Hello all,

i am trying to get running voiceRSS with my sonos… but i get no sound out of it!
i am triggering a rule when my sonos is starting due to the morning Sonos-timer and the log info is working well. but i get no sound out of it!
It only plays the radio station which is configured in the sonos timer…

rule “GutenMorgen”

when 
  Item SonosP4Office_Controller changed from UNDEF to PLAY
then
  var String AudioSink
  AudioSink="sonos:PLAY1:RINCON_7828CA9F7B2201400"
  var String SayCommand 
  SayCommand="Guten Morgen. Heute ist der " + CurrentDateStr.state.format("%1$td.%1$tm.%1$tY") + ". Die Sonne geht heute um  " + san_agustin_Sunset_Time.state.format("%1$tH") + " Uhr " + san_agustin_Sunset_Time.state.format("%1$tM") + " Minuten unter."
  logInfo("SayCommand", "SayCommand: {}",SayCommand)
  say(SayCommand,"voicerss:deDE",AudioSink)

end

i also was looking for the libs i have to import:

import org.openhab.voice.voicerss.tool.CreateTTSCache
import org.eclipse.smarthome.core.voice.Voice
import org.eclipse.smarthome.core.voice.TTSService
import org.openhab.voice.voicerss.internal.cloudapi.CachedVoiceRSSCloudImplementation
import org.eclipse.smarthome.voice

for sure in have configured openhab … api key in voicerss.cfg config file… and in paper ui i put rule-based interpreter… hope that is correct.
but further i have no idea….

hope to find help here… i am using openhab 2.4 in docker (on a qnap nas) - all working fine…

saludos,

Olly

Imports are not needed!
Did you set the volume for the notification sound? That is not the normalvolume! It is set in the configuration of the thing.
Did you configure VoiceRSS correctly? You should have the created soundfile in the cache (can’t say the exact location ATM).

Hi Jürgen (ok in english for the other members…),

the voicerss file i have in the folder voicerss/cache.
the notificacion volume… dont know how to set correctly… tried this now

val Number NotificationVolume = 20
SonosP4Office_NotVolume.postUpdate(NotificationVolume)
logInfo(“IntialNotificationVolumeSetting”,“NotificationVolume set!”)

i also set the notificacion Volume via paperui for that sonos player

That’s what I meant with “configuration”.

Since your from Germany as well there might be another problem. The played radio station will only be muted if it is played via TuneIn!
If it was started via an echo-device it might be played directly via the “ARD Mediathek”.
In this case the binding does not notice it correctly.

Please check if you can play a notification if nothing is played.

Hi JĂĽrgen,
ok i got it running! my radio station via tunel stops when playing the notification.
now i face the next problems: the correct triggering and rule implementation!
i use the sonos alarm to wake up with our famous station FFN :slight_smile: and

when
Item SonosP4Schlafzimmer_Controller changed from UNDEF to PLAY
then… the creation and playing of the notification should take place!
but i have some faults in it i think…
i am trying to make this rule variable, so that it is checking all devices… that it doesnt matter where is the alarm… and on every alarm playing the notificaion or also an individual regarding the room/the sonos device…
might it be good to make a good morning rule for every sonos device / sleeping room separate ?
i have to check how rules are working…if f.ex. filling the string saycommand within a rule… is it possible that another rule is checking this and on change of the string it please it ?
for sure lots of people already have such a solution… i want to say the date of the day, the actual temperature and the time when sun is going down. in future i am planing to integrate a calender api, so that i can get the daily events from that calender which will be said in the notificacion… nice idea… but lots of problems i guess.

so for any hint i am glad,

kind regards,

oliver

At least on this forum not that many!
There are users that use notifications BUT such a complex rule , I don’t think so!

One rule calling another rule, for such look into Lambdas

That sounds like the “daily announcement” from an Echo device, which kind of Sonos Players do you have? The newer Play:One with an Echo?
All of that is possible, but the text might get to long for VoiceRSS (have to look it up). Personally I would like to SEE most of that information somehow (Magic mirror? )
I would start small, we got annoyed really quick by the talking, you might find the complete idea not so good in the end.

For any specific question on the rule-creation I’m/ we are standing by.

I have created my Rule similar to the one here. Only that I send a sendCommand to a URI item of my Sonos speaker instead of using say.

In the meantime, however, I have extended this so that I can use tts without Voice RSS. Maybe someone here is interested in the code. I use Jython and can access the gTTS library here. So that I have a URI, I save a MP3 file in the html directory of the openHAB configuration.

My code looks like this:

import os
from gtts import gTTS
from org.python.core.util import StringUtil
from core.rules import rule
from core.triggers import when
from core.actions import LogAction

@rule("Text-to-Speech Rule")
@when("Item tts_buffer changed")
def text_to_speech(event):
    text = str(ir.getItem("tts_buffer").state)
    mp3_path = "/etc/openhab3/html/tts/tts.mp3"

    if os.path.exists(mp3_path):
        os.remove(mp3_path)

    ip_address = str(StringUtil.toUnicode(ir.get("SystemInformation_Item_IPAddress")))
    language = "en"
    # language = "de"
    # language = "fr"

    try:
        tts = gTTS(text=text, lang=language, slow=False)
        tts.save(mp3_path)
    except Exceptions as e:
        LogAction.logError("Text-to-Speech Rule", "Error converting text to speech: {}".format(e))

    uri = "http://" + ip_address + "/static/tts/tts.mp3"
    events.sendCommand("sonos_play_uri_item", uri)

I like Jython because you can use the might of python in openhab rules.

My fault. Sorry. Using the gTTS-Library will automatically use a cloud connection to google cloud. But you can use pyttsx3 locally:

import os
import pyttsx3
from pydub import AudioSegment
from org.python.core.util import StringUtil
from core.rules import rule
from core.triggers import when
from core.actions import LogAction

def synthesize_text(text, output_path):
    engine = pyttsx3.init()
    temp_wav = output_path + "temp.wav"
    engine.save_to_file(text, temp_wav)
    engine.runAndWait()

    audio = AudioSegment.from_wav(temp_wav)

    audio.export(output_file + "tts.mp3", format="mp3")

@rule("Text-to-Speech Rule")
@when("Item tts_buffer changed")
def text_to_speech(event):
    text = str(ir.getItem("tts_buffer").state)
    mp3_path = "/etc/openhab3/html/tts/"

    if os.path.exists(mp3_path + "temp.wav"):
        os.remove(mp3_path + "temp.wav")

        if os.path.exists(mp3_path + "tts.mp3"):
            os.remove(mp3_path + "tts.mp3")

    ip_address = str(StringUtil.toUnicode(ir.get("SystemInformation_Item_IPAddress")))
    language = "en"
    # language = "de"
    # language = "fr"

    try:
        synthesize_text(text, mp3_path)
    except Exceptions as e:
        LogAction.logError("Text-to-Speech Rule", "Error converting text to speech: {}".format(e))

    uri = "http://" + ip_address + "/static/tts/tts.mp3"
    events.sendCommand("sonos_play_uri_item", uri)