Exemplo n.º 1
0
        internal RequestMessage Encode(ControllerRequest command, byte?callbackID)
        {
            if (command == null)
            {
                throw new ArgumentNullException(nameof(command));
            }

            // create writer to serialize te request
            using (var writer = new PayloadWriter())
            {
                // write the function
                writer.WriteByte((byte)command.Function);

                // does the command has payload?
                if (command.Payload != null)
                {
                    // yes, so write the payload
                    writer.WriteObject(command.Payload);
                }

                if (callbackID != null)
                {
                    // write the callback
                    writer.WriteByte(callbackID.Value);
                }

                // create a hostmessage, use the serialized payload
                return(new RequestMessage(writer.ToPayload()));
            }
        }
Exemplo n.º 2
0
        public static async Task <NodeInfo> SendRequestNodeInfo(this ZWaveChannel channel, byte nodeID, CancellationToken cancellationToken = default)
        {
            if (channel == null)
            {
                throw new ArgumentNullException(nameof(channel));
            }
            if (nodeID == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(nodeID), nodeID, "nodeID must be greater than 0");
            }

            var command = new ControllerRequest(Function.RequestNodeInfo, new Payload(nodeID));
            var request = channel.Encode(command, null);

            var responsePipeline = channel.Messages
                                   // decode the response
                                   .Select(message => channel.Decode(message, hasCallbackID: false))
                                   // we only want responses (no events)
                                   .OfType <ControllerResponse>()
                                   // verify matching function
                                   .Where(response => Equals(response.Function, command.Function))
                                   // unknown what the 0x01 byte means, probably: ready, finished, OK
                                   .Where(response => response.Payload[0] == 0x01);

            var pipeline = channel.Messages
                           // wait until the response pipeline has finished
                           .SkipUntil(responsePipeline)
                           // decode the response
                           .Select(message => channel.Decode(message, hasCallbackID: false))
                           // we only want events (no responses)
                           .OfType <ControllerEvent>()
                           // verify matching function
                           .Where(@event => Equals(@event.Function, Function.ApplicationUpdate))
                           // deserialize the received payload to a NodeUpdate
                           .Select(@event => @event.Payload.Deserialize <NodeUpdate>());

            // send request
            var nodeUpdate = await channel.Send(request, pipeline, cancellationToken);

            // verify the state
            if (nodeUpdate.State != NodeUpdateState.InfoReceived)
            {
                throw new OperationFailedException($"RequestNodeInfo failed with state: {nodeUpdate.State}");
            }

            // return the data
            return(nodeUpdate.Info);
        }
Exemplo n.º 3
0
        // NodeCommand, no return value. Request followed by:
        // 1) a response from the controller
        // 2) a event from the controller: command deliverd at node)
        internal async Task Send(byte nodeID, Command command, CancellationToken cancellationToken = default)
        {
            if (nodeID == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(nodeID), nodeID, "nodeID must be greater than 0");
            }
            if (command == null)
            {
                throw new ArgumentNullException(nameof(command));
            }

            // generate new callback
            var callbackID = GetNextCallbackID();

            // create the request
            var nodeRequest       = new NodeRequest(nodeID, command);
            var controllerRequest = new ControllerRequest(Function.SendData, nodeRequest.Serialize());

            var responsePipeline = Messages
                                   // decode the response
                                   .Select(message => Decode(message, hasCallbackID: false))
                                   // we only want responses (no events)
                                   .OfType <ControllerResponse>()
                                   // verify matching function
                                   .Where(response => Equals(response.Function, controllerRequest.Function))
                                   // unknown what the 0x01 byte means, probably: ready, finished, OK
                                   .Where(response => response.Payload[0] == 0x01);

            var pipeline = Messages
                           // wait until the response pipeline has finished
                           .SkipUntil(responsePipeline)
                           // decode the response
                           .Select(message => Decode(message, hasCallbackID: true))
                           // we only want events (no responses)
                           .OfType <ControllerEvent>()
                           // verify matching function
                           .Where(@event => Equals(@event.Function, controllerRequest.Function))
                           // verify mathing callback
                           .Where(@event => Equals(@event.CallbackID, callbackID))
                           // deserialize the received payload to a NodeCommandCompleted
                           .Select(@event => @event.Payload.Deserialize <NodeCommandCompleted>())
                           // verify the state
                           .Verify(completed => completed.TransmissionState == TransmissionState.CompleteOK, completed => new TransmissionException(completed.TransmissionState));

            await Send(Encode(controllerRequest, callbackID), pipeline, cancellationToken);
        }
Exemplo n.º 4
0
        // ControllerRequest: request followed by one response from the controller
        internal async Task <T> Send <T>(ControllerRequest request, CancellationToken cancellationToken = default) where T : IPayloadSerializable, new()
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            // create the response pipeline
            var pipeline = Messages
                           // decode the response
                           .Select(message => Decode(message, hasCallbackID: false))
                           // we only want responses (no events)
                           .OfType <ControllerResponse>()
                           // verify matching function
                           .Where(response => Equals(response.Function, request.Function))
                           // and finally deserialize the received payload
                           .Select(response => response.Payload.Deserialize <T>());

            return(await Send(Encode(request, null), pipeline, cancellationToken));
        }
Exemplo n.º 5
0
        public static async Task <NeighborUpdateStatus> SendRequestNeighborUpdate(this ZWaveChannel channel, byte nodeID, IProgress <NeighborUpdateStatus> progress, CancellationToken cancellationToken = default)
        {
            if (channel == null)
            {
                throw new ArgumentNullException(nameof(channel));
            }
            if (nodeID == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(nodeID), nodeID, "nodeID must be greater than 0");
            }

            var responseTimeout = TimeSpan.FromSeconds(5);
            var callbackID      = ZWaveChannel.GetNextCallbackID();

            var command = new ControllerRequest(Function.RequestNodeNeighborUpdate, new Payload(nodeID));
            var request = channel.Encode(command, callbackID);

            var pipeline = channel.Messages
                           // decode the response
                           .Select(message => channel.Decode(message, hasCallbackID: true))
                           // we only want events (no responses)
                           .OfType <ControllerEvent>()
                           // verify matching function
                           .Where(@event => Equals(@event.Function, command.Function))
                           // verify mathing callback (can be null)
                           .Where(@event => Equals(@event.CallbackID, callbackID))
                           // deserialize the received payload
                           .Select(@event => @event.Payload.Deserialize <Payload>())
                           // report progress
                           .Do(payload => progress?.Report((NeighborUpdateStatus)payload[0]))
                           // and check for final state
                           .Where(payload => (NeighborUpdateStatus)payload[0] == NeighborUpdateStatus.Done || (NeighborUpdateStatus)payload[0] == NeighborUpdateStatus.Failed);

            // send request
            var response = await channel.Send(request, pipeline, cancellationToken);

            // return the status of the final response
            return((NeighborUpdateStatus)response[0]);
        }
Exemplo n.º 6
0
        // NodeCommand, with return value. Request followed by:
        // 1) a response from the controller
        // 2) a event from the controller: command deliverd at node)
        // 3) a event from the node: return value
        internal async Task <Command> Send(byte nodeID, Command command, byte responseCommandID, CancellationToken cancellationToken = default)
        {
            if (nodeID == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(nodeID), nodeID, "nodeID must be greater than 0");
            }
            if (command == null)
            {
                throw new ArgumentNullException(nameof(command));
            }
            if (responseCommandID == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(responseCommandID), responseCommandID, "responseCommandID must be greater than 0");
            }

            // generate new callback
            var callbackID = GetNextCallbackID();

            // create the request
            var nodeRequest       = new NodeRequest(nodeID, command);
            var controllerRequest = new ControllerRequest(Function.SendData, nodeRequest.Serialize());

            var responsePipeline = Messages
                                   // decode the response
                                   .Select(message => Decode(message, hasCallbackID: false))
                                   // we only want responses (no events)
                                   .OfType <ControllerResponse>()
                                   // verify matching function
                                   .Where(response => Equals(response.Function, controllerRequest.Function))
                                   // unknown what the 0x01 byte means, probably: ready, finished, OK
                                   .Where(response => response.Payload[0] == 0x01);


            var eventPipeline = Messages
                                // decode the response
                                .Select(message => Decode(message, hasCallbackID: true))
                                // we only want events (no responses)
                                .OfType <ControllerEvent>()
                                // verify matching function
                                .Where(@event => Equals(@event.Function, controllerRequest.Function))
                                // verify matching callback
                                .Where(@event => Equals(@event.CallbackID, callbackID))
                                // deserialize the received payload to a NodeCommandCompleted
                                .Select(@event => @event.Payload.Deserialize <NodeCommandCompleted>())
                                // verify the state
                                .Verify(completed => completed.TransmissionState == TransmissionState.CompleteOK, completed => new TransmissionException(completed.TransmissionState));

            var commandPipeline = Messages
                                  // wait until the response pipeline has finished
                                  .SkipUntil(responsePipeline)
                                  // wait until the event pipeline has finished
                                  .SkipUntil(eventPipeline)
                                  // decode the response
                                  .Select(message => Decode(message, hasCallbackID: false))
                                  // we only want events (no responses)
                                  .OfType <ControllerEvent>()
                                  // after SendData controler will respond with ApplicationCommandHandler
                                  .Where(@event => Equals(@event.Function, Function.ApplicationCommandHandler))
                                  // deserialize the received payload to a NodeResponse
                                  .Select(@event => @event.Payload.Deserialize <NodeResponse>())
                                  // verify if the responding node is the correct one
                                  .Where(response => response.NodeID == nodeID)
                                  // and select the command
                                  .Select(response => response.Command);

            // check if the command contains an ecapsulated MultiChannelCommand
            if (Encapsulation.Flatten(command).OfType <MultiChannelCommand>().Any())
            {
                // extract MultiChannelCommand
                var multiChannelRequestCommand = Encapsulation.Flatten(command).OfType <MultiChannelCommand>().Single();

                // insert MultiChannel filtering
                commandPipeline = commandPipeline
                                  // extract the MultiChannelCommand from the response
                                  .Select(reply => Encapsulation.Flatten(reply).OfType <MultiChannelCommand>().Single())
                                  // verify if the MultiChannelCommand is the correct one
                                  .Where(reply => reply.CommandClass == multiChannelRequestCommand.CommandClass && reply.CommandID == multiChannelRequestCommand.CommandID)
                                  // verify if the endpoint the correct one
                                  .Where(reply => reply.SourceEndpointID == multiChannelRequestCommand.TargetEndpointID);
            }

            // get the most inner command
            var requestCommand = Encapsulation.Flatten(command).Last();

            commandPipeline = commandPipeline
                              // select the inner most command
                              .Select(reply => Encapsulation.Flatten(reply).Last())
                              // verify if the response conmmand is the correct one
                              .Where(reply => reply.CommandClass == requestCommand.CommandClass && reply.CommandID == responseCommandID);

            return(await Send(Encode(controllerRequest, callbackID), commandPipeline, cancellationToken));
        }