/// <summary>
 /// 定时保存值到历史记录
 /// </summary>
 /// <param name="client"></param>
 /// <param name="device"></param>
 static void saveValueOnTime_Thread(MyDriverClient client, Device device)
 {
     if (client.SaveOnTimeInfos.Count == 0)
     {
         return;
     }
     Task.Run(() =>
     {
         while (client.Released == false)
         {
             foreach (var itemInfo in client.SaveOnTimeInfos)
             {
                 if (itemInfo.CurrentValue != itemInfo.SaveValue && (DateTime.Now - itemInfo.SaveTime).TotalSeconds >= itemInfo.PointObj.DevicePoint.ValueOnTimeChangeSetting)
                 {
                     WriteHistory(itemInfo.PointObj.DevicePoint, itemInfo.CurrentValue);
                     itemInfo.SaveValue = itemInfo.CurrentValue;
                     itemInfo.SaveTime  = DateTime.Now;
                 }
             }
             Thread.Sleep(1000);
         }
     });
 }
        static void start()
        {
            try
            {
                if (hisDB != null)
                {
                    lock (hisDB)
                    {
                        hisDB.CommitTransaction();
                        hisDB.Dispose();
                    }
                    hisDB = null;
                }
                using (SysDB db = new SysDB())
                {
                    var sysSetting = db.SystemSetting.FirstOrDefault();
                    if (string.IsNullOrEmpty(sysSetting.HistoryPath))
                    {
                        return;
                    }
                    try
                    {
                        //目录不存在,创建目录
                        if (System.IO.Directory.Exists(sysSetting.HistoryPath) == false)
                        {
                            System.IO.Directory.CreateDirectory(sysSetting.HistoryPath);
                        }
                        HistoryDataPath = $"data source=\"{sysSetting.HistoryPath.Replace("\\", "/")}/history_data.db\"";
                        hisDB           = new DB.SunRiz(HistoryDataPath, Way.EntityDB.DatabaseType.Sqlite);
                        LastHisTime     = DateTime.Now;
                        hisDB.BeginTransaction();
                    }
                    catch
                    {
                        return;
                    }


                    var pointGroups = from m in db.DevicePoint
                                      where m.ValueRelativeChange == true || m.ValueAbsoluteChange == true || m.ValueOnTimeChange == true || m.IsAlarm == true
                                      group m by m.DeviceId into g
                                      select g;
                    foreach (var pointArr in pointGroups)
                    {
                        var deviceId = pointArr.Key.GetValueOrDefault();
                        var device   = db.Device.AsTracking().FirstOrDefault(m => m.id == deviceId);
                        var driver   = db.CommunicationDriver.AsTracking().FirstOrDefault(m => m.id == device.DriverID);

                        MyDriverClient client = new MyDriverClient(driver.Address, driver.Port.Value);
                        client.Points = (from m in pointArr
                                         select new MyDevicePoint(m)).ToArray();
                        AllClients.Add(client);
                        string[] pointAddrs = new string[client.Points.Length];
                        for (int i = 0; i < client.Points.Length; i++)
                        {
                            pointAddrs[i] = client.Points[i].DevicePoint.Address;
                            if (client.Points[i].DevicePoint.ValueOnTimeChange == true)
                            {
                                client.SaveOnTimeInfos.Add(new SaveOnTimeInfo()
                                {
                                    PointObj = client.Points[i],
                                    PointId  = client.Points[i].DevicePoint.id.Value,
                                    Interval = client.Points[i].DevicePoint.ValueOnTimeChangeSetting.GetValueOrDefault(),
                                });
                            }
                        }
                        watchClient(client, device, pointAddrs);
                        //启动定时保存的线程
                        saveValueOnTime_Thread(client, device);
                    }
                }
            }
            catch (Exception ex)
            {
                using (Way.Lib.CLog log = new Way.Lib.CLog("HistoryAutoRec error "))
                {
                    log.Log(ex.ToString());
                }
            }
        }
        /// <summary>
        /// 实时监测设备值变化
        /// </summary>
        /// <param name="client"></param>
        /// <param name="device"></param>
        /// <param name="pointAddrs"></param>
        static void watchClient(MyDriverClient client, Device device, string[] pointAddrs)
        {
            client.NetClient = client.AddPointToWatch(device.Address, pointAddrs, (addr, value) =>
            {
                var myPoint = client.Points.FirstOrDefault(m => m.DevicePoint.Address == addr);

                if (myPoint != null)
                {
                    var point = myPoint.DevicePoint;
                    var jobj  = GetJsonObject(point);
                    double dblValue;
                    value = SunRizDriver.Helper.Transform(jobj, value);
                    try
                    {
                        dblValue = Convert.ToDouble(value);
                    }
                    catch
                    {
                        return;
                    }

                    if (point.Type == DevicePoint_TypeEnum.Digital)
                    {
                        //开关量,直接保存
                        WriteHistory(point, dblValue);
                    }
                    else if (point.ValueOnTimeChange == true)
                    {
                        //定时保存
                        var timeInfo = client.SaveOnTimeInfos.FirstOrDefault(m => m.PointId == point.id);
                        if (timeInfo != null)
                        {
                            timeInfo.CurrentValue = dblValue;
                        }
                    }
                    else if (point.ValueAbsoluteChange == true)
                    {
                        //绝对变化是指这个变量当前值与前一个历史值比较,变化超过设定数值后进行历史保存
                        if (myPoint.LastValue == null || Math.Abs(dblValue - myPoint.LastValue.GetValueOrDefault()) >= point.ValueAbsoluteChangeSetting)
                        {
                            WriteHistory(point, dblValue);
                            myPoint.LastValue = dblValue;
                        }
                    }
                    else if (point.ValueRelativeChange == true)
                    {
                        //相对变化是指这个变量当前值与前一个历史值比较,变化超过设定值(这个值是该变量量程的百分比)后进行历史保存
                        if (myPoint.LastValue == null)
                        {
                            myPoint.LastValue = dblValue;
                        }
                        else if (myPoint.LastValue == 0 || Math.Abs(dblValue - myPoint.LastValue.GetValueOrDefault()) * 100 / myPoint.LastValue >= point.ValueRelativeChangeSetting)
                        {
                            WriteHistory(point, dblValue);
                            myPoint.LastValue = dblValue;
                        }
                    }

                    if (point.IsAlarm == true)
                    {
                        SystemHelper.AutoBackAlarm(point.id.Value, dblValue);
                        if (point.Type == DevicePoint_TypeEnum.Analog)
                        {
                            foreach (var lowAlarm in myPoint.LowAlarmConfig)
                            {
                                if (dblValue < lowAlarm.Value)
                                {
                                    SystemHelper.AddAlarm(new Alarm()
                                    {
                                        Content     = $"触发低{lowAlarm.Number}报警",
                                        Address     = point.Name,
                                        AddressDesc = point.Desc,
                                        PointId     = point.id,
                                        PointValue  = dblValue,
                                        Priority    = lowAlarm.Priority,
                                        Expression  = "{0}<" + lowAlarm.Value
                                    });
                                    break;
                                }
                            }
                            foreach (var hiAlarm in myPoint.HiAlarmConfig)
                            {
                                if (dblValue > hiAlarm.Value)
                                {
                                    SystemHelper.AddAlarm(new Alarm()
                                    {
                                        Content     = $"触发高{hiAlarm.Number}报警",
                                        Address     = point.Name,
                                        AddressDesc = point.Desc,
                                        PointId     = point.id,
                                        PointValue  = dblValue,
                                        Priority    = hiAlarm.Priority,
                                        Expression  = "{0}>" + hiAlarm.Value
                                    });
                                    break;
                                }
                            }

                            if (point.IsAlarmOffset == true)
                            {
                                if (Math.Abs(dblValue - point.AlarmOffsetOriginalValue.GetValueOrDefault()) > point.AlarmOffsetValue)
                                {
                                    SystemHelper.AddAlarm(new Alarm()
                                    {
                                        Content     = $"偏差报警",
                                        Address     = point.Name,
                                        AddressDesc = point.Desc,
                                        PointId     = point.id,
                                        PointValue  = dblValue,
                                        Priority    = point.AlarmOffsetPriority,
                                        Expression  = "{0}-" + point.AlarmOffsetOriginalValue + ">" + point.AlarmOffsetValue + " or {0}-" + point.AlarmOffsetOriginalValue + "<-" + point.AlarmOffsetValue
                                    });
                                }
                            }
                            else if (point.IsAlarmPercent == true)
                            {
                                if (myPoint.LastValue == null)
                                {
                                    myPoint.LastValue     = dblValue;
                                    myPoint.LastValueTime = DateTime.Now;
                                }
                                else if (myPoint.LastValue == 0 || Math.Abs(dblValue - myPoint.LastValue.GetValueOrDefault()) * 100 / myPoint.LastValue > point.Percent)
                                {
                                    if ((DateTime.Now - myPoint.LastValueTime).TotalSeconds < point.ChangeCycle)
                                    {
                                        SystemHelper.AddAlarm(new Alarm()
                                        {
                                            Content     = $"变化率报警",
                                            Address     = point.Name,
                                            AddressDesc = point.Desc,
                                            PointId     = point.id,
                                            PointValue  = dblValue,
                                            Priority    = point.AlarmPercentPriority
                                        });
                                    }
                                    myPoint.LastValue     = dblValue;
                                    myPoint.LastValueTime = DateTime.Now;
                                }
                            }
                        }
                        else
                        {
                            if (point.AlarmValue == dblValue)
                            {
                                SystemHelper.AddAlarm(new Alarm()
                                {
                                    Content     = $"触发报警",
                                    Address     = point.Name,
                                    AddressDesc = point.Desc,
                                    PointId     = point.id,
                                    PointValue  = dblValue,
                                    Expression  = "{0}=" + point.AlarmValue
                                });
                            }
                        }
                    }
                    //System.Diagnostics.Debug.WriteLine($"name:{addr} value:{value}");
                }
            }, (err) =>
            {
                if (client.Released)
                {
                    return;
                }

                Task.Run(() =>
                {
                    Thread.Sleep(2000);
                    watchClient(client, device, pointAddrs);
                });
            });
        }