Say function doesn't return any execution status

Because of some reasons GoogleTTS doesn’t work properly on first run with specific phrase. Second run is usually ok and appropriate communication is established and voice file for say function is accessible.

To address this problem (and any other problems with communication with service and give a chance to retry say action) I’ve wrote lambda:

val saySomething = [ String ttsMessage |
    logInfo("lambda", ttsMessage)
    var boolean googleSuccess = false

    var i = 0
    while((i=i+1) <= 3 && !googleSuccess) {
      logInfo("Say info", "{} - familyroom - attempt {}", ttsMessage, i)
      try {
        say (ttsMessage, "googletts:enUSStandardA", "chromecast:chromecast:familyroom")
        logInfo("Say error", "{} - familyroom - attempt {} - after say", ttsMessage, i)
        googleSuccess = true
      } catch (Throwable e) {
        logError("Say error", "{} - familyroom - attempt {}", ttsMessage, i)
      }
    }

    if (googleSuccess) {
      logInfo("Say info", "{} - bedroom - attempt {}", ttsMessage, 1)
      say (ttsMessage, "googletts:enUSStandardA", "chromecast:chromecast:bedroom")
    }
    "executed"
]


with excecution in rule:

saySomething.apply("Hello world")

Unfortunately say() function does not return any value (explicit: it is void function) and exception. In case of error WARN messages are present in log, however any exception is not thrown.

In my lambda ‘after say’ log is always present. I have no chance to detect wrong call and retry.

Is any workaround possible? In my opinion proper exception should be thrown.

You might ask for an enhancement to say(), to get a return value. Trouble is that would become ‘blocking’ - how long should it wait to see if it gets a response from the remote service?
It could be made to work like executeCommandLine() perhaps, with an optional timeout. Provide a timeout to get the response (or failure).

I wrote workaround:

  val saySomething = [ String ttsMessage |
    var boolean googleSuccess = false

    var i = 0
    while((i=i+1) <= 3 && !googleSuccess) {
      logInfo("Say info", "{} - bedroom - attempt {}", ttsMessage, i)
      try {
        say (ttsMessage, "googletts:enUSStandardA", "chromecast:chromecast:bedroom")
        var String result = executeCommandLine (Duration.ofSeconds(10), "/openhab/conf/scripts/GOOGLETTS/detect_error.sh", ttsMessage)
        if (result.contains("GoogleOK")) {
          googleSuccess = true
        }
      } catch (Throwable e) {
        logError("Say error", "{} - bedroom - attempt {}", ttsMessage, i)
      }
    }

    if (googleSuccess) {
      logInfo("Say info", "{} - familyroom - attempt {}", ttsMessage, 1)
      say (ttsMessage, "googletts:plPLStandardA", "chromecast:chromecast:familyroom")
    }
    "executed"
]

To detect GoogleTTS errors (/openhab/conf/scripts/GOOGLETTS/detect_error.sh):

#!/bin/bash +e

PHRASE=$@
cat /openhab/userdata/logs/openhab.log | grep -i "Error saying" | tail -n 1 | grep "$PHRASE"
RET_VAL=$?
if [[ "$RET_VAL" == "0" ]]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') GoogleError - \"$PHRASE\"" | tee -a /openhab/userdata/logs/openhab.log
    echo "$(date '+%Y-%m-%d %H:%M:%S') error saying - reset error indicator" | tee -a /openhab/userdata/logs/openhab.log
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') GoogleOK - \"$PHRASE\"" | tee -a /openhab/userdata/logs/openhab.log
fi

Depends of installation type log path and script path have to be set properly. Not perfect, but works.

Yet another problem with GoogleTTS and yet another workaround:

Problem statement: After migration to 3.4 and refreshing Google configuration OH started to have problems with configuration:

2022-12-30 20:04:01.801 [WARN ] [core.voice.internal.VoiceManagerImpl] - Error saying 'Hello World': Missing service configuration.

This problem happens after some time after successful execution.

Solution (workaround):

  1. Move GoogleTTS configuration into file (described in documentation)
  2. Effectively change configuration (change one of configuration keys) in case of error detected
  3. After configuration change OH refresh TTS configuration and GoogleTTS starts to work again (for some time).

Scripts:

  1. Rule
  val saySomething = [ String ttsMessage, String voice |
    var boolean googleSuccess = false

    var i = 0
    while((i=i+1) <= 3 && !googleSuccess) {
      logInfo("Say info", "{} - bedroom - attempt {}", ttsMessage, i)
      try {
        logInfo("Say info", "------ SAY_START ------")
        say (ttsMessage, voice, "chromecast:chromecast:bedroom")
        var String result = executeCommandLine (Duration.ofSeconds(10), "/openhab/conf/scripts/GOOGLETTS/detect_error.sh", ttsMessage)
        if (result.contains("GoogleOK")) {
          googleSuccess = true
        }
      } catch (Throwable e) {
        logError("Say error", "{} - bedroom - attempt {}", ttsMessage, i)
      } finally {
        logInfo("Say info", "------ SAY_STOP  ------")
      }
    }
    "executed"
]

  1. Bash script:
#!/bin/bash +e

PHRASE=$@

LINE_START=$(cat /openhab/userdata/logs/openhab.log | grep -n "SAY_START" | tail -n 1 | awk -F: '{ print$1 }')
echo "$(date '+%Y-%m-%d %H:%M:%S') GoogleTTS check - Line start: $LINE_START" | tee -a /openhab/userdata/logs/openhab.log

LINE_ERROR=$(cat /openhab/userdata/logs/openhab.log | grep -n "Error saying" | tail -n 1 | awk -F: '{ print$1 }')
echo "$(date '+%Y-%m-%d %H:%M:%S') GoogleTTS check - Line error: $LINE_ERROR" | tee -a /openhab/userdata/logs/openhab.log
if [[ "$LINE_ERROR" == "" ]]; then
    LINE_ERROR=0
fi

LINE_MISMATCH_SERVICE=$(cat /openhab/userdata/logs/openhab.log | grep -n "Missing service configuration" | tail -n 1 | awk -F: '{ print$1 }')
echo "$(date '+%Y-%m-%d %H:%M:%S') GoogleTTS check - Line mismatch: $LINE_MISMATCH_SERVICE" | tee -a /openhab/userdata/logs/openhab.log
if [[ "$LINE_MISMATCH_SERVICE" == "" ]]; then
    LINE_MISMATCH_SERVICE=0
fi

if [[ $LINE_ERROR -gt $LINE_START ]]; then
    ERROR_SAY="true"
fi

if [[ $LINE_MISMATCH_SERVICE -gt $LINE_START ]]; then
    ERROR_CONF="true"
fi

if [[ "$ERROR_CONF" == "true" ]]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') GoogleTTS check - Missing configuration detected" | tee -a /openhab/userdata/logs/openhab.log
    # Effectively change googletts key pitch 0<->1
    cat /openhab/conf/services/googletts.cfg | grep -i "pitch=0"
    PITCH=$?
    if [[ "$PITCH" == "0" ]]; then
        sed -i -r 's/^org.openhab.voice.googletts:pitch=.*/org.openhab.voice.googletts:pitch=1/g' /openhab/conf/services/googletts.cfg
        echo "$(date '+%Y-%m-%d %H:%M:%S') GoogleTTS check - pitch to 1" | tee -a /openhab/userdata/logs/openhab.log
    else
        sed -i -r 's/^org.openhab.voice.googletts:pitch=.*/org.openhab.voice.googletts:pitch=0/g' /openhab/conf/services/googletts.cfg
        echo "$(date '+%Y-%m-%d %H:%M:%S') GoogleTTS check - pitch to 0" | tee -a /openhab/userdata/logs/openhab.log
    fi
    sleep 2
fi

if [[ "$ERROR_SAY" == "true" ]] || [[ "$ERROR_CONF" == "true" ]]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') GoogleTTS check - GoogleError - \"$PHRASE\"" | tee -a /openhab/userdata/logs/openhab.log
    echo "$(date '+%Y-%m-%d %H:%M:%S') GoogleTTS check - Error saying - reset error indicator" | tee -a /openhab/userdata/logs/openhab.log
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') GoogleTTS check - GoogleOK - \"$PHRASE\"" | tee -a /openhab/userdata/logs/openhab.log
fi

Not elegant but works. Hope it help someone.

Definitely something is wrong in OH GoogleTTS configuration (releasing configuration after some time).