Belkin Wemo plug & shellscript automated control
A client who uses paxton door access control for their gym wanted to have their TV switch on when a customer enters, and switch off after 1 hour. I bought a Belkin WeMo Switch and found a shellscript that can switch the wemo on and off (original script.)
For this I created a C# console application in combination with the paxton sdk that fetches the last time a user entered the premises, and it will write the desired state of the TV power switch to a simple txt file (ON or OFF):
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Paxton.Net2.OemClientLibrary; using System.Xml.Linq; using System; using System.IO; using System.Collections.Generic; using System.Data; namespace ConsoleApplication2 { class Program { private const int REMOTE_PORT = 8025; private const string REMOTE_HOST = "192.168.2.2"; private OemClient _net2Client = new OemClient(REMOTE_HOST, REMOTE_PORT); private static string switchFile = @"C:\cygwin64\home\user\switch.txt"; static void Main(string[] args) { Program main = new Program(); main.startUp(); System.Environment.Exit(0); } public int startUp() { bool res = AuthenticateUser("OEM Client", "password"); if (res != true) { Log("Authentication failed, exiting application"); return 1; } Log("Authentication success"); IEvents events = _net2Client.ViewEvents(1, "EventType = 20", "EventId desc"); IEventView evt = events.EventsList()[events.EventsList().Keys.ElementAt(events.EventsList().Count - 1)]; Log(evt.EventType + " " + evt.EventTypeDescription + " " + evt.EventTime + " " +evt.EventDate+" "+evt.EventDescription+ " " +evt.Username+ " " + evt.UserId); double lastAccess = DateTimeToUnixTimestamp(stringToDateTime(evt.EventDate + " " + evt.EventTime)); double currentTime = DateTimeToUnixTimestamp(DateTime.Now); Log(lastAccess.ToString()); Log(currentTime.ToString()); //Longer than an hour? switch off if(Math.Round(currentTime - lastAccess) > 3600) { File.WriteAllText(switchFile, "OFF"); } else { File.WriteAllText(switchFile, "ON"); } return 1; } private DateTime stringToDateTime(string date) { // Date strings are interpreted according to the current culture. // If the culture is en-US, this is interpreted as "January 8, 2008", // but if the user's computer is fr-FR, this is interpreted as "August 1, 2008" DateTime dt = Convert.ToDateTime(date); return dt; } public static double DateTimeToUnixTimestamp(DateTime dateTime) { return (TimeZoneInfo.ConvertTimeToUtc(dateTime) - new DateTime(1970, 1, 1)).TotalSeconds; } /** * Authenticate user * For some reason we can't authenticate with username password, only with userId Password.. * So we need to get the userId and Authenticate with it.. **/ private bool AuthenticateUser(string userName, string password) { IOperators operators = _net2Client.GetListOfOperators(); Dictionary<int, string> operatorsList = operators.UsersDictionary(); foreach (int userID in operatorsList.Keys) { if (operatorsList[userID] == userName) { Dictionary<string, int> methodList = _net2Client.AuthenticateUser(userID, password); return (methodList != null); } } return false; } private void Log(string logMessage) { Console.WriteLine(logMessage); Console.WriteLine("--------------------"); } } }
This application is scheduled every few minutes, after wich a shell script is called that will switch the tv to the desired state, the shellscript:
#!/bin/sh # # WeMo Control Script # # IP=192.168.2.21 #switch.txt contains ON or OFF COMMAND=`cat ~/switch.txt` PORT=0 #Do a quick port test (1 of 4 is used) for PTEST in 49152 49153 49154 49155 do PORTTEST=$(curl -s -m 3 $IP:$PTEST | grep "404") if [ "$PORTTEST" != "" ] then PORT=$PTEST break fi done if [ $PORT = 0 ] then echo "Cannot find a port" exit fi #get the state first, so we can decide if we need to switch at all or TV already has desired state STATE=$(curl -0 -A '' -X POST -H 'Accept: ' -H 'Content-type: text/xml; charset="utf-8"' -H "SOAPACTION: \"urn:Belkin:service:basicevent:1#GetBinaryState\"" --data '<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetBinaryState xmlns:u="urn:Belkin:service:basicevent:1"><BinaryState>1</BinaryState></u:GetBinaryState></s:Body></s:Envelope>' -s http://$IP:$PORT/upnp/control/basicevent1 | grep "<BinaryState" | cut -d">" -f2 | cut -d "<" -f1 | sed 's/0/OFF/g' | sed 's/1/ON/g') if [ $COMMAND = "ON" ] && [ $STATE != "ON" ] then curl -0 -A '' -X POST -H 'Accept: ' -H 'Content-type: text/xml; charset="utf-8"' -H "SOAPACTION: \"urn:Belkin:service:basicevent:1#SetBinaryState\"" --data '<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetBinaryState xmlns:u="urn:Belkin:service:basicevent:1"><BinaryState>1</BinaryState></u:SetBinaryState></s:Body></s:Envelope>' -s http://$IP:$PORT/upnp/control/basicevent1 | grep "<BinaryState" | cut -d">" -f2 | cut -d "<" -f1 elif [ $COMMAND = "OFF" ] && [ $STATE != "OFF" ] then curl -0 -A '' -X POST -H 'Accept: ' -H 'Content-type: text/xml; charset="utf-8"' -H "SOAPACTION: \"urn:Belkin:service:basicevent:1#SetBinaryState\"" --data '<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetBinaryState xmlns:u="urn:Belkin:service:basicevent:1"><BinaryState>0</BinaryState></u:SetBinaryState></s:Body></s:Envelope>' -s http://$IP:$PORT/upnp/control/basicevent1 | grep "<BinaryState" | cut -d">" -f2 | cut -d "<" -f1 else echo "No change in state" echo "" echo "" fi