We had a problem this week, where a user created a PI point to track the servicing of a piece of equipment, and then was going back and manually adding data, dating back to 2015 - very commendable.

The problem was that there is a known issue of "Arc Off-line" appearing for archives that do not contain any data (see 26495OSI8).

While this issue can be resolved for 2016 R2 and beyond, it requires either a reconfiguration and restart - not always immediately available, or reprocessing all of the affected archive files.

A third workaround, not mentioned in the article, is to insert, and then delete, a data point in the archive(s) that are missing data. This creates a record entry for the PI point in the archive, and resolves the Arc Off-line.

 

While this can be done manually (and I have), the following PowerShell script will do that.

Given a server, PI Point, and a start and end time, it will try to get all compressed points, and where it finds an Arc Off-line error, it will insert, then remove a data point, and then gets the compressed values again, recursively adding points to the archives.

 

param (
    [string]$server = 'Server',                      # AF or PI server
    [string]$pointSearch = 'PIPoint',        # PI Point
    [string]$startTime = '2015-08-11 12 am',              # Start Time
    [string]$endTime = '*'                                # End Time
)


# We download all data between start and end, then when we get an Arc Off-line, we 


$refToMyAssembly = [reflection.assembly]::loadwithpartialname("OSIsoft.AFSDK")
$oPIServers = New-Object OSIsoft.AF.PI.PIServers


$PIServer = $oPIServers[$Server]
$classicAttr = $PIServer.PointClasses.Item("classic").GetAttributes()




$con = Connect-PIDataArchive -PIDataArchiveMachineName $server
$piPoint = [OSIsoft.AF.PI.PIPoint]::FindPIPoint($PIServer, $pointSearch)
if ($piPoint -eq $null) { 
    write-host "Trouble finding PI Point: " $pointSearch " on PI Server: " $PIServer
    exit 1
}
$AFTime = New-Object OSIsoft.AF.Time.AFTime($startTime)
$AFStartTime = New-Object OSIsoft.AF.Time.AFTime($startTime)
$AFEndTime = New-Object OSIsoft.AF.Time.AFTime($endTime)


$AFTimeRange = New-Object OSIsoft.AF.Time.AFTimeRange($AFStartTime, $AFEndTime)


$CompressValues = $pipoint.RecordedValues($AFTimeRange, [OSIsoft.AF.Data.AFBoundaryType]::Inside, "", $false)




for ($i = 0; $i -lt  $CompressValues.Count; $i++ ) {
    $cValue =  $CompressValues[$i]


    if ( $cValue.Value.Name -eq "Arc Off-line" ) {
        $cStartTime = $cValue.TimeStamp
        if ($cStartTime -lt $AFStartTime ) {$cStartTime = $AFStartTime}


        $newAFvalue = New-Object OSIsoft.AF.Asset.AFValue($cValue)
        $newAFvalue.Timestamp = $cStartTime
        $newAFValue.Value = 1
        write-host "Updating Time: " $newAFvalue.PIPoint " : " $newAFvalue.Timestamp
        $res = $piPoint.UpdateValue($newAFvalue, [OSIsoft.AF.Data.AFUpdateOption]::Insert, [OSIsoft.AF.Data.AFBufferOption]::BufferIfPossible)
        if ( $res -eq $null ) {
            $res = $piPoint.UpdateValue($newAFvalue, [OSIsoft.AF.Data.AFUpdateOption]::Remove, [OSIsoft.AF.Data.AFBufferOption]::BufferIfPossible)
            if ( $res -eq $null ) {
                $CompressValues = $pipoint.RecordedValues($AFTimeRange, [OSIsoft.AF.Data.AFBoundaryType]::Inside, "", $false)
                $i = 0
            } else {
                write-host "   Trouble Removing Data at " $newAFvalue.Timestamp
            }
        } else {
            write-host "   Trouble Inserting Data at " $newAFvalue.Timestamp
        }
    }
}

 

I have only really verified this for sparse data, but it works with AF SDK 2016 R2.

Your mileage may vary.