From 20a42cafc7562acdc68a36846f0f1cd1c8aa2c4a Mon Sep 17 00:00:00 2001 From: Kareem Sultan Date: Sun, 9 Feb 2014 14:46:45 -0500 Subject: [PATCH] First Commit --- .gitignore | 1 + SharpSpark.Tests/App.config.sample | 7 ++ SharpSpark.Tests/Properties/AssemblyInfo.cs | 36 ++++++++ SharpSpark.Tests/SharpSpark.Tests.csproj | 97 +++++++++++++++++++++ SharpSpark.Tests/SharpSparkTests.playlist | 1 + SharpSpark.Tests/SparkClientTests.cs | 51 +++++++++++ SharpSpark.Tests/TinkerUnitTests.cs | 57 ++++++++++++ SharpSpark.sln | 28 ++++++ SharpSpark/CloudApiHttpClient.cs | 42 +++++++++ SharpSpark/Properties/AssemblyInfo.cs | 36 ++++++++ SharpSpark/SharpSpark.csproj | 77 ++++++++++++++++ SharpSpark/SparkClient.cs | 81 +++++++++++++++++ SharpSpark/SparkDevice.cs | 12 +++ SharpSpark/SparkErrorResult.cs | 8 ++ SharpSpark/SparkResult.cs | 22 +++++ SharpSpark/TinkerClient.cs | 44 ++++++++++ SharpSpark/packages.config | 7 ++ 17 files changed, 607 insertions(+) create mode 100644 SharpSpark.Tests/App.config.sample create mode 100644 SharpSpark.Tests/Properties/AssemblyInfo.cs create mode 100644 SharpSpark.Tests/SharpSpark.Tests.csproj create mode 100644 SharpSpark.Tests/SharpSparkTests.playlist create mode 100644 SharpSpark.Tests/SparkClientTests.cs create mode 100644 SharpSpark.Tests/TinkerUnitTests.cs create mode 100644 SharpSpark.sln create mode 100644 SharpSpark/CloudApiHttpClient.cs create mode 100644 SharpSpark/Properties/AssemblyInfo.cs create mode 100644 SharpSpark/SharpSpark.csproj create mode 100644 SharpSpark/SparkClient.cs create mode 100644 SharpSpark/SparkDevice.cs create mode 100644 SharpSpark/SparkErrorResult.cs create mode 100644 SharpSpark/SparkResult.cs create mode 100644 SharpSpark/TinkerClient.cs create mode 100644 SharpSpark/packages.config diff --git a/.gitignore b/.gitignore index bdc3535..0ffb192 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,4 @@ Generated_Code #added for RIA/Silverlight projects _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML +SharpSpark.Tests/App.config diff --git a/SharpSpark.Tests/App.config.sample b/SharpSpark.Tests/App.config.sample new file mode 100644 index 0000000..c698949 --- /dev/null +++ b/SharpSpark.Tests/App.config.sample @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/SharpSpark.Tests/Properties/AssemblyInfo.cs b/SharpSpark.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ff310fd --- /dev/null +++ b/SharpSpark.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("sharpspark.tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("sharpspark.tests")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("eb6b72e1-5002-4dd8-97d6-31fc9f9ec948")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SharpSpark.Tests/SharpSpark.Tests.csproj b/SharpSpark.Tests/SharpSpark.Tests.csproj new file mode 100644 index 0000000..ba67c61 --- /dev/null +++ b/SharpSpark.Tests/SharpSpark.Tests.csproj @@ -0,0 +1,97 @@ + + + + Debug + AnyCPU + {9D4E71FE-7394-43FA-A4D4-F75E004EF319} + Library + Properties + sharpspark.tests + sharpspark.tests + v4.5 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + {75c52157-bb62-4888-a321-dc7962de313d} + SharpSpark + + + + + Designer + + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/SharpSpark.Tests/SharpSparkTests.playlist b/SharpSpark.Tests/SharpSparkTests.playlist new file mode 100644 index 0000000..4ddb0e3 --- /dev/null +++ b/SharpSpark.Tests/SharpSparkTests.playlist @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/SharpSpark.Tests/SparkClientTests.cs b/SharpSpark.Tests/SparkClientTests.cs new file mode 100644 index 0000000..2b4d541 --- /dev/null +++ b/SharpSpark.Tests/SparkClientTests.cs @@ -0,0 +1,51 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Maybe5.SharpSpark; +using System.Configuration; + +namespace Maybe5.SharpSpark.Tests +{ + [TestClass] + public class SparkClientTests + { + SparkClient client; + + [TestInitialize] + public void Setup() + { + var accessToken = ConfigurationManager.AppSettings["accessToken"]; + var deviceId = ConfigurationManager.AppSettings["deviceId"]; + client = new SparkClient(accessToken, deviceId); + } + + [TestMethod] + public void GivenClientInfoExpectDeviceInfo() + { + SparkDevice device = client.GetDevice(); + + Assert.IsNotNull(device); + Assert.IsNotNull(device.Name); + Assert.AreEqual(client.DeviceId, device.Id); + } + + [TestMethod] + public void GivenInvalidFunctionExpectErrorFunctionNotFound() + { + SparkResult result = client.ExecuteFunction("thisdoesnotexist"); + + Assert.IsTrue(result.HasErrors); + Assert.AreEqual("Function not found", result.ErrorResult.Error); + } + + [Ignore]//This test only passes if the device is offline + [TestMethod] + public void GivenOfflineDeviceFunctionExpectErrorTimedOut() + { + SparkResult result = client.ExecuteFunction("digitalRead"); + + Assert.IsTrue(result.HasErrors); + Assert.AreEqual("Timed out.", result.ErrorResult.Error); + } + + } +} diff --git a/SharpSpark.Tests/TinkerUnitTests.cs b/SharpSpark.Tests/TinkerUnitTests.cs new file mode 100644 index 0000000..7f0582c --- /dev/null +++ b/SharpSpark.Tests/TinkerUnitTests.cs @@ -0,0 +1,57 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Maybe5.SharpSpark; +using System.Configuration; + + +namespace Maybe5.SharpSpark.Tests +{ + [TestClass] + public class TinkerUnitTests + { + TinkerClient client; + + [TestInitialize] + public void Setup() + { + var accessToken = ConfigurationManager.AppSettings["accessToken"]; + var deviceId = ConfigurationManager.AppSettings["deviceId"]; + client = new TinkerClient(accessToken, deviceId); + } + + [TestMethod] + public void GivenLowPin7WhenDigitalReadExpectPinoutLow() + { + var pinValue = client.DigitalRead(TinkerClient.DigitalPins.D7); + + Assert.AreEqual(TinkerClient.DigitalValue.Low, pinValue); + } + + [TestMethod] + public void GivenLowPin7WhenDigitalWriteHighExpectValidReturnValue() + { + client.DigitalWrite(TinkerClient.DigitalPins.D7, TinkerClient.DigitalValue.High); + + var pinValue = client.DigitalRead(TinkerClient.DigitalPins.D7); + + Assert.AreNotEqual(TinkerClient.ERROR_RETURN_VALUE, pinValue); + } + + [TestMethod] + public void GivenLowA5WhenAnalogReadExpectValidReturnValue() + { + + var pinValue = client.AnalogRead(TinkerClient.AnalogPins.A5); + + Assert.AreNotEqual(TinkerClient.ERROR_RETURN_VALUE, pinValue); + } + + [TestMethod] + public void GivenA5WhenAnalogWrite255ExpectValidReturnValue() + { + var pinValue = client.AnalogRead(TinkerClient.AnalogPins.A5); + + Assert.AreNotEqual(TinkerClient.ERROR_RETURN_VALUE, pinValue); + } + } +} diff --git a/SharpSpark.sln b/SharpSpark.sln new file mode 100644 index 0000000..9e42a4a --- /dev/null +++ b/SharpSpark.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpSpark.Tests", "SharpSpark.Tests\SharpSpark.Tests.csproj", "{9D4E71FE-7394-43FA-A4D4-F75E004EF319}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpSpark", "SharpSpark\SharpSpark.csproj", "{75C52157-BB62-4888-A321-DC7962DE313D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9D4E71FE-7394-43FA-A4D4-F75E004EF319}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D4E71FE-7394-43FA-A4D4-F75E004EF319}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D4E71FE-7394-43FA-A4D4-F75E004EF319}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D4E71FE-7394-43FA-A4D4-F75E004EF319}.Release|Any CPU.Build.0 = Release|Any CPU + {75C52157-BB62-4888-A321-DC7962DE313D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75C52157-BB62-4888-A321-DC7962DE313D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75C52157-BB62-4888-A321-DC7962DE313D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75C52157-BB62-4888-A321-DC7962DE313D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/SharpSpark/CloudApiHttpClient.cs b/SharpSpark/CloudApiHttpClient.cs new file mode 100644 index 0000000..edce996 --- /dev/null +++ b/SharpSpark/CloudApiHttpClient.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; + +namespace Maybe5.SharpSpark +{ + class CloudApiHttpClient + { + public string AccessToken { get; private set; } + public string DeviceId { get; private set; } + + public CloudApiHttpClient(string accessToken, string deviceId) + { + AccessToken = accessToken; + DeviceId = deviceId; + } + + public string GetRawResultForGet(string variableName) + { + using (var client = new HttpClient()) + { + var result = client.GetAsync(String.Format("https://api.spark.io/v1/devices/{0}/{1}?access_token={2}", DeviceId, variableName, AccessToken)).Result; + result.EnsureSuccessStatusCode(); + return result.Content.ReadAsStringAsync().Result; + } + } + + + public HttpResponseMessage GetRawResultForPost(string functionKey, string[] args) + { + using (var client = new HttpClient()) + { + var content = new FormUrlEncodedContent(new[] + { + new KeyValuePair("params", String.Join(",",args)) + }); + return client.PostAsync(String.Format("https://api.spark.io/v1/devices/{0}/{1}?access_token={2}", DeviceId, functionKey, AccessToken), content).Result; + + } + } + } +} diff --git a/SharpSpark/Properties/AssemblyInfo.cs b/SharpSpark/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b8783c3 --- /dev/null +++ b/SharpSpark/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SharpSpark")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SharpSpark")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("01ced307-07e0-47d6-9a3b-13ad769f4ff9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SharpSpark/SharpSpark.csproj b/SharpSpark/SharpSpark.csproj new file mode 100644 index 0000000..06ffa8b --- /dev/null +++ b/SharpSpark/SharpSpark.csproj @@ -0,0 +1,77 @@ + + + + + Debug + AnyCPU + {75C52157-BB62-4888-A321-DC7962DE313D} + Library + Properties + SharpSpark + SharpSpark + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Newtonsoft.Json.6.0.1\lib\net45\Newtonsoft.Json.dll + + + + + + ..\packages\Microsoft.Net.Http.2.2.18\lib\net45\System.Net.Http.Extensions.dll + + + ..\packages\Microsoft.Net.Http.2.2.18\lib\net45\System.Net.Http.Primitives.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SharpSpark/SparkClient.cs b/SharpSpark/SparkClient.cs new file mode 100644 index 0000000..1249e30 --- /dev/null +++ b/SharpSpark/SparkClient.cs @@ -0,0 +1,81 @@ +using Newtonsoft.Json; +using System; + +namespace Maybe5.SharpSpark +{ + public class SparkClient + { + public const int ERROR_RETURN_VALUE = 1; + + public string AccessToken + { + get + { + return CloudApiClient.AccessToken; + } + } + + public string DeviceId + { + get + { + return CloudApiClient.DeviceId; + } + } + + private CloudApiHttpClient CloudApiClient { get; set; } + + public SparkClient(string accessToken, string deviceId) + { + CloudApiClient = new CloudApiHttpClient(accessToken, deviceId); + } + + public SparkResult GetVariable(string variableName) + { + return CloudGet(variableName); + } + + public SparkResult ExecuteFunction(string functionKey, params string[] args) + { + return CloudPost(functionKey, args); + } + + public T GetVariableReturnValue(string variableName) + { + var result = GetVariable(variableName); + return (T)Convert.ChangeType(result.Return_value.ToString(),typeof(T)); + } + + public int ExecuteFunctionReturnValue(string functionKey, params string[] args) + { + var result = ExecuteFunction(functionKey, args); + return int.Parse(result.Return_value.ToString()); + } + + private SparkResult CloudGet(string variableName) + { + var json = CloudApiClient.GetRawResultForGet(variableName); + return JsonConvert.DeserializeObject(json); + } + + private SparkResult CloudPost(string functionKey, string[] args) + { + var response = CloudApiClient.GetRawResultForPost(functionKey, args); + var rawContent = response.Content.ReadAsStringAsync().Result; + if (!response.IsSuccessStatusCode || rawContent.StartsWith("{\n \"error\":")) + { + return new SparkResult() { ErrorResult = JsonConvert.DeserializeObject(rawContent) }; + } + return JsonConvert.DeserializeObject(rawContent); + } + + public SparkDevice GetDevice() + { + var json = CloudApiClient.GetRawResultForGet(String.Empty); + return JsonConvert.DeserializeObject(json); + } + + + + } +} diff --git a/SharpSpark/SparkDevice.cs b/SharpSpark/SparkDevice.cs new file mode 100644 index 0000000..8e3508f --- /dev/null +++ b/SharpSpark/SparkDevice.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace Maybe5.SharpSpark +{ + public class SparkDevice + { + public string Id { get; set; } + public string Name { get; set; } + public Dictionary Variables { get; set; } + public List Functions { get; set; } + } +} diff --git a/SharpSpark/SparkErrorResult.cs b/SharpSpark/SparkErrorResult.cs new file mode 100644 index 0000000..48890c2 --- /dev/null +++ b/SharpSpark/SparkErrorResult.cs @@ -0,0 +1,8 @@ + +namespace Maybe5.SharpSpark +{ + public class SparkErrorResult + { + public string Error { get; set; } + } +} diff --git a/SharpSpark/SparkResult.cs b/SharpSpark/SparkResult.cs new file mode 100644 index 0000000..7ec8ad0 --- /dev/null +++ b/SharpSpark/SparkResult.cs @@ -0,0 +1,22 @@ + +namespace Maybe5.SharpSpark +{ + public class SparkResult + { + public string Id { get; set; } + public string Name { get; set; } + public string Last_app { get; set; } + public bool Connected { get; set; } + public string Return_value { get; set; } + public SparkErrorResult ErrorResult { get; set; } + public bool HasErrors + { + get + { + return ErrorResult != null; + } + } + + + } +} diff --git a/SharpSpark/TinkerClient.cs b/SharpSpark/TinkerClient.cs new file mode 100644 index 0000000..723948d --- /dev/null +++ b/SharpSpark/TinkerClient.cs @@ -0,0 +1,44 @@ +using System; + +namespace Maybe5.SharpSpark +{ + + public class TinkerClient : SparkClient + { + const int DIGITAL_HIGH_RETURN_VALUE = 1; + + public enum DigitalPins { D0, D1, D2, D3, D4, D5, D6, D7 }; + public enum AnalogPins { A0, A1, A2, A3, A4, A5, A6, A7 }; + public enum DigitalValue { Low, High}; + + public TinkerClient(string accessToken, string deviceId) : base(accessToken, deviceId) { } + + public DigitalValue DigitalRead(DigitalPins pin) + { + + var returnValue = ExecuteFunctionReturnValue("digitalread", pin.ToString()); + + if (returnValue == SparkClient.ERROR_RETURN_VALUE) + { + throw new Exception("Failed to read value."); + } + return returnValue == DIGITAL_HIGH_RETURN_VALUE ? DigitalValue.High : DigitalValue.Low; + } + + public int DigitalWrite(DigitalPins pin, DigitalValue pinValue) + { + var returnValue = ExecuteFunctionReturnValue("digitalwrite", pin.ToString(), pinValue.ToString().ToUpper()); + return returnValue; + } + + public int AnalogRead(AnalogPins pin) + { + return ExecuteFunctionReturnValue("analogread", pin.ToString()); + } + + public int AnalogWrite(AnalogPins pin, int pinValue) + { + return ExecuteFunctionReturnValue("analogwrite", pin.ToString(), pinValue.ToString()); + } + } +} diff --git a/SharpSpark/packages.config b/SharpSpark/packages.config new file mode 100644 index 0000000..d7b1cc6 --- /dev/null +++ b/SharpSpark/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file