Пример #1
0
        /// <summary>
        /// 写入单个标签点的历史数据
        /// 这个方法主要用于从csv文件导入历史数据到golden数据库中。从csv读取的数据是字符串型二维数组,因此这里的历史数据入参是字符串型二维数组,而不是List<PValue>
        /// </summary>
        /// <param name="tagname"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public int PutArchivedValues(string tagname, string[][] data)
        {
            //注意,只能向数据库第一个有效数据的时间之后,插入历史数据。
            //——如果插入的值得历史时刻在第一个有效值前,则插入不返回错误,但是数据写不进去。
            //准备数据
            PISDK.PIValues pivalues = new PISDK.PIValues(); //新建PIValues,ReadOnly属性为true
            pivalues.ReadOnly = false;                      //只有将PIValues的readonly属性置为false,才能写入。

            //数据点的描述,是一个NamedValues类型。该类型是一个集合。可以添加不同的描述项,并给项设定值
            NamedValues nvatts = new NamedValues();

            nvatts.Add("questionable", true);

            //将数据写入pivalues
            //——只使用第1个值即实时值,第2个值时间。
            int i = 0;

            //try
            //{
            for (i = 0; i < data.Length; i++)
            {
                try
                {
                    //在PI导出的数据中,value有可能是字符串。有时候表示服务器启停,有时候表示“IO timeout”等,这些值都无法转换成数值型,必须跳过。
                    if (data[i] != null && data[i].Length != 0)
                    {
                        pivalues.Add(Convert.ToDateTime(data[i][2]), Convert.ToDouble(data[i][1]), nvatts);
                    }
                }
                catch
                {
                    continue;
                }
            }
            //}
            //catch (Exception ex)
            //{
            //    //将pi的异常PgimDataException记录在_exception中,并以PgimDataException的名称继续抛出异常
            //    this._exception = "写历史数据时,转换数据格式错误!错误行数"+i.ToString();
            //    throw ex;     //将pgim的异常继续向外传递。
            //}

            //使用piPoint.Data.UpdateValues更新点历史数据
            //this._piPoint = new PISDK.PIPoint();
            try
            {
                this._piPoint = this._piServer.PIPoints[tagname];
                PISDKCommon.PIErrors pierror = this._piPoint.Data.UpdateValues(pivalues);
                //处理写入结果
                return(pierror.Count);
            }
            catch (Exception ex)
            {
                //将pi的异常PgimDataException记录在_exception中,并以PgimDataException的名称继续抛出异常
                this._exception = "PI其他未知错误。通常是服务器故障、标签中对应的服务器名称不正确导致!";
                throw ex;     //将pgim的异常继续向外传递。
                return(-1);
            }
        }
Пример #2
0
        public PValue GetActValue(string tagname)
        {
            List <PValue> pvalues = new List <PValue>();


            //准备读值列表PIValues
            PISDK.PIValue pival;
            this._piPoint = this._piServer.PIPoints[tagname];
            pival         = this._piPoint.Data.Snapshot;     //PI的快照值为只读

            //未做完。待续

            return(pvalues[0]);
        }
Пример #3
0
        //历史值的读写
        #region 读取历史数据原始值:public List<PValue> GetRawValues(string tagname, DateTime startdate, DateTime enddate)。重点函数,概化计算引擎用。
        /// <summary>
        /// GetRawValues是实时库读取历史数据接口的对外封装。无论何种实时数据库,读取历史数据功能都是指,读取某一个指定标签(tagname)在一段时间内(startdate、enddate)的历史值(浮点型)
        /// 而不同的实时数据库,真正的读取方法和返回值的数据类型略有区别
        /// 要求起始时刻和截止时刻,必须为精确的实时值。如果恰好有这两个时刻点的值,就直接取得。如果没有就采用插值。
        /// 对于PI数据库,读取历史数据接口,当第三个参数设定为btInterp时,接口会自动的获取起始时刻和截止时刻的插值。
        /// </summary>
        /// <param name="tagname">标签名</param>
        /// <param name="startdate">起始时间</param>
        /// <param name="enddate">结束时间</param>
        /// <returns>历史数据,PValue集合</returns>
        public List <PValue> GetRawValues(string tagname, DateTime startdate, DateTime enddate)
        {
            //经过测试,PI数据库读取原始数据时,在起始时刻点,和截止时刻点,可以通过参数设置实现以下几种方式:
            //在piPoint.Data.RecordedValues()中的第三个参数,BoundaryType,可以选择:
            //——auto,自动决定边界点
            //——btInside,只取时间戳大于起始时间的点和时间戳小于截止时刻的点。
            //——btOutside,取得实时数据包含起始时刻前一个有效时刻的值,和截止时刻后一个有效时刻的值。
            //——btInterp,在起始时刻和截止时刻,进行插值。
            //对于计算引擎,需要的就是btInterp这种方式,即在起始时刻和截止时刻,进行精确的插值
            //如果已经取到数据库最早的时间值,则不再向前补值。比如数据最早是2018-1-2 00:00:00的值。取值周期起始时刻是2018-1-1。RecordedValues返回的第一个值是2018-1-2 00:00:00的,不会向前补值。

            //为了在使用长连接时保险起见,这里仅检查是否连接。如果未连接就直接返回空。
            if (this._piServer == null || !this._piServer.Connected)
            {
                return(null);                                                  //如果未登陆,直接返回空值
            }
            //准备读值列表PIValues
            PIValues pivalues = new PIValues();

            if (enddate <= startdate)
            {
                return(null);
            }
            try
            {
                this._piPoint = this._piServer.PIPoints[tagname];
                pivalues      = this._piPoint.Data.RecordedValues(startdate, enddate, BoundaryTypeConstants.btOutside); //BoundaryTypeConstants.btInterp采用边界取外值的办法,起始时刻取前值,截止时刻取后值
            }
            catch (Exception ex)
            {
                //将pi的异常记录在_exception中,并以PgimDataException的名称继续抛出异常
                this._exception = "PI其他未知错误。通常是服务器故障、标签中对应的服务器名称不正确导致!详细错误信息:" + ex.ToString();
                throw ex;     //将PI的异常继续向外传递。
            }

            //PI的RecordedValues()接口,返回的数据,起始时刻和截止时刻的值,均为根据前后值插值得到。除此以外,PI还会返回其他标志值,比如停止,IO超驰等。
            //所以,不能依据pivalues>=2,来判断是否包含了完整的起始时刻和截止时刻的值。
            //如果count为0,直接返回空。外部程序可以根据pvalues==null来处理
            if (pivalues == null || pivalues.Count == 0)
            {
                return(null);
            }

            //将pivalues转换为Pvalue值
            //——返回的pvalues,由于采用了BoundaryTypeConstants.btOutside读法,正常情况应该包含一个等于或早于起始时刻的首值,包含一个早于、等于或者晚于截止时刻的后值。
            //——pivalues中可能有非数值数据,转换后的pivalues只包含数值型数据
            List <PValue> pvalues = PIValues2PValuesHist(pivalues);

            if (pvalues == null || pvalues.Count == 0)
            {
                return(null);
            }

            //处理首值
            if (pvalues[0].Timestamp < startdate)
            {
                pvalues[0].Timestamp = startdate;       //如果首值的时刻小于起始时刻,说明btOutside方式正确取到了前点。则将前点时刻改为起始时刻
            }
            else if (pvalues[0].Timestamp == startdate)
            {
                //如果首值的时刻恰好等于起始时刻,则什么也不做
            }
            else
            {
                //将pi的异常记录在_exception中,并以PgimDataException的名称继续抛出异常
                this._exception = "PI接口读取原始数据错误。未正常读取到起始时刻前值!";
                throw new Exception(this._exception);     //将XIANDB的异常继续向外传递。
            }

            //处理尾值
            if (pvalues[pvalues.Count - 1].Timestamp < enddate)
            {
                //如果最后一个点的时间戳小于截止时刻,则说明没有找到截止时刻后值
                pvalues[pvalues.Count - 1].Endtime = enddate;
                pvalues.Add(new PValue(pvalues[pvalues.Count - 1].Value, enddate, enddate, pvalues[pvalues.Count - 1].Status)); //添加截止时刻点
            }
            else if (pvalues[pvalues.Count - 1].Timestamp == enddate)
            {
                //恰好有截止时刻点,将该值作为截止时刻值
                pvalues[pvalues.Count - 1].Endtime = enddate;
            }
            else
            {
                //取到截止时刻点后值
                pvalues[pvalues.Count - 2].Endtime = enddate;           //修改前一个值的结束时刻到enddate
                //将最后一个值,变为截止时刻点
                pvalues[pvalues.Count - 1].Value     = pvalues[pvalues.Count - 2].Value;
                pvalues[pvalues.Count - 1].Timestamp = enddate;
                pvalues[pvalues.Count - 1].Endtime   = enddate;
                pvalues[pvalues.Count - 1].Status    = pvalues[pvalues.Count - 2].Status;
            }

            return(pvalues);
        }
Пример #4
0
        /// <summary>
        /// 查询间隔数据
        /// </summary>
        /// <param name="tagName">查询条件</param>
        /// <param name="startTime">起始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="sampleInterVal">间隔时间:1h,2h,3h,4h</param>
        /// <param name="fvc">过滤方式</param>
        /// <param name="filter">过滤</param>
        /// <returns></returns>
        public virtual DataTable GetInterpolatedValues(string[] tagName, DateTime startTime, DateTime endTime, object sampleInterVal, string filter)
        {
            if (this.server == null)
            {
                //log4net.ILog log = log4net.LogManager.GetLogger(this.GetType());
                //log.Debug("PIServer未初始化");
                logs.writelog("PIServer未初始化");
                throw new Exception("PIserver未初始化。");
            }
            //PIValues pivalues = null;
            DataSet ds = new DataSet();
            //声明一个数据表,表名为LoadValue
            DataTable dt = new DataTable("LoadValue");

            //该表有3列,分别为piID,ptValue,ptTime
            dt.Columns.Add("ptID", typeof(System.String));
            dt.Columns.Add("ptValue", typeof(System.String));
            dt.Columns.Add("ptTime", typeof(DateTime));

            //StringBuilder sb = new StringBuilder();
            //由于历史数据可能过多,所以选择用datatable返回
            try
            {
                if (!this.server.Connected)
                {
                    this.server.Open(this.piConnectionString);
                }
                //分别对pointID取数
                for (int i = 0; i < tagName.Length; i++)
                {
                    //pisdk的pipoint为pointID对应的原子点名
                    PISDK.PIPoint piPoint = this.server.PIPoints[tagName[i].ToString()];
                    //取2min内的2个点
                    PISDK.PIValues piValues = piPoint.Data.InterpolatedValues(
                        System.DateTime.Now.AddMinutes(-2),
                        System.DateTime.Now.AddMinutes(-1),
                        3,
                        "1=1",
                        PISDK.FilteredViewConstants.fvShowFilteredState,
                        new PISDKCommon.PIAsynchStatus());
                    if (piValues.Count > 0)
                    {
                        //将每个点对应的数据和事件加入到数据表LoadValue中
                        for (int j = 1; j <= piValues.Count; j++)
                        {
                            DataRow dr = dt.NewRow();
                            dr["ptID"]    = tagName[i];
                            dr["ptValue"] = piValues[j].Value.ToString();
                            dr["ptTime"]  = piValues[j].TimeStamp.LocalDate;
                            dt.Rows.Add(dr);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //log4net.ILog log = log4net.LogManager.GetLogger(this.GetType());
                //log.Error(ex);
                logs.writelog("按照时间间隔查询数据发生错误:" + ex);
                throw new Exception("按照时间间隔查询数据发生错误:" + ex.Message);
            }
            return(dt);
        }