siriproxy and vera - a new approach

I don’t think this idea has been written up anywhere else, and someone might be interested in playing with it.

All the siriproxy/vera code I’ve seen so far requires you to hard-code devices and commands into the siriproxy Ruby script. Which is a bit redundant as Vera knows what devices there are and what they can do.

Here’s some siriproxy-example code which collects the device and scene list from Vera at run time. Commands are therefore dynamic, depending on the device type.

[code]
require ‘cora’
require ‘siri_objects’
require ‘pp’
require ‘open-uri’
require ‘json’

########################################################

Improved Vera Voice Control plugin for Siri Proxy on Raspberry Pi

Version: 0.0.1

Date: 20130624

By: ARM

class SiriProxy::Plugin::Example < SiriProxy::Plugin
def initialize(config)
@actionUrl = “http://192.168.2.19:3480/data_request?id=lu_action&
@dataUrl = “http://192.168.2.19:3480/data_request?
end

#On/Off devices
def checkOnOff(device)

end

listen_for /test home automation/i do
say “Vera plugin for Siri Proxy is up and running!”
request_completed
end

@userData = JSON.parse(open(“http://192.168.2.19:3480/data_request?id=user_data2” ).read)

#Devices
@userData[“devices”].each do |device|
case device[“device_type”]

#SWITCHABLE LIGHTS ++++++++++++++++++++++
when "urn:schemas-upnp-org:device:BinaryLight:1"
  #example: BEDROOM LIGHT ON
  listen_for /(#{device["name"]}) (on|off)/i do |name,command|
    signal = (command == "on") ? "1" : "0"
    say "Switching " + name + " " + command
    service = "&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue="
    open(@actionUrl + 'DeviceNum=' + device["id"] + service + signal)
    request_completed
  end
  
#DIMMERS ++++++++++++++++++++++++++++++++
when "urn:schemas-upnp-org:device:DimmableLight:1"
  #example: BEDROOM LIGHT ON
  listen_for /(#{device["name"]}) (on|off)/i do |name,command|
    signal = (command == "on") ? "1" : "0"
    say "Switching " + name + " " + command
    service = "&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue="
    open(@actionUrl + 'DeviceNum=' + device["id"] + service + signal)
    request_completed
  end
  #example: BEDROOM LIGHT FIFTY
  listen_for /(#{device["name"]}) ([0-9,].*[0-9])/i do |name,level|
    say "Setting" + name + " to " + level + "%"
    service = "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget="
    open(@actionUrl + 'DeviceNum=' + device["id"] + service + level)
    request_completed
  end
  
#DOOR LOCKS +++++++++++++++++++++++++++++
when "urn:schemas-micasaverde-com:device:DoorLock:1"
  #example: UNLOCK THE FRONT DOOR
  listen_for /(unlock|lock)(?: the)? (#{device["name"]})/i do |command,name|
    if command == "Unlock"
      signal = "0"
      verb = "Unlocking the"
    else #default to lock
      signal = "1"
      verb = "Locking the "
    end
    say verb + " " + name
    service = "&serviceId=urn:micasaverde-com:serviceId:DoorLock1&action=SetTarget&newTargetValue="
    open(@actionUrl + 'DeviceNum=' + device["id"] + service + signal)
    request_completed
  end
  #example: IS THE FRONT DOOR LOCKED
  listen_for /is(?: the)? (#{device["name"]}) locked/i do |name|
    service = "&serviceId=urn:micasaverde-com:serviceId:DoorLock1&Variable=Status"
    llock = open(@dataUrl + 'id=lu_variableget&DeviceNum=' + device["id"] + service)
    if llock.read[0] == "1"
      say "The " + name + " is locked."
    else
      response = ask "The " + name + " is unlocked.  Would you like me to lock it for you?" 
      if(response =~ /yes/i) #process their response
        signal = "1"
        verb = "Locking the "
        say verb + " " + name
        service = "&serviceId=urn:micasaverde-com:serviceId:DoorLock1&action=SetTarget&newTargetValue="
        open(@actionUrl + 'DeviceNum=' + device["id"] + service + signal)
        request_completed
      else
        say "OK.  No problem!"
        request_completed
      end #if 
    end #if
  end #listen_for
  
#THERMOSTATS +++++++++++++++++++++++++++++
when "urn:schemas-upnp-org:device:HVAC_ZoneThermostat:1"
  #example:WHAT IS THE TEMPERATURE INSIDE?
  listen_for /temperature inside/i do
    service = "&serviceId=urn:upnp-org:serviceId:TemperatureSensor1&Variable=CurrentTemperature"
    ltemp = open(@dataUrl + 'id=lu_variableget&DeviceNum=' + device["id"] + service)
    say "The temperature in the living room is #{ltemp.read} degrees."
    request_completed
  end
  #example: SET COOLING TWENTY ONE
  listen_for /Set cooling.*([0-9,].*[0-9])/i do |level|
    say "Setting your cooling target to " + level + " degrees"
    service = "&serviceId=urn:upnp-org:serviceId:TemperatureSetpoint1_Cool&action=SetCurrentSetpoint&NewCurrentSetpoint="
    open(@actionUrl + 'DeviceNum=' + device["id"] + service + level)
    request_completed
  end 
  #example: SET HEATING TWENTY FOUR
  listen_for /Set heating.*([0-9,].*[0-9])/i do |level|
    say "Setting your heating target to " + level + " degrees"
    service = "&serviceId=urn:upnp-org:serviceId:TemperatureSetpoint1_Heat&action=SetCurrentSetpoint&NewCurrentSetpoint="
    open(@actionUrl + 'DeviceNum=' + device["id"] + service + level)
    request_completed
  end
  #example: AIR CONDITIONING ON / OFF
  listen_for /Air conditioning (on|off)/i do |command|
    signal = (command == "on") ? "CoolOn" : "Off"
    say "Switching air conditioning " + command
    service = "&serviceId=urn:upnp-org:serviceId:HVAC_UserOperatingMode1&action=SetModeTarget&NewModeTarget="
    open(@actionUrl + 'DeviceNum=' + device["id"] + service + signal)
    request_completed
  end
  #example: HEATING ON / OFF
  listen_for /Heating (on|off)/i do |command|
    signal = (command == "on") ? "HeatOn" : "Off"
    say "Switching heating " + command
    service = "&serviceId=urn:upnp-org:serviceId:HVAC_UserOperatingMode1&action=SetModeTarget&NewModeTarget="
    open(@actionUrl + 'DeviceNum=' + device["id"] + service + signal)
    request_completed
  end

end #case

end #foreach device

#now check through scenes
@userData[“scenes”].each do |scene|
listen_for /(#{scene[“name”]})/i do |name|
say "OK, setting " + name
service = “serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum=”
open(@actionUrl + service + scene[“id”].to_s)
request_completed
end #listen_for
end #foreach scene

########################################

end[/code]

  • to run a scene, just say the scene name, eg LIVING ROOM LIGHTS MEDIUM
  • to open a door say UNLOCK - eg UNLOCK FRONT DOOR
  • to switch on (or off) a lamp say ON or OFF - eg TABLE LAMP OFF
  • to dim a lamp, say - eg BEDROOM LAMP FIFTY

I only have one thermostat, so the first thermostat item in the device list is controlled as:
AIR CONDITIONING ON
AIR CONDITIONING OFF
HEATING ON
HEATING OFF
SET HEATING - eg SET HEATING TWENTYTHREE
SET COOLING

I cribbed the
IS THE LOCKED? idea from WSeverino whose code I started with - so thanks to him (or her) although there’s not much of that code left.

There’s no error handling or checking of return codes (yet)
You have to put your Vera’s IP address in the code, that should move to the config.yml eventually, but I’ve a lot to learn about the file structure of Ruby gems, yet.

If I ever get a UPnP tv, guess what I’m going to be using as a remote :slight_smile:

ps. Make sure to choose device and scene names carefully, so that Siri can work out what you’re talking about.

EDIT: code updated

Ooooh, I’ll be giving this a go tonight… Thanks for sharing!

And if I can make a tiny suggestion, put vera’s IP address in a global variable, so you only have to amend it in one location :wink:

Wow, it worked exactly as you described it… well impressed!

What would be really, really cool (if you take feature requests ;)) if it could take ‘Rooms’ into account? And then you could say things like “switch on in the ” or “what is the in the ”, etc…

I can see the value of “what is the temperature in the bedroom?”, I’ll think about that. But I only have one thermostat (I like a simple life) so it’s not much use to me.

Another option I thought of was to give each item a “spoken name” - I think you can specifiy custom parameters for devices.

I’d like Siri to be able to work out which room you’re in when you give a command. I don’t think the gps is quite up to it, but even if it were I don’t see an interface in siriproxy to get that information back to the server.

I’m going to look for some natural language processing website with an API. Doing it with regexps is too tedious.

The AGPS is next to useless indoors, unless you have a very large bungalow ;), but the idea is a good one. The holy grail of presence detection (and positioning) is still a long way off

This is fantastic. I copied this into my example file today and was able to get it running pretty smoothly out of the box. I’ve started making some modifications, simply to the language, to allow for alternate speach commands when I forget the exact context. Can anyone point out if there is perhaps an easier way to create optional “listen_for” patterns that can still leverage the rest of each section?

Please excuse my lack of programming knowledge. I’m an IT worker, but programming is not my strong suit. I understand the basics and can follow the logic, but the rules that go along with it are what I don’t have a strong foundation of.

Some example code I’ve modified:

[code] #SWITCHABLE LIGHTS ++++++++++++++++++++++
when “urn:schemas-upnp-org:device:BinaryLight:1”
#example: BEDROOM LIGHT ON
listen_for /(?:turn|set|put )?(?:the )?(#{device[“name”]})(?: light|lights)? (on|off)/i do |name,command|
signal = (command == “on”) ? “1” : “0”
say "Switching " + name + " " + command
service = “&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=”
open(@actionUrl + ‘DeviceNum=’ + device[“id”] + service + signal)
request_completed
end

#DIMMERS ++++++++++++++++++++++++++++++++
when "urn:schemas-upnp-org:device:DimmableLight:1"
  #example: BEDROOM LIGHT ON
  listen_for /(?:turn |set |put )?(?:the )?(#{device["name"]})(?: light| lights| dimmer)? (on|off)/i do |name,command|
    signal = (command == "on") ? "1" : "0"
    say "Switching " + name + " " + command
    service = "&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue="
    open(@actionUrl + 'DeviceNum=' + device["id"] + service + signal)
    request_completed
  end
  #example: BEDROOM LIGHT FIFTY
  listen_for /(?:turn |set |put )?(?:the )?(#{device["name"]})(?: light| lights| dimmer)?(?: to| at)? ([0-9,].*[0-9])(?:%)?/i do |name,level|
    say "Setting " + name + " to " + level + "%"
    service = "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget="
    open(@actionUrl + 'DeviceNum=' + device["id"] + service + level)
    request_completed
  end[/code]

Excuse my ignorance but how do I modify the script to match my zwave devices? Do I just edit the name of the device or am i totally missing the point?

Also once I save the file is this replacing the ruby script?

Bboy486,

In both this “script” and the plugin I created (http://forum.micasaverde.com/index.php/topic,16081.0.html), which is not related, your vera devices and scene names are pulled from your vera box automatically. You do not need to configure anything related to device names, etc.

Once you get either of them up and running, they should just work with the names of whatever you have configured.

Hope this helps.

Hi @autotoronto, @shmixx and @Quinten

I was just wondering if your example code has evolved any further ?

I’ve managed to create one for a urn:schemas-micasaverde-com:device:TemperatureSensor:1

#TEMPERATURE +++++++++++++++++++++++++++++ when "urn:schemas-micasaverde-com:device:TemperatureSensor:1" #example:WHAT IS EMMA'S TEMPERATURE ? listen_for /what is (#{device["name"]})/i do |name| service = "&serviceId=urn:upnp-org:serviceId:TemperatureSensor1&Variable=CurrentTemperature" ltemp = open(@dataUrl + 'id=lu_variableget&DeviceNum=' + device["id"] + service) say "The temperature in " + name + " is #{ltemp.read} degrees." request_completed end

But I’m having trouble with my HRT4-ZW which seems to be a urn:schemas-upnp-org:device:Heating:1

#HEATING THERMOSTATS +++++++++++++++++++++++++++++ when "urn:schemas-upnp-org:device:Heating:1" #example:WHAT TEMPERATURE IS THE CONSERVATORY THERMOSTAT? listen_for /what tempersture is the (#{device["name"]})set to/i do |name| service = "&serviceId=urn:upnp-org:serviceId:TemperatureSensor1&Variable=CurrentTemperature" ltemp = open(@dataUrl + 'id=lu_variableget&DeviceNum=' + device["id"] + service) say "The temperature in the living room is #{ltemp.read} degrees." request_completed end #example: SET THE CONSERVATORY THERMOSTAT TO TWENTY FOUR listen_for /turn(?: the)? (#{device["name"]}) to ([0-9,].*[0-9])/i do |name,level| say "Setting your " + name + " to " + level + " degrees" service = "&serviceId=urn:upnp-org:serviceId:TemperatureSetpoint1_Heat&action=SetCurrentSetpoint&NewCurrentSetpoint=" open(@actionUrl + 'DeviceNum=' + device["id"] + service + level) request_completed end

Siri Proxy just says that it cannot find a match, yet it seems to confirm the correct phrase was captured? Any ideas?

Andrew,

Since I am trying to make sense of all the information on this subject I am trying to put together a guide for myself (and most likely others) to follow step-by-step. I do not yet know enough of github to know how to use (I am reading it over though).

So, my question is now how do I use the code above and/or your plugin code after step 20 (below) (yes, i have no experience with RaspPi). I believe the steps below are for your plugin (I think the code on this page is a more all-in-one solution (re: Thermo) for my needs). If, you have a moment could you review the steps I collected below and let me know what if anything I am missing. Again, I cannot stress that this is all new to me, but I know I am not alone in trying to consolidate this information.

Also, is the config.yml file a file within the Raspberry Pi?

Source: [url=http://www.domotics.sg/siri-raspberry-pi-z-wave-voice-pod/]http://www.domotics.sg/siri-raspberry-pi-z-wave-voice-pod/[/url]

You will require the following:

A Raspberry Pi
An empty SD Card in FAT32 format (and a USB reader)
A copy of Raspberry Pi SD image with SiriProxy installed (Link - [url=http://sourceforge.net/projects/siriproxyrpi/]http://sourceforge.net/projects/siriproxyrpi/[/url])

Setting-up the Raspberry Pi.

Steps:

  1. Open Terminal and go to the directory that you have downloaded the SD card image

  2. Plugin your SD card reader with the SD card

  3. Follow the instruction stated here [url=http://elinux.org/RPi_Easy_SD_Card_Setup#Copying_an_image_to_the_SD_card_in_Mac.C2.A0OS.C2.A0X_.28mostly_graphical_interface.29]RPi Easy SD Card Setup - eLinux.org to copy the image onto the SD card. The copy process will run for a long time (> 1hr). To check the progress you can press Option + T.

  4. Once done, insert the SD card into the Raspberry Pi, connect to a HDMI display, LAN cable, keyboard and connect the power to start the device.

  5. Login with user id root and password siriproxy

  6. You may want to find out the IP address assigned to your Raspberry Pi. You may want to reserve this IP address to Raspberry Pi on your router

  7. Setup the DNS (this is to make Siri believe Raspberry Pi is apple server) by using the following command vi /etc/dnsmasq.conf

  8. Find this line address=/guzzoni.apple.com/###.###.###.###

  9. Replace ###.###.###.### with the IP address of your Raspberry Pi and save the changes with the following command :wq

  10. Restart the DNS by using the following command sh /etc/init.d/dnsmasq restart

  11. The next step is to generate the certificate to be installed on your iPhone and to point your iPhone DNS to Raspberry Pi.

  12. Generate the certificate by using the following command siriproxy gencerts

  13. Copy the certificate to your proxy server directory cp /root/.siriproxy/ca.pem /root/SiriProxy

  14. Copy the file out of Raspberry Pi and email the certificate to your iPhone. You may access the file system on Raspberry Pi over samba with same user id and password.

  15. Tab the email attachment on your iPhone to install the certificate.

  16. Goto the wifi settings on your iPhone and change the DNS IP address to the IP address of your Raspberry Pi.

  17. On your Raspberry Pi, goto the the SiriProxy directory it should already have a sample SiriProxy plugin installed.

  18. Rebuild and run the SiriProxy server with the siriproxy update .followed by siriproxy server

  19. Activate Siri on your iPhone and say ?Test SiriProxy? it should reply ?SiriProxy up and running?

  20. Once you made sure that SiriProxy is working fine, use Control + T to stop the SiriProxy.

Setting-up the SiriProxy with Vera.

Steps:

  1. Source - [url=https://github.com/andrewgarfield/siriproxy-vera]https://github.com/andrewgarfield/siriproxy-vera[/url]

  2. Add the following information to your installation’s config.yml file:

- name: 'Vera' git: 'git://github.com/andrewgarfield/siriproxy-vera.git' vera_ip: 'vera' # enter the ip or hostname for your vera vera_port: '3480'

  1. Change the “vera_ip” option within the stuff you just pasted into config.yml to the IP address or hostname of your vera unit.

`vera_ip: ‘192.168.1.56’

  1. Update your SiriProxy installation

rvmsudo siriproxy update

  1. Start the SiriProxy server

rvmsudo siriproxy server -u nobody

If the plugin is installed correctly you will see a message like this as the server starts up:

“Vera plugin running. Detected 20 scenes, 4 dimmable lights, and 7 binary lights.”

Bboy486,

Glad you are putting this together. I don’t have much experience with the Raspberry Pi (unfortunately) so I cannot comment much on those specific steps. I am running my SiriProxy on an Ubuntu virtual machine running on a Citrix XenServer in my house. So i’m not using a Raspberry Pi.

With that in mind, there’s only two comments I can think to make:

  1. Newer versions of SiriProxy do not require the DNSMasq stuff to work at all. It uses another method to successfully poison the DNS of your network to perform the man-in-the-middle. But, I don’t know if this new version is baked in to the SiriProxy for Raspberry Pi, so your steps might still be valid (and even required).

  2. One thing I didn’t mention in my documentation (because it was obvious based on where I was hosting the code) was that you need to have git installed on your box as a prerequisite to download the code from github. I bet that the raspberry pi version of SiriProxy has git built in, but I am not sure. It may not.

I think the only way to ensure your steps are correct is to actually perform them and see if they work and/or what needs to be tweaked.

Andrew

I’ve got siriproxy running on a RaspberryPi using the sourceforge image and Andrew’s plugin. So far so good all zwave switches are recognised and work ( well they do occasionally because Siri has problems with my Yorkshire accent!!), however my 2 dimmable lights are Lightwave via RFXtrx and whilst the names are recognised nothing actually happens. I can’t find anywhere to modify as Andrew’s plugin doesn’t seem to create a siriproxy-vera.rb (as per siriproxy-example). Any solutions?

David

Hey dsroberts1945,

Happy to hear that you’re running the plugin and that it’s performing okay (for the most part). If you had any additional feedback, I’d love to hear it.

I have a few ideas that might address your concerns here (hopefully).

First, I’m sorry to hear about the dimmable lights not working. Unfortunately I can only test with what I have and I do not have any Lightwave lights. But since they were identified by the plugin, I’m assuming that they should work similarly. So my thoughts are that it might be the plugin itself that may have had a bug in it. There was a bit of a time over the last few weeks when a bug was in code submitted to github. I had actually done some work last night on it, and did a fair amount of testing to which everything seems to work fine.

So my first suggestion is simply to run siriproxy update again to download the latest. I think there’s a good chance that it will fix your issue.

As for where the plugin actually downloads, I am actually a bit embarrassed to say that I actually didn’t know (until a few moments ago) where siriproxy downloaded my plugin to! But I did some searching around and found it.

It’s in a directory similar to this structure:

/home//.rvm/gems/ruby-2.0.0-p247/bundler/gems/

From there, just do an ls -l to find the version of the plugin with the latest date, and go into that directory. Within the lib directory there you should see the siriproxy-vera.rb file. You can also view it on the github site:

If the latest version of the code doesn’t fix your dimmable light issue, there are a few things we can do:

  1. If you’re able to code, you can make some changes to the plugin and submit them to the project, or simply for your own uses.
  2. Point me to the files that the lightwave devices use within vera so I can look at the config files to identify where the plugin might be going wrong.

Hope this helps!

Oh, one last thing. Regarding the not being able to understand your accent, I would recommend trying out some alternative device names. I have a standard midwestern American accent (that the newscasters here use), and despite that I also had problems with siri understanding me. The biggest offender was having the word “light” within any of my device names. For some reason Siri, 9 times out of ten, thought I said the word “late” when I most clearly said “light”. I simply removed the word light from my device names and now it works quite reliably. You may want to identify some problem words you run into and see if we can enhance the plugin accordingly. A good example, is with the “set scene” command. Siri often comes back with “set seen” or “set seem”, but I coded those as alternatives that the plugin will detect properly. If there’s other phrasings like this that may help let me know.

Andrew

Andrew
Thanks for the quick reply, I will try over the weekend. The next few days will be spent upgrading my IOS devices to IOS7!!! ( and hopefully persuading my wife that I need to upgrade to the IPhone 5S).

David

dsroberts1945,

Just a word of warning regarding iOS 7 – from what I was reading online, SiriProxy likely doesn’t work with it yet.

But I too will be upgrading to iOS 7 too on my phone while leaving my iPad at iOS 6 (for a little while, at least) so i can still use SiriProxy and the plugin to control the house.

Good luck with persuading your wife! I know with mine things like this can be a tough sell!

Andrew

bboy486,
I do not have a dnsmasq.conf in my /etc

what is wrong ?

I stop in that step
can you send for me your files ?
dnsmasq.conf and config.yml

  • after some hours, in according with Elvis (author of siriproxy image) this new version do not uses dnsmasq.conf anymore.

I have installed the image and waiting instructions because if I put the ip of my Rpi in my DNS wifi settings in iphone, I lose the internet connection in that.

I think after this job we will have a complete tutorial to install.

thanks to all.

thanks

Hey Piwtorak,

You shouldn’t need to change your DNS settings on your phone to the raspberry pi for it to work. Keep it, as it was before, to the DNS of your router (or other DNS server). Siriproxy should take care of the rest.

Once you change back your DNS setting on your phone, start up the siriproxy server on your rapsberry pi and hopefully it should work. Then install any plugins you were wanting to install.

Andrew

Andrew,

thanks…

is normal the messages:
starting siriproxy in 0.0.0.0:443 ?
siriproxy up and running

I do not have vera plugin installed yet. I am wanting test before.

do you how I test ? because I speak in iphone but nothing happens in Rpi or Iphone.

Yes, that those messages are normal and are exactly what you should see.

You are testing correctly. If your phone’s siri traffic is correctly going through siriproxy you should see a lot of additional messages coming up on the screen as the traffic flows through it.

If you do not see those messages coming up when you try siri, then traffic is definitely not flowing through it and therefore it cannot do anything.

This is likely a DNS issue of some kind, or could also perhaps be if you don’t have the siriproxy certificate correctly installed on your phone. If you performed multiple tries installing siriproxy, then ensure that you are using the certificate generated from this exact installation. If you installed it from an earlier installation and tried again, the certificate will no longer be valid.

Another way you should be able to test is to ping “guzzoni.apple.com” on your computer. It should return pings from the raspberry pi IP local on your network (usually a 192.168.x.x address, but could also be a 10.x.x.x or 172.x.x.x address) if it’s working. If it’s not working then you’ll receive the correct IP address of Apple’s true guzzoni server.

Hope this helps.

Andrew