[Tutorial] Random TTS responses via rules

This tutorial assumes you already have TTS set up. It will not teach you how to set up TTS. If you need assistance in that please search as there are topics on that or create a help thread.

Many thanks to @rlkoshak for helping develop these rules!!

Goal: The goal of this tutorial is to create a method so that random audio messages are played over TTS triggered by rules. The desire for this was to give my home automation system a little more personality instead of the same response every time. The pool of responses is supplied by you so that you can create your own style (proper, sassy, funny, technical, ect.).

Version: OH2
Hardware: Google Home (although another audio sink would work the same)
Bindings: VoiceRSS (or another TTS), Chromecast (for Google Home to act as an audio sink), Expire

There are two methods we will use. One method is to contain the pool of responses within the rule itself. This is helpful when the responses are tailored to the event that will be occurring. In my example, this rule turns on lights at sunset (Astro 2 binding is used in this example).

Rule:

import java.util.concurrent.ThreadLocalRandom;
 
rule "Lights on at Sunset"
when
    Channel 'astro:sun:local:set#event' triggered START
then
	if(LightsOnAtSunset.state==ON) {
		FrontDoorLight.sendCommand(ON)
		FrontDoorDecorations.sendCommand(ON)
		FoyerLanternLoadLevelStatus.sendCommand(30)
		switch ThreadLocalRandom::current().nextInt(0, 3+ 1): {
            case 0: say("I know you're afraid of the dark so here's some lights.")
            case 1: say("It's getting dark out so bring in the kids.")
            case 2: say("You want some lights, fine.  Grumble grumble grumble.")
            case 3: say("You know, there are physical switches installed in this house.")
        }
	}
	end

Note the number of cases. There are four total (starts with zero). You can add or subtract any number of messages you want. Your final number of cases must be randomized within the rule. This is done via the part “nextInt(0, 3+ 1)”. Your highest number of case must be where the “3” is. “+1” is added because nextInt is not inclusive of the integer (in this case 3). To make it inclusive you need to add one. For example, if you only had 3 cases (case 0, case 1, case 2) you would have “nextInt(0, 2+ 1)”.

The second method is to create a switch that activates a pool of responses. I use this method for general use, specifically giving voice commands through Google Home. Since it is used for a variety of commands it made more sense to create this once and activate it via a switch than to write them into every rule.

Item:

/* Play Random Response */
Switch RandomResponse "Random Response" {expire="2s,command=OFF"}

Note the Expire binding is used to return to switch to an OFF state.

Rule:

import java.util.concurrent.ThreadLocalRandom;

rule "Play Random Response"
when
	Item RandomResponse received command ON
then
	switch ThreadLocalRandom::current().nextInt(0, 5+ 1): {
            case 0: say("Your wish is my command.")
            case 1: say("You know, you could easily do this yourself.")
            case 2: say("I live to serve. Apparently")
            case 3: say("Just another day in my cold existence.")
            case 4: say("What master wants, master gets.")
            case 5: say("You only talk to me when you need something.")
            }
end

You may add the following to any rule to play a response from the above cases:

RandomResponse.sendCommand(ON)

The same condition applies to the previous method where you must adjust the nextInt command to match the number of cases you have (notice mine is adjusted to be “5+ 1”)

I hope this tutorial allows you to bring a little more personality to your system. I know I chuckle every time I ask “her” to do something and she gives me a snarky response. With this method it is easy to add or change the responses over time giving variety to your experience.

13 Likes

I like how you think :grin:

Love the idea !!

Great idea. Just implemented this (random daily wakeup call - except for Friday which is allays “TGIF” :wink: )
and there was one small problem: Designer complained about this line:
ThreadLocalRandom::current().nextInt(0, 3+ 1):
with "extraneous input ‘:’ expecting ‘{’"
removing the “:” solved the issue.
Cheers,
-OLI

nice stuff. What I don’t understand:

I thought whenever I say a command to GoogleHome, it will reply with a standard response.
Like me: OK google turn on the kitchen light
Google: Sure, I turn on the kitchen light.

Are you saying I can modify these kind of responses?

Stefan

Thanks for this great tip! I’m not sure why but my initial effort didn’t work:

import java.util.concurrent.ThreadLocalRandom;

rule "Alexa reminder CLOSE lolas door"

when
Item LolasRoomDoor_Contact changed from OPEN to CLOSED

then

switch ThreadLocalRandom::current().nextInt(0, 8+ 1):{
            case 0: OfficeBot_Remind.sendCommand("Please lock Lola's door.") 
            case 1: OfficeBot_Remind.sendCommand("Don't forget to lock Lola's door.") 
            case 2: OfficeBot_Remind.sendCommand("to lock Lola's door.") 
            case 3: OfficeBot_Remind.sendCommand("Please secure Lola's door.") 
            case 4: OfficeBot_Remind.sendCommand("Please make sure Lola's door has been locked.") 
            case 5: OfficeBot_Remind.sendCommand("Please make sure Lola's door is secure.") 
            case 6: OfficeBot_Remind.sendCommand("lola's door needs be kept locked.") 
            case 7: OfficeBot_Remind.sendCommand("Lola feels better when her door is locked.") 
            case 8: OfficeBot_Remind.sendCommand("Lola wants us to keep her door locked.") 
            case 9: OfficeBot_Remind.sendCommand("Lola prefers us to keep her door locked.")
            case 10: OfficeBot_Remind.sendCommand("Lola prefers her door locked.")
            case 11: OfficeBot_Remind.sendCommand("Lola wants her door locked.")
        }

logInfo("Smartthings", "Alexa reminder CLOSE lolas door reminder")


end

The error in the openhab.log was:

2018-05-08 20:01:27.763 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model ‘AlexaOfficeLolaDoorReminder.rules’ has errors, therefore ignoring it: [10,53]: extraneous input ‘:’ expecting ‘{’

The problem seemed to be the colon “:” in line 10

switch ThreadLocalRandom::current().nextInt(0, 8+ 1):{

and removing the colon didn’t help

switch ThreadLocalRandom::current().nextInt(0, 8+ 1){

But removing the colon and putting the bracket “{” on the next line worked right away:

import java.util.concurrent.ThreadLocalRandom;

rule "Alexa reminder CLOSE lolas door"

when
Item LolasRoomDoor_Contact changed from OPEN to CLOSED

then

switch ThreadLocalRandom::current().nextInt(0, 8+ 1)
        {
            case 0: OfficeBot_Remind.sendCommand("Please lock Lola's door.") 
            case 1: OfficeBot_Remind.sendCommand("Don't forget to lock Lola's door.") 
            case 2: OfficeBot_Remind.sendCommand("to lock Lola's door.") 
            case 3: OfficeBot_Remind.sendCommand("Please secure Lola's door.") 
            case 4: OfficeBot_Remind.sendCommand("Please make sure Lola's door has been locked.") 
            case 5: OfficeBot_Remind.sendCommand("Please make sure Lola's door is secure.") 
            case 6: OfficeBot_Remind.sendCommand("lola's door needs be kept locked.") 
            case 7: OfficeBot_Remind.sendCommand("Lola feels better when her door is locked.") 
            case 8: OfficeBot_Remind.sendCommand("Lola wants us to keep her door locked.") 
            case 9: OfficeBot_Remind.sendCommand("Lola prefers us to keep her door locked.")
            case 10: OfficeBot_Remind.sendCommand("Lola prefers her door locked.")
            case 11: OfficeBot_Remind.sendCommand("Lola wants her door locked.")
        }

logInfo("Smartthings", "Alexa reminder CLOSE lolas door reminder")


end

BTW: Lola is a green iguana, who we rescued at the humane society. Like a cat in a Thorndike box she’s figured out how to escape her enclosure.
If we don’t remember to lock her cage she gets out and could get hurt. But the reminder was so repetitive. Now the variations can be endless, almost.

Cool, was just about to ask how to do this and found this post… Works a treat!
For a laugh Alexa now says something random each time the fridge is opened :slight_smile: Won’t be long before I get told to disable it I’m sure!