public override string ToString() { StringBuilder builder = new StringBuilder(); builder.Append("CommandResult ["); if (IsSuccess()) { builder.Append("SUCCESS, ") .Append(Response.ToString()); } else if (IsTimeout()) { builder.Append("TIMEOUT"); } else { ZclStatus status = (ZclStatus)GetStatusCode(); builder.Append("ERROR (") .Append(status.ToString()) .Append(string.Format(",0x{0}), ", ((int)status).ToString("X2"))) .Append(Response); } builder.Append(']'); return(builder.ToString()); }
/// <summary> /// The Default Response /// /// The default response command is generated when a device receives a unicast /// command, there is no other relevant response specified for the command, and /// either an error results or the Disable default response bit of its Frame control field /// is set to 0. /// /// @param commandIdentifier {@link byte} Command identifier /// @param statusCode {@link ZclStatus} Status code /// @return the Task<CommandResult> command result Task /// </summary> public Task <CommandResult> DefaultResponse(byte commandIdentifier, ZclStatus statusCode) { DefaultResponse command = new DefaultResponse(); // Set the fields command.CommandIdentifier = commandIdentifier; command.StatusCode = statusCode; return(Send(command)); }
/// <summary> /// The Write Attributes Structured Command /// /// The write attributes structured command is generated when a device wishes to /// change the values of one or more attributes located on another device. Each write /// attribute record shall contain the identifier and the actual value of the attribute, or /// element thereof, to be written. /// /// @param status {@link ZclStatus} Status /// @param attributeSelectors {@link object} Attribute selectors /// @return the Task<CommandResult> command result Task /// </summary> public Task <CommandResult> WriteAttributesStructuredCommand(ZclStatus status, object attributeSelectors) { WriteAttributesStructuredCommand command = new WriteAttributesStructuredCommand(); // Set the fields command.Status = status; command.AttributeSelectors = attributeSelectors; return(Send(command)); }
/// <summary> /// The Write Attributes Structured Response /// /// The write attributes structured response command is generated in response to a /// write attributes structured command. /// /// @param status {@link ZclStatus} Status /// @param records {@link List<WriteAttributeStatusRecord>} Records /// @return the Task<CommandResult> command result Task /// </summary> public Task <CommandResult> WriteAttributesStructuredResponse(ZclStatus status, List <WriteAttributeStatusRecord> records) { WriteAttributesStructuredResponse command = new WriteAttributesStructuredResponse(); // Set the fields command.Status = status; command.Records = records; return(Send(command)); }
/// <summary> /// The Remove All Scenes Response /// /// <param name="status" <see cref="ZclStatus"> Status</ param > /// <param name="groupId" <see cref="ushort"> Group ID</ param > /// <returns> the command result Task </returns> /// </summary> public Task <CommandResult> RemoveAllScenesResponse(ZclStatus status, ushort groupId) { RemoveAllScenesResponse command = new RemoveAllScenesResponse(); // Set the fields command.Status = status; command.GroupId = groupId; return(Send(command)); }
/// <summary> /// The Configure Reporting Response /// /// The Configure Reporting Response command is generated in response to a /// Configure Reporting command. /// /// @param status {@link ZclStatus} Status /// @param records {@link List<AttributeStatusRecord>} Records /// @return the Task<CommandResult> command result Task /// </summary> public Task <CommandResult> ConfigureReportingResponse(ZclStatus status, List <AttributeStatusRecord> records) { ConfigureReportingResponse command = new ConfigureReportingResponse(); // Set the fields command.Status = status; command.Records = records; return(Send(command)); }
/// <summary> /// The Add Group Response /// /// The add group response is sent by the groups cluster server in response to an add /// group command. /// /// <param name="status" <see cref="ZclStatus"> Status</ param > /// <param name="groupId" <see cref="ushort"> Group ID</ param > /// <returns> the command result Task </returns> /// </summary> public Task <CommandResult> AddGroupResponse(ZclStatus status, ushort groupId) { AddGroupResponse command = new AddGroupResponse(); // Set the fields command.Status = status; command.GroupId = groupId; return(Send(command)); }
/// <summary> /// The View Group Response /// /// The view group response command is sent by the groups cluster server in response to a /// view group command. /// /// <param name="status" <see cref="ZclStatus"> Status</ param > /// <param name="groupId" <see cref="ushort"> Group ID</ param > /// <param name="groupName" <see cref="string"> Group Name</ param > /// <returns> the command result Task </returns> /// </summary> public Task <CommandResult> ViewGroupResponse(ZclStatus status, ushort groupId, string groupName) { ViewGroupResponse command = new ViewGroupResponse(); // Set the fields command.Status = status; command.GroupId = groupId; command.GroupName = groupName; return(Send(command)); }
/// <summary> /// The Copy Scene Response /// /// <param name="status" <see cref="ZclStatus"> Status</ param > /// <param name="groupId" <see cref="ushort"> Group ID</ param > /// <param name="sceneId" <see cref="byte"> Scene ID</ param > /// <returns> the command result Task </returns> /// </summary> public Task <CommandResult> CopySceneResponse(ZclStatus status, ushort groupId, byte sceneId) { CopySceneResponse command = new CopySceneResponse(); // Set the fields command.Status = status; command.GroupId = groupId; command.SceneId = sceneId; return(Send(command)); }
/// <summary> /// The Upgrade End Command /// /// Upon reception all the image data, the client should verify the image to ensure its /// integrity and validity. If the device requires signed images it shall examine the /// image and verify the signature. Clients may perform additional manufacturer /// specific integrity checks to validate the image, for example, CRC check on the /// actual file data. <br> If the image fails any integrity checks, the client shall /// send an Upgrade End Request command to the upgrade server with a status of /// INVALID_IMAGE. In this case, the client may reinitiate the upgrade process in /// order to obtain a valid OTA upgrade image. The client shall not upgrade to the bad /// image and shall discard the downloaded image data. <br> If the image passes all /// integrity checks and the client does not require additional OTA upgrade image /// file, it shall send back an Upgrade End Request with a status of SUCCESS. However, if /// the client requires multiple OTA upgrade image files before performing an /// upgrade, it shall send an Upgrade End Request command with status /// REQUIRE_MORE_IMAGE. This shall indicate to the server that it cannot yet upgrade /// the image it received. <br> If the client decides to cancel the download process for /// any other reasons, it has the option of sending Upgrade End Request with status of /// ABORT at anytime during the download process. The client shall then try to /// reinitiate the download process again at a later time. /// /// <param name="status" <see cref="ZclStatus"> Status</ param > /// <param name="manufacturerCode" <see cref="ushort"> Manufacturer Code</ param > /// <param name="imageType" <see cref="ushort"> Image Type</ param > /// <param name="fileVersion" <see cref="uint"> File Version</ param > /// <returns> the command result Task </returns> /// </summary> public Task <CommandResult> UpgradeEndCommand(ZclStatus status, ushort manufacturerCode, ushort imageType, uint fileVersion) { UpgradeEndCommand command = new UpgradeEndCommand(); // Set the fields command.Status = status; command.ManufacturerCode = manufacturerCode; command.ImageType = imageType; command.FileVersion = fileVersion; return(Send(command)); }
/// <summary> /// Sends a default response to the client /// /// <param name="transactionId">the transaction ID to use in the response</param> /// <param name="commandIdentifier">the command identifier to which this is a response</param> /// <param name="status">the ZclStatus to send in the response</param> /// </summary> public void SendDefaultResponse(byte transactionId, byte commandIdentifier, ZclStatus status) { DefaultResponse defaultResponse = new DefaultResponse(); defaultResponse.TransactionId = transactionId; defaultResponse.CommandIdentifier = commandIdentifier; defaultResponse.DestinationAddress = _zigbeeEndpoint.GetEndpointAddress(); defaultResponse.ClusterId = _clusterId; defaultResponse.StatusCode = status; _zigbeeEndpoint.SendTransaction(defaultResponse); }
/// <summary> /// The Get Scene Membership Response /// /// <param name="status" <see cref="ZclStatus"> Status</ param > /// <param name="capacity" <see cref="byte"> Capacity</ param > /// <param name="groupId" <see cref="ushort"> Group ID</ param > /// <param name="sceneCount" <see cref="byte"> Scene Count</ param > /// <param name="sceneList" <see cref="List<byte>"> Scene List</ param > /// <returns> the command result Task </returns> /// </summary> public Task <CommandResult> GetSceneMembershipResponse(ZclStatus status, byte capacity, ushort groupId, byte sceneCount, List <byte> sceneList) { GetSceneMembershipResponse command = new GetSceneMembershipResponse(); // Set the fields command.Status = status; command.Capacity = capacity; command.GroupId = groupId; command.SceneCount = sceneCount; command.SceneList = sceneList; return(Send(command)); }
/// <summary> /// The Query Specific File Response /// /// The server sends Query Specific File Response after receiving Query Specific File /// Request from a client. The server shall determine whether it first supports the /// Query Specific File Request command. Then it shall determine whether it has the /// specific file being requested by the client using all the information included in /// the request. The upgrade server sends a Query Specific File Response with one of the /// following status: SUCCESS, NO_IMAGE_AVAILABLE or NOT_AUTHORIZED. <br> A status /// of NO_IMAGE_AVAILABLE indicates that the server currently does not have the /// device specific file available for the client. A status of NOT_AUTHORIZED /// indicates the server is not authorized to send the file to the client. /// /// <param name="status" <see cref="ZclStatus"> Status</ param > /// <param name="manufacturerCode" <see cref="ushort"> Manufacturer Code</ param > /// <param name="imageType" <see cref="ushort"> Image Type</ param > /// <param name="fileVersion" <see cref="uint"> File Version</ param > /// <param name="imageSize" <see cref="uint"> Image Size</ param > /// <returns> the command result Task </returns> /// </summary> public Task <CommandResult> QuerySpecificFileResponse(ZclStatus status, ushort manufacturerCode, ushort imageType, uint fileVersion, uint imageSize) { QuerySpecificFileResponse command = new QuerySpecificFileResponse(); // Set the fields command.Status = status; command.ManufacturerCode = manufacturerCode; command.ImageType = imageType; command.FileVersion = fileVersion; command.ImageSize = imageSize; return(Send(command)); }
/// <summary> /// The Enhanced View Scene Response /// /// <param name="status" <see cref="ZclStatus"> Status</ param > /// <param name="groupId" <see cref="ushort"> Group ID</ param > /// <param name="sceneId" <see cref="byte"> Scene ID</ param > /// <param name="transitionTime" <see cref="ushort"> Transition Time</ param > /// <param name="sceneName" <see cref="string"> Scene Name</ param > /// <param name="extensionFieldSets" <see cref="List<ExtensionFieldSet>"> Extension Field Sets</ param > /// <returns> the command result Task </returns> /// </summary> public Task <CommandResult> EnhancedViewSceneResponse(ZclStatus status, ushort groupId, byte sceneId, ushort transitionTime, string sceneName, List <ExtensionFieldSet> extensionFieldSets) { EnhancedViewSceneResponse command = new EnhancedViewSceneResponse(); // Set the fields command.Status = status; command.GroupId = groupId; command.SceneId = sceneId; command.TransitionTime = transitionTime; command.SceneName = sceneName; command.ExtensionFieldSets = extensionFieldSets; return(Send(command)); }
/// <summary> /// The Image Block Response /// /// Upon receipt of an Image Block Request command the server shall generate an Image /// Block Response. If the server is able to retrieve the data for the client and does not /// wish to change the image download rate, it will respond with a status of SUCCESS and /// it will include all the fields in the payload. The use of file offset allows the /// server to send packets with variable data size during the upgrade process. This /// allows the server to support a case when the network topology of a client may change /// during the upgrade process, for example, mobile client may move around during the /// upgrade process. If the client has moved a few hops away, the data size shall be /// smaller. Moreover, using file offset eliminates the need for data padding since /// each Image Block Response command may contain different data size. A simple server /// implementation may choose to only support largest possible data size for the /// worst-case scenario in order to avoid supporting sending packets with variable /// data size. <br> The server shall respect the maximum data size value requested by /// the client and shall not send the data with length greater than that value. The /// server may send the data with length smaller than the value depending on the network /// topology of the client. For example, the client may be able to receive 100 bytes of /// data at once so it sends the request with 100 as maximum data size. But after /// considering all the security headers (perhaps from both APS and network levels) /// and source routing overhead (for example, the client is five hops away), the /// largest possible data size that the server can send to the client shall be smaller /// than 100 bytes. /// /// <param name="status" <see cref="ZclStatus"> Status</ param > /// <param name="manufacturerCode" <see cref="ushort"> Manufacturer Code</ param > /// <param name="imageType" <see cref="ushort"> Image Type</ param > /// <param name="fileVersion" <see cref="uint"> File Version</ param > /// <param name="fileOffset" <see cref="uint"> File Offset</ param > /// <param name="imageData" <see cref="ByteArray"> Image Data</ param > /// <returns> the command result Task </returns> /// </summary> public Task <CommandResult> ImageBlockResponse(ZclStatus status, ushort manufacturerCode, ushort imageType, uint fileVersion, uint fileOffset, ByteArray imageData) { ImageBlockResponse command = new ImageBlockResponse(); // Set the fields command.Status = status; command.ManufacturerCode = manufacturerCode; command.ImageType = imageType; command.FileVersion = fileVersion; command.FileOffset = fileOffset; command.ImageData = imageData; return(Send(command)); }
static void Main(string[] args) { // Configure Serilog Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .WriteTo.Console() .CreateLogger(); try { Console.Write("Enter COM Port: "); string port = Console.ReadLine(); ZigBeeSerialPort zigbeePort = new ZigBeeSerialPort(port); IZigBeeTransportTransmit dongle = new ZigBeeDongleTiCc2531(zigbeePort); ZigBeeNetworkManager networkManager = new ZigBeeNetworkManager(dongle); JsonNetworkSerializer deviceSerializer = new JsonNetworkSerializer("devices.json"); networkManager.NetworkStateSerializer = deviceSerializer; ZigBeeDiscoveryExtension discoveryExtension = new ZigBeeDiscoveryExtension(); discoveryExtension.SetUpdatePeriod(60); networkManager.AddExtension(discoveryExtension); // Initialise the network networkManager.Initialize(); networkManager.AddCommandListener(new ZigBeeNetworkDiscoverer(networkManager)); //networkManager.AddCommandListener(new ZigBeeNodeServiceDiscoverer(networkManager)); networkManager.AddCommandListener(new ZigBeeTransaction(networkManager)); networkManager.AddCommandListener(new ConsoleCommandListener()); networkManager.AddNetworkNodeListener(new ConsoleNetworkNodeListener()); networkManager.AddSupportedCluster(0x06); networkManager.AddSupportedCluster(0x08); networkManager.AddSupportedCluster(0x0300); ((ZigBeeDongleTiCc2531)dongle).SetLedMode(1, false); // green led ((ZigBeeDongleTiCc2531)dongle).SetLedMode(2, false); // red led ZigBeeStatus startupSucceded = networkManager.Startup(false); if (startupSucceded == ZigBeeStatus.SUCCESS) { Log.Logger.Information("ZigBee console starting up ... [OK]"); } else { Log.Logger.Information("ZigBee console starting up ... [FAIL]"); return; } ZigBeeNode coord = networkManager.GetNode(0); Console.WriteLine("Joining enabled..."); string cmd = Console.ReadLine(); while (cmd != "exit") { Console.WriteLine(networkManager.Nodes.Count + " node(s)"); if (cmd == "join") { coord.PermitJoin(true); } else if (cmd == "unjoin") { coord.PermitJoin(false); } else if (!string.IsNullOrEmpty(cmd)) { Console.WriteLine("Destination Address: "); string nwkAddr = Console.ReadLine(); if (ushort.TryParse(nwkAddr, out ushort addr)) { var node = networkManager.GetNode(addr); if (node != null) { ZigBeeEndpointAddress endpointAddress = null; var endpoint = node.Endpoints.Values.FirstOrDefault(); if (endpoint != null) { endpointAddress = endpoint.GetEndpointAddress(); } if (endpointAddress == null) { Console.WriteLine("No endpoint found"); continue; } try { if (cmd == "toggle") { networkManager.Send(endpointAddress, new ToggleCommand()).GetAwaiter().GetResult(); } else if (cmd == "level") { Console.WriteLine("Level between 0 and 255: "); string level = Console.ReadLine(); Console.WriteLine("time between 0 and 65535: "); string time = Console.ReadLine(); var command = new MoveToLevelWithOnOffCommand() { Level = byte.Parse(level), TransitionTime = ushort.Parse(time) }; networkManager.Send(endpointAddress, command).GetAwaiter().GetResult(); } else if (cmd == "move") { networkManager.Send(endpointAddress, new MoveCommand() { MoveMode = 1, Rate = 100 }).GetAwaiter().GetResult(); } else if (cmd == "on") { networkManager.Send(endpointAddress, new OnCommand()).GetAwaiter().GetResult(); } else if (cmd == "off") { networkManager.Send(endpointAddress, new OffCommand()).GetAwaiter().GetResult(); } else if (cmd == "effect") { networkManager.Send(endpointAddress, new OffCommand()).GetAwaiter().GetResult(); bool state = false; for (int i = 0; i < 10; i++) { if (state) { networkManager.Send(endpointAddress, new OffCommand()).GetAwaiter().GetResult(); } else { networkManager.Send(endpointAddress, new OnCommand()).GetAwaiter().GetResult(); } state = !state; System.Threading.Thread.Sleep(1000); } } else if (cmd == "desc") { NodeDescriptorRequest nodeDescriptorRequest = new NodeDescriptorRequest() { DestinationAddress = endpointAddress, NwkAddrOfInterest = addr }; networkManager.SendTransaction(nodeDescriptorRequest); } else if (cmd == "color") { Console.WriteLine("Red between 0 and 255: "); string r = Console.ReadLine(); Console.WriteLine("Green between 0 and 255: "); string g = Console.ReadLine(); Console.WriteLine("Blue between 0 and 255: "); string b = Console.ReadLine(); if (int.TryParse(r, out int _r) && int.TryParse(g, out int _g) && int.TryParse(b, out int _b)) { CieColor xyY = ColorConverter.RgbToCie(_r, _g, _b); MoveToColorCommand command = new MoveToColorCommand() { ColorX = xyY.X, ColorY = xyY.Y, TransitionTime = 10 }; networkManager.Send(endpointAddress, command).GetAwaiter().GetResult(); } } else if (cmd == "hue") { Console.WriteLine("Red between 0 and 255: "); string hue = Console.ReadLine(); if (byte.TryParse(hue, out byte _hue)) { MoveToHueCommand command = new MoveToHueCommand() { Hue = _hue, Direction = 0, TransitionTime = 10 }; networkManager.Send(endpointAddress, command).GetAwaiter().GetResult(); } } else if (cmd == "read") { //var value = ((ZclOnOffCluster)endpoint.GetInputCluster(6)).GetAttribute(ZclOnOffCluster.ATTR_ONOFF); var result = ((ZclColorControlCluster)endpoint.GetInputCluster(ZclColorControlCluster.CLUSTER_ID)).Read(ZclColorControlCluster.ATTR_CURRENTY).Result; if (result.IsSuccess()) { ReadAttributesResponse response = result.GetResponse <ReadAttributesResponse>(); if (response.Records.Count == 0) { Console.WriteLine("No records returned"); continue; } ZclStatus statusCode = response.Records[0].Status; if (statusCode == ZclStatus.SUCCESS) { Console.WriteLine("Cluster " + string.Format("%04X", response.ClusterId) + ", Attribute " + response.Records[0].AttributeIdentifier + ", type " + response.Records[0].AttributeDataType + ", value: " + response.Records[0].AttributeValue); } else { Console.WriteLine("Attribute value read error: " + statusCode); } } } } catch (Exception ex) { Log.Logger.Error(ex, "{Error}"); } } else { Console.WriteLine($"Node {addr} not found"); } } } cmd = Console.ReadLine(); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } }
public override void Deserialize(ZclFieldDeserializer deserializer) { CommandIdentifier = deserializer.Deserialize <byte>(ZclDataType.Get(DataType.UNSIGNED_8_BIT_INTEGER)); StatusCode = deserializer.Deserialize <ZclStatus>(ZclDataType.Get(DataType.ZCL_STATUS)); }
static async Task Main(string[] args) { // Configure Serilog Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .WriteTo.Console() .CreateLogger(); bool showHelp = false; ZigBeeDongle zigBeeDongle = ZigBeeDongle.TiCc2531; OptionSet options = new OptionSet { { "h|help", "show this message and exit", h => showHelp = h != null }, { "zbd|zigbeeDongle=", "the zigbee dongle to use. 0 = TiCc2531 | 1 = DigiXBee", (ZigBeeDongle zbd) => zigBeeDongle = zbd } }; try { IList <string> extraArgs = options.Parse(args); foreach (string extraArg in extraArgs) { Console.WriteLine($"Error: Unknown option: {extraArg}"); showHelp = true; } Console.Write("Enter COM Port: "); string port = Console.ReadLine(); ZigBeeSerialPort zigbeePort = new ZigBeeSerialPort(port); IZigBeeTransportTransmit dongle; switch (zigBeeDongle) { case ZigBeeDongle.TiCc2531: { dongle = new ZigBeeDongleTiCc2531(zigbeePort); } break; case ZigBeeDongle.DigiXbee: { dongle = new ZigBeeDongleXBee(zigbeePort); } break; default: { dongle = new ZigBeeDongleTiCc2531(zigbeePort); } break; } ZigBeeNetworkManager networkManager = new ZigBeeNetworkManager(dongle); JsonNetworkSerializer deviceSerializer = new JsonNetworkSerializer("devices.json"); //networkManager.NetworkStateSerializer = deviceSerializer; ZigBeeDiscoveryExtension discoveryExtension = new ZigBeeDiscoveryExtension(); discoveryExtension.SetUpdatePeriod(60); networkManager.AddExtension(discoveryExtension); // Initialise the network networkManager.Initialize(); /* Network (de)serialization */ //networkManager.AddCommandListener(new ZigBeeNetworkDiscoverer(networkManager)); //networkManager.AddCommandListener(new ZigBeeNodeServiceDiscoverer(networkManager)); networkManager.AddCommandListener(new ZigBeeTransaction(networkManager)); networkManager.AddCommandListener(new ConsoleCommandListener()); networkManager.AddNetworkNodeListener(new ConsoleNetworkNodeListener()); networkManager.AddSupportedCluster(ZclOnOffCluster.CLUSTER_ID); networkManager.AddSupportedCluster(ZclColorControlCluster.CLUSTER_ID); networkManager.AddSupportedCluster(ZclTouchlinkCluster.CLUSTER_ID); networkManager.AddExtension(new ZigBeeBasicServerExtension()); if (zigBeeDongle == ZigBeeDongle.TiCc2531) { ((ZigBeeDongleTiCc2531)dongle).SetLedMode(1, false); // green led ((ZigBeeDongleTiCc2531)dongle).SetLedMode(2, false); // red led } ZigBeeStatus startupSucceded = networkManager.Startup(false); if (startupSucceded == ZigBeeStatus.SUCCESS) { Log.Logger.Information("ZigBee console starting up ... [OK]"); } else { Log.Logger.Information("ZigBee console starting up ... [FAIL]"); Log.Logger.Information("Press any key to exit..."); Console.ReadKey(); return; } ZigBeeNode coord = networkManager.GetNode(0); Console.WriteLine("Joining enabled..."); string cmd = string.Empty; while (cmd != "exit") { Console.WriteLine(networkManager.Nodes.Count + " node(s)" + Environment.NewLine); if (cmd == "join") { coord.PermitJoin(true); } else if (cmd == "unjoin") { coord.PermitJoin(false); } else if (!string.IsNullOrEmpty(cmd)) { var tmp = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.DarkGreen; Console.Write("Destination Address: "); Console.ForegroundColor = tmp; string nwkAddr = Console.ReadLine(); if (ushort.TryParse(nwkAddr, out ushort addr)) { var node = networkManager.GetNode(addr); if (node != null) { ZigBeeEndpointAddress endpointAddress = null; var endpoint = node.Endpoints.Values.FirstOrDefault(); if (endpoint != null) { endpointAddress = endpoint.GetEndpointAddress(); } if (endpointAddress == null) { Console.WriteLine("No endpoint found"); continue; } try { if (cmd == "toggle") { await networkManager.Send(endpointAddress, new ToggleCommand()); } else if (cmd == "level") { Console.WriteLine("Level between 0 and 255: "); string level = Console.ReadLine(); Console.WriteLine("time between 0 and 65535: "); string time = Console.ReadLine(); var command = new MoveToLevelWithOnOffCommand() { Level = byte.Parse(level), TransitionTime = ushort.Parse(time) }; await networkManager.Send(endpointAddress, command); } else if (cmd == "move") { await networkManager.Send(endpointAddress, new MoveCommand() { MoveMode = 1, Rate = 100 }); } else if (cmd == "on") { await networkManager.Send(endpointAddress, new OnCommand()); } else if (cmd == "off") { await networkManager.Send(endpointAddress, new OffCommand()); } else if (cmd == "effect") { await networkManager.Send(endpointAddress, new OffCommand()); bool state = false; for (int i = 0; i < 10; i++) { if (state) { await networkManager.Send(endpointAddress, new OffCommand()); } else { await networkManager.Send(endpointAddress, new OnCommand()); } state = !state; await Task.Delay(1000); } } else if (cmd == "stress") { await networkManager.Send(endpointAddress, new OffCommand()); bool state = false; for (int i = 0; i < 100; i++) { if (state) { await networkManager.Send(endpointAddress, new OffCommand()); } else { await networkManager.Send(endpointAddress, new OnCommand()); } state = !state; await Task.Delay(1); } } else if (cmd == "desc") { NodeDescriptorRequest nodeDescriptorRequest = new NodeDescriptorRequest() { Destination = endpointAddress, NwkAddrOfInterest = addr }; networkManager.SendTransaction(nodeDescriptorRequest); } else if (cmd == "color") { Console.WriteLine("Red between 0 and 255: "); string r = Console.ReadLine(); Console.WriteLine("Green between 0 and 255: "); string g = Console.ReadLine(); Console.WriteLine("Blue between 0 and 255: "); string b = Console.ReadLine(); if (int.TryParse(r, out int _r) && int.TryParse(g, out int _g) && int.TryParse(b, out int _b)) { CieColor xyY = ColorConverter.RgbToCie(_r, _g, _b); MoveToColorCommand command = new MoveToColorCommand() { ColorX = xyY.X, ColorY = xyY.Y, TransitionTime = 10 }; await networkManager.Send(endpointAddress, command); } } else if (cmd == "hue") { Console.WriteLine("Red between 0 and 255: "); string hue = Console.ReadLine(); if (byte.TryParse(hue, out byte _hue)) { MoveToHueCommand command = new MoveToHueCommand() { Hue = _hue, Direction = 0, TransitionTime = 10 }; await networkManager.Send(endpointAddress, command); } } else if (cmd == "read") { var result = await((ZclElectricalMeasurementCluster)endpoint.GetInputCluster(ZclElectricalMeasurementCluster.CLUSTER_ID)).Read(ZclElectricalMeasurementCluster.ATTR_MEASUREMENTTYPE); if (result.IsSuccess()) { ReadAttributesResponse response = result.GetResponse <ReadAttributesResponse>(); if (response.Records.Count == 0) { Console.WriteLine("No records returned"); continue; } ZclStatus statusCode = response.Records[0].Status; if (statusCode == ZclStatus.SUCCESS) { Console.WriteLine("Cluster " + response + ", Attribute " + response.Records[0].AttributeIdentifier + ", type " + response.Records[0].AttributeDataType + ", value: " + response.Records[0].AttributeValue); } else { Console.WriteLine("Attribute value read error: " + statusCode); } } } } catch (Exception ex) { Log.Logger.Error(ex, "{Error}"); } } else { Console.WriteLine($"Node {addr} not found"); } } } var currentForeGroundColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.DarkGreen; Console.Write("cmd> "); Console.ForegroundColor = currentForeGroundColor; cmd = Console.ReadLine(); } } catch (OptionException e) { Console.WriteLine(e.Message); showHelp = true; } catch (Exception ex) { Console.WriteLine(ex.ToString()); } if (showHelp) { Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } }