Collect Ambient Weather Data with PowerShell Azure Function

You may have seen my previous post on collecting weather data from WeatherUnderground. With this post I will show you how to collect Ambient Weather data from the API with Azure Functions. Why a new post? A few reasons. One, that post was with the experimental Windows PowerShell Azure Functions, which are no longer available. PowerShell Core Azure Functions are officially supported now. Two, Acurite had no API and required you to send your data to weather underground to access via an API. Three, IBM bought Weather Underground and as they are apt to do, ruined a good thing. The API is no longer freely available. Four, Acurite was going to disable my hub which was how I got my weather data out to the internet. So instead of buying something else from them, I went with what my friend Kris Turner uses, an Ambient Weather Falcon.

Requirements

  • Ambient Weather Station
  • API Key from Ambient Weather
  • App Key from Ambient Weather
  • PowerShell Core Azure Function
  • Log Analytics Workspace
  • Log Analytics workspace ID and key

 

Ambient Weather API

To collect your data from Ambient Weather you’ll need and App Key and API Key. You can create them under your profile at https://dashboard.ambientweather.net/account 

 

Collect Ambient Weather Data

Create an API Key and App Key, as you’ll need both in the URI.

You can read the full API Doc here. https://ambientweather.docs.apiary.io/#

Setup Azure Function

I’m not going to go over how to deploy an Azure Function, its fairly trivial, if you need help you can find numerous results on your favorite search engine.

Once setup, go to your Function App -> Configuration and create keys for:

  • Ambient Weather API
  • Ambient Weather App Key
  • Log Analytics Workspace ID
  • Log Analytics Key

 

Collect Ambient Weather Data

Next setup a TimerTrigger function, I set mine to run every five minutes. From the API Docs they don’t want you to collect any faster than that.

In our run.ps1 we’ll use

$env: with the key name to get our keys.

$env:appkey

$env:apikey

this gets our appkey and api key in which we’ll add to the URI to collect our data.

 

 


# Input bindings are passed in via param block.
param($Timer)

# build URI for Ambient Weather API
$uri = "https://api.ambientweather.net/v1/devices?" + "applicationKey=" + $env:appkey + "&apiKey=" + $env:apikey

#get weather data
$weather = invoke-restmethod -uri $uri

# Specify the name of the record type that you'll be creating
$LogType = "Weather"

$TimeStampField = get-date
$TimeStampField = $TimeStampField.GetDateTimeFormats(115)

Function Build-Signature ($customerId, $sharedKey, $date, $contentLength, $method, $contentType, $resource)
{
          $xHeaders = "x-ms-date:" + $date
          $stringToHash = $method + "`n" + $contentLength + "`n" + $contentType + "`n" + $xHeaders + "`n" + $resource

          $bytesToHash = [Text.Encoding]::UTF8.GetBytes($stringToHash)
          $keyBytes = [Convert]::FromBase64String($sharedKey)

          $sha256 = New-Object System.Security.Cryptography.HMACSHA256
          $sha256.Key = $keyBytes
          $calculatedHash = $sha256.ComputeHash($bytesToHash)
          $encodedHash = [Convert]::ToBase64String($calculatedHash)
          $authorization = 'SharedKey {0}:{1}' -f $customerId,$encodedHash
return $authorization
}

# Create the function to create and post the request
Function Post-LogAnalyticsData($customerId, $sharedKey, $body, $logType)
{
$method = "POST"
$contentType = "application/json"
$resource = "/api/logs"
$rfc1123date = [DateTime]::UtcNow.ToString("r")
$contentLength = $body.Length
$signature = Build-Signature `
           -customerId $customerId `
           -sharedKey $sharedKey `
           -date $rfc1123date `
           -contentLength $contentLength `
           -fileName $fileName `
           -method $method `
           -contentType $contentType `
           -resource $resource
$uri = "https://" + $customerId + ".ods.opinsights.azure.com" + $resource + "?api-version=2016-04-01"

$headers = @{
         "Authorization" = $signature;
         "Log-Type" = $logType;
         "x-ms-date" = $rfc1123date;
         "time-generated-field" = $TimeStampField;
}

$response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Headers $headers -Body $body -UseBasicParsing
return $response.StatusCode

}

$weather = ConvertTo-Json $weather.lastdata

# Submit the data to the API endpoint
Post-LogAnalyticsData -customerId $env:ID -sharedKey $env:key -body ([System.Text.Encoding]::UTF8.GetBytes($weather)) -logType $logType

 

Log Analytics Cost

You might be asking, how much does that cost you to collect every 5 minutes? Read below to find out.

I started collecting in May of last year.

Collect Ambient Weather Data

At five minute collection, I’ve collected 92k logs, which has equaled .017 of a GB.

Collect Ambient Weather Data

An efficient custom log, collecting only what you need, can be extremely cheap, even at a relatively high collection rate. Stay tuned as I’ll show you how to visualize all this data.

Stay tuned as I’ll be building a Azure Monitor workbook with the data collected in this post.