[RELEASE] Text to Alexa, "Tell me a joke","did Chelsea win?" or any question

This function allows you to send commands to alexa service , and you can hear the audio in your speakers, you dont need to have an echo or even an amazon account, just to use this app.

You can ask something like “Tell me a joke” , “What’s the weather in New York?”,“when do the Seattle Storm play next?”, or any question you like

T answer going to play in the speaker you have selected

This is in a beta stage, but works great

You can use this too to send messages like “the door it’s open”, “Time to sleep” or any sentence you want, alexa can repeat if you send the command “Alexa, Simon says, your sentence”, you must to just add a #s = “Alexa, Simon says”.

When you ask, you no need to write Alexa, just the question, “Tell me a joke” or if you want Alexa repeat just “#s the mail has arrived”

I have used the Media renderer events app to launch the events to ask to alexa, I known it’s not the better app for alexa, but, I already have it

Like a command it’s different from a message I have to use a wildcard #s to known if its a speeach command. the #s add the text “Alexa, Simon says” and its removed if you use other tts engine like ivona or smartThings, the #s works to to know if its a time sentence or no time answerd.

The answer form alexa can be large or short , I can’t known , then if you send a command to Alexa the player can not restore the song if some music is playing before the answer, but if you send a #s speech, the music can be restored because the time can be calculated

I plan to use the music service to launch music to the speakers form tune in and other sources, but amazon use other system to achieve that and need tom work more.

now this is made from a global account, but I’m working to you can set your own device and can control personal preferences.

The app ask for an api key , this key it’s just to avoid abuse request, now its disabled, you can write any

If you like this project, please consider a donation to support it, thanks donation

4 Likes

How do I set this up as when I download and install the app it is just asking me questions as if it is a usual text to speech smartapp.

Hi @Rigi03.

Yes , it´s basically a text to speech, but Alexa answer your questions,

  1. In message write “Tell me a joke”
  2. In tts settings select Alexa
  3. select your Speaker
  4. select your trigger

each time your event occurs, alexa will tell you a joke or answer any question you write.

you can press the play button next to the name of the smartapp to trigger the event, easy way to test

finish.

works fine as described.
but it is useless if we can’t find a way to pass the message to the app through a speech recognition method.

could it be possible to pass a speech to text message from an Android app (like Autovoice) to your smart app with the help of Tasker ?

Tasker can call a ST “thing” with parameters with the help of SharpTools
For example you can call a speaker from Tasker with a “speak” command and any text attribute.
So if you can write a device handler with speak capability and get text as parameter, then transfer this text to your Alexa app ? maybe ?

1 Like

I’ve tried to write a device handler which would handle text received with speak command and send it to Alexa to play on Sonos speaker.
I’d appreciate if you can check :

/** 
 *  Alexa Simulator
 *
 */

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException; 

preferences {
		section {
			input "sonos", "capability.musicPlayer", title: "On this Speaker", required: true,multiple:true
			input "alexaApiKey", "text", title: "Alexa Access Key", defaultValue:"millave"
		}
}
metadata {
	// Automatically generated. Make future change here.
	definition (name: "Alexa Device", namespace: "alexa", author: "ooo") {
		capability "Speech Synthesis"
	
		command "speak", ["string"]
	}

	// Main
	standardTile("main", "device.status", width: 1, height: 1, canChangeIcon: true) {
		state "playing", label:'Playing', action:"music Player.stop", icon:"st.Electronics.electronics16", nextState:"paused", backgroundColor:"#79b821"
		state "stopped", label:'Stopped', action:"music Player.play", icon:"st.Electronics.electronics16", backgroundColor:"#ffffff"
		state "paused", label:'Paused', action:"music Player.play", icon:"st.Electronics.electronics16", nextState:"playing", backgroundColor:"#ffffff"
		state "no_media_present", label:'No Media', icon:"st.Electronics.electronics16", backgroundColor:"#ffffff"
        state "no_device_present", label:'No Present', icon:"st.Electronics.electronics16", backgroundColor:"#b6b6b4"
		state "grouped", label:'Grouped', icon:"st.Electronics.electronics16", backgroundColor:"#ffffff"
	}

	standardTile("status", "device.status", width: 1, height: 1, decoration: "flat", canChangeIcon: true) {
		state "playing", label:'Playing', action:"music Player.stop", icon:"st.Electronics.electronics16", nextState:"paused", backgroundColor:"#ffffff"
		state "stopped", label:'Stopped', action:"music Player.play", icon:"st.Electronics.electronics16", nextState:"playing", backgroundColor:"#ffffff"
		state "no_media_present", label:'No Media', icon:"st.Electronics.electronics16", backgroundColor:"#ffffff"
		state "no_device_present", label:'No Present', icon:"st.Electronics.electronics16", backgroundColor:"#ffffff"
		state "paused", label:'Paused', action:"music Player.play", icon:"st.Electronics.electronics16", nextState:"playing", backgroundColor:"#ffffff"
	}

	valueTile("currentSong", "device.trackDescription", inactiveLabel: true, height:1, width:3, decoration: "flat") {
		state "default", label:'${currentValue}', backgroundColor:"#ffffff"
	}

	
	standardTile("refreshPlayer", "device.status", inactiveLabel: false, decoration: "flat") {
		state "default", label:"", action:"refresh", icon:"st.secondary.refresh", backgroundColor:"#ffffff"
	}

	main "main"

	details([
		"status","refreshPlayer"
	])
}


def installed() {
	sendEvent(name:"model",value:getDataValue("model"),isStateChange:true)
}



def timer(){
    def eventTime = new Date().time
	state.gapTime = refreshFrequency > 0 ? (refreshFrequency? (refreshFrequency as Integer):0) * 60  : (parent.refreshMRInterval? (parent.refreshMRInterval as Integer):0) * 60 
    if ((state.lastRefreshTime ?:0) + (state.lastChange ? state.gapTime * 1000 : 300000)  <=  eventTime ){
    	refresh()
    }
}
def refresh() {
    def eventTime = new Date().time

    if( eventTime > state.secureEventTime ?:0)
    {
        if ((state.lastRefreshTime ?: 0) > (state.lastStatusTime ?:0)){
            sendEvent(name: "status", value: "no_device_present", data: "no_device_present", displayed: false)
        }
        state.lastRefreshTime = eventTime
        log.trace "Refresh()"
        def result = []
        //result << unsubscribe()
        //result << delayAction(10000)
        result << subscribe()
        result << getCurrentStatus()
        result << getVolume()
        result << getPlayMode()
        result << getCurrentMedia() 
        result.flatten()
    }else{
        log.trace "Refresh skipped"
    }

}

def speak(String msg){
	//log.debug ("ALEXA: " + msg)
	  def speech
      speech = safeTextToSpeech(normalizeMessage(message,evt))
      sonos.playTrack(speech.uri)
}
				
def normalizeMessage(message, evt){
	if (evt && message){
        message = message.replace("#name", evt?.displayName?:"") 
        message = message.replace("#type", evt?.name?:"")
        message = message.replace("#value", evt?.value?:"") 
    }
    if (message){
    	message = message.replace("#mode", location.mode)
    	message = message.replace("#location", location.name)
        message = message.replace("#s", ttsMode == "Alexa" ? "Alexa, Simon says":"")

    }
return message
}


private safeTextToSpeech(message) {
	message = message?:"You selected the Text to Speach Function but did not enter a Message"
   	[uri: "x-rincon-mp3radio://tts.freeoda.com/alexa.php/" + "?key=$alexaApiKey&text=" + URLEncoder.encode(message, "UTF-8").replaceAll(/\+/,'%20') +"&sf=//s3.amazonaws.com/smartapp-" , duration: "${5 + Math.max(Math.round(message.length()/12),2)}"]
}  

How would I set this up and use this

unfortunately I’ve learnt the hard way that a device can not call another device.

How can I handle this ?
I know that I need a smartapp between devices now but how can I write a basic smart app to read the attribute of speak command from this device ?

ok. issue solved. now I have a device handler and an app for this purpose. See below if anyone would like to use:

Alexa-Sonos Binder

/** 
 *  Alexa Device  Sonos Binder
 *
 *  Receives speak command from Alexa Device and sends to Alexa for TTS process
 *  Result will be sent to your Sonos speaker selected on the Alexa Device Sonos Binder app
 *
 *  Author: SmartThings - ilker Aktuna
 *
 */
 
import java.util.regex.*
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException; 

definition(
	name: "Alexa Device Sonos Binder",
	namespace: "Alexa",
	author: "ilker Aktuna",
	description: "Get text from Alexa device , process TTS and send URI to Sonos Speaker.",
	category: "Convenience",
    iconUrl: "https://raw.githubusercontent.com/MichaelStruck/SmartThings/master/Other-SmartApps/AlexaHelper/Alexa.png",
    iconX2Url: "https://raw.githubusercontent.com/MichaelStruck/SmartThings/master/Other-SmartApps/AlexaHelper/Alexa@2x.png",
    iconX3Url: "https://raw.githubusercontent.com/MichaelStruck/SmartThings/master/Other-SmartApps/AlexaHelper/Alexa@2x.png"
)

preferences {
	page(name: "mainPage", title: "Bind your Sonos Speaker to your Alexa Device Switch", install: true, uninstall: true)
}

def mainPage() {
	dynamicPage(name: "mainPage") {
        section("Control these bulbs...") {
			input "mySwitch", "capability.switch", title: "Alexa Device Turned On", required: false, multiple: true
			input "sonos", "capability.musicPlayer", title: "On this Speaker", required: true,multiple:true
			input "alexaApiKey", "text", title: "Alexa Access Key", defaultValue:"millave"
		}
	}
}

def installed() {
	log.debug "Installed with settings: ${settings}"
	subscribeToEvents()
}

def updated() {
	log.debug "Updated with settings: ${settings}"
	unsubscribe()
	unschedule()
	subscribeToEvents()
}

def subscribeToEvents() {
	subscribe(mySwitch, "switch.on", eventHandlerOn)
	subscribe(mySwitch, "switch.off", eventHandlerOff)
}

def eventHandlerOn(evt) {
	speak(mySwitch.currentMsgtxt)
}

def speak(String msg){
	  def speech
      def uri
      speech = safeTextToSpeech(normalizeMessage(msg))
      log.debug ("URI:" + speech.uri)
      sonos.each {
        //it.playTrack(speech.uri)
        //it.playTrackAndResume(speech.uri)
        it.playTrackAndRestore(speech.uri, speech.duration * 2 , null)
        }
      //sonos.playTrack(speech.uri)
}

def eventHandlerOff(evt) {
	  sonos.each {
        it.stop()
      }
}
				
def normalizeMessage(message){
    if (message){
    	message = message.replace("#mode", location.mode)
    	message = message.replace("#location", location.name)
        message = message.replace("#s", ttsMode == "Alexa" ? "Alexa, Simon says":"")

    }
return message
}


private safeTextToSpeech(message) {
message = message?:"You selected the Text to Speech Function but did not enter a Message"
   	[uri: "x-rincon-mp3radio://tts.freeoda.com/alexa.php/" + "?key=$alexaApiKey&text=" + URLEncoder.encode(message, "UTF-8").replaceAll(/\+/,'%20') +"&sf=//s3.amazonaws.com/smartapp-" , duration: "${5 + Math.max(Math.round(message.length()/12),2)}"]
}  

Virtual Alexa Device:

/** 
 *  Alexa Device Virtual
 *
 *  Send speak command to this device from your Android phone using Tasker & SharpTools and turn its switch on
 *  Using the Alexa Device Sonos Binder you can get the text from this device and send to Alexa for TTS process
 *  Result will be sent to your Sonos speaker selected on the Alexa Device Sonos Binder app
 *
 *  Author: SmartThings - ilker Aktuna
 *
 */

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException; 

preferences {
		section {
			input "sonos", "capability.musicPlayer", title: "On this Speaker", required: true,multiple:true
			input "alexaApiKey", "text", title: "Alexa Access Key", defaultValue:"millave"
		}
}
metadata {
	definition (name: "Alexa Device", namespace: "Alexa", author: "ilker Aktuna") {
		capability "Speech Synthesis"
		capability "Switch"
	
    	attribute "msgtxt", "string"

		command "speak", ["string"]
	}

	standardTile("refreshPlayer", "device.status", inactiveLabel: false, decoration: "flat") {
		state "default", label:"", action:"refresh", icon:"st.secondary.refresh", backgroundColor:"#ffffff"
	}

    valueTile("msgText", "device.msgtxt", inactiveLabel: false, decoration: "flat", width: 3, height:2) {
            state "default", label:'${currentValue}'
	}
        standardTile("on", "device.switch", inactiveLabel: false, decoration: "flat") {
			state "default", label:'on', action:"switch.on", icon:"st.Electronics.electronics16"
		}
		standardTile("off", "device.switch", inactiveLabel: false, decoration: "flat") {
			state "default", label:'off', action:"switch.off", icon:"st.Electronics.electronics16"
		}
        
	main "refreshPlayer"

	details([
		"on","off","refreshPlayer",
        "msgText"
	])
}


def installed() {
}

def on() {
	sendEvent(name: "switch", value: "on",isStateChange: true)
}

def off() {
	sendEvent(name: "switch", value: "off",isStateChange: true)
}

def timer(){
    def eventTime = new Date().time
	state.gapTime = refreshFrequency > 0 ? (refreshFrequency? (refreshFrequency as Integer):0) * 60  : (parent.refreshMRInterval? (parent.refreshMRInterval as Integer):0) * 60 
    if ((state.lastRefreshTime ?:0) + (state.lastChange ? state.gapTime * 1000 : 300000)  <=  eventTime ){
    	refresh()
    }
}
def refresh() {
    def eventTime = new Date().time

    if( eventTime > state.secureEventTime ?:0)
    {
        state.lastRefreshTime = eventTime
        log.trace "Refresh()"
        def result = []
        result << subscribe()
        result << getCurrentStatus()
        result << getVolume()
        result << getPlayMode()
        result << getCurrentMedia() 
        result.flatten()
    }else{
        log.trace "Refresh skipped"
    }

}

def speak(String msg){
      sendEvent (name: "msgtxt", value:msg) 
}

Hi
Great job but what about iOS users

I don’t know even if iOS has something like Tasker, or even SharpTools ?
if they exist, it is pretty simple to integrate.

how do you get an Alexa API key ?
I want to access my own alexa setup so that I can integrate ST devices with Alexa.
How can I do that ? (without an Echo)

For iOS there may be a different but also very interesting solution when connecting this to Homebridge and virtual switches.This can be used for standard questions that have different responses dependent on time (e.g. weather, traffice).

Here is an example:

  • set up a homebridge/homekit scene “Alexa What is the weather today” as a Siri command that activates a virtual “Alexa weather” switch.
  • Turning on the “Alexa weather” switch will trigger sending a “What is the weather today” message to Alexa
  • Alexa will return the weather forecast through the speaker.

Hi @pizzinini, just you need to add a city to check the weather, like “What is the weather in New York”, now its in a general account, but its in beta stage, the next step its to customize the account, to allow personal setting. and of course a voice method. wait for news soon.

Ok, I’m confused. Do I have to use tasker to make this work? I installed the Sonos binder and app, But I’m not sure what to do next.

Hi @bamarayne, You just need to have a speaker working with smartthings and install this app.

Ok, I have a speaker set up. Which smart app? The one at the top of the thread?

Ok, I guess I’m confusing how this works.

I have several Alexa devices in my home. I also have several speakers setup with ST.

I want to say to Alexa, “tell the boys to come down for dinner”

And that plays on the speakers.

Am I able to do that with this application?

HI @bamarayne , yes, in short time I will publish other smartapps

Ok, so, I installed the Sonos binder and the Alexa virtual device.

Do I now just talk to Alexa and she plays it on the speakers?