Alexa - -Unsolicited TTS

Hi,

I'm struggling to ge this to work with your Alexa HTTP switch, do you still need the -e speak:xxxx in the node-red command?

e.g.

"bash /home/pi/home-automation/alexatts/ha-alexa-tts/alexa_remote_control.sh -d "Living room echo" -e speak:"

the get node

the function node labelled test

the exec node

Brilliant! Thanks for sharing. This is working for me. Would you mind sharing your version of the shell script? I'm trying to figure out why I'm having the 10 second ish delay before the speech..

Thanks again!

I added the following line to the device code so that it would work with a string that has spaces in it..

message = message.replaceAll(' ','_')

Not that its helped with the delay I'm experiencing but I tried the _plain version of the script. This seems to log in consistently and re-pull the cookie reliably.. might be worth a try...

https://raw.githubusercontent.com/thorsten-gehrig/alexa-remote-control/master/alexa_remote_control_plain.sh

Sorry if I asked this already. What are you running the script on. Pi? Is it overloaded doing anything else?? Do you have another machine you can try with?

It's running on a pi, I'll try and run it on something else to see if that makes a difference..

Its worth a shot to try and rule out where the lag may be coming from.

So just checking in I have been playing with this script more and more.

Something that has not been mentioned here is the ability to trigger alexa automations and also some pretty good music control from your amazon library or tunein.

I have found both to be working well. Just wanted to share.

I have not an issue with a cookie in some time - I am having more and more fun with this.

1 Like

Have you shared your Driver for this integration? I would like to take a look at this again in the near future...

Or are you still using node-red?

Thanks.

Actually I used the code you posted to start with. It worked rather well. What I have is a mess currently as I have been playing and trying to figure out the best way to poll for connection status because if my pi reboots it drops the connection.

1 Like

Working well for me too, just the long lag before it plays. I tried rubbing on a clean pi and it’s exactly the same. I suspect it’s something to do with amazon.co.uk rather than amazon.com

Well here is a Telnet driver for alexa tts.

If you are running a pi, I suggest modifying your alexa tts script to create the cookies in another directory as, at least on my pi the tmp directory is wiped on every reboot. This has allowed my cookie to persist for quite some time now. I am curious to how long it goes, and if I am correct in thinking that if you have a previously valid cookie present the login script may work to renew.

I also commented out all pesky RM lines that were removing my cookies.

Supports:

  • Alexa tts
  • Pause/Play/Next track/Prev track/
  • Volume control - Mute/unmute to come
    Connection status / Refresh - Is a work in progress - It does not seem I always catch the disconnect - So I think some sort of polling every 30 minutes or so - send a command - parse for appropriate response.
  • Retrieve Devices - getDevices button retrieves Echo devices in the account and displays them in the Current States column for easy reference. - These are not persistent. (I attempted to make a drop down list that auto populated with your Echo devices - I thought it would be similar to what @stephack did with his join api driver but alas my attempts eventually locked up my hub and I gave up - any tips along these lines would be helpful)
  • Support For Amazon music playlist playback through the Play track button (you have to enter the amazon id for the playlist - It can be found in the browser address bar. I have had success triggering specific tracks - but getting the correct ID is a bit of a pain - I have found a consistent method. It however is a pain in the butt - maybe down the line someone can figure out how to simplify this - for now I have no other way than manually creating a list)

I do not think there is a way to getting any resume/restore functions working, so maybe we can use them to play different playlists/tracks. I have however tested and TTS function works then automatically resumes what was playing.

/**
    *  Alexa Telnet TTS
    *
    *
    *  Copyright 2018 Chris Wilson
    *
    *  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.
    *
    *  9/2/2018 - Initial Release - Chris Wilson
    */

    preferences {
    		input "ip", "text", title: "RPi IP Address", description: "Ip address of your pi", required: true, displayDuringSetup: true
    		input "port", "text", title: "RPi Telnet Port", description: "Port for your pi", required: true, displayDuringSetup: true
    		input "username", "text", title: "RPi Username", description: "Input username for your pi", required: true, displayDuringSetup: true
    		input "password", "text", title: "RPi Password", description: "Input password for your pi", required: true, displayDuringSetup: true
            input "echoName", "text", title: "Echo Device Name", description: "Name of your device", required: true, displayDuringSetup: true
            input "ttsPath", "text", title: "Path to Alexa TTS script", description: "Path to Alexa TTS script i.e. /opt/ha-alexa-tts-master", required: true, displayDuringSetup: true
            input "cookPath", "text", title: "Path to Alexa TTS cookie", description: "Path to Alexa TTS cookie - default /tmp", defaultValue: "/tmp", required: false, displayDuringSetup: true
    }
    metadata {
        definition (name: "Alexa Telnet TTS", namespace: "cw", author: "Chris Wilson") {
            capability "Speech Synthesis"
            capability "Telnet"
            capability "Switch"
            capability "Refresh"
            capability "Music Player"
            
            command "getDevices"
            attribute "Telnet", ""
                }        
        
    }



    def installed() {
        initialize()
    }

    def updated() {
        telnetClose()
        initialize()   
    }

    def initialize() {
        log.debug "Connecting to telnet - IP = ${ip}, Port = ${port.toInteger()}, Username = ${username}, Password = ${password}"
        telnetConnect([termChars:[13,10]], ip, port.toInteger(), username, password)
       }




    def getDevices(){
        if (cookPath == null){
            cookPath = "/tmp"
            
            }
       // def msg = 'cat /opt/alexacookie/alexa.devicelist.json | jq \'.devices\''
         //def msg = 'jq -r \'.devices[].accountName\' /opt/alexacookie/.alexa.devicelist.json > device.txt && nl device.txt > numbereddevice.txt &&cat numbereddevice.txt'
        def msg = "jq -r \'.devices[].accountName\' " + "${cookPath}" + "/.alexa.devicelist.json > device.txt && nl device.txt > numbereddevice.txt && cat numbereddevice.txt"
        // def msg = 'nl /opt/alexacookie/test.txt'
       
       
        
        sendMsg(msg)
    }
    def refresh(){
        def msg = 'ping -c 1 192.168.1.129'
        sendMsg(msg)
    }

    def setLevel(level){
        def msg =  "${ttsPath}" + '/alexa_remote_control.sh -d "' + "${echoName}" + '" -e vol:' + "${level}"
        sendMsg(msg)

    }

    def play(){
        def msg =  "${ttsPath}" + '/alexa_remote_control.sh -d "' + "${echoName}" + '" -e play'
        sendMsg(msg)

    }
    def pause(){
        def msg =  "${ttsPath}" + '/alexa_remote_control.sh -d "' + "${echoName}" + '" -e pause'
        sendMsg(msg)

    }
    def stop(){
        def msg =  "${ttsPath}" + '/alexa_remote_control.sh -d "' + "${echoName}" + '" -e pause'
        sendMsg(msg)

    }
    def playTrack(playlist){
        def msg =  "${ttsPath}" + '/alexa_remote_control.sh -d "' + "${echoName}" + '" -w' + " ${playlist}"
        sendMsg(msg)

    }
    def nextTrack(){
        def msg =  "${ttsPath}" + '/alexa_remote_control.sh -d "' + "${echoName}" + '" -e next'
        sendMsg(msg)

    }
    def previousTrack(){
        def msg =  "${ttsPath}" + '/alexa_remote_control.sh -d "' + "${echoName}" + '" -e prev'
        sendMsg(msg)

    }
    def speak(message) {
        //def msg = '/opt/ha-alexa-tts-master/alexa_remote_control.sh -d "' + "${echoName}" + '" -e speak:"' + "${message}" + '"\r\n'
        def msg =  "${ttsPath}" + '/alexa_remote_control.sh -d "' + "${echoName}" + '" -e speak:"' + "${message}\""
        sendEvent(name: "Telnet", value: "Connected")
        sendMsg(msg)
    }

    def sendMsg(String msg) {
        log.debug "Sending msg = ${msg}"
    	return new hubitat.device.HubAction(msg, hubitat.device.Protocol.TELNET)
    }



    def parse(String msg) {

        log.debug "Telnet Response = ${msg}"
        if (msg == "permitted by applicable law.") {
            sendEvent(name: "Telnet", value: "Connected");
            
            
        }
        if (msg == "Sequence command: Alexa.Speak") {
            sendEvent(name: "Telnet", value: "Connected");
            }
        if (msg.startsWith("     1")) {
            sendEvent(name: "Device_1", value: msg.substring(7))
            
        	}
        if (msg.startsWith("     2")) {
            sendEvent(name: "Device_2", value: msg.substring(7))
       		}
        if (msg.startsWith("     3")) {
           sendEvent(name: "Device_3", value: msg.substring(7))
        	}
        if (msg.startsWith("     4")) {
            sendEvent(name: "Device_4", value: msg.substring(7))
        	}
        if (msg.startsWith("     5")) {
            sendEvent(name: "Device_5", value: msg.substring(7))
            }
        if (msg.startsWith("     6")) {
            sendEvent(name: "Device_6", value: msg.substring(7))
            }
        if (msg.startsWith("     7")) {
            sendEvent(name: "Device_7", value: msg.substring(7))
            }
        if (msg.startsWith("     8")) {
            sendEvent(name: "Device_8", value: msg.substring(7))
            }
        if (msg.startsWith("     9")) {
            sendEvent(name: "Device_9", value: msg.substring(7))
            }
         if (msg.startsWith("    10")) {
            sendEvent(name: "Device_10", value: msg.substring(7))
            }
        if (msg.startsWith("    11")) {
            sendEvent(name: "Device_11", value: msg.substring(7))
            }
        if (msg.startsWith("    12")) {
            sendEvent(name: "Device_12", value: msg.substring(7))
            }
        if (msg.startsWith("    13")) {
            sendEvent(name: "Device_13", value: msg.substring(7))
            }
        if (msg.startsWith("    14")) {
            sendEvent(name: "Device_14", value: msg.substring(7))
            }
        if (msg.startsWith("    15")) {
            sendEvent(name: "Device_15", value: msg.substring(7))
            }
        if (msg.startsWith("    16")) {
            sendEvent(name: "Device_16", value: msg.substring(7))
            }
        if (msg.startsWith("    17")) {
            sendEvent(name: "Device_17", value: msg.substring(7))
            }
        if (msg.startsWith("    18")) {
            sendEvent(name: "Device_18", value: msg.substring(7))
            }
        if (msg.startsWith("    19")) {
            sendEvent(name: "Device_19", value: msg.substring(7))
            }
        if (msg.startsWith("    20")) {
            sendEvent(name: "Device_20", value: msg.substring(7))
            }
        if (msg.startsWith("    21")) {
            sendEvent(name: "Device_21", value: msg.substring(7))
            }
        if (msg.startsWith("    22")) {
            sendEvent(name: "Device_22", value: msg.substring(7))
            }
        if (msg.startsWith("    23")) {
            sendEvent(name: "Device_23", value: msg.substring(7))
            }
        if (msg.startsWith("    24")) {
            sendEvent(name: "Device_24", value: msg.substring(7))
            }
        if (msg.startsWith("    25")) {
            sendEvent(name: "Device_25", value: msg.substring(7))
            }
        
    }

    def telnetStatus(String status){
    	log.info "telnetStatus- error: ${status}"
    	if (status == "receive error: Stream is closed"){
    		
    		log.error "Telnet connection dropped..."
            sendEvent(name: "Telnet", value: "Disconnected")
    		initialize()
    	} else {
    		sendEvent(name: "Telnet", value: "Connected")
    	}
    }

As always you have to enter some things to make it work. Most is self explanatory - of note are the Path the Alexa TTS script and path to Alexa TTS cookie.

If you took my advice and moved the location where your cookies are stored enter the path here. If left blank it should default to /tmp

Path to Alexa TTS script - just tell the driver where to find your script. I have a feeling this may vary a lot from user to user.

So this is me just playing around - my knowledge is limited. There are likely more efficient way to do things and bugs that need stomping. I am open to any and all feedback.

Please do not let this deter anyone who really knows what they are doing from making something better.

1 Like

Well I figured out a way to parse out a lot of information. I will try and get the driver updated to show these states. I would be really curious if this actually works for anyone else. If you are feeling adventurous please let me know.

1 Like

I've been playing around with the native alexa capability to speak based on a smartthings trigger. I found that if you add an HE virtual lock to the Alexa Skill, it shows up under "Devices" in Alexa Routines as a trigger, but says "This device is not currently supported". My August lock shows up there too, but gives the same message when you tap on it. So it seems anything that is designated a lock, might be usable in the future as a trigger, possibly without requiring an updated Alexa Skill.

Anyone encounter any other devices that show up in the Alexa Routines as a trigger? I just need one to make it work. I'm reluctant to use the telnet method. I think it might force me to have to add another Pi and it doesn't do more than I'm already able to do (less actually) with the Google Assistant Relay, so the effort doesn't seem worthwhile for me.

1 Like

I'm tried ST for this, create virtual switch in Hubitat and use other hub app to get it to ST and use that one in Alexa. Only problem is that routines don't work with Sonos One so i can't use it......

Yes, that method works, but the ST cloud is slow and unreliable.

1 Like

I don't think another pi would be required. Really no over head here. It is not a server that always run.

Totaly agree, but doesn't seem to be a other way if they dont update the alexa skill for hubitat :wink:

1 Like