Skip to content

Commit

Permalink
HAInterface -> Expanded to allow delegating incoming commands. Basic …
Browse files Browse the repository at this point in the history
…State Device. Start on Basic REST API. All Unit Tests pass.
  • Loading branch information
zonyl committed Sep 16, 2015
1 parent b3bcc6b commit 0f89735
Show file tree
Hide file tree
Showing 10 changed files with 357 additions and 101 deletions.
31 changes: 31 additions & 0 deletions Netomity/Devices/StateDevice.cs
@@ -0,0 +1,31 @@
using Netomity.Core;
using Netomity.Interfaces;
using Netomity.Interfaces.HA;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Netomity.Devices
{
public class StateDevice: NetomityObject
{
HAInterface _iface = null;
string _address = null;

public StateDevice(HAInterface iface, string address)
{
_iface = iface;
_address = address;

_iface.OnCommand(address: _address, action: _CommandReceived);
}

private void _CommandReceived(Command command)
{

}

}
}
99 changes: 73 additions & 26 deletions Netomity/Interfaces/HA/HAInterface.cs
Expand Up @@ -9,16 +9,20 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Threading;
using System.Collections.Generic;

namespace Netomity.Interfaces.HA
{

public class HAInterface: NetomityObject
{
protected BasicInterface _interface = null;
protected ConcurrentQueue<string> _receivedData = null;
protected ConcurrentQueue<string> _receivedMessages = null;
protected Dictionary<Guid, CommandQueueDetail> _outgoingCommandQueueDetail = null;
protected Task _taskDispatch = null;
protected List<Tuple<string, OnCommandCallBack>> _OnCommandList = null;
protected List<Tuple<string, Action<Command>>> _OnCommandListA = null;

private const int SEND_RETRIES = 3;

Expand All @@ -35,6 +39,8 @@ public HAInterface(BasicInterface basicInterface)
_interface = basicInterface;
_receivedData = new ConcurrentQueue<string>();
_outgoingCommandQueueDetail = new Dictionary<Guid, CommandQueueDetail>();
_OnCommandList = new List<Tuple<string, OnCommandCallBack>>();
_OnCommandListA = new List<Tuple<string, Action<Command>>>();

_interface.DataReceived += _DataReceived;
Log("Initialized");
Expand All @@ -54,7 +60,9 @@ public HAInterface(BasicInterface basicInterface)

public virtual void _DataReceived(string data)
{
Log(data);
Log(String.Format("HA Interface Received: >{0}< ({1})",
data,
Conversions.AsciiToHex(data)));
_receivedData.Enqueue(data);
}

Expand Down Expand Up @@ -87,12 +95,13 @@ public async Task<bool> Send(SendParams sp)
Log("Waiting Results");
return await Task.Run(() =>
{
var success = false;
Log("Waiting");
commandResponseEvent.WaitOne();
if (commandQueueDetail.Status == CommandStatus.Success)
return true;
else
return false;
success = true;
_outgoingCommandQueueDetail.Remove(commandId);
return success;
});

}
Expand All @@ -114,24 +123,58 @@ private void DispatchIncoming()
string data;
if (_receivedData.TryDequeue(out data))
{
foreach (var key in _outgoingCommandQueueDetail.Keys)
{
var commandDetail = _outgoingCommandQueueDetail[key];
if (commandDetail.Success == data)
{
Log("Success");
commandDetail.Status = CommandStatus.Success;
commandDetail.CommandResponseEvent.Set();
}
if (commandDetail.Failure == data)
{
Log("Failure");
commandDetail.Status = CommandStatus.Failure;
commandDetail.CommandResponseEvent.Set();
}
if (!DispatchIncomingExpected(data))
DispatchIncomingUnexpected(data);
}
}

private bool DispatchIncomingExpected(string data)
{

foreach (var key in _outgoingCommandQueueDetail.Keys)
{
var commandDetail = _outgoingCommandQueueDetail[key];
Log(String.Format("Received Something in Queue: {0} {1} {2}",
Conversions.AsciiToHex(data),
Conversions.AsciiToHex(commandDetail.Success),
Conversions.AsciiToHex(commandDetail.Failure)
));
if (commandDetail.Success == data)
{
Log("Success");
commandDetail.Status = CommandStatus.Success;
commandDetail.CommandResponseEvent.Set();
return true;
}
if (commandDetail.Failure == data)
{
Log("Failure");
commandDetail.Status = CommandStatus.Failure;
commandDetail.CommandResponseEvent.Set();
return true;
}

}
return false;
}

public virtual void DispatchIncomingUnexpected(string data)
{
var command = _DataToCommand(data);

var delegates = _OnCommandList.Where(x => x.Item1 == command.Destination || x.Item1 == null).ToList();
delegates.ForEach(x => x.Item2(command));
var delegatesA = _OnCommandListA.Where(x => x.Item1 == command.Destination || x.Item1 == null).ToList();
delegatesA.ForEach(x => x.Item2(command));

}

private Command _DataToCommand(string data)
{
if (data.ToLower() == CommandType.On.ToString().ToLower())
return new Command() { Type = CommandType.On, Destination = null };
else
return new Command() { Type = CommandType.Off, Destination = null };
}

private void DispatchOutgoing()
Expand All @@ -140,7 +183,9 @@ private void DispatchOutgoing()
.Where((x) => x.Status == CommandStatus.Pending);
foreach (var outgoing in outgoingList)
{
Log(String.Format("Sending Command: {0}", outgoing.Command));
Log(String.Format("HA Interface Sending: >{0}< ({1})",
outgoing.Command,
Conversions.AsciiToHex(outgoing.Command)));
_interface.Send(outgoing.Command);
outgoing.OriginalSentTime = DateTime.Now;
outgoing.Status = CommandStatus.Sent;
Expand All @@ -162,16 +207,18 @@ private void DispatchOutgoingTimeouts()
}
}

private void ProcessIncoming(string data)
{
Log(String.Format(
"Unexpected Incoming Data: >{0}<",
data)
);
public delegate void OnCommandCallBack(Command command);

public void OnCommand(string address, OnCommandCallBack callback )
{
_OnCommandList.Add(new Tuple<string, OnCommandCallBack>( address, callback ));

}

public void OnCommand(string address, Action<Command> action)
{
_OnCommandListA.Add(new Tuple<string, Action<Command>>(address, action));
}
}

public class CommandQueueDetail
Expand Down
9 changes: 6 additions & 3 deletions Netomity/Interfaces/HA/Insteon.cs
Expand Up @@ -54,13 +54,16 @@ public void Command(Command command)
var failResponse = lCommand;
failResponse.Add(0x15);

Send(new SendParams(){
var response = Send(new SendParams(){
SendData = aCommand,
SuccessResponse = aCommand + 0x06,
FailureResponse = aCommand + 0x15,
SuccessResponse = aCommand + Conversions.HexToAscii("06"),
FailureResponse = aCommand + Conversions.HexToAscii("15"),
Timeout = 2000
}
);

Log(String.Format("Command Status: {0}", response.Result));


}

Expand Down
5 changes: 5 additions & 0 deletions Netomity/Netomity.csproj
Expand Up @@ -44,6 +44,8 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.ServiceModel.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
Expand All @@ -57,6 +59,7 @@
<Compile Include="Core\NetomitySystem.cs" />
<Compile Include="Core\NetomityObject.cs" />
<Compile Include="Core\PeriodicTimer.cs" />
<Compile Include="Devices\StateDevice.cs" />
<Compile Include="Interfaces\Basic\BasicConnector.cs" />
<Compile Include="Interfaces\Basic\BasicInterface.cs" />
<Compile Include="Interfaces\Basic\IBasicInterface.cs" />
Expand All @@ -70,6 +73,8 @@
<Compile Include="Interfaces\HA\SendParams.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utility\Conversions.cs" />
<Compile Include="Web\RestAPI.cs" />
<Compile Include="Web\RestHost.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand Down
22 changes: 22 additions & 0 deletions Netomity/Web/RestAPI.cs
@@ -0,0 +1,22 @@
using Netomity.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Threading.Tasks;

namespace Netomity.Web
{
[ServiceContract()]
public class RestAPI: NetomityObject
{
[WebGet(ResponseFormat = WebMessageFormat.Json)]
[OperationContract()]
public long Add(int a, int b)
{
return (a + b);
}
}
}
49 changes: 49 additions & 0 deletions Netomity/Web/RestHost.cs
@@ -0,0 +1,49 @@
using Netomity.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;

namespace Netomity.Web
{
public class RestHost : NetomityObject
{
public const string BASE_URL = "http://localhost:8081/Netomity/API/v1";
ServiceHost _host = null;

public RestHost()
{
Open();
}

public void Open()
{
//http://msdn.microsoft.com/en-us/library/ms733768.aspx
//netsh http add urlacl url=http://+:8081/Netomity/API/v1 user=DOMAIN\user
//netsh http add urlacl url=http://+:8081/Netomity/API/v1 user=jason
_host = new ServiceHost(typeof(RestAPI),
new Uri[] { });

WebHttpBinding binding = new WebHttpBinding(WebHttpSecurityMode.None);

ServiceEndpoint endPoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(RestAPI)),
binding, new EndpointAddress(BASE_URL));
WebHttpBehavior webBehavior = new WebHttpBehavior();
endPoint.Behaviors.Add(webBehavior);
_host.AddServiceEndpoint(endPoint);

_host.Open();
Log("Netomity RestAPI Service Started");
}

public void Close()
{
if (_host == null)
_host.Close();

}
}
}
38 changes: 38 additions & 0 deletions NetomityTests/Devices/StateDeviceTests.cs
@@ -0,0 +1,38 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Netomity.Devices;
using Netomity.Interfaces.HA;
using Netomity.Interfaces.Basic;

namespace NetomityTests.Devices
{
[TestClass]
public class StateDeviceTests
{
StateDevice _sd = null;
HAInterface _ha = null;
BasicInterface _t = null;

string _data;

[TestInitialize]
public void SetUp()
{
_t = new Netomity.Interfaces.Basic.Fakes.StubBasicInterface()
{
SendString = (data) => { _data = data; },
DataReceivedEvent = (ev) => { _t._DataReceived(ev); },
};
_ha = new Netomity.Interfaces.HA.Fakes.StubHAInterface(basicInterface: _t)
{

};
_sd = new StateDevice(iface: _ha, address: "12.34.56");
}
[TestMethod]
public void TestInstantiation()
{
Assert.IsNotNull(_sd);
}
}
}

0 comments on commit 0f89735

Please sign in to comment.