Hi,
I am trying to write a device handler which will get a “text” attribute to “speak” command, process TTS and then send URI to my Sonos speaker.
Everything was going well until I got this error which states that I should not call a device from another device.
Now I understand (from this thread) that I need to use a SmartApp between those devices.
But I don’t know how to write a basic one which will read the attribute from device. Can anyone guide me plase ?
my device handler is:
/**
* Alexa Simulator
*
* Author: SmartThings
*
*/
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){
def speech
def uri
speech = safeTextToSpeech(normalizeMessage(msg))
log.debug ("URI:" + speech.uri)
sonos.each {
it.playTrack(speech.uri)
}
//sonos.playTrack(speech.uri)
}
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 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)}"]
}
I want to send the attribute of speak command to another device in line “sonos.playTrack”