stuart.watson

Azure Machine Learning: PowerShell script to store the web service results

Blog Post created by stuart.watson Champion on Nov 9, 2018

So - you hear all of this talk about machine learning, and artificial intelligence, and you think

"Nah - that sounds way too difficult to implement."

or

"I'm going to need the PI integrator for Business Analytics for that, and that's not included in my EA agreement."

Well, I'm here to tell you that neither of these is totally true.

 

One of the cool things about the Azure ML is that it can easily be adapted to provide a web service to your hard work. You provide the input, and it will return your results.

Converting PI data to ML input and the ML output to PI data, then becomes a problem of mapping.

 

The following PowerShell script can be adapted to pull PI data from the Asset Framework structure, send it in a web request to your Azure ML web service, and then write the results back to AF.

It should be general enough to work with any web service - but I have only used it with Azure.

In our environment, we are using it to make predictions, based on current conditions, for a process 60 minutes in the future - but that is determined by your AI.

 

Enjoy!

 

$Input_Data = @{}

$Output_Data = @{}

###### BEGIN AF / WS CONFIGURATION AND MAPPING DATA

$api_key="PUT_YOUR_API_KEY_HERE==" # Get this from the Azure ML Web Service pages ...

$WS_URL = "https://ussouthcentral.services.azureml.net/workspaces/WORK_SPACE_URL_HERE/execute?api-version=2.0&format=swagger" # ... and this one

$Input_Data.TimeStamp = "TimeStamp"  # ML Timestamp input column name

$Input_Data.AFRoot = "\\SERVER NAME\PATH TO AF INPUT ROOT ELEMENT"

$Input_Data.AFTags = [ordered]@{

    "AF Attribute" = "ML Attribute";

    "2nd AF Attribute"  = "2nd ML Attribute"

} # Mapping between AF and ML attributes

$Output_Data.TimeStamp = "TimeStamp" # ML Timestamp output column name

$Output_Data.AFRoot = "\\SERVER NAME\PATH TO AF OUTPUT ROOT ELEMENT"

$Output_Data.AFTags = @{

    "ML Prediction Column" = "AF Attribute|Relative to AFRoot";

    "Next ML Prediction Column" = "Next AF Attribute"

} # Mapping of ML output to AF attributes

####### END AF / WS CONFIGURATION AND MAPPING DATA

$Input_Array = @() + $Input_Data.TimeStamp + $Input_Data.AFTags.Keys

# Load the OSIsoft AF SDK

$refToMyAssembly = [reflection.assembly]::loadwithpartialname("OSIsoft.AFSDK")

$ElementURI = $Input_Data.AFRoot

[OSIsoft.AF.Asset.AFElement] $rootElement = [OSIsoft.AF.Asset.AFElement]::FindElementsByPath([string[]] @($ElementURI), $null)[$ElementURI]

$AFTime =  New-Object OSIsoft.AF.Time.AFTime('*')

$Data_Hash = [ordered]@{}

$Data_Hash.($Input_Data.TimeStamp) = $AFTime.LocalTime.ToString()

Foreach ( $Attr in $rootElement.Attributes) {

    if ($Input_Array -match $Attr.Name) {

        $Data_Hash.($Attr.Name) = $Attr.GetValue($AFTime).Value.ToString()

    }

}

$Input_Hash = [ordered]@{}

Foreach ( $Attr in $Input_Array ) {

    $Input_Hash.$Attr = $Data_Hash.$Attr

}

$jsonObject=[ordered]@{}

$jsonObject.Inputs=@{}

$instance=@{}

$instance.FeatureVector=@{}

$features=@{}

$instance.FeatureVector+=$features

$Inputs = [ordered]@{}

$Inputs."input" = @($Input_Hash)

$jsonObject.Inputs = $Inputs

$jsonObject.GlobalParameters=@{}

$jsonObject=$jsonObject |convertto-json -depth 3

$headers=@{'Authorization'=('Bearer '+ $api_key)}

#Which of the following, depends on how your corporate proxy is setup

#$result = Invoke-Webrequest -UseBasicParsing -UseDefaultCredentials -uri $WS_URL -method post -body $jsonObject -ContentType 'application/json' -headers $headers

$result = Invoke-Webrequest -Proxy "PUT YOUR PROXY URL IN HERE" -UseBasicParsing -ProxyUseDefaultCredentials -uri $WS_URL -method post -body $jsonObject -ContentType 'application/json' -headers $headers

$Output_Hash = ($result.Content | ConvertFrom-Json).Results[0].output

# Prepare Output

$ElementURI = $Output_Data.AFRoot

[OSIsoft.AF.Asset.AFElement] $rootElement = [OSIsoft.AF.Asset.AFElement]::FindElementsByPath([string[]] @($ElementURI), $null)[$ElementURI]

if ( $Output_Hash.($Output_Data.TimeStamp) -ne $null ) {

    $AFTime =  New-Object OSIsoft.AF.Time.AFTime($Output_Hash.($Output_Data.TimeStamp))

    foreach ($tagKey in $Output_Data.AFTags.Keys ) {

        $tag = $Output_Data.AFTags.($tagKey)

        if ( $tag -ne "" ) {

            $attr = [OSIsoft.AF.Asset.AFAttribute]::FindAttribute($tag, $rootElement)

            $outVal = $Output_Hash.($tagKey)

            $outAFVal = New-Object OSIsoft.AF.Asset.AFValue($outVal, $AFTime)

 

            $attr.Data.UpdateValue($outAFVal, [OSIsoft.AF.Data.AFUpdateOption]::Replace)

        }

    }

}

Outcomes