SCRIPT UPDATED as of 10.25.23
Here’s my “temp” solution until @J-N-K has time to focus on it. This is based on file configuration of OH 3.4.4. Goal was to try to keep everything the same as it was still working before and just populate fields needed.
Some caveats to this setup:
- it runs every 2 minutes, there can only be 1 OH command issued that your looking for within in a 2 minute window for it to work.
- this will work across many Alexa devices based on serial number identifying.
- if your Alexa routine is saying something back for that OH command like “sure”, “ok”, etc. then the lastCommand is cleared out from the API side. Better off not saying anything back on the Alexa routine app side, do nothing.
- if you have other rules using the Alexa items, there could be an issue with “too many attempts” with the 2 minute API query and your other rules calling Alexa items within X seconds.
Items:
Group AlexaCmds "Last Voice Command [%s]"
String Echo_LivingRoom_LastVoiceCommand "Last Voice Command [%s]" <recorder> (AlexaCmds) { channel="amazonechocontrol:echo:account1:echolivingroom:lastVoiceCommand" }
String Echo_Bathroom_LastVoiceCommand "Last Voice Command [%s]" <recorder> (AlexaCmds) { channel="amazonechocontrol:echo:account1:echobathroom:lastVoiceCommand" }
Rules:
rule "Alexa Last Voice Command Assignment"
when
Time cron "0 0/1 * * * ?" // every 1 Minute
then
if (systemStarted.state != ON && Alexa_Status.state == 'ONLINE' && gInternet.state == ON && OH_Uptime_HumanReadable.state != NULL && OH_Uptime_HumanReadable.state !== null && OH_Uptime_HumanReadable.state != UNDEF) {
if (Part1Zone1Status.state != OPEN && Part1Zone2Status.state != OPEN && Part1Zone3Status.state != OPEN) { gExtDoors.postUpdate(CLOSED) } // using this rule for the minute run interval
var String alexa_LastVoiceCommandString = sendHttpGetRequest("http://192.168.0.32:8080/amazonechocontrol/account1/PROXY/api/activities?startTime=&size=1&offset=1")
if (alexa_LastVoiceCommandString !== null && alexa_LastVoiceCommandString != NULL && alexa_LastVoiceCommandString.toString() != '' && alexa_LastVoiceCommandString != UNDEF) {
try {
var serialNumber_alexa_LastVoiceCommand = transform("JSONPATH","$.activities[0]sourceDeviceIds[0]serialNumber",alexa_LastVoiceCommandString)
var PreLastVoiceCommand = transform("JSONPATH","$.activities[0].description",alexa_LastVoiceCommandString)
var LastVoiceCommand = transform("JSONPATH","$.summary",PreLastVoiceCommand)
if (LastVoiceCommand === null || LastVoiceCommand == NULL || LastVoiceCommand.toString() == '' || LastVoiceCommand == UNDEF) { return; }
if (serialNumber_alexa_LastVoiceCommand === null || serialNumber_alexa_LastVoiceCommand == NULL || serialNumber_alexa_LastVoiceCommand.toString() == '' || serialNumber_alexa_LastVoiceCommand == UNDEF) { return; }
if (serialNumber_alexa_LastVoiceCommand.toString() == "<html>Request failed<br><a href='/amazonechocontrol/account1'>Try again</a></html>") { return; }
// Eliminate trigger keywords
LastVoiceCommand = (LastVoiceCommand.toLowerCase()).replaceAll('alexa ','')
LastVoiceCommand = (LastVoiceCommand.toLowerCase()).replaceAll('echo ','')
LastVoiceCommand = (LastVoiceCommand.toLowerCase()).replaceAll('amazon ','')
LastVoiceCommand = (LastVoiceCommand.toLowerCase()).replaceAll('alexa','')
LastVoiceCommand = (LastVoiceCommand.toLowerCase()).replaceAll('echo','')
LastVoiceCommand = (LastVoiceCommand.toLowerCase()).replaceAll('amazon','')
if (LastVoiceCommand === null || LastVoiceCommand == NULL || LastVoiceCommand.toString() == '' || LastVoiceCommand == UNDEF) { return; }
// Alexa Routine Call Names
if (LastVoiceCommand.toString() == 'play music from the seventies on music') { return; }
if (LastVoiceCommand.toString() == 'Close Garage') { return; }
if (LastVoiceCommand.toString() == 'routine good morning loft') { return; }
if (LastVoiceCommand.toString() == 'routine good morning kitchen') { return; }
if (LastVoiceCommand.toString() == 'Good Morning Guest Bathroom') { return; }
if (LastVoiceCommand.toString() == 'play seventies') { return; }
if (LastVoiceCommand.toString() == 'close blind') { return; }
if (LastVoiceCommand.toString() == 'open blind') { return; }
if (LastVoiceCommand.toString() == 'Good Morning Bathroom') { return; }
if (LastVoiceCommand.toString() == 'play eighties') { return; }
if (LastVoiceCommand.toString() == 'kill use backyard echo') { return; }
if (LastVoiceCommand.toString() == 'Open Garage') { return; }
if (serialNumber_alexa_LastVoiceCommand.toString == Echo_PreviousSerialNumber.state.toString && LastVoiceCommand.toString == Echo_PreviousVoiceCommand.state.toString) { return; }
Echo_PreviousSerialNumber.postUpdate(serialNumber_alexa_LastVoiceCommand)
Echo_PreviousVoiceCommand.postUpdate(LastVoiceCommand)
// logInfo("ECHO","API Minute Call Last Voice Command Serial Number is " + serialNumber_alexa_LastVoiceCommand)
// logInfo("ECHO","API Minute Call Last Voice Command Description is " + PreLastVoiceCommand)
// logInfo("ECHO","API Minute Call Last Voice Command is " + LastVoiceCommand)
logInfo("ECHO","-----------------------------------------------------------------------------")
switch (serialNumber_alexa_LastVoiceCommand.toString) {
case "G090XG0994912345": { logInfo("ECHO","Echo_FrontOffice G090XG0994912345 Used - " + LastVoiceCommand.toString)
Echo_FrontOffice_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_FrontOffice_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G8M0XG1111012345": { logInfo("ECHO","Echo_Jay G8M0XG1111012345 Used - " + LastVoiceCommand.toString)
Echo_Jay_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_Jay_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G8M0XG1114212345": { logInfo("ECHO","Echo_GuestRoom G8M0XG1114212345 Used - " + LastVoiceCommand.toString)
Echo_GuestRoom_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_GuestRoom_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G8M11W1103212345": { logInfo("ECHO","Echo_Guest G8M11W1103212345 Used - " + LastVoiceCommand.toString)
Echo_Guest_Bathroom_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_Guest_Bathroom_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G6G0XG1223412345": { logInfo("ECHO","Echo_Gym G6G0XG1223412345 Used - " + LastVoiceCommand.toString)
Echo_Gym_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_Gym_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G090U50991112345": { logInfo("ECHO","Echo_Bedroom G090U50991112345 Used - " + LastVoiceCommand.toString)
Echo_Bedroom_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_Bedroom_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G6G1AA1521812345": { logInfo("ECHO","Echo_Ryan G6G1AA1521812345 Used - " + LastVoiceCommand.toString)
Echo_Ryan_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_Ryan_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G6G0XG1223412345": { logInfo("ECHO","Echo_Basement G6G0XG1223412345 Used - " + LastVoiceCommand.toString)
Echo_Basement_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_Basement_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G090XG0692812345": { logInfo("ECHO","Echo_Bathroom G090XG0692812345 Used - " + LastVoiceCommand.toString)
Echo_Bathroom_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_Bathroom_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G090LF1072412345": { logInfo("ECHO","Echo_BackYard G090LF1072412345 Used - " + LastVoiceCommand.toString)
Echo_BackYard_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_BackYard_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G8M0XG1111012345": { logInfo("ECHO","Echo_Loft G8M0XG1111012345 Used - " + LastVoiceCommand.toString)
Echo_Loft_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_Loft_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G2A1A60304612345": { logInfo("ECHO","Echo_LivingRoom G2A1A60304612345 Used - " + LastVoiceCommand.toString)
Echo_LivingRoom_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_LivingRoom_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G8M0XG1111412345": { logInfo("ECHO","Echo_Garage G8M0XG1111412345 Used - " + LastVoiceCommand.toString)
Echo_Garage_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_Garage_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G8M0XG1114112345": { logInfo("ECHO","Echo_Parker G8M0XG1114112345 Used - " + LastVoiceCommand.toString)
Echo_Parker_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_Parker_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
case "G090LF1073412345": { logInfo("ECHO","Echo_RIS G090LF1073412345 Used - " + LastVoiceCommand.toString)
Echo_RIS_LastVoiceCommandProxy.postUpdate(LastVoiceCommand.toString)
Echo_RIS_LastVoiceCommand.postUpdate(LastVoiceCommand.toString)
return;
}
default: { logInfo("ECHO","NO match on CASE statement for Echo Serial Number which is " + serialNumber_alexa_LastVoiceCommand)
return;
}
}
} catch (Exception e) {
logInfo("ECHO","Alexa Last Voice Command Assignment BLEW up. Exception is " + e.getMessage)
}
}
}
end
rule "Alexa Status via Voice"
when
Member of AlexaCmds changed
then
if (systemStarted.state != OFF) { return; }
if (gInternet.state == ON && (triggeringItem.name == NULL || triggeringItem.name === null || triggeringItem.name == 'UNDEF')) { return; }
if (gInternet.state == ON && (triggeringItem.state == NULL || triggeringItem.state === null || triggeringItem.state == UNDEF || triggeringItem.state == '')) { return; }
if (gInternet.state == ON && (triggeringItem.state == 'play notifications' || triggeringItem.state == 'stop' || triggeringItem.state == 'play notification' || triggeringItem.state == 'cancel' || triggeringItem.state == 'connect' || triggeringItem.state == 'snooze' || triggeringItem.state == 'discover devices' || triggeringItem.state == 'what is the weather')) { return; }
if (gInternet.state == ON && (triggeringItem.state == 'volume up' || triggeringItem.state == 'volume down' || triggeringItem.state == 'no' || triggeringItem.state == 'yes')) { return; }
if (gInternet.state == ON && (triggeringItem.state == 'Sure' || triggeringItem.state == 'Ok')) { return; }
// special line for single and double quotes values
if (gInternet.state == ON && (triggeringItem.state == "i'm home" || triggeringItem.state == "what's the weather")) { return; }
if (systemStarted.state != ON && Alexa_Status.state == 'ONLINE' && gInternet.state == ON) {
var String sourceRoom = triggeringItem.name.split("_").get(1)
var String TheRoom_TTS = "Echo_"+sourceRoom+"_TTS"
var String TheRoom_DoNotDisturb = "Echo_"+sourceRoom+"_doNotDisturb"
if (triggeringItem.state == 'echo' || triggeringItem.state == 'amazon' || triggeringItem.state == 'alexa' || triggeringItem.state == 'off') { return; }
// Logic Starts Here
if (Home_Away.state == ON && (triggeringItem.state == 'living room off' || triggeringItem.state == 'living room lights off')) {
logInfo("ECHO","Living Room OFF in order to turn OFF Cubby quicker " + triggeringItem.name)
Wallplug_Cubby_Light.sendCommand(OFF)
Thread::sleep(1500)
Wallplug_Cubby_Light.sendCommand(OFF)
Thread::sleep(1500)
Wallplug_Living_Room_Light.sendCommand(OFF)
Thread::sleep(1500)
Wallplug_Living_Room_Light.sendCommand(OFF)
return;
}
if (gInternet.state == ON && Home_Away.state == ON && (triggeringItem.state == 'sonos on' || triggeringItem.state == 'sonos play' || triggeringItem.state == 'play sonos')) {
if (TheRoom_TTS == 'Echo_LivingRoom_TTS' && systemStarted.state != ON) {
logInfo("ECHO","Alexa Sonos Play in Living Room via Voice has been triggered using " + triggeringItem.name)
Thread::sleep(500)
logInfo("tAlive","CREATING Generic 199 Timer!")
createTimer(now().plusNanos(1000), [ |
var String SonosPlayMsg = '<speak><prosody rate="fast">I have started Sonos, for the living room, and any rooms connected to the living room queue.</prosody></speak>'
// Starts Playing Sonos in the Living Room
Sonos_LivingRoom_Favorite.sendCommand(Sonos_Today_Favorite)
Thread::sleep(1500)
Sonos_LivingRoom2_Favorite.sendCommand(Sonos_Today_Favorite)
Thread::sleep(1500)
Sonos_LivingRoom_Controller.sendCommand(PLAY)
Thread::sleep(1500)
Sonos_LivingRoom_CurrentAlbumCoverArtURL_Proxy.postUpdate(Sonos_LivingRoom_CurrentAlbumCoverArtURL.state)
Sonos_LivingRoom2_CurrentAlbumCoverArtURL_Proxy.postUpdate(Sonos_LivingRoom2_CurrentAlbumCoverArtURL.state)
TheRoom_TTS.sendCommand(SonosPlayMsg)
Echo_LivingRoom_LastVoiceCommand.postUpdate(nullValue)
])
return;
}
if (TheRoom_TTS == 'Echo_Basement_TTS' && systemStarted.state != ON) {
logInfo("ECHO","Alexa Sonos Play in Basement via Voice has been triggered using " + triggeringItem.name)
Thread::sleep(500)
logInfo("tAlive","CREATING Generic 200 Timer!")
createTimer(now().plusNanos(1000), [ |
var String SonosPlayMsg = '<speak><prosody rate="fast">I have started Sonos, for the Basement, and any rooms connected to the Basement queue.</prosody></speak>'
// Starts Playing Sonos in the Basement
Sonos_Basement_Favorite.sendCommand(Sonos_Today_Favorite)
Thread::sleep(1500)
Sonos_Basement2_Favorite.sendCommand(Sonos_Today_Favorite)
Thread::sleep(1500)
Sonos_Basement_Controller.sendCommand(PLAY)
Thread::sleep(1500)
Sonos_Basement_CurrentAlbumCoverArtURL_Proxy.postUpdate(Sonos_Basement_CurrentAlbumCoverArtURL.state)
Sonos_Basement2_CurrentAlbumCoverArtURL_Proxy.postUpdate(Sonos_Basement2_CurrentAlbumCoverArtURL.state)
TheRoom_TTS.sendCommand(SonosPlayMsg)
Echo_Basement_LastVoiceCommand.postUpdate(nullValue)
])
return;
}
}
}
end
Best, Jay