private void NotificationHandler() { //osae.AddToLog("Notification: " + m_notification.GetType().ToString(), false); switch (m_notification.GetType()) { case ZWNotification.Type.ValueAdded: { Node node = GetNode(m_notification.GetHomeId(), m_notification.GetNodeId()); using (zvsEntities2 db = new zvsEntities2(zvsEntityControl.GetzvsConnectionString)) { device d = GetDevices(db).FirstOrDefault(o => o.node_id == node.ID); if (d != null) { ZWValueID vid = m_notification.GetValueID(); Value value = new Value(); value.ValueID = vid; value.Label = m_manager.GetValueLabel(vid); value.Genre = vid.GetGenre().ToString(); value.Index = vid.GetIndex().ToString(); value.Type = vid.GetType().ToString(); value.CommandClassID = vid.GetCommandClassId().ToString(); value.Help = m_manager.GetValueHelp(vid); bool read_only = m_manager.IsValueReadOnly(vid); node.AddValue(value); string data = ""; bool b = m_manager.GetValueAsString(vid, out data); WriteToLog(Urgency.INFO, "[ValueAdded] Node:" + node.ID + ", Label:" + value.Label + ", Data:" + data + ", result: " + b.ToString()); //Values are 'unknown' at this point so dont report a value change. DefineOrUpdateDeviceValue(new device_values { device_id = d.id, value_id = vid.GetId().ToString(), label_name = value.Label, genre = value.Genre, index = value.Index, type = value.Type, commandClassId = value.CommandClassID, value = data, read_only = read_only }, true); #region Install Dynamic Commands if (!read_only) { Data_Types pType = Data_Types.NONE; //Set param types for command switch (vid.GetType()) { case ZWValueID.ValueType.List: pType = Data_Types.LIST; break; case ZWValueID.ValueType.Byte: pType = Data_Types.BYTE; break; case ZWValueID.ValueType.Decimal: pType = Data_Types.DECIMAL; break; case ZWValueID.ValueType.Int: pType = Data_Types.INTEGER; break; case ZWValueID.ValueType.String: pType = Data_Types.STRING; break; case ZWValueID.ValueType.Short: pType = Data_Types.SHORT; break; case ZWValueID.ValueType.Bool: pType = Data_Types.BOOL; break; } //Install the Node Specific Command int order; switch (value.Genre) { case "User": order = 1; break; case "Config": order = 2; break; default: order = 99; break; } device_commands dynamic_dc = new device_commands { device_id = d.id, name = "DYNAMIC_CMD_" + value.Label.ToUpper(), friendly_name = "Set " + value.Label, arg_data_type = (int)pType, help = value.Help, custom_data1 = value.Label, custom_data2 = vid.GetId().ToString(), sort_order = order }; //Special case for lists add additional info if (vid.GetType() == ZWValueID.ValueType.List) { //Install the allowed options/values String[] options; if (m_manager.GetValueListItems(vid, out options)) foreach (string option in options) dynamic_dc.device_command_options.Add(new device_command_options { name = option }); } DefineOrUpdateDeviceCommand(dynamic_dc); } #endregion } } break; } case ZWNotification.Type.ValueRemoved: { try { Node node = GetNode(m_notification.GetHomeId(), m_notification.GetNodeId()); ZWValueID vid = m_notification.GetValueID(); Value val = node.GetValue(vid); WriteToLog(Urgency.INFO, "[ValueRemoved] Node:" + node.ID + ",Label:" + m_manager.GetValueLabel(vid)); node.RemoveValue(val); //TODO: Remove from values and command table } catch (Exception ex) { WriteToLog(Urgency.ERROR, "ValueRemoved error: " + ex.Message); } break; } case ZWNotification.Type.ValueChanged: { //try //{ Node node = GetNode(m_notification.GetHomeId(), m_notification.GetNodeId()); ZWValueID vid = m_notification.GetValueID(); Value value = new Value(); value.ValueID = vid; value.Label = m_manager.GetValueLabel(vid); value.Genre = vid.GetGenre().ToString(); value.Index = vid.GetIndex().ToString(); value.Type = vid.GetType().ToString(); value.CommandClassID = vid.GetCommandClassId().ToString(); value.Help = m_manager.GetValueHelp(vid); bool read_only = m_manager.IsValueReadOnly(vid); string data = GetValue(vid); //m_manager.GetValueAsString(vid, out data); WriteToLog(Urgency.INFO,"[ValueChanged] Node:" + node.ID + ", Label:" + value.Label + ", Data:" + data); using (zvsEntities2 db = new zvsEntities2(zvsEntityControl.GetzvsConnectionString)) { device d = GetDevices(db).FirstOrDefault(o => o.node_id == node.ID); if (d != null) { // d.last_heard_from = DateTime.Now; //db.SaveChanges(); //Update Device Commands if (!read_only) { //User commands are more important so lets see them first in the GUIs int order; switch (value.Genre) { case "User": order = 1; break; case "Config": order = 2; break; default: order = 99; break; } device_commands dc = d.device_commands.FirstOrDefault(c => c.custom_data2 == vid.GetId().ToString()); if (dc != null) { //After Value is Added, Value Name other value properties can change so update. dc.friendly_name = "Set " + value.Label; dc.help = value.Help; dc.custom_data1 = value.Label; dc.sort_order = order; } } //Some dimmers take x number of seconds to dim to desired level. Therefor the level recieved 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 repoll the device a second or two after a level change was recieved. bool EnableDimmerRepoll = false; bool.TryParse(device_property_values.GetDevicePropertyValue(d.id, "ENABLEREPOLLONLEVELCHANGE"), out EnableDimmerRepoll); if (FinishedInitialPoll && EnableDimmerRepoll) { switch (node.Label) { case "Multilevel Switch": case "Multilevel Power Switch": { switch (value.Label) { case "Basic": device_values dv_basic = d.device_values.FirstOrDefault(v => v.value_id == vid.GetId().ToString()); if (dv_basic != null) { string prevVal = dv_basic.value; //If it is truely new if (!prevVal.Equals(data)) { System.Timers.Timer t = new System.Timers.Timer(); t.Interval = 5000; t.Elapsed += (sender, e) => { m_manager.RefreshNodeInfo(m_homeId, (byte)d.node_id); t.Enabled = false; }; t.Enabled = true; } } break; } break; } } } DefineOrUpdateDeviceValue(new device_values { device_id = d.id, value_id = vid.GetId().ToString(), label_name = value.Label, genre = value.Genre, index = value.Index, type = value.Type, commandClassId = value.CommandClassID, value = data, read_only = read_only }); } else { WriteToLog(Urgency.WARNING, "Getting changes on an unknown device!"); } } //} //catch (Exception ex) //{ // WriteToLog(Urgency.ERROR, "error: " + ex.Message); //} break; } case ZWNotification.Type.Group: { WriteToLog(Urgency.INFO, "[Group]"); ; break; } case ZWNotification.Type.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) //{ Node node = new Node(); node.ID = m_notification.GetNodeId(); node.HomeID = m_notification.GetHomeId(); m_nodeList.Add(node); WriteToLog(Urgency.INFO, "[NodeAdded] ID:" + node.ID.ToString() + " Added"); //} break; } case ZWNotification.Type.NodeNew: { // Add the new node to our list (and flag as uninitialized) Node node = new Node(); node.ID = m_notification.GetNodeId(); node.HomeID = m_notification.GetHomeId(); m_nodeList.Add(node); WriteToLog(Urgency.INFO, "[NodeNew] ID:" + node.ID.ToString() + " Added"); break; } case ZWNotification.Type.NodeRemoved: { foreach (Node node in m_nodeList) { if (node.ID == m_notification.GetNodeId()) { WriteToLog(Urgency.INFO, "[NodeRemoved] ID:" + node.ID.ToString()); m_nodeList.Remove(node); break; } } break; } case ZWNotification.Type.NodeProtocolInfo: { using (zvsEntities2 db = new zvsEntities2(zvsEntityControl.GetzvsConnectionString)) { Node node = GetNode(m_notification.GetHomeId(), m_notification.GetNodeId()); if (node != null) { node.Label = m_manager.GetNodeType(m_homeId, node.ID); } string deviceName = "UNKNOWN"; device_types device_type = null; if (node != null) { WriteToLog(Urgency.INFO, "[Node Protocol Info] " + node.Label); switch (node.Label) { case "Toggle Switch": case "Binary Toggle Switch": case "Binary Switch": case "Binary Power Switch": case "Binary Scene Switch": case "Binary Toggle Remote Switch": deviceName = "OpenZWave Switch " + node.ID; device_type = GetDeviceType("SWITCH", db); break; case "Multilevel Toggle Remote Switch": case "Multilevel Remote Switch": case "Multilevel Toggle Switch": case "Multilevel Switch": case "Multilevel Power Switch": case "Multilevel Scene Switch": deviceName = "OpenZWave Dimmer " + node.ID; device_type = GetDeviceType("DIMMER", db); break; case "Multiposition Motor": case "Motor Control Class A": case "Motor Control Class B": case "Motor Control Class C": deviceName = "Variable Motor Control " + node.ID; device_type = GetDeviceType("DIMMER", db); break; case "General Thermostat V2": case "Heating Thermostat": case "General Thermostat": case "Setback Schedule Thermostat": case "Setpoint Thermostat": case "Setback Thermostat": case "Thermostat": deviceName = "OpenZWave Thermostat " + node.ID; device_type = GetDeviceType("THERMOSTAT", db); break; case "Static PC Controller": case "Static Controller": case "Portable Remote Controller": case "Portable Installer Tool": case "Static Scene Controller": case "Static Installer Tool": deviceName = "OpenZWave Controller " + node.ID; device_type = GetDeviceType("CONTROLLER", db); break; case "Secure Keypad Door Lock": case "Advanced Door Lock": case "Door Lock": case "Entry Control": deviceName = "OpenZWave Door Lock " + node.ID; device_type = GetDeviceType("DOORLOCK", db); break; case "Alarm Sensor": case "Basic Routing Alarm Sensor": case "Routing Alarm Sensor": case "Basic Zensor Alarm Sensor": case "Zensor Alarm Sensor": case "Advanced Zensor Alarm Sensor": case "Basic Routing Smoke Sensor": case "Routing Smoke Sensor": case "Basic Zensor Smoke Sensor": case "Zensor Smoke Sensor": case "Advanced Zensor Smoke Sensor": case "Routing Binary Sensor": case "Routing Multilevel Sensor": deviceName = "OpenZWave Sensor " + node.ID; device_type = GetDeviceType("SENSOR", db); break; default: { WriteToLog(Urgency.INFO, "[Node Label] " + node.Label); break; } } if (device_type != null) { device ozw_device = GetDevices(db).FirstOrDefault(d => d.node_id == node.ID); //If we dont already have the device if (ozw_device == null) { ozw_device = new device { node_id = node.ID, device_types = device_type, friendly_name = deviceName }; db.devices.AddObject(ozw_device); db.SaveChanges(); ozw_device.CallAdded(new EventArgs()); } #region Last Event Value Storeage //Node event value placeholder DefineOrUpdateDeviceValue(new device_values { device_id = ozw_device.id, value_id = LaastEventNameValueId, label_name = "Last Node Event Value", genre = "Custom", index = "0", type = "Byte", commandClassId = "0", value = "0", read_only = true }); #endregion } else WriteToLog(Urgency.WARNING, string.Format("Found unknown device '{0}', node #{1}!", node.Label, node.ID)); } } break; } case ZWNotification.Type.NodeNaming: { string ManufacturerNameValueId = "9999058723211334120"; string ProductNameValueId = "9999058723211334121"; string NodeLocationValueId = "9999058723211334122"; string NodeNameValueId = "9999058723211334123"; using (zvsEntities2 db = new zvsEntities2(zvsEntityControl.GetzvsConnectionString)) { Node node = GetNode(m_notification.GetHomeId(), m_notification.GetNodeId()); if (node != null) { node.Manufacturer = m_manager.GetNodeManufacturerName(m_homeId, node.ID); node.Product = m_manager.GetNodeProductName(m_homeId, node.ID); node.Location = m_manager.GetNodeLocation(m_homeId, node.ID); node.Name = m_manager.GetNodeName(m_homeId, node.ID); device d = GetDevices(db).FirstOrDefault(o => o.node_id == node.ID); if (d != null) { //lets store the manufacturer name and product name in the values table. //Giving ManufacturerName a random value_id 9999058723211334120 DefineOrUpdateDeviceValue(new device_values { device_id = d.id, value_id = ManufacturerNameValueId, label_name = "Manufacturer Name", genre = "Custom", index = "0", type = "String", commandClassId = "0", value = node.Manufacturer, read_only = true }); DefineOrUpdateDeviceValue(new device_values { device_id = d.id, value_id = ProductNameValueId, label_name = "Product Name", genre = "Custom", index = "0", type = "String", commandClassId = "0", value = node.Product, read_only = true }); DefineOrUpdateDeviceValue(new device_values { device_id = d.id, value_id = NodeLocationValueId, label_name = "Node Location", genre = "Custom", index = "0", type = "String", commandClassId = "0", value = node.Location, read_only = true }); DefineOrUpdateDeviceValue(new device_values { device_id = d.id, value_id = NodeNameValueId, label_name = "Node Name", genre = "Custom", index = "0", type = "String", commandClassId = "0", value = node.Name, read_only = true }); } } WriteToLog(Urgency.INFO, "[NodeNaming] Node:" + node.ID + ", Product:" + node.Product + ", Manufacturer:" + node.Manufacturer + ")"); } break; } case ZWNotification.Type.NodeEvent: { Node node = GetNode(m_notification.GetHomeId(), m_notification.GetNodeId()); byte gevent = m_notification.GetEvent(); if (node != null) { WriteToLog(Urgency.INFO, string.Format("[NodeEvent] Node: {0}, Event Byte: {1}", node.ID, gevent)); using (zvsEntities2 db = new zvsEntities2(zvsEntityControl.GetzvsConnectionString)) { #region Last Event Value Storeage device d = GetDevices(db).FirstOrDefault(o => o.node_id == node.ID); if (d != null) { //Node event value placeholder device_values dv = d.device_values.FirstOrDefault(v => v.value_id == LaastEventNameValueId); if (dv != null) { dv.value = gevent.ToString(); db.SaveChanges(); //Since events are differently than values fire the value change event every time we recieve the event regardless if //it is the same value or not. dv.DeviceValueDataChanged(new device_values.ValueDataChangedEventArgs { device_value_id = dv.id, previousValue = string.Empty}); } } #endregion } } break; } case ZWNotification.Type.PollingDisabled: { Node node = GetNode(m_notification.GetHomeId(), m_notification.GetNodeId()); if (node != null) { WriteToLog(Urgency.INFO, "[PollingDisabled] Node:" + node.ID); } break; } case ZWNotification.Type.PollingEnabled: { Node node = GetNode(m_notification.GetHomeId(), m_notification.GetNodeId()); if (node != null) { WriteToLog(Urgency.INFO, "[PollingEnabled] Node:" + node.ID); } break; } case ZWNotification.Type.DriverReady: { m_homeId = m_notification.GetHomeId(); WriteToLog(Urgency.INFO, "Initializing: Driver with Home ID 0x" + m_homeId); WriteToLog(Urgency.INFO, "[DriverReady] Initializing...driver with Home ID 0x" + m_homeId); break; } case ZWNotification.Type.NodeQueriesComplete: { Node node = GetNode(m_notification.GetHomeId(), m_notification.GetNodeId()); if (node != null) { using (zvsEntities2 db = new zvsEntities2(zvsEntityControl.GetzvsConnectionString)) { device d = GetDevices(db).FirstOrDefault(o => o.node_id == node.ID); if (d != null) { d.last_heard_from = DateTime.Now; } db.SaveChanges(); zvsEntityControl.CallDeviceModified(d, "last_heard_from"); } WriteToLog(Urgency.INFO, "Initializing: Node " + node.ID + " query complete."); WriteToLog(Urgency.INFO, "[NodeQueriesComplete] Initializing...node " + node.ID + " query complete."); } break; } case ZWNotification.Type.AllNodesQueried: { using (zvsEntities2 db = new zvsEntities2(zvsEntityControl.GetzvsConnectionString)) { foreach (Node n in m_nodeList) { device d = GetDevices(db).FirstOrDefault(o => o.node_id == n.ID); if (d != null) { if (device_property_values.GetDevicePropertyValue(d.id, "ENABLEPOLLING").ToUpper().Equals("TRUE")) EnablePolling(n.ID); } } } WriteToLog(Urgency.INFO, "Ready: All nodes queried. Plug-in now ready."); IsReady = true; FinishedInitialPoll = true; break; } case ZWNotification.Type.AwakeNodesQueried: { using (zvsEntities2 db = new zvsEntities2(zvsEntityControl.GetzvsConnectionString)) { foreach (Node n in m_nodeList) { device d = GetDevices(db).FirstOrDefault(o => o.node_id == n.ID); if (d != null) { if (device_property_values.GetDevicePropertyValue(d.id, "ENABLEPOLLING").ToUpper().Equals("TRUE")) EnablePolling(n.ID); } } } WriteToLog(Urgency.INFO, "Ready: Awake nodes queried (but not some sleeping nodes)."); IsReady = true; FinishedInitialPoll = true; break; } } }
public void AddValue(Value val) { m_values.Add(val); }
public void RemoveValue(Value val) { m_values.Remove(val); }
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 } } }