Universal App of Things – The Server Side

October 14, 2014

Those who know me know that I love gadgets, and more than that, I love writing code for gadgets. I have used Internet of Things before it was called like that (IoT). My biggest gadget is my home. I have a home automation system based on EIB/KNX technology. The nice thing about this technology is that there is no central processing unit. Many home automation systems are based on a central PLC that controls the house. In EIB/KNX, each device is connected to a bus. The device is actually a tiny computer that has its own physical and logical bus address and that can issue or listen to bus commands. When I press a wall panel button to turn on the light, this button sends a command telling to an actuator that listens to this command, to turn on the light. Each actuator can listen to several different addresses and act upon them. For example it can listen to its own private address, or to a group address that all actuators on the floor listen to (to turn off all the lights in that floor), or another group address that belongs to all light devices in the house. An actuator can execute a simple or a complex command, for example setting the light state requires only one-bit value, but setting a dimmer or a shutter position needs a byte.

imageimage

Some of the devices have additional logic capabilities that allow executing a sequence of commands (for running scenarios such as light and shutter settings when leaving the house or when watching a movie).

A computer can be connected to the EIB/KNX bus using special devices such as USB/Serial or IP Gateways. In many cases, the computer is only used to program bus devices, however having a computer as part of the system enables much more complex scenarios, those that a PLC can do and much more. I use a computer to implement these scenarios:

1. Turning the boiler on, according to the current weather, using a forecast web service

2. Turning the garden lights on at sunset

3. Raising the shutters in the morning, and close them at midnight

4. Turn off all garden lights at midnight

5. provide statistics about the usage of controlled electrical devices

6. Provide a vacation mode to keep away thieves

7. Have a web/Windows/Phone remote control app

I started my project in 2004, and I use an Atom based machine to host it. The old project was built using ASP.Net ASMX services, C++/CLI wrapper on top of EIB Falcon COM object, an Executable that was used to call the web service from within the Windows Task Scheduler and a Media Center application that allowed me to control my home from my TV.

I decided that now it is a good time to create my Home Automation 2.0 project, this time with new Microsoft technologies.

The new architecture is based on a classical layer architecture. The server side has a device access layer, a business logic layer and a service layer, which is based on ASP.NET MVC Web API.

There are several clients. The main client is the Windows 8.1 and Windows Phone 8.1 Universal app that communicate with the server side through the RESTful web interface. There are two other clients that enable executing bus commads from the Windows Task Scheduler, and a bridge DLL that supports my old Windows Media Center application (built as .NET 2.0 assembly) as well as my Boiler setter, which is based on the forecast application.

The Architecture

image

Layer Description

Falcon COM Object

Connecting to the EIB/KNX Bus, send telegrams and listen to bus events

FalconWrapper

An access layer that:

1. Handle bus connections

2. Transform .NET commands to bus telegrams and vice versa

3. Provide bus events as .NET events

4. Map Falcon COM error to .NET exceptions with meaningful messages

Instead of having C++/CLI layer, I used the Falcon PIA. I also use the new syntax to connect to the bus. Since my developer machine has a USB gateway and my Atom runtime machine uses Serial connection I created a code segment that tries to connect to the bus first using COM and then using USB:

   1: private void OpenConnection()

   2:         {

   3:             const PortNumber selectedPort = PortNumber.PortNumberCom1;

   4:

   5:             //Create connection and group data objects

   6:             var ediMan = new EdiManager();

   7:             _connection = new ConnectionObject();

   8:             _groupDataTransfer = new GroupDataClient();

   9:

  10:             //Set connection mode as connectionless

  11:             _connection.Mode = ConnectionMode.ConnectionModeLLBusmon;

  12:

  13:             //For the open parameter EdiGuid the Edi manager is used

  14:             //Serial COM1:(homeautomation)

  15:

  16:             bool isConnected = false;

  17:             try

  18:             {

  19:                 _connection.Open(ediMan.GetStandardEdiGuid(selectedPort, EdiType.EdiTypeBcu1xPei16x9600));

  20:                 isConnected = true;

  21:                 EventLog.WriteEntry("Falcon Wrapper", "EIB communication on COM1 has succeeded",

  22:                     EventLogEntryType.Information);

  23:             }

  24:             catch (COMException exception)

  25:             {

  26:                 var falconException = new FalconException(exception);

  27:                 EventLog.WriteEntry("Falcon Wrapper",

  28:                     "An attempt to open EIB communication on COM1 has failed. Trying USB. Error:" + falconException.Message,

  29:                     EventLogEntryType.Error);

  30:             }

  31:

  32:             if (!isConnected) //Trying USB 

  33:             {

  34:                 try

  35:                 {

  36:                     _connection.Open2("FalconEdi.UsbEdi.1", "Device=0;");

  37:                     EventLog.WriteEntry("Falcon Wrapper", "EIB communication on USB 0 has succeeded",

  38:                         EventLogEntryType.Information);

  39:                 }

  40:                 catch (COMException exception)

  41:                 {

  42:                     var falconException = new FalconException(exception);

  43:                     EventLog.WriteEntry("Falcon Wrapper",

  44:                         "An attempt to open EIB communication on COM1 has failed. Trying USB. Error:" +

  45:                         falconException.Message,

  46:                         EventLogEntryType.Error);

  47:                     return;

  48:                 }

  49:             }

  50:

  51:             _groupDataTransfer.Connection = _connection;

  52:

  53:             //Register to bus events

  54:             _busmonClient = new BusmonClient {Connection = _connection};

  55:             _busmonClient.OnTelegram += BusMonitorOnTelegram;

  56:

  57:         }

FalconWrapper Main interface:
   1: public interface IEIBController : IDisposable

   2: {

   3:     event Action<string, byte?> BusMonitorEvent;

   4:     event Action<string, byte?> SendTelegramEvent;

   5:     void SendTelegram(string address, byte data);

   6:     void SendTelegramGroup(IEnumerable<Tuple<string, byte>> telegramInfo);

   7:     void SwitchOn(string address);

   8:     void SwitchOff(string address);

   9:     byte? ReadData(string address);

  10:     void CloseConnection();

  11: }

FliessHomeAutomationLogic

Hosted as part of the service in IIS – the main server logic layer

1. Provide devices metadata such as addresses and capabilities

2. Provide device-building map, i.e. devices by rooms, levels, and home

3. Provide device real-time status data

4. Handle device commands

5. Handle scheduler commands

The main interface:

   1: public interface IHomeController

   2: {

   3:     void SendTelegram(string address, byte data);

   4:     void SendTelegramGroup(IEnumerable<Tuple<string, byte>> telegramInfo);

   5:     void SwitchOn(string address);

   6:     void SwitchOff(string address);

   7:     int ReadData(string address);

   8:     void ScheduleTelegrams(string serviceAddress, IEnumerable<ScheduleTelegramData> telegrams);

   9:     void DeleteScheduleTelegrams(IEnumerable<ScheduleTelegramData> telegrams);

  10:     IEnumerable<ScheduleTelegramData> GetScheduleTelegrams(string address);

  11:     DeviceInfo GetDeviceById(int deviceId, bool forceRefreshValue = false);

  12:     List<DeviceInfo> GetRoomDevices(int roomId, bool forceRefreshValue = false);

  13:     List<Room> GetLevelRooms(byte levelId);

  14:     List<Level> GetHomeLevels();

  15:     List<DeviceInfo> GetAllDevices(bool forceRefreshValue = false);

  16:     void RefreshHomeDeviceValues();

  17:     }

The layer provides three types of functions, a home device topology functions (“DNS”), EIB/KNX bus related functions, and a task scheduler related functions.

Implementing the “DNS” functions:

I built a DOM that describes the home device topology using LINQ to XML based set of queries from an embedded resource XML file:

image

At initialization time, The DOM is built from the above XML file:

image

The building has number of levels. Each level has rooms. Each room has a list of devices, and each device has a list of EIB Actions. EIB Action has the EIB device address, the current device value, the last device value update time and if this value is valid. When the application gets a BUS event – for example when I turn on the light using the wall panel, the application searches the DOM for the bus command EIB address. This address might belong to a single device, or effect the whole room, level or home. According to the Effect value of this address, I invalidate all affected devices. When a client needs to get the device info, and the value is invalid, the application issues an EIB bus read telegram.

Having the DOM ready, a simple LINQ query provides the DNS information:

The Business logic layer:

   1: public List<Room> GetLevelRooms(byte levelId)

   2:         {

   3:             try

   4:             {

   5:                 return _homeDeviceAccessor.GetLevelRooms(levelId).ToList();

   6:             }

   7:             catch (Exception ex)

   8:             {

   9:                 EventLog.WriteEntry("HomeController", "Error getting level rooms by level id: " + levelId + "  Error: " + ex.Message, EventLogEntryType.Error);

  10:             }

  11:             return null;

  12:         }

The Accessor layer:

   1: public IEnumerable<Room> GetLevelRooms(byte levelId)

   2:         {

   3:             var rooms = (from level in _levels.Values

   4:                 where level.Id == levelId

   5:                 from room in level.Rooms

   6:                 select room.Value).ToList();

   7:             return rooms;

   8:         }

Implementing the EIB telegram functions:

Sending a telegram is implemented by calling the EIB Falcon Wrapper:

   1: _groupDataTransfer.Write(address, Priority.PriorityLow, 6, less7Bit, data))

Implementing the Scheduler functions:

To have a bus command set to be executed in the future, I use the Windows Task Scheduler.The Windows Task Scheduler executes code that calls the REST service. When I set the schedule task, I save the command parameters. When the Task Scheduler executes the command it passes those parameters and the code calls the Home Automation Service. I have two different tasks. To enable my “old” 2004 boiler control client, I use an executable that gets the telegram data (boiler address and data) in its command line arguments. The executable is a simple REST client:

   1: using System;

   2: using System.Configuration;

   3: using System.Diagnostics;

   4: using System.Net.Http;

   5: using System.Net.Http.Headers;

   6: using System.Threading.Tasks;

   7:

   8: namespace EIBExecuter

   9: {

  10:     internal class Program

  11:     {

  12:         private const string EventSource = "EIBExecuter";

  13:

  14:         private static void ShowInfo()

  15:         {

  16:             Console.WriteLine("Usage: EIBExecuter address ON/OFF/value");

  17:             Console.WriteLine("Example:");

  18:             Console.WriteLine("EIBExecuter 1/0/63 ON");

  19:             Console.WriteLine("EIBExecuter 1.63 OFF");

  20:             Console.WriteLine("EIBExecuter 2/66 100");

  21:         }

  22:

  23:         private static int Main(string[] args)

  24:         {

  25:             try

  26:             {

  27:                 if (args.Length < 2 || args[0] == "/?")

  28:                 {

  29:                     ShowInfo();

  30:                     return -1;

  31:                 }

  32:

  33:                 var dataArgument = args[1].ToUpper();

  34:

  35:                 var data = dataArgument == "ON"

  36:                     ? (byte) 1

  37:                     : dataArgument == "OFF"

  38:                         ? (byte) 0

  39:                         : byte.Parse(dataArgument);

  40:

  41:                 var eibAddress = args[0].Replace('/', '.');

  42:                 var serviceAddress = ConfigurationManager.AppSettings["serviceAddress"];

  43:

  44:                 SendTelegramAsync(serviceAddress, eibAddress, data).Wait();

  45:             }

  46:             catch (Exception ex)

  47:             {

  48:                 Console.WriteLine("Error: " + ex.Message);

  49:                 return -2;

  50:             }

  51:             return 0;

  52:         }

  53:

  54:         private static async Task<string> SendTelegramAsync(string serviceAddress, string eibAddress, byte data)

  55:         {

  56:             try

  57:             {

  58:

  59:                 using (var client = new HttpClient())

  60:                 {

  61:                     if (!EventLog.SourceExists(EventSource))

  62:                     {

  63:                         EventLog.CreateEventSource(EventSource, EventSource);

  64:                     }

  65:

  66:                     EventLog.WriteEntry(EventSource,

  67:                         string.Format("About to execute {0}={1}, service address: {2}",

  68:                             eibAddress, data, serviceAddress),

  69:                         EventLogEntryType.Information);

  70:

  71:                     client.BaseAddress = new Uri(serviceAddress);

  72:                     client.DefaultRequestHeaders.Accept.Clear();

  73:                     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

  74:                     var postUrl = string.Format("api/Device?address={0}&data={1}&ApiKey=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",

  75:                         eibAddress, data);

  76:                     var response = await client.PostAsync(postUrl, new StringContent(string.Empty));

  77:                     if (response.IsSuccessStatusCode)

  78:                     {

  79:                         EventLog.WriteEntry(EventSource,

  80:                             string.Format("Executin {0}={1} returned a success status code",

  81:                                 eibAddress, data),

  82:                             EventLogEntryType.Information);

  83:                         return response.ReasonPhrase;

  84:                     }

  85:                     //else error

  86:

  87:                     EventLog.WriteEntry(EventSource,

  88:                             string.Format("Executin {0}={1} did not return a success status code. Status Code: {2}",

  89:                                 eibAddress, data, response.StatusCode),

  90:                             EventLogEntryType.Error);

  91:                 }

  92:             }

  93:             catch (Exception ex)

  94:             {

  95:                 EventLog.WriteEntry(EventSource,

  96:                     string.Format("Executin {0}={1} error with exception: {2}",

  97:                         eibAddress, data, ex.Message), EventLogEntryType.Error);

  98:             }

  99:             return "Error";

 100:         }

 101:     }

 102: }

For implementing the new task scheduling command, I use an Enterprise Service COM object that implements the ITaskHandler, to spare the need to run an external executable. This object is signed, GAC installed and regsvcs registered. This is the simplest way to implement ITaskHandler in .NET. For more information look at this project.

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Diagnostics;

   4: using System.Linq;

   5: using System.Net.Http;

   6: using System.Net.Http.Headers;

   7: using System.Runtime.InteropServices;

   8: using System.Text;

   9: using System.Threading.Tasks;

  10:

  11: namespace EIBCommandTask

  12: {

  13:

  14:     [ComVisible(true), Guid("6B0852C5-779C-417E-B610-C47902A81E89"),

  15: ClassInterface(ClassInterfaceType.None)]

  16:     public class CommandTaskHandler : TaskHandlerBase

  17:     {

  18:         //http://www.lukebrowning.com/blog/event-viewer-logging-in-c/

  19:         private const string EventSource = "EIB CommandTaskHandler";

  20:         public override async void Start(string data)

  21:         {

  22: #if DEBUG

  23:             Debugger.Launch();

  24: #endif

  25:             try

  26:             {

  27:

  28:                 using (var client = new HttpClient())

  29:                 {

  30:                     if (!EventLog.SourceExists(EventSource))

  31:                     {

  32:                         EventLog.CreateEventSource(EventSource, EventSource);

  33:                     }

  34:

  35:                     var commandInfo = CommandInfo.Parse(data);

  36:                     EventLog.WriteEntry(EventSource,

  37:                         string.Format("About to execute {0}={1}, service address: {2}",

  38:                             commandInfo.EIBAddress, commandInfo.Data, commandInfo.ServiceAddress),

  39:                                 EventLogEntryType.Information);

  40:

  41:                     client.BaseAddress = new Uri(commandInfo.ServiceAddress);

  42:                     client.DefaultRequestHeaders.Accept.Clear();

  43:                     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

  44:                     var postUrl = string.Format("api/Device?address={0}&data={1}&ApiKey= XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX ",

  45:                         commandInfo.EIBAddress, commandInfo.Data);

  46:                     var response = await client.PostAsync(postUrl, new StringContent(string.Empty));

  47:                     if (response.IsSuccessStatusCode)

  48:                     {

  49:                         EventLog.WriteEntry(EventSource,

  50:                         string.Format("Executin {0}={1} returned a success status code",

  51:                             commandInfo.EIBAddress, commandInfo.Data),

  52:                                 EventLogEntryType.Information);

  53:                     }

  54:                     else

  55:                     {

  56:                         EventLog.WriteEntry(EventSource,

  57:                         string.Format("Executin {0}={1} did not return a success status code",

  58:                             commandInfo.EIBAddress, commandInfo.Data),

  59:                                 EventLogEntryType.Error);

  60:                     }

  61:                 }

  62:             }

  63:             catch (Exception ex)

  64:             {

  65:                 EventLog.WriteEntry(EventSource,

  66:                         string.Format("Exception when trying to set: {0}, exception:{1}", data, ex), EventLogEntryType.Error);

  67:             }

  68:         }

  69:     }

  70: }

The Scheduler:

In the server, I use the Task Scheduler COM interface API to set the future task. I also provide an interface to query and delete future commands. Later when I will write about the client app, I will show how the client manages future tasks:

image

The Scheduler code:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Configuration;

   4: using System.Diagnostics;

   5: using TaskScheduler;

   6:

   7: namespace FliessHomeAutomationLogic.Scheduler

   8: {

   9:     class HomeAutomationScheduler : IHomeAutomationScheduler

  10:     {

  11:         private const string EIBDelayedSendTelegram = "EibDelayedSendTelegram";

  12:

  13:         public void ScheduleTelegrams(string serviceAddress, IEnumerable<ScheduleTelegramData> telegrams)

  14:         {

  15:             foreach (var telegram in telegrams)

  16:             {

  17:                 SetDelayedTask(serviceAddress, telegram.Address, telegram.Data, telegram.Start);

  18:             }

  19:         }

  20:

  21:         public void DeleteScheduleTelegrams(IEnumerable<ScheduleTelegramData> telegrams)

  22:         {

  23:             foreach (var telegram in telegrams)

  24:             {

  25:                 DeleteDelayedTask(telegram.Address, telegram.Data, telegram.Start);

  26:             }

  27:         }

  28:

  29:         public IEnumerable<ScheduleTelegramData> GetScheduleTelegrams(string address)

  30:         {

  31:             try

  32:             {

  33:                 EventLog.WriteEntry("HomeAutomationScheduler", "Getting list of scheduled tasks", EventLogEntryType.Information);

  34:

  35:                 var currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture;

  36:                 System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("EN-US");

  37:

  38:                 var telegrams = new List<ScheduleTelegramData>();

  39:                 try

  40:                 {

  41:                     ITaskService taskScheduler = new TaskScheduler.TaskScheduler();

  42:                     taskScheduler.Connect();

  43:

  44:                     ITaskFolder taskFolder = GetOrCreateTaskFolder(taskScheduler);

  45:

  46:                     IRegisteredTaskCollection tasks = taskFolder.GetTasks(0);

  47:

  48:                     foreach (IRegisteredTask task in tasks)

  49:                     {

  50:                         if (task.LastRunTime.Year != 1899) //already ran

  51:                             continue;

  52:

  53:                         var actionIter = task.Definition.Actions.GetEnumerator();

  54:                         actionIter.MoveNext();

  55:                         dynamic action = actionIter.Current;

  56:                         var commandInfo = CommandInfo.Create(action.Data);

  57:

  58:                         if (commandInfo.EIBAddress != address)

  59:                             continue;

  60:

  61:                         var triggerIter = task.Definition.Triggers.GetEnumerator();

  62:                         triggerIter.MoveNext();

  63:                         dynamic trigger = triggerIter.Current;

  64:                         var date = DateTime.Parse(trigger.StartBoundary);

  65:

  66:                         telegrams.Add(

  67:                             new ScheduleTelegramData

  68:                             {

  69:                                 Address = commandInfo.EIBAddress,

  70:                                 Data = commandInfo.Data,

  71:                                 Start = date

  72:                             });

  73:                     }

  74:                     return telegrams;

  75:                 }

  76:                 finally

  77:                 {

  78:                     System.Threading.Thread.CurrentThread.CurrentCulture = currentCulture;

  79:                 }

  80:             }

  81:             catch (Exception exception)

  82:             {

  83:                 EventLog.WriteEntry("HomeAutomationScheduler", "Error getting tasks. Error: " + exception, EventLogEntryType.Error);

  84:                 throw;

  85:             }

  86:         }

  87:

  88:         private void SetDelayedTask(string serviceAddress, string address, byte data, DateTime trigger)

  89:         {

  90:            var currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture;

  91:            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("EN-US");

  92:             try

  93:             {

  94:

  95:                 var taskName = "EIBTask " + address.Replace('/','.') + "=" + data + " " + trigger.ToLongTimeString().Replace(':',' ');

  96:                 RegisterSendTelegramTask(serviceAddress, address, data, trigger, taskName);

  97:             }

  98:             finally

  99:             {

 100:                 System.Threading.Thread.CurrentThread.CurrentCulture = currentCulture;

 101:             }

 102:

 103:         }

 104:

 105:         private void DeleteDelayedTask(string address, byte data, DateTime trigger)

 106:         {

 107:             var currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture;

 108:             System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("EN-US");

 109:             try

 110:             {

 111:

 112:                 var taskName = "EIBTask " + address.Replace('/', '.') + "=" + data + " " + trigger.ToLongTimeString().Replace(':', ' ');

 113:                 DeleteRegisteredTelegramTask(taskName);

 114:             }

 115:             finally

 116:             {

 117:                 System.Threading.Thread.CurrentThread.CurrentCulture = currentCulture;

 118:             }

 119:

 120:         }

 121:

 122:

 123:         public static void RegisterSendTelegramTask(string serviceAddress, string address, byte data, DateTime trigger, string taskName)

 124:         {

 125:             try

 126:             {

 127:                 var commandInfo = new CommandInfo { Data = data, EIBAddress = address, ServiceAddress = serviceAddress };

 128:

 129:                 ITaskService taskScheduler = new TaskScheduler.TaskScheduler();

 130:                 taskScheduler.Connect();

 131:

 132:                 ITaskFolder taskFolder = GetOrCreateTaskFolder(taskScheduler);

 133:

 134:

 135:                 ITaskDefinition newTask = taskScheduler.NewTask(0);

 136:

 137:

 138:                 var action = newTask.Actions.Create(_TASK_ACTION_TYPE.TASK_ACTION_COM_HANDLER) as IComHandlerAction;

 139:                 Debug.Assert(action != null);

 140:                 var jsonData = commandInfo.ToString();

 141:

 142:                 //newTask.Data = jsonData;

 143:                 action.Data = jsonData;

 144:                 action.ClassId = "6B0852C5-779C-417E-B610-C47902A81E89";

 145:                 action.Id = "Send EIB Telegram " + taskName;

 146:

 147:                 //Delete the task 20 minutes after execution

 148:                 newTask.Settings.DeleteExpiredTaskAfter = "PT20M";

 149:                 newTask.Settings.DisallowStartIfOnBatteries = false;

 150:

 151:                 newTask.Settings.Enabled = true;

 152:

 153:                 //5 minutes to finish execution

 154:                 newTask.Settings.ExecutionTimeLimit = "PT5M";

 155:                 newTask.Settings.WakeToRun = true;

 156:                 newTask.Settings.StartWhenAvailable = true;

 157:

 158:                 var timeTrigger = newTask.Triggers.Create(_TASK_TRIGGER_TYPE2.TASK_TRIGGER_TIME) as ITimeTrigger;

 159:                 Debug.Assert(timeTrigger != null);

 160:

 161:                 timeTrigger.Id = "Send EIB Telegram " + taskName + " " + trigger.TimeOfDay;

 162:                 timeTrigger.StartBoundary = trigger.ToString("s");

 163:                 timeTrigger.EndBoundary = (trigger + TimeSpan.FromHours(1)).ToString("s");

 164:

 165:                 string user = ConfigurationManager.AppSettings["User"];

 166:                 string password = ConfigurationManager.AppSettings["Password"];

 167:

 168:                 if (string.IsNullOrWhiteSpace(user) || string.IsNullOrWhiteSpace(password))

 169:                 {

 170:                     EventLog.WriteEntry("HomeAutomationScheduler", "Error getting user credential from application config file (app.config/web.config)", EventLogEntryType.Error);

 171:                     throw new ConfigurationErrorsException("Error getting user credential from application config file (app.config/web.config)");

 172:                 }

 173:

 174:                 IRegisteredTask registeredTask =

 175:                     taskFolder.RegisterTaskDefinition(taskName, newTask, (int)_TASK_CREATION.TASK_CREATE_OR_UPDATE, user, password,

 176:                                                      _TASK_LOGON_TYPE.TASK_LOGON_PASSWORD, null);

 177:

 178:

 179:                 EventLog.WriteEntry("HomeAutomationScheduler", "Task " + taskName + "run at " + registeredTask.NextRunTime.ToLongTimeString(), EventLogEntryType.Information);

 180:             }

 181:             catch (Exception exception)

 182:             {

 183:                 EventLog.WriteEntry("HomeAutomationScheduler", "Error setting task " + taskName + "  Error: " + exception, EventLogEntryType.Error);

 184:                 throw;

 185:             }

 186:         }

 187:

 188:         public static void DeleteRegisteredTelegramTask(string taskName)

 189:         {

 190:             try

 191:             {

 192:                 ITaskService taskScheduler = new TaskScheduler.TaskScheduler();

 193:                 taskScheduler.Connect();

 194:

 195:                 ITaskFolder taskFolder = GetOrCreateTaskFolder(taskScheduler);

 196:

 197:                 taskFolder.DeleteTask(taskName, 0);

 198:

 199:                 EventLog.WriteEntry("HomeAutomationScheduler",

 200:                         "Task " + taskName + "was deleted", EventLogEntryType.Information);

 201:             }

 202:             catch (Exception exception)

 203:             {

 204:                 EventLog.WriteEntry("HomeAutomationScheduler", "Error deleting task " + taskName + "  Error: " + exception, EventLogEntryType.Error);

 205:                 throw;

 206:             }

 207:         }

 208:

 209:         private static ITaskFolder GetOrCreateTaskFolder(ITaskService taskScheduler)

 210:         {

 211:              ITaskFolder rootFolder = taskScheduler.GetFolder(@"\");

 212:

 213:              ITaskFolder eibDelayedSendTelegramFolder = null;

 214:

 215:             try

 216:              {

 217:                  eibDelayedSendTelegramFolder = rootFolder.GetFolder(EIBDelayedSendTelegram);

 218:              }

 219:              catch (Exception exception)

 220:              {

 221:                  EventLog.WriteEntry("HomeAutomationScheduler", "Error getting EibDelayedSendTelegram Scheduler folder: " + exception, EventLogEntryType.Warning);

 222:              }

 223:

 224:              eibDelayedSendTelegramFolder = eibDelayedSendTelegramFolder ?? rootFolder.CreateFolder(EIBDelayedSendTelegram, "D:(A;;FA;;;WD)");

 225:

 226:              return eibDelayedSendTelegramFolder;

 227:         }

 228:

 229:

 230:     }

 231: }

FliessHomeAutomationGateway

The REST service ASP.NET MVC app:

a. I have implemented the AuthorizationFilterAttribute to support simple ApiKey based security, when using with https, I have client app authentication and authorization

b. Using the C# XML document generation, we get the API help page:

image

Turning on the light using the Test Page:

image

Get the Device Info:

image

The result:

image

In the next blog post I will write about the client side – the Windows 8.1 Universal App!

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*