Alexa - -Unsolicited TTS

So a little googling brought me across this github repository.

After a small amount of fuss I can confirm that I can trigger TTS directly on my alexa device with my pi.

Seems this is what everyone is looking for.

Device driver for Alexa TTS via Telnet

Device driver for sending tts text via http to the tts script.

/**
 *  Alexa HTTP speach device
 *
 *  
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 *  Change History:
 *
 *    Date        Who            What
 *    ----        ---            ----
 *    2018-09-01 Chris Wilson   Modified to speach device for alexa tts
 *    2018-02-18  Dan Ogorchock  Original Creation
 *
 * 
 */
metadata {
	definition (name: "HTTP Momentary ALEXA TTS Switch", namespace: "cw", author: "cwwilson08") {
      
        capability "Notification"
    	
    	capability "Speech Synthesis"
	}

	preferences {
		input(name: "deviceIP", type: "string", title:"Device IP Address", description: "Enter IP Address of your HTTP server", required: true, displayDuringSetup: true)
		input(name: "devicePort", type: "string", title:"Device Port", description: "Enter Port of your HTTP server (defaults to 80)", defaultValue: "80", required: false, displayDuringSetup: true)
		
		input(name: "deviceMethod", type: "enum", title: "POST, GET, or PUT", options: ["POST","GET","PUT"], defaultValue: "POST", required: true, displayDuringSetup: true)
	}
}

def parse(String description) {
	log.debug(description)
}

def push(message) {
    //toggle the switch to generate events for anything that is subscribed
    sendEvent(name: "switch", value: "on", isStateChange: true)
    runIn(1, toggleOff)
    //sendEvent(name: "switch", value: "off", isStateChange: true)
    runCmd(message, deviceMethod)
}





def speak(message) {
     runCmd(message, deviceMethod)
}

def runCmd(String message, String method) {
	def localDevicePort = (devicePort==null) ? "80" : devicePort
	def path = "/alexaspeak/" + message
	def body = "" 
	def headers = [:] 
    headers.put("HOST", "${deviceIP}:${localDevicePort}")
	headers.put("Content-Type", "application/x-www-form-urlencoded")

	try {
		def hubAction = new hubitat.device.HubAction(
			method: method,
			path: path,
			body: body,
			headers: headers
			)
		log.debug hubAction
		return hubAction
	}
	catch (Exception e) {
        log.debug "runCmd hit exception ${e} on ${hubAction}"
	}  
}

here is the flow I use for the alexa tts script

image
image.png771x276 13.1 KB

The node that passes the tts text to the alexa script

[image
image.png535x640 19.9 KB

](https://community.hubitat.com/uploads/default/original/2X/3/3f145ca872304baec9d5ed5f5e85222fd4746b5e.png)

2 Likes

I have to setup Home Assistant? That’s not a small amount of fuss :stuck_out_tongue_winking_eye:

1 Like

No I changed three lines. No HA needed.

I am going to see if I can get a driver working using telnet.

I think this is a game changer.

2 Likes

:sunglasses::grinning:

I can currently trigger directly from tasked using ssh. The script is just a .sh. If I can figure out how to make the telnet work, this should work for tts announcements from hubitat. There are many other options as well

3 Likes

So this is the only documentation I can seem to find on telnet from @bravenel

I am unable to make it work in a driver - go figure. Any kind soul out there who has an example of this action, or could help me.

Edit: Just locked my hub up pretty good trying this - I am definitely not the man for the job.

  1. I need to open telnet connection
  2. send a single command to execute a script - /opt/ha-alexa-tts-master/alexa_remote_control.sh -d "chris's Echo Dot" -e speak:This_actually_works
    3. close telnet connection.

Here you go:

This part goes in your initialization code, to open the telnet connection.

		//open telnet connection
		telnetConnect(ip, 23, "lutron", "integration")
		//give it a chance to start
		pauseExecution(1000)

That opens a telnet connection on port 23 of "ip", with login "lutron" and password "integration".

Use a method like this to send a message:

def sendMsg(String msg) {
	return new hubitat.device.HubAction(msg, hubitat.device.Protocol.TELNET)
}

Thanks for the assist @bravenel

However despite my best efforts I keep locking my hub trying this. I obviously do not know what I am doing enough to make this work. It was worth a shot though.

I will not wast any more of your time on it.

I am sure someone will come along with the know how who finds this useful enough to make it work eventually.

Have you tried this just directly via Telnet? That's what you need to do first, make sure you can connect via Telnet and manually type in that command.

Yes I have confirmed it works via the command line. I am even fairly sure I have managed to open the connection through hubitat. Just not exactly sure where to go from there - to get my command to send. After a few attempts the hub slows to a crawl and I have to reboot.

Again I am sure it is because I do not know how to properly write the code. LOL I save lives for a living - HA is what I do to annoy my wife on the weekends. I am a copy and paste kind of guy.

def sendMsg(String msg) {
	return new hubitat.device.HubAction(msg, hubitat.device.Protocol.TELNET)
}

image

where is "telnetclosed" coming from? Looks like an infinite loop, which would explain your hub crashing.

You could just post your driver code here, and we could see what you're doing. Harder to do it blind...

2 Likes

lol you do want me to embarass myself. what I have looks like this. At the moment if I try to access the device using this code it just spins and spins.

metadata {
    definition (name: "test alexa", namespace: "cw", author: "cwwilson08") {
        capability "Actuator"
        capability "Sensor"
        capability "Switch"
    }

    preferences {}

}  
telnetConnect("192.168.1.121", 23, "username", "password")
pauseExecution(1000)
def parse(String description) {
}

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

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

def installed() {
    off()
}

Looks like you forgot to add the capability "Telnet" at the top. I hope that isn't what is locking up your hub. If adding it in and the problem goes away, let us know and we can submit a bug on it and hopefully get that fixed.

Adding this capability did not change anything :frowning: . It seems anytime I try to add a line that includes telnet my hub gets pissed.

Move the three lines starting with telnetConnect to your installed method, and remove the off() from it. Why do you want to close the telnet connection? You can just leave it open. So you could remove the telnetClose() from off().

You need to add the sendMsg() method I showed above, or the guts of it, to your on() method (assuming you want to send the message when you turn on the "switch".

Try that. If you remove the device you create from this driver, that would close the telnet connection.

TBH I did not know if not doing something with the connection after opening it was causing my problems, so I figured why not try to close it. I was also just trying to figure out IF I was actually opening and closing connections. - Made sense to me at the time lol.

I think I am getting closer - I decided to try a much simpler command - as I cant seem to get the code to save with my command. I guess I will get to that later. I decided to simply send the date command. My code is below. I get the following error.

metadata {
    definition (name: "test alexa", namespace: "cw", author: "cwwilson08") {
        capability "Actuator"
        capability "Sensor"
        capability "Switch"
        capability "Telnet"
    }

    preferences {}

}  


def parse(String msg) {
}

def on() {
    sendEvent(name: "switch", value: "on", isStateChange: true)
    sendMsg("date") {
	return new hubitat.device.HubAction(msg, hubitat.device.Protocol.TELNET)
}
}

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

def installed() {
    telnetConnect("192.168.1.121", 23, "", "")
log.debug "openingconnection"
    pauseExecution(1000)

    
}

That's because you didn't put in the code for sendMsg().

Well it seems I am missing the painfully obvious. I fear I have put a large amount of time into something that should have been trivial. My wife is staring at me in annoyance so I must toss in the towel on this one.

@bravenel Thank you so much for your help - Sorry for the time wasted.

This is the latest I have tried - I am unable to paste in the entire command string I need to send due to errors, something likely needs to be escaped I suppose.

metadata {
    definition (name: "test alexa", namespace: "cw", author: "cwwilson08") {
        capability "Actuator"
        capability "Sensor"
        capability "Switch"
        capability "Telnet"
        
        command "sendMsg"
       
    }

    preferences {}

}  


def parse(String msg) {
}

def on() {
    sendEvent(name: "switch", value: "on", isStateChange: true)
}
def sendMsg() {
    log.debug "sending"
	return new hubitat.device.HubAction("/opt/ha-alexa-tts-master/alexa_remote_control.sh -e speak:This_actually_works", hubitat.device.Protocol.TELNET)
log.debug "sent"
}


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

def installed() {
    telnetConnect("192.168.1.121", 23, "username", "pass")
log.debug "openingconnection"
    pauseExecution(1000)

    
}

Have you tried the command manually via telnet? I saw earlier that you had manually tried the command, but was it specifically from telnet - rather than SSH or directly from the terminal on the device.