Как запросить необработанные данные у Proficy Historian?

StackOverflow https://stackoverflow.com/questions/306642

  •  08-07-2019
  •  | 
  •  

Вопрос

Как я могу получить необработанные данные временных рядов из Proficy Historian/iHistorian?

В идеале я бы запросил данные для определенного тега между двумя датами.

Это было полезно?

Решение

Существует несколько различных режимов выборки, с которыми вы можете поэкспериментировать.

  • Сырой
  • Интерполированный
  • Лаборатория
  • Тренд
  • Рассчитано

Эти режимы доступны с использованием всех следующих API.

  • Пользовательский API (ihuapi.dll)
  • SDK (ihsdk.dll)
  • OLEDB (iholedb.dll)
  • API клиентского доступа (Proficy.Historian.ClientAccess.API)

Из них, вероятно, вам нужен режим выборки тренда, поскольку он специально разработан для построения графиков/трендов.Хотя лабораторные и интерполированные данные тоже могут быть полезны.

Прочтите электронную книгу для получения дополнительной информации о каждом режиме отбора проб.На моей машине он хранится как C:\Program Files\GE Fanuc\Proficy Historian\Docs\iHistorian.chm и у меня установлена ​​версия 3.5.Обратите особое внимание на следующие разделы.

  • Использование поставщика Historian OLE DB
  • Расширенные темы | Возвращение

Вот как вы можете создать OLEDB для выборки тенденций.

set 
    SamplingMode = 'Trend',
    StartTime = '2010-07-01 00:00:00',
    EndTime = '2010-07-02 00:00:00',
    IntervalMilliseconds = 1h
select 
    timestamp, 
    value, 
    quality 
from 
    ihRawData 
where 
    tagname = 'YOUR_TAG'

Демонстрация эквивалентных методов с использованием User API и SDK сложна (особенно с User API), поскольку для их настройки требуется много работы в коде.API клиентского доступа является более новым и использует WCF «за кулисами».

Кстати, у метода OLEDB есть несколько ограничений.

  • Несмотря на то, что написано в документации, у меня есть никогда удалось заставить работать собственные параметры запроса.Это препятствие, если вы хотите использовать его, например, со службами отчетов SQL Server.
  • Вы не можете записывать образцы в архив или каким-либо образом вносить изменения в конфигурацию Historian, включая добавление/изменение тегов, написание сообщений и т. д.
  • В некоторых случаях это может быть немного медленно.
  • В нем не предусмотрено перекрестное объединение нескольких тэгов в столбцы с последующим переносом образцов так, чтобы существовало значение для каждой комбинации временной метки и тега.Режим выборки трендов позволяет сделать это наполовину, но при этом не создает перекрестную таблицу и не загружает необработанные выборки.Опять же, User API и SDK тоже не могут этого сделать.

Другие советы

Мой коллега соединил это:

В web.config:

<add name="HistorianConnectionString" 
     providerName="ihOLEDB.iHistorian.1" 
     connectionString="
       Provider=ihOLEDB.iHistorian;
       User Id=;
       Password=;
       Data Source=localhost;"
/>

На уровне данных:

public DataTable GetProficyData(string tagName, DateTime startDate, DateTime endDate)
{
    using (System.Data.OleDb.OleDbConnection cn = new System.Data.OleDb.OleDbConnection())
    {
        cn.ConnectionString = webConfig.ConnectionStrings.ConnectionStrings["HistorianConnectionString"];
        cn.Open();

        string queryString = string.Format(
                "set samplingmode = rawbytime\n select value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' and value > 0 order by timestamp",
                tagName.Replace("'", "\""), startDate, endDate);

        System.Data.OleDb.OleDbDataAdapter adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn);
        DataSet ds = new DataSet();

        adp.Fill(ds);
        return ds.Tables[0];
    }
}
<Ч>

Обновление:

Это сработало хорошо, но мы столкнулись с проблемой с тегами, которые обновляются не очень часто. Если бы тег не обновлялся около начала или конца запрошенных startDate и endDate, тренды выглядели бы плохо. Хуже того, все еще были случаи, когда во время запрошенного окна не было никаких явных точек - мы не получили бы данных обратно.

Я решил эту проблему, сделав три запроса:

<Ол>
  • Предыдущее значение перед датой начала
  • Точки между startDate и endDate
  • Следующее значение после endDate
  • Это потенциально неэффективный способ сделать это, но он работает:

    public DataTable GetProficyData(string tagName, DateTime startDate, DateTime endDate)
    {
        DataSet ds = new DataSet();
        string queryString;
        System.Data.OleDb.OleDbDataAdapter adp;
    
        using (System.Data.OleDb.OleDbConnection cn = new System.Data.OleDb.OleDbConnection())
        {
            cn.ConnectionString = proficyConn.ConnectionString;
            cn.Open();
    
            // always get a start value
            queryString = string.Format(
                 "set samplingmode = lab\nselect value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' order by timestamp",
                tagName.Replace("'", "\""), startDate.AddMinutes(-1), startDate);
            adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn);
            adp.Fill(ds);
    
            // get the range
            queryString = string.Format(
                 "set samplingmode = rawbytime\nselect value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' order by timestamp",
                tagName.Replace("'", "\""), startDate, endDate);
            adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn);
            adp.Fill(ds);
    
            // always get an end value
            queryString = string.Format(
                 "set samplingmode = lab\nselect value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' order by timestamp",
            tagName.Replace("'", "\""), endDate.AddMinutes(-1), endDate);
            adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn);
            adp.Fill(ds);
    
            return ds.Tables[0];
        }
    }
    

    И да, я знаю, эти запросы должны быть параметризованы.

    Майкл - в IP21 есть "Интерполированный" таблица, а также «фактическая» таблица точек данных. У Proficy это тоже есть?

    Мы написали DLL-оболочку, которая выглядела примерно так:

    [DllImport("IHUAPI.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "ihuReadRawDataByTime@24")]
    public static extern int ihuReadRawDataByTime(int serverhandle, string tagname, ref IHU_TIMESTAMP startTime, ref IHU_TIMESTAMP endTime, ref int noOfSamples, ref IHU_DATA_SAMPLE* dataValues);
    ...
    private int _handle;
    
    public HistorianTypes.ErrorCode ReadRawByTime(string tagName, DateTime startTime, DateTime endTime,
                                                  out double[] timeStamps, out double[] values, out IhuComment [] comments)
    {
        var startTimeStruct = new IhuApi.IHU_TIMESTAMP();  //Custom datetime to epoch extension method
        var endTimeStruct = new IhuApi.IHU_TIMESTAMP();
    
        int lRet = 0;
        int noOfSamples = 0;
        startTimeStruct = DateTimeToTimeStruct(dstZone.ToUniversalTime(startTime));
        endTimeStruct = DateTimeToTimeStruct(dstZone.ToUniversalTime(endTime));
        IhuApi.IHU_DATA_SAMPLE* dataSample = (IhuApi.IHU_DATA_SAMPLE*)new IntPtr(0);
    
        try {
            lRet = IhuApi.ihuReadRawDataByTime
                (
                    _handle, // the handle returned from the connect
                    tagName, // the single tagname to retrieve
                    ref startTimeStruct, // start time for query
                    ref endTimeStruct, // end time for query
                    ref noOfSamples, // will be set by API
                    ref dataSample // will be allocated and populated in the user API
                );
                ....
    

    В некоторых заметках iFIX будет проверять, загружена ли DLL при запуске, поэтому вам нужно выполнять такие вещи, как динамическая загрузка / выгрузка DLL, чтобы другие приложения не зависали. Мы сделали это, удалив / добавив ключи реестра на лету.

    Еще один вариант: если вы опросите 10 000 образцов и 1 из них будет поврежден, все 10 000 образцов будут отброшены. Вам необходимо реализовать обработчик неверных данных, который будет запускаться по обе стороны от неверных данных и постепенно увеличиваться, чтобы получить все данные по обе стороны от неверного образца.

    Существует несколько заголовочных файлов C, которые содержат все коды ошибок и заголовок функции для DLL.

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top