This project has moved and is read-only. For the latest updates, please go here.
openHistorian Version 1.0 is an integral part of the openPDC. Please see http://openpdc.codeplex.com

openHistorian Version 2.0 Beta is planned for the Fall of 2015.

If you are just needing to archive data from the openPDC, it is recommended to setup an Internal Subscription to the openPDC - follow the same steps as you would for SIEGate or other tools:

https://siegate.codeplex.com/wikipage?title=Creating%20internal%20gateway%20connections

Just make sure you set the subscription historian to "PPA" before you save the connection to make sure all subscribed data gets archived.

FYI - we have just added SQL Server link for the openHistorian. You can now query data openHistorian from within SQL Server using the GetHistorianData function that can be enabled by running the EnableHistorianSqlClr.sql script included with the latest installation:

https://www.gridprotectionalliance.org/NightlyBuilds/openHistorian/Beta/

Example API use to "read" data:

using System;
using System.Collections.Generic;
using GSF.Snap;
using GSF.Snap.Filters;
using GSF.Snap.Services;
using GSF.Snap.Services.Reader;
using openHistorian.Net;
using openHistorian.Snap;

// Define a historian measurement for floating-point values
public struct HistorianMeasurement
{
    public readonly ulong ID;
    public readonly DateTime Time;
    public readonly float Value;

    public HistorianMeasurement(ulong id, DateTime time, float value)
    {
        ID = id;
        Time = time;
        Value = value;
    }
}

// Read historian data from server, e.g., var enumerator = GetHistorianData("127.0.0.1", "PPA", DateTime.UtcNow.AddMinutes(-1.0D), DateTime.UtcNow)
public static IEnumerable<HistorianMeasurement> GetHistorianData(string historianServer, string instanceName, DateTime startTime, DateTime stopTime, string measurementIDs = null)
{
    const int DefaultHistorianPort = 38402;

    if (string.IsNullOrEmpty(historianServer))
        throw new ArgumentNullException("historianServer", "Missing historian server parameter");

    if (string.IsNullOrEmpty(instanceName))
        throw new ArgumentNullException("instanceName", "Missing historian instance name parameter");

    if (startTime > stopTime)
        throw new ArgumentException("Invalid time range specified", "startTime");

    string[] parts = historianServer.Split(':');
    string hostName = parts[0];
    int port;

    if (parts.Length < 2 || !int.TryParse(parts[1], out port))
        port = DefaultHistorianPort;

    // Open historian connection
    using (HistorianClient client = new HistorianClient(hostName, port))
    using (ClientDatabaseBase<HistorianKey, HistorianValue> reader = client.GetDatabase<HistorianKey, HistorianValue>(instanceName))
    {
        // Setup time-range and point ID selections
        SeekFilterBase<HistorianKey> timeFilter = TimestampSeekFilter.CreateFromRange<HistorianKey>(startTime, stopTime);
        MatchFilterBase<HistorianKey, HistorianValue> pointFilter = null;
        HistorianKey key = new HistorianKey();
        HistorianValue value = new HistorianValue();

        if (!string.IsNullOrEmpty(measurementIDs))
            pointFilter = PointIdMatchFilter.CreateFromList<HistorianKey, HistorianValue>(measurementIDs.Split(',').Select(ulong.Parse));

        // Start stream reader for the provided time window and selected points
        TreeStream<HistorianKey, HistorianValue> stream = reader.Read(SortedTreeEngineReaderOptions.Default, timeFilter, pointFilter);

        while (stream.Read(key, value))
            yield return new HistorianMeasurement(key.PointID, key.TimestampAsDate, value.AsSingle);
    }
}


Example API use to "write" data:

// Write historian data
public static void WriteHistorianData(string historianServer, string instanceName, IEnumerable<HistorianMeasurement> measurements)
{
    const int DefaultHistorianPort = 38402;

    if (string.IsNullOrEmpty(historianServer))
        throw new ArgumentNullException("historianServer", "Missing historian server parameter");

    if (string.IsNullOrEmpty(instanceName))
        throw new ArgumentNullException("instanceName", "Missing historian instance name parameter");

    if (startTime > stopTime)
        throw new ArgumentException("Invalid time range specified", "startTime");

    string[] parts = historianServer.Split(':');
    string hostName = parts[0];
    int port;

    if (parts.Length < 2 || !int.TryParse(parts[1], out port))
        port = DefaultHistorianPort;

    // Open historian connection
    using (HistorianClient client = new HistorianClient(m_hostName, m_port))
    using (ClientDatabaseBase<HistorianKey, HistorianValue> database = client.GetDatabase<HistorianKey, HistorianValue>(m_instanceName))
    using (HistorianInputQueue queue = new HistorianInputQueue(() => database))
    {
        HistorianKey key = new HistorianKey();
        HistorianValue value = new HistorianValue();
        
        foreach (HistorianMeasurement measurement in measurements)
        {
            key.PointID = measurement.ID;
            key.TimestampAsDate = measurement.Time;
            value.AsSingle = measurement.Value;
            queue.Enqueue(key, value);
        }

        // Wait for queue to be processed
        while (queue.Size > 0)
            Thread.Sleep(1000);
    }
}


Example code to "reduce", via skipping, resolution of returned data:

    TimeSpan interval = Resolutions.GetInterval("Every 30 Seconds");

    SeekFilterBase<HistorianKey> timeFilter;

    if (interval.Ticks != 0)
       timeFilter = TimestampSeekFilter.CreateFromIntervalData<HistorianKey>(startTime, stopTime, interval, new TimeSpan(TimeSpan.TicksPerMillisecond));
    else
        timeFilter = TimestampSeekFilter.CreateFromRange<HistorianKey>(startTime, stopTime);

    // Some example down-sampling resolutions...        
    public static class Resolutions
    {
        public static List<string> GetAllResolutions()
        {
            List<string> rv = new List<string>();
            rv.Add("Full");
            rv.Add("10 per Second");
            rv.Add("Every Second");
            rv.Add("Every 10 Seconds");
            rv.Add("Every 30 Seconds");
            rv.Add("Every Minute");
            rv.Add("Every 10 Minutes");
            rv.Add("Every 30 Minutes");
            rv.Add("Every Hour");
            return rv;
        }
 
        public static TimeSpan GetInterval(string resolution)
        {
            switch (resolution)
            {
                case "Full":
                    return TimeSpan.Zero;
                case "10 per Second":
                    return new TimeSpan(TimeSpan.TicksPerMillisecond * 100);
                case "Every Second":
                    return new TimeSpan(TimeSpan.TicksPerSecond * 1);
                case "Every 10 Seconds":
                    return new TimeSpan(TimeSpan.TicksPerSecond * 10);
                case "Every 30 Seconds":
                    return new TimeSpan(TimeSpan.TicksPerSecond * 30);
                case "Every Minute":
                    return new TimeSpan(TimeSpan.TicksPerMinute * 1);
                case "Every 10 Minutes":
                    return new TimeSpan(TimeSpan.TicksPerMinute * 10);
                case "Every 30 Minutes":
                    return new TimeSpan(TimeSpan.TicksPerMinute * 30);
                case "Every Hour":
                    return new TimeSpan(TimeSpan.TicksPerHour * 1);
                default:
                    throw new Exception("Unknown resolution");
            }
        } 
    }


Thanks,
Ritchie

Last edited May 14, 2015 at 8:09 PM by ritchiecarroll, version 7

Comments

No comments yet.