diff --git a/ThinkingHome.NooLite.Console/Program.cs b/ThinkingHome.NooLite.Console/Program.cs index 1f29420..e1a63d2 100644 --- a/ThinkingHome.NooLite.Console/Program.cs +++ b/ThinkingHome.NooLite.Console/Program.cs @@ -61,6 +61,8 @@ static void Main(string[] args) app.Command("ports", PortsCommand); app.Command("bind", BindCommand); + app.Command("bindstart", BindStartCommand); + app.Command("bindstop", BindStopCommand); app.Command("unbind", UnbindCommand); app.Command("on", OnCommand); app.Command("off", OffCommand); @@ -109,6 +111,22 @@ private static void BindCommand(CommandLineApplication cmd) cmd.OnExecute(() => Invoke(args, (a, c) => a.Bind(c), (a, c) => a.BindF(c))); } + private static void BindStartCommand(CommandLineApplication cmd) + { + var args = AddCommonArgs(cmd); + + cmd.Description = "Start binding the specified adapter channel to the nooLite sensor."; + cmd.OnExecute(() => Invoke(args, (a, c) => a.BindStart(c), (a, c) => a.BindStart(c))); + } + + private static void BindStopCommand(CommandLineApplication cmd) + { + var args = AddCommonArgs(cmd); + + cmd.Description = "Stop binding the specified adapter channel from the nooLite sensor."; + cmd.OnExecute(() => Invoke(args, (a, c) => a.BindStop(), (a, c) => a.BindStop())); + } + private static void UnbindCommand(CommandLineApplication cmd) { var args = AddCommonArgs(cmd); diff --git a/ThinkingHome.NooLite.Tests/F/CommandTest.cs b/ThinkingHome.NooLite.Tests/F/CommandTest.cs new file mode 100644 index 0000000..fdb2299 --- /dev/null +++ b/ThinkingHome.NooLite.Tests/F/CommandTest.cs @@ -0,0 +1,12 @@ +using Xunit; + +namespace ThinkingHome.NooLite.Tests.MicroclimateData +{ + using H = TestHelpers; + + public class CommandTest + { + + + } +} \ No newline at end of file diff --git a/ThinkingHome.NooLite.Tests/SendData/ParseTests.cs b/ThinkingHome.NooLite.Tests/SendData/ParseTests.cs new file mode 100644 index 0000000..ac73e53 --- /dev/null +++ b/ThinkingHome.NooLite.Tests/SendData/ParseTests.cs @@ -0,0 +1,96 @@ +using System; +using ThinkingHome.NooLite.Internal; +using Xunit; + +namespace ThinkingHome.NooLite.Tests.SendData +{ + using H = TestHelpers; + + public class ParseTests + { + [Fact] + public void Parse_Mode_IsCorrect() + { + const byte RXF_CODE = 3; + byte[] bytes = H.GetBytes().Set(1, RXF_CODE); + + var data = new NooLite.ReceivedData(bytes); + + Assert.Equal(MTRFXXMode.RXF, data.Mode); + } + + [Fact] + public void Parse_ResultCode_IsCorrect() + { + const byte NO_RESPONSE_CODE = 1; + byte[] bytes = H.GetBytes().Set(2, NO_RESPONSE_CODE); + + var data = new NooLite.ReceivedData(bytes); + + Assert.Equal(ResultCode.NoResponse, data.Result); + } + + [Fact] + public void Parse_Remains_IsCorrect() + { + const byte REMAINS_TEST_VALUE = 133; + byte[] bytes = H.GetBytes().Set(3, REMAINS_TEST_VALUE); + + var data = new NooLite.ReceivedData(bytes); + + Assert.Equal(REMAINS_TEST_VALUE, data.Remains); + } + + [Fact] + public void Parse_Channel_IsCorrect() + { + const byte CHANNEL_TEST_VALUE = 8; + byte[] bytes = H.GetBytes().Set(4, CHANNEL_TEST_VALUE); + + var data = new NooLite.ReceivedData(bytes); + + Assert.Equal(CHANNEL_TEST_VALUE, data.Channel); + } + + [Fact] + public void Parse_Command_IsCorrect() + { + const byte COMMAND_SEND_STATE_CODE = 130; + byte[] bytes = H.GetBytes().Set(5, COMMAND_SEND_STATE_CODE); + + var data = new NooLite.ReceivedData(bytes); + + Assert.Equal(MTRFXXCommand.SendState, data.Command); + } + + [Fact] + public void Parse_Data_IsCorrect() + { + const byte FMT_TEST_VALUE = 2; + byte[] TEST_DATA = {22, 33, 44, 55}; + + byte[] bytes = H.GetBytes() + .Set(6, FMT_TEST_VALUE) + .Set(7, TEST_DATA); + + var data = new NooLite.ReceivedData(bytes); + + Assert.Equal(FMT_TEST_VALUE, data.DataFormat); + Assert.Equal(22, data.Data1); + Assert.Equal(33, data.Data2); + Assert.Equal(44, data.Data3); + Assert.Equal(55, data.Data4); + } + + [Fact] + public void Parse_DeviceId_IsCorrect() + { + byte[] bytesOfId = {0, 21, 5, 13}; + byte[] bytes = H.GetBytes().Set(11, bytesOfId); + + var data = new NooLite.ReceivedData(bytes); + + Assert.Equal((UInt32) 1377549, data.DeviceId); + } + } +} \ No newline at end of file diff --git a/ThinkingHome.NooLite.Tests/SendData/ValidationTests.cs b/ThinkingHome.NooLite.Tests/SendData/ValidationTests.cs new file mode 100644 index 0000000..33127f6 --- /dev/null +++ b/ThinkingHome.NooLite.Tests/SendData/ValidationTests.cs @@ -0,0 +1,54 @@ +using System; +using Xunit; + +namespace ThinkingHome.NooLite.Tests.ReceivedData +{ + public class ValidationTests + { + public const int VALID_DATA_SIZE = 17; + + [Fact] + public void Constructor_ForNull_ThrowsException() + { + byte[] nullReceivedData = null; + + Exception ex = Assert.ThrowsAny(() => new NooLite.ReceivedData(nullReceivedData)); + + Assert.Contains("null", ex.Message); + } + + [Fact] + public void Constructor_ForInvalidDataSize_ThrowsException() + { + byte[] invalidSizeData = new byte[3]; + + Exception ex = Assert.ThrowsAny(() => new NooLite.ReceivedData(invalidSizeData)); + + Assert.Contains("length", ex.Message); + } + + + [Fact] + public void Constructor_ForInvalidFirstByte_ThrowsException() + { + byte[] testData = new byte[VALID_DATA_SIZE]; + testData[0] = 124; + + Exception ex = Assert.ThrowsAny(() => new NooLite.ReceivedData(testData)); + + Assert.Contains("start", ex.Message); + } + + [Fact] + public void Constructor_ForInvalidLastByte_ThrowsException() + { + byte[] testData = new byte[VALID_DATA_SIZE]; + testData[0] = 173; // valid start marker + testData[VALID_DATA_SIZE - 1] = 124; + + Exception ex = Assert.ThrowsAny(() => new NooLite.ReceivedData(testData)); + + Assert.Contains("stop", ex.Message); + } + } +} \ No newline at end of file diff --git a/ThinkingHome.NooLite/Internal/MTRFXXAction.cs b/ThinkingHome.NooLite/Internal/MTRFXXAction.cs index 3246157..6101ce8 100644 --- a/ThinkingHome.NooLite/Internal/MTRFXXAction.cs +++ b/ThinkingHome.NooLite/Internal/MTRFXXAction.cs @@ -1,5 +1,20 @@ namespace ThinkingHome.NooLite.Internal { + /* + Бит 5…0 – Команда адаптеру(0…63) + Значение=0 – Передать команду + Значение=1 – Передать широковещательную команду + (одновременно всем устройствам на канале CH) + Значение=2 – Считать ответ(состояние приѐмного буфера) + Значение=3 – Включить привязку + Значение=4 – Выключить привязку + Значение=5 – Очистить ячейку(канал) + Значение=6 – Очистить память(все каналы) + Значение=7 – Отвязать адрес от канала + Значение=8 – Передать команду по указанному адресу + nooLite-F + Бит 6…7 – Nrep, количество дополнительных повторовкоманды(0...3). Количество передач команд = 2+Nrep + */ public enum MTRFXXAction : byte { SendCommand = 0, diff --git a/ThinkingHome.NooLite/MTRFXXAdapterExtensions.cs b/ThinkingHome.NooLite/MTRFXXAdapterExtensions.cs index ff7cf3a..4ebfea3 100644 --- a/ThinkingHome.NooLite/MTRFXXAdapterExtensions.cs +++ b/ThinkingHome.NooLite/MTRFXXAdapterExtensions.cs @@ -34,6 +34,21 @@ private static void SendData(MTRFXXAdapter adapter, MTRFXXCommand command, bool } + + #endregion + + #region read state + + public static void ReadState(this MTRFXXAdapter adapter, byte channel) + { + throw new NotSupportedException("Not supported in basic mode."); + } + + public static void ReadStateF(this MTRFXXAdapter adapter, byte channel, UInt32? deviceId = null) + { + SendReadState(adapter, channel); + } + #endregion #region brightness @@ -262,6 +277,11 @@ public static void UnbindF(this MTRFXXAdapter adapter, byte channel) #region RX mode + private static void SendReadState(this MTRFXXAdapter adapter, byte channel) + { + adapter.SendCommand(MTRFXXMode.TXF, MTRFXXAction.SendCommand, channel, MTRFXXCommand.ReadState); + } + public static void BindStart(this MTRFXXAdapter adapter, byte channel) { adapter.SendCommand(MTRFXXMode.RX, MTRFXXAction.StartBinding, channel, MTRFXXCommand.None); @@ -288,6 +308,7 @@ public static void ExitServiceMode(this MTRFXXAdapter adapter) adapter.SendCommand(MTRFXXMode.Service, MTRFXXAction.SendCommand, 0, MTRFXXCommand.None); } + #endregion } } \ No newline at end of file diff --git a/ThinkingHome.NooLite/ReceivedData.cs b/ThinkingHome.NooLite/ReceivedData.cs index 3c5f46b..bf2294b 100644 --- a/ThinkingHome.NooLite/ReceivedData.cs +++ b/ThinkingHome.NooLite/ReceivedData.cs @@ -6,6 +6,8 @@ namespace ThinkingHome.NooLite { public class ReceivedData { + //https://www.noo.by/wiki/index.php?title=API_%D1%88%D0%BB%D1%8E%D0%B7%D0%B0/%D0%B0%D0%B4%D0%B0%D0%BF%D1%82%D0%B5%D1%80%D0%B0_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B_nooLite(-F)&mobileaction=toggle_view_mobile + #region static public const byte START_MARKER = 173;