I am moving a button rule for my Inovelli Switch from Rule Machine 4.0 to Button Controllers. One of my multi taps scense confirms the event by announcing the activity using LANnouncer. I just noticed that the methods called in LANnouncer is differenet based on the Hubitat application where it is configured.
In Button Controller 5.1 it calls a "Toast" method for TTS:
From the device event log:
And throws the following error:
2022-06-04 01:01:15.545 pm [error](http://hubitat-home-c7.vargofamily.com/device/edit/202)groovy.lang.MissingMethodException: No signature of method: user_driver_RonV42_LANnouncer_Alerter_Hubitat_494.speak() is applicable for argument types: (java.lang.String, null) values: [Living Room Programmatic On, null]
But when using TTS in Notifications everything works fine and it calling the Speak method:
The device event:
The question is why would one built in app use the speak method and another built in app use the "Toast" method? This may be a bug in the Button Controller since TOAST would be a text or SMS method vs a TTS method. I am using a slightly modified LANnouncer driver that I modified to replace spaces in the string to be web service call safe.
/**
* LANnouncer Alerter-Hubitat (Originally LANdroid Alerter)
*
* Requires the Android TTSService (aka LANnouncer in the Play Store; https://play.google.com/store/apps/details?id=com.keybounce.lannouncer )
*
* Copyright 2015 Tony McNamara
* 8/1/2019 - Further modifyed by Ron Vargo to remove SmartThings references and support spaces in TTS strings
*
* 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.
*
*/
metadata {
definition (name: "LANnouncer Alerter-Hubitat", namespace: "RonV42", author: "Ron Vargo") {
capability "Alarm"
capability "Speech Synthesis"
capability "Notification"
capability "Tone"
attribute "LANnouncerSMS","string"
}
preferences {
input("DeviceLocalLan", "string", title:"Android IP Address", description:"Please enter your tablet's I.P. address", defaultValue:"" , required: false, displayDuringSetup: true)
input("DevicePort", "string", title:"Android Port", description:"Port the Android device listens on", defaultValue:"1035", required: false, displayDuringSetup: true)
input("ReplyOnEmpty", "bool", title:"Say Nothing", description:"When no speech is found, announce LANdroid? (Needed for the speech and notify tiles to work)", defaultValue: true, displayDuringSetup: true)
}
simulator {
}
tiles {
standardTile("alarm", "device.alarm", width: 2, height: 2) {
state "off", label:'off', action:'alarm.both', icon:"st.alarm.alarm.alarm", backgroundColor:"#ffffff"
state "strobe", label:'strobe!', action:'alarm.off', icon:"st.Lighting.light11", backgroundColor:"#e86d13"
state "siren", label:'siren!', action:'alarm.off', icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13"
state "both", label:'alarm!', action:'alarm.off', icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13"
}
standardTile("strobe", "device.alarm", inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"alarm.strobe", icon:"st.secondary.strobe"
}
standardTile("siren", "device.alarm", inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"alarm.siren", icon:"st.secondary.siren"
}
standardTile("speak", "device.speech", inactiveLabel: false, decoration: "flat") {
state "default", label:'Speak', action:"Speech Synthesis.speak", icon:"st.Electronics.electronics13"
}
standardTile("toast", "device.notification", inactiveLabel: false, decoration: "flat") {
state "default", label:'Notify', action:"notification.deviceNotification", icon:"st.Kids.kids1"
}
standardTile("beep", "device.tone", inactiveLabel: false, decoration: "flat") {
state "default", label:'Tone', action:"tone.beep", icon:"st.Entertainment.entertainment2"
}
main "alarm"
details(["alarm","strobe","siren","speak","toast","beep"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle 'alarm' attribute
}
// handle commands
def off() {
log.debug "Executing 'off'"
// TODO: handle 'off' command
}
def strobe() {
log.debug "Executing 'strobe'"
// TODO: handle 'strobe' command
def command="&FLASH=STROBE&"+getDoneString()
sendCommands(command)
}
def siren() {
log.debug "Executing 'siren'"
// TODO: handle 'siren' command
def command="&ALARM=SIREN&"+getDoneString()
sendCommands(command)
}
def beep() {
log.debug "Executing 'beep'"
// TODO: handle 'siren' command
def command="&ALARM=CHIME&"+getDoneString()
sendCommands(command)
}
def both() {
log.debug "Executing 'both'"
// TODO: handle 'both' command
def command="&ALARM=ON&FLASH=ON&"+getDoneString()
sendCommands(command)
}
def speak(toSay) {
log.debug "Executing 'speak'"
if (!toSay?.trim()) {
if (ReplyOnEmpty) {
toSay = "Landroid Speech Synthesizer"
}
}
toSay = toSay.replaceAll("\\s","%20")
if (toSay?.trim()) {
def command="&SPEAK="+toSay+"&"+getDoneString()
sendCommands(command)
}
}
def deviceNotification(toToast) {
log.debug "Executing notification with "+toToast
if (!toToast?.trim()) {
if (ReplyOnEmpty) {
toToast = "Landroid Speech Synthesizer"
}
}
toToast = toToast.replaceAll("\\s","%20")
if (toToast?.trim()) {
def command="&TOAST="+toToast+"&"+getDoneString()
sendCommands(command)
}
}
/* Send to IP and to SMS as appropriate */
private sendCommands(command) {
log.debug "Command request: "+command
// sendSMSCommand(command)
sendIPCommand(command)
}
private sendIPCommand(commandString ) {
log.debug "Sending command to "+DeviceLocalLan
sendEvent(name: "LANnouncerIP", value: commandString, isStateChange: true)
if (DeviceLocalLan?.trim()) {
def host = DeviceLocalLan
def hosthex = convertIPtoHex(host)
def porthex = convertPortToHex(DevicePort)
device.deviceNetworkId = "$hosthex:$porthex"
def headers = [:]
headers.put("HOST", "$host:$DevicePort")
def method = "GET"
def hubAction = new hubitat.device.HubAction([
method: method,
path: "/"+commandString,
headers: headers],
device.deviceNetworkId
)
hubAction
}
}
private sendSMSCommand(commandString) {
def preface = "+@TTSSMS@+"
def smsValue = preface+"&"+commandString
state.lastsmscommand = smsValue
sendEvent(name: "LANnouncerSMS", value: smsValue, isStateChange: true)
/*
if (SMSPhone?.trim()) {
sendSmsMessage(SMSPhone, preface+"&"+commandString)
}
*/
}
private String getDoneString() {
return "@DONE@"
}
private String convertIPtoHex(ipAddress) {
String hex = ipAddress.tokenize( '.' ).collect { String.format( '%02x', it.toInteger() ) }.join()
log.debug "IP address entered is $ipAddress and the converted hex code is $hex"
return hex
}
private String convertPortToHex(port) {
String hexport = port.toString().format( '%04x', port.toInteger() )
log.debug hexport
return hexport
}