Text To Speech (TTS) With Sonos - Creating Dynamic Messages

My little snippet used when someone calls us… Feel free to modify for your needs…
This code works in Sweden… but there is probably similar services in other countries that can be used for looking up phonenumbers.

--
-- Uses the swedish number-to-name service 188100.se to lookup who is calling (using Fritz!Box integration) 
-- and announce it in your sonos speaker system
-- 
-- You need to install xpath.lua (found here: http://code.mios.com/trac/mios_genericutils/browser) 
-- under /usr/lib/lua/ of your vera unit
-- 
-- Update the following parameters below:
--   apiKey118100 - Your personal api key requested here: http://utveckling.118100.se/node/10
--   AV_DEV - sonos device id
--   FB_DEV - Fritz!Box device id
--   sayText - Text you want the sonos to say (%s = name of caller) 
--   sayLang - Laguage (sv = swedish, en=english, ...)
--   sayVolume - Volume of the announcement
--

local url = require("socket.url")
local xp = require ("xpath")
local lom = require ("lxp.lom")
local http = require('socket.http')

local AV_DEV = 115
local FB_DEV = 122
local LS_SID = "urn:micasaverde-com:serviceId:Sonos1"
local FB_SID = "urn:hek:serviceId:FritzBox1"
local apiKey118100 = "XXXXXXXXXXXXXX.XXXXXXXX"
local serviceUrl = "http://developer.118100.se:8080/openapi-1.1/appetizing?query=%s&key=%s"
local sayTextPrivate = "%s %s is calling"
local sayTextCompany = "The company %s is calling"
local sayLang = "sv"
local sayVolume = 30
local number = luup.variable_get( FB_SID, "Number", FB_DEV)

http.TIMEOUT = 5
luup.log("Incoming number: " .. number)
local result = http.request(string.format(serviceUrl, number, apiKey118100))

local lomobj = lom.parse(result)
local firstName = xpath.selectNodes(lomobj,"//individual/name[@type='first']/text()")[1]
local lastName = xpath.selectNodes(lomobj,"//individual/name[@type='last']/text()")[1]
local company = xpath.selectNodes(lomobj,"//company/name[@type='legal']/text()")[1]
local sayText = ""
if company then
    sayText = string.format(sayTextCompany, company)
else
    sayText = string.format(sayTextPrivate, firstName, lastName)
end


luup.log("Saying: " .. sayText)
luup.call_action(LS_SID, "Say", {Text = sayText, Language=sayLang, Volume=sayVolume}, AV_DEV)

I cannot get the Say function in the device interface to work, though the device works fine with Sonos radio channels and other files. When I enter say “welcome home” and run it, an MP3 is called but no no sound plays, as if the MP3 is a blank recording.

Any ideas? Thank you!

Does your Vera have internet accces?

It does. I can stream pandora through sonos and write you now… etc. Using vera 3 as my wireless router.

Any ideas? Thank you!

Weird… And your Sonos speakers is also plugged into Vera?

I’ve got a Vera Light so there is another network topology… The Say command uses some “magic” to get the Vera ipnumber which is needed to let your sonos speakers find the generated mp3.
I hope this magic works for Vera 3 aswell… @guessed… you also run Vera3 right?

See the other thread, since it looks like a similar issue:
http://forum.micasaverde.com/index.php/topic,13232.0.html

Any way to say temperature from weather.com, google search results or other services?

As the work is already done with the Weather plugin you could install that and then use something similar to this *(which has maintained the conventions of the previous Say Temp).

[code]url = require(“socket.url”)

local AV_DEV = Sonos DeviceID
local LS_SID = “urn:micasaverde-com:serviceId:Sonos1”

local TEMP_SID = “urn:upnp-org:serviceId:TemperatureSensor1”
local WUGTemp1 = luup.variable_get(TEMP_SID, “CurrentTemperature”, Weather Underground Temperature DeviceId)

luup.call_action(LS_SID, “Say”, {Text = string.format(“The current temperature outside is %s degrees”, WUGTemp1 )}, AV_DEV)
[/code]

[quote=“Brientim, post:28, topic:173177”]As the work is already done with the Weather plugin you could install that and then use something similar to this *(which has maintained the conventions of the previous Say Temp).

[code]url = require(“socket.url”)

local AV_DEV = Sonos DeviceID
local LS_SID = “urn:micasaverde-com:serviceId:Sonos1”

local TEMP_SID = “urn:upnp-org:serviceId:TemperatureSensor1”
local WUGTemp1 = luup.variable_get(TEMP_SID, “CurrentTemperature”, Weather Underground Temperature DeviceId)

luup.call_action(LS_SID, “Say”, {Text = string.format(“The current temperature outside is %s degrees”, WUGTemp1 )}, AV_DEV)
[/code][/quote]

Thanks a lot!
But why it say only 1st string, if I insert 2 lines, for example:

luup.call_action(LS_SID, “Say”, {Text = string.format(“The current temperature outside is %s degrees”, WUGTemp1 )}, AV_DEV)
luup.call_action(LS_SID, “Say”, {Text = string.format(“Tomorrow will be %s degrees”, WUGTemp1 )}, AV_DEV)

?

You can have it get, return and say multiple variable as long as they are available.
You just need to declare where there are coming from… Once again, I will say with the precedence that has been displayed in previous posts.

E.g.
local WUGTempCurrent = luup.variable_get(TEMP_SID, “CurrentTemperature”, 288)
local WUGTempHigh= luup.variable_get(TEMP_SID, “CurrentTemperature”, 289)

So, in the example below
377 is the Sonos and the remaining are other devices that have a Variable called CurrentTemperature

url = require("socket.url")

local AV_DEV = 377
local LS_SID = "urn:micasaverde-com:serviceId:Sonos1"

local TEMP_SID = "urn:upnp-org:serviceId:TemperatureSensor1"
local RoomTemp1 = luup.variable_get(TEMP_SID,"CurrentTemperature", 389)
local RoomTemp2 = luup.variable_get(TEMP_SID,"CurrentTemperature", 36)
local RoomTemp3 = luup.variable_get(TEMP_SID,"CurrentTemperature", 381)
local WUGTempCurrent = luup.variable_get(TEMP_SID, "CurrentTemperature", 288)
local WUGTempHigh= luup.variable_get(TEMP_SID, "CurrentTemperature", 289)

luup.call_action(LS_SID, "Say", {Text = string.format("Bedroom1 is currently %s degrees  Room2 is currently at %s degrees, Room3 is currently %s degrees the outside is currently %s degrees" and the maximum excepted today is %s degrees, RoomTemp1,RoomTemp2,RoomTemp3,WUGTempCurrent,WUGTempHigh )}, AV_DEV)

[quote=“Brientim, post:30, topic:173177”]You can have it get, return and say multiple variable as long as they are available.
You just need to declare where there are coming from… Once again, I will say with the precedence that has been displayed in previous posts.

E.g.
local WUGTempCurrent = luup.variable_get(TEMP_SID, “CurrentTemperature”, 288)
local WUGTempHigh= luup.variable_get(TEMP_SID, “CurrentTemperature”, 289)

So, in the example below
377 is the Sonos and the remaining are other devices that have a Variable called CurrentTemperature

[code]
url = require(“socket.url”)

local AV_DEV = 377
local LS_SID = “urn:micasaverde-com:serviceId:Sonos1”

local TEMP_SID = “urn:upnp-org:serviceId:TemperatureSensor1”
local RoomTemp1 = luup.variable_get(TEMP_SID,“CurrentTemperature”, 389)
local RoomTemp2 = luup.variable_get(TEMP_SID,“CurrentTemperature”, 36)
local RoomTemp3 = luup.variable_get(TEMP_SID,“CurrentTemperature”, 381)
local WUGTempCurrent = luup.variable_get(TEMP_SID, “CurrentTemperature”, 288)
local WUGTempHigh= luup.variable_get(TEMP_SID, “CurrentTemperature”, 289)

luup.call_action(LS_SID, “Say”, {Text = string.format(“Bedroom1 is currently %s degrees Room2 is currently at %s degrees, Room3 is currently %s degrees the outside is currently %s degrees” and the maximum excepted today is %s degrees, RoomTemp1,RoomTemp2,RoomTemp3,WUGTempCurrent,WUGTempHigh )}, AV_DEV)
[/code][/quote]

Question was about other thing :slight_smile:
Why TTS not read 2nd line luup.call_action, without variables too. One more example:

luup.call_action(LS_SID, “Say”, {Text = string.format(“The current temperature outside is %s degrees”, WUGTemp1 )}, AV_DEV) – SAID
luup.call_action(LS_SID, “Say”, {Text = string.format(“Thanks you”)}, AV_DEV) – DIDN’T SAY

Because the plugin is not able to say several things at the same time

Sorry, I missed answering your question. As lolodomo stated, and that is why the several things are included in the same string… In the example, there is actually four statements and uses the four variables.

So, including your two statements into the single string would appears like.
luup.call_action(LS_SID, “Say”, {Text = string.format(“The current temperature outside is %s degrees, Thankyou”, WUGTemp1 )}, AV_DEV)

So, if WUGTemp1 = 68 the response would be
“The current temperature outside is 68 degrees, Thankyou”

Another TTS template for people to look at and hopefully improve for me and others.

The intent here is to do a occupancy check of the house and then report back if the house is presumed to be empty of if someone is maybe still there.

Occupancy Check

[code]local MO_DEV1 = 119
local MO_DEV2 = 124
local MO_DEV3 = 135
local SEC_SERV = “urn:micasaverde-com:serviceId:SecuritySensor11”

local AV_DEV = 5
local LS_SID = “urn:micasaverde-com:serviceId:Sonos1”

local livingroommotion = luup.variable_get(SEC_SERV, “Tripped”,MO_DEV2)
local hallwaymotion = luup.variable_get(SEC_SERV, “Tripped”,MO_DEV1)
local kitchenmotion = luup.variable_get(SEC_SERV, “Tripped”,MO_DEV3)

if ((livingroommotion == “0”) and (hallwaymotion == “0”) and (kitchenmotion == “0”)) then
luup.log(“All motion sensor report no motion seen”)
luup.call_action(LS_SID, “Say”, {Text = string.format(“All motion sensores report that no motion is being seen.”)}, AV_DEV)
else
luup.log(“One or more motion sensors have reported motion”)
luup.call_action(LS_SID, “Say”, {Text = string.format(“One or more motion sensores have reported motion.”)}, AV_DEV)
end[/code]

If anyone can work out how to extract which sensor is still reporting motion out of a list of devices, it would be a nice touch for Sonos to say e.g. “Motion Is Still Being Reported in the Living Room”

I believe this is available in RTS Vera Alerts Plugin, and now you can send text directly from that Plugin to the Sonos Plugin his formatting may be better documented to create this dynamic string, and it may be very easy to push it to the sonos (or maybe not) I dont remember but it seemed to work well… I’m using THIS code to send the weather information via TTS to Vera Alerts that plays through my Sonos

local currentTemp = luup.variable_get("urn:upnp-org:serviceId:TemperatureSensor1", "CurrentTemperature", 333)
local lowTemp = luup.variable_get("urn:upnp-org:serviceId:TemperatureSensor1", "CurrentTemperature", 334)
local highTemp = luup.variable_get("urn:upnp-org:serviceId:TemperatureSensor1", "CurrentTemperature", 335)
local currentCondition = luup.variable_get("urn:upnp-micasaverde-com:serviceId:Weather1", "Condition", 332)
local currentWind = luup.variable_get("urn:upnp-micasaverde-com:serviceId:Weather1", "WindCondition", 332)

local speakMessage = "{tone:1} Good Morning.  Current conditions are " .. currentCondition .. ".  The temperature is " .. currentTemp .. " degrees with a high today of " .. highTemp .. " and a low of " .. lowTemp

luup.call_action("urn:richardgreen:serviceId:VeraAlert1", "SendAlert", 
                  {Message = speakMessage, Recipients = ""}, 397)

This was put together by Signal16 by the way.

So the last line there of luup.call_action would probably be where we would point the Vera Alerts plugin to deliver this message as “SAY” to the Sonos we choose.
Again, i’m not sure how to do that, but RTS would probably be able to advise fairly quickly.

You call the SendAlert action of the Vera Alerts plugin that will call the Say action of the Sonos plugin (forward) if the Vera Alerts is correctly setup. So it is just an indirect call to the Say action. That’s mainly interesting if you want to use several kinds of notification at the same time.

Using the code I posted above, can you modify that to send to Sonos plugin?
Thank you.

You have to setup how to forward to the Sonos plugin in a tab of the Vera Alerts device. It is explained in the wiki of Vera Alerts. The luup code you posted is, I suppose, correct.

Creating a queue for TTS is in my TODO list.

To come back to the subject of this topic, I would like Vera/Sonos telling me when e-mails arrive, not all time but for example when I come back to home. Any idea ?

To join the two - see here - as i want this too. http://forum.micasaverde.com/index.php/topic,13463.msg103821.html#msg103821