internal async Task<Result> ExecuteDeviceCommandAsync(DeviceCommand command, string argument, string argument2, CancellationToken cancellationToken)
        {
            using (var context = new ZvsContext(EntityContextConnection))
            {
                var deviceCommand = await context.DeviceCommands
                    .Include(o => o.Device)
                    .Include(o => o.Device.Type)
                    .Include(o => o.Device.Type.Adapter)
                    .FirstOrDefaultAsync(o => o.Id == command.Id, cancellationToken);

                if (deviceCommand == null)
                    return Result.ReportErrorFormat("Cannot locate device command with id of {0}", command.Id);

                var commandAction = string.Format("{0}{1} ({3}) on {2} ({4})",
                    deviceCommand.Name,
                    string.IsNullOrEmpty(argument) ? "" : " " + argument,
                    deviceCommand.Device.Name, deviceCommand.Id, deviceCommand.Device.Id);

                var aGuid = deviceCommand.Device.Type.Adapter.AdapterGuid;
                var adapter = AdapterManager.FindZvsAdapter(aGuid);
                if (adapter == null)
                {
                    return Result.ReportErrorFormat("{0} failed, device adapter is not loaded!",
                        commandAction);
                }

                if (!adapter.IsEnabled)
                    return Result.ReportErrorFormat("{0} failed because the '{1}' adapter is disabled",
                        commandAction,
                        deviceCommand.Device.Type.Adapter.Name);

                await adapter.ProcessDeviceCommandAsync(deviceCommand.Device, deviceCommand, argument, argument2);
                return Result.ReportSuccessFormat("{0} complete", commandAction);
            }
        }
        public async Task<Result> RegisterAsync(int deviceId, DeviceCommand deviceCommand, CancellationToken cancellationToken)
        {
            if (deviceCommand == null)
                return Result.ReportError("Device command is null");

            using (var context = new ZvsContext(EntityContextConnection))
            {
                var device = await context.Devices.FirstOrDefaultAsync(o => o.Id == deviceId, cancellationToken);

                if(device == null )
                    return Result.ReportError("Invalid device id");

                //Does device type exist? 
                var existingDc = await context.DeviceCommands
                    .Include(o => o.Options)
                    .FirstOrDefaultAsync(c => c.UniqueIdentifier == deviceCommand.UniqueIdentifier &&
                                              c.DeviceId == deviceId, cancellationToken);

                if (existingDc == null)
                {
                    device.Commands.Add(deviceCommand);
                    return await context.TrySaveChangesAsync(cancellationToken);
                }

                var changed = false;
                PropertyChangedEventHandler handler = (s, a) => changed = true;
                existingDc.PropertyChanged += handler;

                existingDc.ArgumentType = deviceCommand.ArgumentType;
                existingDc.CustomData1 = deviceCommand.CustomData1;
                existingDc.CustomData2 = deviceCommand.CustomData2;
                existingDc.Description = deviceCommand.Description;
                existingDc.Name = deviceCommand.Name;
                existingDc.Help = deviceCommand.Help;
                existingDc.SortOrder = deviceCommand.SortOrder;

                existingDc.PropertyChanged -= handler;

                var addedOptions = deviceCommand.Options.Where(option => existingDc.Options.All(o => o.Name != option.Name)).ToList();
                foreach (var option in addedOptions)
                {
                    existingDc.Options.Add(option);
                    changed = true;
                }

                var removedOptions = existingDc.Options.Where(option => deviceCommand.Options.All(o => o.Name != option.Name)).ToList();
                foreach (var option in removedOptions)
                {
                    context.CommandOptions.Local.Remove(option);
                    changed = true;
                }

                if (changed)
                    return await context.TrySaveChangesAsync(cancellationToken);

                return Result.ReportSuccess("Nothing to update");
            }
        }
        public async Task RegisterAsyncInvalidDeviceIdTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "dcb-RegisterAsyncInvalidDeviceIdTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());
            var dvb = new DeviceCommandBuilder(dbConnection);

            var deviceCommand = new DeviceCommand();

            //act
            var result = await dvb.RegisterAsync(3, deviceCommand, CancellationToken.None);

            //assert 
            Assert.IsTrue(result.HasError);
            Console.WriteLine(result.Message);
        }
        public async Task RegisterAsyncInvalidDeviceIdTest()
        {
            //arrange 
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());
            var dvb = new DeviceCommandBuilder(dbConnection);

            var deviceCommand = new DeviceCommand();

            //act
            var result = await dvb.RegisterAsync(3, deviceCommand, CancellationToken.None);

            //assert 
            Assert.IsTrue(result.HasError);
            Console.WriteLine(result.Message);
        }
Example #5
0
 private Task Publish(DeviceType deviceType, Device device, DeviceTypeCommand deviceTypeCommand,
                      DeviceCommand deviceCommand, string argument)
 {
     JavaScriptSerializer js = new JavaScriptSerializer();
     var o =
         new
             {
                 DeviceName = device.Name,
                 DeviceCommandName = (deviceCommand == null ? null : deviceCommand.Name),
                 DeviceTypeCommandName = (deviceTypeCommand == null ? null : deviceTypeCommand.Name),
                 DeviceTypeCommandValue = (deviceTypeCommand == null ? null : deviceTypeCommand.Value),
                 Argument = argument,
                 DeviceTypeName = (device == null || device.Type == null ? null : device.Type.Name),
                 device.CurrentLevelInt,
                 device.CurrentLevelText
             };
     var str = js.Serialize(o);
     client.Publish(SystemTopic, Encoding.UTF8.GetBytes(str));
     return Task.FromResult(0);
 }
        public async Task RegisterAsyncAddedCommandOptionsTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "dcb-RegisterAsyncAddedCommandOptionsTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());
            var dvb = new DeviceCommandBuilder(dbConnection);

            var device = UnitTesting.CreateFakeDevice();
            var deviceCommand = new DeviceCommand
            {
                Name = "Unit Testing Command",
            };
            var option1 = new CommandOption
            {
                Name = "Option 1"
            };
            var option2 = new CommandOption
            {
                Name = "Option 2"
            };
            deviceCommand.Options.Add(option1);
            deviceCommand.Options.Add(option2);

            using (var context = new ZvsContext(dbConnection))
            {
                device.Commands.Add(deviceCommand);
                context.Devices.Add(device);
                await context.SaveChangesAsync();
            }

            var option3 = new CommandOption
            {
                Name = "Option 3"
            };
            deviceCommand.Options.Add(option3);

            //act
            var result = await dvb.RegisterAsync(device.Id, deviceCommand, CancellationToken.None);
            Console.WriteLine(result.Message);

            List<DeviceCommand> deviceCommands;
            using (var context = new ZvsContext(dbConnection))
            {
                deviceCommands = await context.DeviceCommands
                    .Include(o => o.Options)
                    .Include(o => o.Device)
                    .Where(o => o.Id == deviceCommand.Id)
                    .ToListAsync();
            }

            //assert 
            Assert.IsFalse(result.HasError, result.Message);
            Assert.IsTrue(deviceCommands.Count == 1, "Device has an unexpected number of commands");
            Assert.IsTrue(deviceCommands[0].Options.Count == 3, "Option not removed as expected");
            Assert.IsTrue(deviceCommands[0].Options[2].Name == option3.Name, "Option mismatch");
        }
Example #7
0
        public override Task ProcessDeviceCommandAsync(Device device, DeviceCommand command, string argument,
                                                       string argument2)
        {
            return Publish(device.Type, device, null, command, argument);

        }
Example #8
0
        private void AddCommand(int deviceID, string name, ZvsContext context)
        {
            context.DeviceCommands.FirstOrDefaultAsync(d => d.Name == name && d.DeviceId == deviceID).ContinueWith(
                t =>
                    {
                        if (motionCommand != null)
                            return;

                        motionCommand =
                            context.DeviceCommands.Add(new DeviceCommand()
                                {
                                    DeviceId = deviceID,
                                    Description = name,
                                    Name = name,
                                    UniqueIdentifier = Guid.NewGuid().ToString(),
                                    ArgumentType = DataType.STRING,
                                    Help = name,
                                    CustomData1 = "Value",
                                    CustomData2 = name,
                                    SortOrder = 0
                                
                                });

                        context.TrySaveChangesAsync().ContinueWith(tt =>
                            {
                                if (tt.Result.HasError)
                                    ZvsEngine.log.Error(tt.Result.Message);

                            }).Wait();
                    }).Wait();

        }
        public async Task RunCommandTest()
        {
            //Arrange
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());

            int? commandIdRan = 0;
            var arg1Ran = "";
            var arg2Ran = "";

            var commandProcessor = new StubICommandProcessor
            {
                RunCommandAsyncNullableOfInt32StringStringCancellationToken = (commandId, argument, argument2, cancellationToken) =>
                {
                    commandIdRan = commandId;
                    arg1Ran = argument;
                    arg2Ran = argument2;
                    return Task.FromResult(Result.ReportSuccess());
                }
            };
            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e);
                    return Task.FromResult(0);
                }
            };

            var device0 = UnitTesting.CreateFakeDevice();
            var device = UnitTesting.CreateFakeDevice();

            using (var context = new ZvsContext(dbConnection))
            {
                var deviceCommand = new DeviceCommand
                {
                    Name = "Turn On"
                };
                device.Commands.Add(deviceCommand);
                context.Devices.Add(device0);
                context.Devices.Add(device);
                await context.SaveChangesAsync(CancellationToken.None);

                var cts = new CancellationTokenSource();
                var runner = new JavaScriptRunner(log, commandProcessor, dbConnection);
                var script =
                    $@"
function f1() {{ 
       var result = runCommand({deviceCommand.Id
                        },'98', '0'); 
       logInfo(result.Message);
}};
f1();";

                //Act
                var result = await runner.ExecuteScriptAsync(script, cts.Token);

                //Assert
                Assert.IsFalse(result.HasError, result.Message);
                Assert.IsTrue(deviceCommand.Id == commandIdRan, "Wrong command ran!");
                Assert.IsTrue("98" == arg1Ran, "command argument1 not passed in correctly.");
                Assert.IsTrue("0" == arg2Ran, "command argument2 not passed in correctly.");
            }
        }
        public override async Task ProcessDeviceCommandAsync(Device device, DeviceCommand command, string argument, string argument2)
        {
            if (!command.UniqueIdentifier.Contains("DYNAMIC_CMD_")) return;
            var nodeNumber = Convert.ToByte(device.NodeNumber);

            //Get more info from this Node from OpenZWave
            var node = GetNode(MHomeId, nodeNumber);

            if (!IsNodeReady(nodeNumber))
            {
                await Log.ReportInfoFormatAsync(CancellationToken, "Failed to issue command on {0}, node {1}. Node not ready.", device.Name, nodeNumber);
                return;
            }

            switch (command.ArgumentType)
            {
                case DataType.BYTE:
                    {
                        byte b;
                        byte.TryParse(argument, out b);

                        var value = node.Values.FirstOrDefault(o => o.ValueID.GetId().ToString(CultureInfo.InvariantCulture).Equals(command.CustomData2));
                        if (value != null)
                            MManager.SetValue(value.ValueID, b);
                        break;
                    }
                case DataType.BOOL:
                    {
                        bool b;
                        bool.TryParse(argument, out b);

                        var value = node.Values.FirstOrDefault(o => o.ValueID.GetId().ToString(CultureInfo.InvariantCulture).Equals(command.CustomData2));
                        if (value != null)
                            MManager.SetValue(value.ValueID, b);
                        break;
                    }
                case DataType.DECIMAL:
                    {
                        var f = Convert.ToSingle(argument);

                        var value = node.Values.FirstOrDefault(o => o.ValueID.GetId().ToString(CultureInfo.InvariantCulture).Equals(command.CustomData2));
                        if (value != null)
                            MManager.SetValue(value.ValueID, f);
                        break;
                    }
                case DataType.LIST:
                case DataType.STRING:
                    {
                        var value = node.Values.FirstOrDefault(o => o.ValueID.GetId().ToString(CultureInfo.InvariantCulture).Equals(command.CustomData2));
                        if (value != null)
                            MManager.SetValue(value.ValueID, argument);
                        break;
                    }
                case DataType.INTEGER:
                    {
                        int i;
                        int.TryParse(argument, out i);

                        var value = node.Values.FirstOrDefault(o => o.ValueID.GetId().ToString(CultureInfo.InvariantCulture).Equals(command.CustomData2));
                        if (value != null)
                            MManager.SetValue(value.ValueID, i);
                        break;
                    }
            }
        }
        private async void NotificationHandler()
        {
            switch (MNotification.GetType())
            {

                case ZWNotification.Type.NodeProtocolInfo:
                    {
                        #region NodeProtocolInfo

                        var node = GetNode(MNotification.GetHomeId(), MNotification.GetNodeId());

                        if (node != null)
                        {
                            node.Label = MManager.GetNodeType(MHomeId, node.ID);
                            Debug.WriteLine("[Node Protocol Info] " + node.Label);

                            //Find device type
                            var deviceTypeId = FindDeviceTypeId(node.Label);
                            if (deviceTypeId == UnknownTypeId)
                                await Log.ReportWarningFormatAsync(CancellationToken, "[Unknown Node Label] {0}", node.Label);

                            using (var context = new ZvsContext(EntityContextConnection))
                            {
                                var ozwDevice = await context.Devices
                                    .FirstOrDefaultAsync(d => d.Type.Adapter.AdapterGuid == AdapterGuid &&
                                        d.NodeNumber == node.ID);

                                //If we don't already have the device
                                if (ozwDevice == null)
                                    break;

                                if (ozwDevice.DeviceTypeId != deviceTypeId)
                                {
                                    ozwDevice.DeviceTypeId = deviceTypeId;

                                    var result = await context.TrySaveChangesAsync(CancellationToken);
                                    if (result.HasError)
                                        await Log.ReportErrorFormatAsync(CancellationToken, "Failed to change device type. {0}", result.Message);
                                }

                                #region Last Event Value Storage
                                //Node event value placeholder 
                                var lastEventResult = await DeviceValueBuilder.RegisterAsync(new DeviceValue
                                {
                                    DeviceId = ozwDevice.Id,
                                    UniqueIdentifier = LastEventNameValueId,
                                    Name = "Last Node Event Value",
                                    Genre = "Custom",
                                    Index = "0",
                                    ValueType = DataType.BYTE,
                                    CommandClass = "0",
                                    Value = "0",
                                    IsReadOnly = true
                                }, ozwDevice, CancellationToken);
                                if (lastEventResult.HasError)
                                    await Log.ReportErrorFormatAsync(CancellationToken, "An error occured when registering the last event value. {0}", lastEventResult.Message);
                                #endregion
                            }
                        }
                        break;
                        #endregion
                    }
                case ZWNotification.Type.ValueAdded:
                    {
                        #region ValueAdded

                        var node = GetNode(MNotification.GetHomeId(), MNotification.GetNodeId());
                        var vid = MNotification.GetValueID();
                        var value = new Value
                        {
                            ValueID = vid,
                            Label = MManager.GetValueLabel(vid),
                            Genre = vid.GetGenre().ToString(),
                            Index = vid.GetIndex().ToString(CultureInfo.InvariantCulture),
                            Type = vid.GetType().ToString(),
                            CommandClassID = vid.GetCommandClassId().ToString(CultureInfo.InvariantCulture),
                            Help = MManager.GetValueHelp(vid)
                        };
                        var readOnly = MManager.IsValueReadOnly(vid);
                        node.AddValue(value);
                        var valueIdString = vid.GetId().ToString(CultureInfo.InvariantCulture);

#if DEBUG
                        var sw = new Stopwatch();
                        sw.Start();
#endif

                        string data;
                        var b = MManager.GetValueAsString(vid, out data);

                        Debug.WriteLine("[ValueAdded] Node: {0}, Label: {1}, Data: {2}, result: {3}",
                            node.ID,
                            value.Label,
                            data,
                            b);

                        using (var context = new ZvsContext(EntityContextConnection))
                        {
                            var d = await context.Devices.FirstOrDefaultAsync(o => o.Type.Adapter.AdapterGuid == AdapterGuid &&
                                o.NodeNumber == node.ID);

                            if (d == null)
                            {
                                await Log.ReportWarningAsync("ValueAdded called on a node id that was not found in the database", CancellationToken);
                                break;
                            }

                            //Values are 'unknown' at this point so don't report a value change. 
                            var valueSaveResult = await DeviceValueBuilder.RegisterAsync(new DeviceValue
                            {
                                DeviceId = d.Id,
                                UniqueIdentifier = valueIdString,
                                Name = value.Label,
                                Genre = value.Genre,
                                Index = value.Index,
                                CommandClass = value.CommandClassID,
                                Value = data,
                                ValueType = ConvertType(vid),
                                IsReadOnly = readOnly
                            }, d, CancellationToken);
                            if (valueSaveResult.HasError)
                                await Log.ReportErrorFormatAsync(CancellationToken, "An error occured when registering device value. {0}", valueSaveResult.Message);

                            #region Install Dynamic Commands

                            if (!readOnly)
                            {
                                var argumentType = TranslateDataType(vid.GetType());

                                var deviceCommand = new DeviceCommand
                                {
                                    DeviceId = d.Id,
                                    UniqueIdentifier = string.Format("DYNAMIC_CMD_{0}", valueIdString),
                                    Name = string.Format("Set {0}", value.Label),
                                    ArgumentType = argumentType,
                                    Help = string.IsNullOrEmpty(value.Help) ? string.Empty : value.Help,
                                    CustomData1 = string.IsNullOrEmpty(value.Label) ? string.Empty : value.Label,
                                    CustomData2 = string.IsNullOrEmpty(valueIdString) ? string.Empty : valueIdString,
                                    SortOrder = EvaluateOrder(value.Genre)
                                };

                                //Special case for lists add additional info
                                if (argumentType == DataType.LIST)
                                {
                                    //Install the allowed options/values
                                    String[] options;
                                    if (MManager.GetValueListItems(vid, out options))
                                        foreach (var option in options)
                                            deviceCommand.Options.Add(new CommandOption { Name = option });
                                }

                                var saveDynamicResult = await DeviceCommandBuilder.RegisterAsync(d.Id, deviceCommand, CancellationToken);
                                if (saveDynamicResult.HasError)
                                    await Log.ReportErrorFormatAsync(CancellationToken, "An error occured when registering dynamic command. {0}", saveDynamicResult.Message);

                            }
                            #endregion
                        }
#if DEBUG
                        sw.Stop();
                        Debug.WriteLine("Added new Openzwave Value in {0}", sw.Elapsed.ToString() as object);
#endif
                        break;
                        #endregion
                    }
                case ZWNotification.Type.ValueRemoved:
                    {
                        #region ValueRemoved

                        try
                        {
                            var node = GetNode(MNotification.GetHomeId(), MNotification.GetNodeId());
                            var vid = MNotification.GetValueID();
                            var val = node.GetValue(vid);

                            Debug.WriteLine("[ValueRemoved] Node:" + node.ID + ",Label:" + MManager.GetValueLabel(vid));

                            node.RemoveValue(val);
                            //TODO: Remove from values and command table
                        }
                        catch (Exception ex)
                        {
                            Log.ReportErrorFormatAsync(CancellationToken, "Value removed error. {0}", ex.Message).Wait();
                        }
                        break;
                        #endregion
                    }
                case ZWNotification.Type.ValueChanged:
                    {
                        #region ValueChanged
                        var node = GetNode(MNotification.GetHomeId(), MNotification.GetNodeId());
                        var vid = MNotification.GetValueID();
                        var value = new Value
                        {
                            ValueID = vid,
                            Label = MManager.GetValueLabel(vid),
                            Genre = vid.GetGenre().ToString(),
                            Index = vid.GetIndex().ToString(CultureInfo.InvariantCulture),
                            Type = vid.GetType().ToString(),
                            CommandClassID = vid.GetCommandClassId().ToString(CultureInfo.InvariantCulture),
                            Help = MManager.GetValueHelp(vid)
                        };
                        var readOnly = MManager.IsValueReadOnly(vid);

                        var data = GetValue(vid);
                        //m_manager.GetValueAsString(vid, out data);                          

                        Debug.WriteLine("[ValueChanged] Node:" + node.ID + ", Label:" + value.Label + ", Data:" + data);

                        using (var context = new ZvsContext(EntityContextConnection))
                        {
                            var device = await context.Devices
                                .Include(o => o.Type)
                                .FirstOrDefaultAsync(o => o.Type.Adapter.AdapterGuid == AdapterGuid &&
                                    o.NodeNumber == node.ID);

                            if (device == null)
                            {
                                await Log.ReportWarningAsync("ValueChanged called on a node id that was not found in the database", CancellationToken);
                                break;
                            }
                            var valueIdString = vid.GetId().ToString(CultureInfo.InvariantCulture);
                            var oldValue =
                                await
                                    context.DeviceValues.Where(
                                        o => o.DeviceId == device.Id && o.UniqueIdentifier == valueIdString)
                                        .Select(o => o.Value).FirstOrDefaultAsync();

                            if (oldValue != null && oldValue != data)
                                await Log.ReportInfoFormatAsync(CancellationToken, "{0} {1} {2} changed from {3} to {4}",
                                    device.Location,
                                    device.Name,
                                    value.Label,
                                    oldValue,
                                    data);

                            //Update device value
                            var deviceValueResult = await DeviceValueBuilder.RegisterAsync(new DeviceValue
                             {
                                 DeviceId = device.Id,
                                 UniqueIdentifier = valueIdString,
                                 Name = value.Label,
                                 Genre = value.Genre,
                                 Index = value.Index,
                                 CommandClass = value.CommandClassID,
                                 Value = data,
                                 ValueType = ConvertType(vid),
                                 IsReadOnly = readOnly
                             }, device, CancellationToken);
                            if (deviceValueResult.HasError)
                                await Log.ReportErrorFormatAsync(CancellationToken, "An error occured when updating device values. {0}", deviceValueResult.Message);

                            #region Update Device Status Properties
                            //Update Current Status Field
                            var changed = false;
                            if (device.Type.UniqueIdentifier == OpenzWaveDeviceTypes.Thermostat.ToString())
                            {
                                if (value.Label == "Temperature")
                                {
                                    double level;
                                    double.TryParse(data, out level);
                                    var levelTxt = string.Format("{0}° F", level);

                                    if (!device.CurrentLevelInt.Equals(level))
                                    {
                                        device.CurrentLevelInt = level;
                                        changed = true;
                                    }

                                    if (device.CurrentLevelText != levelTxt)
                                    {
                                        device.CurrentLevelText = levelTxt;
                                        changed = true;
                                    }
                                }
                            }
                            else if (device.Type.UniqueIdentifier == OpenzWaveDeviceTypes.Switch.ToString())
                            {
                                if (value.Label == "Basic")
                                {
                                    double level;
                                    if (double.TryParse(data, out level))
                                    {
                                        var levelOnOff = level > 0 ? 100 : 0;
                                        var leveltxt = level > 0 ? "On" : "Off";

                                        if (!device.CurrentLevelInt.Equals(levelOnOff))
                                        {
                                            device.CurrentLevelInt = levelOnOff;
                                            changed = true;
                                        }

                                        if (device.CurrentLevelText != leveltxt)
                                        {
                                            device.CurrentLevelText = leveltxt;
                                            changed = true;
                                        }
                                    }
                                }
                                else if (value.Label == "Switch" || value.Label == "Level") //Some Intermatic devices do not set basic when changing status
                                {
                                    bool state;
                                    if (bool.TryParse(data, out state))
                                    {
                                        var levelOnOff = state ? 100 : 0;
                                        var leveltxt = state ? "On" : "Off";

                                        if (!device.CurrentLevelInt.Equals(levelOnOff))
                                        {
                                            device.CurrentLevelInt = levelOnOff;
                                            changed = true;
                                        }

                                        if (device.CurrentLevelText != leveltxt)
                                        {
                                            device.CurrentLevelText = leveltxt;
                                            changed = true;
                                        }
                                    }
                                }

                            }
                            else if (device.Type.UniqueIdentifier == OpenzWaveDeviceTypes.Sensor.ToString())
                            {
                                if (value.Label == "Power")
                                {
                                    double watts;
                                    if (double.TryParse(data, out watts))
                                    {
                                        device.CurrentLevelInt = watts;
                                        device.CurrentLevelText = string.Format("{0}W", watts);
                                        changed = true;
                                    }

                                }
                            }
                            else
                            {
                                if (value.Label == "Basic")
                                {
                                    double level;
                                    double.TryParse(data, out level);
                                    var levelInt = (int)level;
                                    var levelTxt = level + "%";

                                    if (!device.CurrentLevelInt.Equals(levelInt))
                                    {
                                        device.CurrentLevelInt = levelInt;
                                        changed = true;
                                    }

                                    if (device.CurrentLevelText != levelTxt)
                                    {
                                        device.CurrentLevelText = levelTxt;
                                        changed = true;
                                    }
                                }
                            }

                            if (changed)
                            {
                                var result = await context.TrySaveChangesAsync(CancellationToken);
                                if (result.HasError)
                                    await Log.ReportErrorFormatAsync(CancellationToken, "Failed update device level. {0}", result.Message);
                            }
                            #endregion

                            #region Update Device Commands
                            if (!readOnly)
                            {
                                var uid = string.Format("DYNAMIC_CMD_{0}", valueIdString);
                                var deviceCommand = await context.DeviceCommands.FirstOrDefaultAsync(o => o.DeviceId == device.Id &&
                                    o.UniqueIdentifier == uid);

                                if (deviceCommand != null)
                                {
                                    //User commands are more important so lets see them first in the GUIs
                                    int order;
                                    switch (value.Genre)
                                    {
                                        case "Basic":
                                            order = 4;
                                            break;
                                        case "User":
                                            order = 3;
                                            break;
                                        case "Config":
                                            order = 2;
                                            break;
                                        default:
                                            order = 1;
                                            break;
                                    }

                                    //After Value is Added, Value Name other values properties can change so update.
                                    deviceCommand.Name = "Set " + value.Label;
                                    deviceCommand.Help = value.Help;
                                    deviceCommand.CustomData1 = value.Label;
                                    deviceCommand.SortOrder = order;

                                    var result = await context.TrySaveChangesAsync(CancellationToken);
                                    if (result.HasError)
                                        await Log.ReportErrorFormatAsync(CancellationToken, "Failed to update device command. {0}", result.Message);
                                }
                            }
                            #endregion

                            #region Repoll Dimmers

                            //Some dimmers take x number of seconds to dim to desired level.  Therefore the level received here initially is a 
                            //level between old level and new level. (if going from 0 to 100 we get 84 here).
                            //To get the real level re-poll the device a second or two after a level change was received.     
                            bool enableDimmerRepoll = bool.TryParse(await
                                device.GetDeviceSettingAsync(OpenzWaveDeviceTypeSettings.EnableRepollOnLevelChange.ToString(), context), out enableDimmerRepoll) && enableDimmerRepoll;

                            if (InitialPollingComplete &&
                                enableDimmerRepoll &&
                                device.Type.UniqueIdentifier == OpenzWaveDeviceTypes.Dimmer.ToString() &&
                                value.Label == "Basic")
                            {
                                //only allow each device to re-poll 1 time.
                                if (!_nodeValuesRepolling.Contains(device.NodeNumber))
                                {
                                    _nodeValuesRepolling.Add(device.NodeNumber);

                                    await Task.Delay(3500);
                                    MManager.RefreshValue(vid);
                                    Debug.WriteLine("Node {0} value re-polled", device.NodeNumber);

                                    //Do not allow another re-poll for 10 seconds
                                    await Task.Delay(10000);
                                    _nodeValuesRepolling.Remove(device.NodeNumber);
                                }
                            }
                            #endregion

                        }

                        break;
                        #endregion
                    }
                case ZWNotification.Type.Group:
                    {
                        #region Group
                        Debug.WriteLine("[Group]");
                        break;
                        #endregion
                    }
                case ZWNotification.Type.NodeAdded:
                    {
                        #region NodeAdded
                        // if this node was in zwcfg*.xml, this is the first node notification
                        // if not, the NodeNew notification should already have been received
                        //if (GetNode(m_notification.GetHomeId(), m_notification.GetNodeId()) == null)
                        //{
                        var node = new Node { ID = MNotification.GetNodeId(), HomeID = MNotification.GetHomeId() };
                        _mNodeList.Add(node);

                        Debug.WriteLine("[NodeAdded] ID:" + node.ID + " Added");
                        await AddNewDeviceToDatabase(node.ID);

                        break;
                        #endregion
                    }
                case ZWNotification.Type.NodeNew:
                    {
                        #region NodeNew
                        // Add the new node to our list (and flag as uninitialized)
                        var node = new Node { ID = MNotification.GetNodeId(), HomeID = MNotification.GetHomeId() };
                        _mNodeList.Add(node);

                        Debug.WriteLine("[NodeNew] ID:" + node.ID + " Added");
                        await AddNewDeviceToDatabase(node.ID);

                        break;
                        #endregion
                    }
                case ZWNotification.Type.NodeRemoved:
                    {
                        #region NodeRemoved

                        foreach (var node in _mNodeList.Where(node => node.ID == MNotification.GetNodeId()))
                        {
                            Debug.WriteLine("[NodeRemoved] ID:" + node.ID);
                            _mNodeList.Remove(node);
                            break;
                        }
                        break;
                        #endregion
                    }
                case ZWNotification.Type.NodeNaming:
                    {
                        #region NodeNaming
                        const string manufacturerNameValueId = "MN1";
                        const string productNameValueId = "PN1";
                        const string nodeLocationValueId = "NL1";
                        const string nodeNameValueId = "NN1";

                        var node = GetNode(MNotification.GetHomeId(), MNotification.GetNodeId());

                        if (node != null)
                        {
                            node.Manufacturer = MManager.GetNodeManufacturerName(MHomeId, node.ID);
                            node.Product = MManager.GetNodeProductName(MHomeId, node.ID);
                            node.Location = MManager.GetNodeLocation(MHomeId, node.ID);
                            node.Name = MManager.GetNodeName(MHomeId, node.ID);

                            Debug.WriteLine("[NodeNaming] Node:" + node.ID + ", Product:" + node.Product + ", Manufacturer:" + node.Manufacturer + ")");

                            using (var context = new ZvsContext(EntityContextConnection))
                            {
                                var device = await context.Devices.FirstOrDefaultAsync(o => o.Type.Adapter.AdapterGuid == AdapterGuid &&
                                    o.NodeNumber == node.ID);

                                if (device == null)
                                {
                                    await Log.ReportWarningAsync("NodeNaming called on a node id that was not found in the database", CancellationToken);
                                    break;
                                }

                                //lets store the manufacturer name and product name in the values table.   
                                //Giving ManufacturerName a random value_id 9999058723211334120                                                           
                                var mNameResult = await DeviceValueBuilder.RegisterAsync(new DeviceValue
                                {
                                    DeviceId = device.Id,
                                    UniqueIdentifier = manufacturerNameValueId,
                                    Name = "Manufacturer Name",
                                    Genre = "Custom",
                                    Index = "0",
                                    ValueType = DataType.STRING,
                                    CommandClass = "0",
                                    Value = node.Manufacturer,
                                    IsReadOnly = true
                                }, device, CancellationToken);
                                if (mNameResult.HasError)
                                    await Log.ReportErrorFormatAsync(CancellationToken, "An error occured when updating manufacturing name value. {0}", mNameResult.Message);

                                var productNameResult = await DeviceValueBuilder.RegisterAsync(new DeviceValue
                                {
                                    DeviceId = device.Id,
                                    UniqueIdentifier = productNameValueId,
                                    Name = "Product Name",
                                    Genre = "Custom",
                                    Index = "0",
                                    ValueType = DataType.STRING,
                                    CommandClass = "0",
                                    Value = node.Product,
                                    IsReadOnly = true
                                }, device, CancellationToken);
                                if (productNameResult.HasError)
                                    await Log.ReportErrorFormatAsync(CancellationToken, "An error occured when updating product name value. {0}", productNameResult.Message);


                                var nodeResult = await DeviceValueBuilder.RegisterAsync(new DeviceValue
                                {
                                    DeviceId = device.Id,
                                    UniqueIdentifier = nodeLocationValueId,
                                    Name = "Node Location",
                                    Genre = "Custom",
                                    Index = "0",
                                    ValueType = DataType.STRING,
                                    CommandClass = "0",
                                    Value = node.Location,
                                    IsReadOnly = true
                                }, device, CancellationToken);
                                if (nodeResult.HasError)
                                    await Log.ReportErrorFormatAsync(CancellationToken, "An error occured when updating node location value. {0}", nodeResult.Message);

                                var nodeNameResult = await DeviceValueBuilder.RegisterAsync(new DeviceValue
                                {
                                    DeviceId = device.Id,
                                    UniqueIdentifier = nodeNameValueId,
                                    Name = "Node Name",
                                    Genre = "Custom",
                                    Index = "0",
                                    ValueType = DataType.STRING,
                                    CommandClass = "0",
                                    Value = node.Name,
                                    IsReadOnly = true
                                }, device, CancellationToken);
                                if (nodeNameResult.HasError)
                                    await Log.ReportErrorFormatAsync(CancellationToken, "An error occured when updating node name value. {0}", nodeNameResult.Message);
                            }
                        }

                        break;
                        #endregion
                    }
                case ZWNotification.Type.NodeEvent:
                    {
                        #region NodeEvent
                        var node = GetNode(MNotification.GetHomeId(), MNotification.GetNodeId());
                        var gevent = MNotification.GetEvent();

                        if (node == null)
                            break;

                        await Log.ReportInfoFormatAsync(CancellationToken, "[NodeEvent] Node: {0}, Event Byte: {1}", node.ID, gevent);

                        using (var context = new ZvsContext(EntityContextConnection))
                        {
                            var device = await context.Devices
                                .FirstOrDefaultAsync(o => o.Type.Adapter.AdapterGuid == AdapterGuid &&
                                    o.NodeNumber == node.ID);

                            if (device == null)
                            {
                                await Log.ReportWarningAsync("NodeNaming called on a node id that was not found in the database", CancellationToken);
                                break;
                            }

                            var dv = await context.DeviceValues.FirstOrDefaultAsync(o => o.DeviceId == device.Id &&
                                o.UniqueIdentifier == LastEventNameValueId);

                            //Node event value placeholder
                            if (dv == null)
                                break;

                            dv.Value = gevent.ToString(CultureInfo.InvariantCulture);

                            var result = await context.TrySaveChangesAsync(CancellationToken);
                            if (result.HasError)
                                await Log.ReportErrorFormatAsync(CancellationToken, "Failed to update device value. {0}", result.Message);

                            //Since open wave events are differently than values changes, we need to fire the value change event every time we receive the 
                            //event regardless if it is the same value or not.
                            //TODO:
                            //dv.DeviceValueDataChanged(new DeviceValue.ValueDataChangedEventArgs(dv.Id, dv.Value, string.Empty));
                        }

                        break;
                        #endregion
                    }
                case ZWNotification.Type.DriverReady:
                    {
                        #region DriverReady
                        _nodesReady.Clear();

                        MHomeId = MNotification.GetHomeId();
                        await Log.ReportInfoFormatAsync(CancellationToken, "Initializing...driver with Home ID 0x{0} is ready.", MHomeId.ToString("X8"));

                        break;
                        #endregion
                    }
                case ZWNotification.Type.NodeQueriesComplete:
                    {
                        #region NodeQueriesComplete
                        var node = GetNode(MNotification.GetHomeId(), MNotification.GetNodeId());
                        if (node != null)
                        {
                            await Log.ReportInfoFormatAsync(CancellationToken, "Initializing...node {0} queries complete", node.ID);

                            if (!_nodesReady.Contains(node.ID))
                                _nodesReady.Add(node.ID);

                            //await UpdateLastHeardFrom(node.ID);
                        }

                        break;
                        #endregion
                    }
                case ZWNotification.Type.EssentialNodeQueriesComplete:
                    {
                        #region EssentialNodeQueriesComplete
                        var node = GetNode(MNotification.GetHomeId(), MNotification.GetNodeId());
                        if (node != null)
                        {
                            await Log.ReportInfoFormatAsync(CancellationToken, "Initializing...node {0} essential queries complete", node.ID);

                            if (!_nodesReady.Contains(node.ID))
                                _nodesReady.Add(node.ID);

                            //await UpdateLastHeardFrom(node.ID);
                        }

                        break;
                        #endregion
                    }
                case ZWNotification.Type.AllNodesQueried:
                    {
                        #region AllNodesQueried
                        //This is an important message to see.  It tells you that you can start issuing commands
                        await Log.ReportInfoAsync("Ready:  All nodes queried", CancellationToken);
                        InitialPollingComplete = true;
                        MManager.WriteConfig(MNotification.GetHomeId());
                        await EnablePollingOnDevices();
                        break;
                        #endregion
                    }
                case ZWNotification.Type.AllNodesQueriedSomeDead:
                    {
                        #region AllNodesQueriedSomeDead
                        //This is an important message to see.  It tells you that you can start issuing commands
                        await Log.ReportInfoAsync("Ready:  All nodes queried but some are dead.", CancellationToken);
                        InitialPollingComplete = true;
                        MManager.WriteConfig(MNotification.GetHomeId());
                        await EnablePollingOnDevices();
                        break;
                        #endregion
                    }
                case ZWNotification.Type.AwakeNodesQueried:
                    {
                        #region AwakeNodesQueried
                        await Log.ReportInfoAsync("Ready:  Awake nodes queried (but not some sleeping nodes)", CancellationToken);
                        InitialPollingComplete = true;
                        MManager.WriteConfig(MNotification.GetHomeId());
                        await EnablePollingOnDevices();
                        break;
                        #endregion
                    }
                case ZWNotification.Type.PollingDisabled:
                    {
                        #region PollingDisabled
                        await Log.ReportInfoAsync("Polling disabled notification", CancellationToken);
                        break;
                        #endregion
                    }
                case ZWNotification.Type.PollingEnabled:
                    {
                        #region PollingEnabled
                        await Log.ReportInfoAsync("Polling enabled notification", CancellationToken);
                        break;
                        #endregion
                    }
                case ZWNotification.Type.SceneEvent:
                    {
                        #region SceneEvent
                        await Log.ReportInfoAsync("Scene event notification received", CancellationToken);
                        break;
                        #endregion
                    }
            }
        }
        public async Task RunCommandAsyncDeviceCommand()
        {
            //Arrange 
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());

            var adapterManager = new StubIAdapterManager
            {
                FindZvsAdapterGuid = adapterGuid => new StubZvsAdapter
                {
                    IsEnabled = true,
                    ProcessDeviceCommandAsyncDeviceDeviceCommandStringString = (adapterDevice, command, argument, argument2) => Task.FromResult(0)
                }
            };
            var log = new StubIFeedback<LogEntry>();

            var cts = new CancellationTokenSource();
            var commmandProcessor = new CommandProcessor(adapterManager, dbConnection, log);

            var device = UnitTesting.CreateFakeDevice();
            using (var context = new ZvsContext(dbConnection))
            {
                var deviceCommand = new DeviceCommand
                {
                    Name = "Turn On"
                };
                device.Commands.Add(deviceCommand);
                context.Devices.Add(device);
                await context.SaveChangesAsync(CancellationToken.None);

                //Act
                var result = await commmandProcessor.RunCommandAsync(deviceCommand.Id, "", "", cts.Token);
                Console.WriteLine(result.Message);

                //Assert
                Assert.IsFalse(result.HasError);
            }
        }
        public async Task ExecuteDeviceCommandAsyncAdapterNotLoadedTest()
        {
            //Arrange 
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());

            var adapterManager = new StubIAdapterManager
            {
                FindZvsAdapterGuid = adapterGuid => null
            };
            var ranstoredCommands = new List<int>();
            var log = new StubIFeedback<LogEntry>();
            var cts = new CancellationTokenSource();
            var commmandProcessor = new CommandProcessor(adapterManager, dbConnection, log);

            var device = UnitTesting.CreateFakeDevice();

            using (var context = new ZvsContext(dbConnection))
            {
                var deviceCommand = new DeviceCommand
                {
                    Name = "Turn On"
                };
                device.Commands.Add(deviceCommand);
                context.Devices.Add(device);
                await context.SaveChangesAsync(CancellationToken.None);

                //Act
                var result = await commmandProcessor.ExecuteDeviceCommandAsync(deviceCommand, "1", "", cts.Token);
                Console.WriteLine(result.Message);

                //Assert
                Assert.IsTrue(result.HasError);
                Assert.IsTrue(ranstoredCommands.Count == 0, "Process did not run the correct amount of commands.");
                Assert.IsTrue(result.Message.Contains("not loaded"), "Expect error message to contain 'not loaded'");
            }
        }
        public async Task ExecuteBuiltinCommandAsyncSceneTest()
        {
            //Arrange 
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());

            var deviceCommandIds = new List<int>();
            var adapterManager = new StubIAdapterManager
            {
                FindZvsAdapterGuid = adapterGuid => new StubZvsAdapter
                {
                    IsEnabled = true,
                    ProcessDeviceCommandAsyncDeviceDeviceCommandStringString = async (adapterDevice, command, argument, argument2) => deviceCommandIds.Add(command.Id)
                }
            };
            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e);
                    return Task.FromResult(0);
                }
            };

            var cts = new CancellationTokenSource();
            var commmandProcessor = new CommandProcessor(adapterManager, dbConnection, log);

            var device = UnitTesting.CreateFakeDevice();
            using (var context = new ZvsContext(dbConnection))
            {
                var deviceCommand = new DeviceCommand
                {
                    Name = "Turn On"
                };
                device.Commands.Add(deviceCommand);
                context.Devices.Add(device);

                var scene = new Scene
                {
                    Name = "Test Scene"
                };
                scene.Commands.Add(new SceneStoredCommand
                {
                    Command = deviceCommand,
                    Argument = "0"
                });
                context.Scenes.Add(scene);

                var builtinCommand = new BuiltinCommand
                {
                    Name = "Activate Scene",
                    UniqueIdentifier = "RUN_SCENE"
                };
                context.Commands.Add(builtinCommand);
                await context.SaveChangesAsync(new CancellationToken());

                //Act
                var result = await commmandProcessor.ExecuteBuiltinCommandAsync(builtinCommand, scene.Id.ToString(CultureInfo.InvariantCulture), "", cts.Token);
                Console.WriteLine(result.Message);

                //Assert
                Assert.IsFalse(result.HasError);
                Assert.IsTrue(deviceCommandIds.Count == 1, "Process did not run the correct amount of commands.");
                Assert.IsTrue(deviceCommand.Id == deviceCommandIds[0], "Ran the wrong scene!");
            }
        }
        public async Task ExecuteDeviceCommandAsyncOkTest()
        {
            //Arrange 
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());

            var commandsSendToAdapter = new List<int>();
            var adapterManager = new StubIAdapterManager
            {
                FindZvsAdapterGuid = adapterGuid => new StubZvsAdapter
                {
                    IsEnabled = true,
                    ProcessDeviceCommandAsyncDeviceDeviceCommandStringString = (adapterDevice, command, argument, argument2) =>
                    {
                        commandsSendToAdapter.Add(command.Id);
                        return Task.FromResult(0);
                    }
                }
            };

            var log = new StubIFeedback<LogEntry>();
            var cts = new CancellationTokenSource();
            var commmandProcessor = new CommandProcessor(adapterManager, dbConnection, log);

            var device = UnitTesting.CreateFakeDevice();

            using (var context = new ZvsContext(dbConnection))
            {
                var deviceCommand = new DeviceCommand
                {
                    Name = "Turn On"
                };
                device.Commands.Add(deviceCommand);
                context.Devices.Add(device);
                await context.SaveChangesAsync(CancellationToken.None);

                //Act
                var result = await commmandProcessor.ExecuteDeviceCommandAsync(deviceCommand, "1", "", cts.Token);
                Console.WriteLine(result.Message);

                //Assert
                Assert.IsFalse(result.HasError);
                Assert.IsTrue(commandsSendToAdapter.Count == 1, "Process did not run the correct amount of commands.");
                Assert.IsTrue(commandsSendToAdapter[0] == deviceCommand.Id, "Wrong command processed");
            }
        }
        public async Task RegisterAsyncAddNewCommandTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "dcb-RegisterAsyncAddNewCommandTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());
            var dvb = new DeviceCommandBuilder( dbConnection);

            var device = UnitTesting.CreateFakeDevice();
            using (var context = new ZvsContext(dbConnection))
            {
                context.Devices.Add(device);
                await context.SaveChangesAsync();
            }

            var deviceCommand = new DeviceCommand()
            {
                Name = "Unit Testing Command"
            };
            
            //act
            var result = await dvb.RegisterAsync(device.Id, deviceCommand, CancellationToken.None);
            Console.WriteLine(result.Message);

            Device d;
            using (var context = new ZvsContext(dbConnection))
            {
                d = await context.Devices
                    .Include(o=> o.Commands)
                    .FirstOrDefaultAsync(o => o.Id == device.Id);
            }

            //assert 
            Assert.IsFalse(result.HasError, result.Message);
            Assert.IsNotNull(d, "device not found!");
            Assert.IsTrue(d.Commands.Count == 1, "Device has an unexpected number of commands");
            Assert.IsTrue(d.Commands[0].Name == deviceCommand.Name, "Device command did not save correctly");
        }
Example #17
0
 public override Task ProcessDeviceCommandAsync(Device device, DeviceCommand command, string argument, string argument2)
 {
     return Task.FromResult(0);
 }
 public override Task ProcessDeviceCommandAsync(Device device, DeviceCommand command, string argument, string argument2)
 {
     throw new NotImplementedException();
 }
Example #19
0
 public abstract Task ProcessDeviceCommandAsync(Device device, DeviceCommand command, string argument, string argument2);