using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Text.RegularExpressions; using System.Threading; using BlubbFish.IoT.Zway.Devices; using BlubbFish.IoT.Zway.Events; using BlubbFish.IoT.Zway.Interfaces; using BlubbFish.IoT.Zway.lib; using LitJson; namespace BlubbFish.IoT.Zway { public class ZwayController : IDisposable { private HttpConnection http; private Thread updatethread; private Thread pollthread; public static ReadOnlyDictionary namelist; private Boolean polling; public delegate void DataUpdate(Object sender, DeviceUpdateEvent e); public event DataUpdate Update; public ReadOnlyDictionary Devices { get; private set; } public ZwayController(String server, String user, String pass, Dictionary names, Boolean enablePoll = true) { namelist = new ReadOnlyDictionary(names); this.polling = enablePoll; this.Connect(server, user, pass); } public ZwayController(Dictionary settings, Dictionary names, Boolean enablePoll = true) { namelist = new ReadOnlyDictionary(names); this.polling = enablePoll; this.Connect(settings["server"], settings["user"], settings["pass"]); } private void Connect(String server, String user, String pass) { this.http = new HttpConnection(server, user, pass); CultureInfo info = new CultureInfo("de-DE"); info.NumberFormat.NumberDecimalSeparator = "."; CultureInfo.DefaultThreadCurrentCulture = info; CultureInfo.DefaultThreadCurrentUICulture = info; Thread.CurrentThread.CurrentCulture = info; Thread.CurrentThread.CurrentUICulture = info; this.CreateDevices(this.http.GetJson("ZWaveAPI/Run/devices")); this.updatethread = new Thread(this.Updater); this.updatethread.Start(); this.pollthread = new Thread(this.Poll); this.pollthread.Start(); foreach (KeyValuePair item in this.Devices) { item.Value.Update += this.DeviceUpdate; } } private void DeviceUpdate(Object sender, DeviceUpdateEvent e) { this.Update?.Invoke(sender, e); } private void Poll() { CultureInfo info = new CultureInfo("de-DE"); info.NumberFormat.NumberDecimalSeparator = "."; CultureInfo.DefaultThreadCurrentCulture = info; CultureInfo.DefaultThreadCurrentUICulture = info; Thread.CurrentThread.CurrentCulture = info; Thread.CurrentThread.CurrentUICulture = info; while(true) { foreach (KeyValuePair item in this.Devices) { item.Value.Poll(); } Thread.Sleep(1000); } } public ACommandClass GetCommandClass(String id) { String[] addr = id.Split('-'); if (addr.Length == 3 || addr.Length == 4) { return this.GetCommandClass(Int32.Parse(addr[0]), Int32.Parse(addr[1]), (ACommandClass.Classes)Int32.Parse(addr[2]), (addr.Length == 4 ? Int32.Parse(addr[3]) : -1)); } return null; } public ACommandClass GetCommandClass(Int32 deviceid, Int32 instanceid, ACommandClass.Classes classid, Int32 subcid = -1) { if(this.Devices.ContainsKey(deviceid) && this.Devices[deviceid].Instances.ContainsKey(instanceid) && this.Devices[deviceid].Instances[instanceid].CommandClasses.ContainsKey(classid)) { ACommandClass commandclass = this.Devices[deviceid].Instances[instanceid].CommandClasses[classid]; if(subcid == -1) { return commandclass; } if (commandclass != null) { if(commandclass.HasSub) { if(commandclass.Sub.ContainsKey(subcid)) { return commandclass.Sub[subcid]; } } } } return null; } private void Updater() { CultureInfo info = new CultureInfo("de-DE"); info.NumberFormat.NumberDecimalSeparator = "."; CultureInfo.DefaultThreadCurrentCulture = info; CultureInfo.DefaultThreadCurrentUICulture = info; Thread.CurrentThread.CurrentCulture = info; Thread.CurrentThread.CurrentUICulture = info; while (true) { Int64 date = ((DateTimeOffset)DateTime.Now.AddSeconds(-2)).ToUnixTimeSeconds(); JsonData notifications = this.http.GetJson("ZWave.zway/Data/"+date); foreach (String item in notifications.Keys) { Match match = new Regex("^devices\\.([0-9]+)\\.instances\\.([0-9]+)\\.commandClasses\\.([0-9]+)(\\.data\\.([0-9]+)|\\.data\\.[a-z].*|\\.data)$", RegexOptions.IgnoreCase).Match(item); if(match.Success) { Int32 deviceid = Int32.Parse(match.Groups[1].Value); Int32 instanceid = Int32.Parse(match.Groups[2].Value); ACommandClass.Classes commandid = (ACommandClass.Classes)Int32.Parse(match.Groups[3].Value); if (this.Devices.ContainsKey(deviceid) && this.Devices[deviceid].Instances.ContainsKey(instanceid) && this.Devices[deviceid].Instances[instanceid].CommandClasses.ContainsKey(commandid)) { this.Devices[deviceid].Instances[instanceid].CommandClasses[commandid].SetUpdate(notifications[item], match); } } /*else { if(item.StartsWith("controller.")) { } else if(item == "updateTime") { } else { match = new Regex("^devices\\.([0-9]+)\\.(data.*)", RegexOptions.IgnoreCase).Match(item); if(!match.Success) { } } }*/ match = new Regex("^devices\\.([0-9]+)\\.(data.*)", RegexOptions.IgnoreCase).Match(item); if(match.Success) { Int32 deviceid = Int32.Parse(match.Groups[1].Value); if (this.Devices.ContainsKey(deviceid)) { this.Devices[deviceid].SetUpdate(notifications[item], match); } } } Thread.Sleep(1500); } } private void CreateDevices(JsonData json) { Dictionary devices = new Dictionary(); foreach (String deviceid in json.Keys) { Device d = Device.CreateDevice(json[deviceid], new Tuple(Int32.Parse(deviceid)), this.http, this.polling); if (d != null) { devices.Add(Int32.Parse(deviceid), d); } } this.Devices = new ReadOnlyDictionary(devices); } public Dictionary GetCommandClasses(ACommandClass.Classes classes) { Dictionary ret = new Dictionary(); foreach (KeyValuePair device in this.Devices) { foreach (KeyValuePair instance in device.Value.Instances) { foreach (KeyValuePair commandclass in instance.Value.CommandClasses) { if (commandclass.Key == classes) { ret.Add(commandclass.Value.Id, commandclass.Value); } } } } return ret; } #region IDisposable Support private Boolean disposedValue = false; protected virtual void Dispose(Boolean disposing) { if (!this.disposedValue) { if (disposing) { this.updatethread.Abort(); this.pollthread.Abort(); } this.updatethread = null; this.pollthread = null; this.Devices = null; this.disposedValue = true; } } ~ZwayController() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion } }