Does This Error Trapping Do What I Want?

Welcome Forums General PowerShell Q&A Does This Error Trapping Do What I Want?

This topic contains 5 replies, has 4 voices, and was last updated by

 
Participant
2 months ago.

  • Author
    Posts
  • #151533

    Participant
    Topics: 1
    Replies: 2
    Points: 16
    Rank: Member

    I am forcing a bunch of Blink cams to take snapshots every 10 minutes.

    That part has been working a-ok 98% of the time.

    98% because, with Blink, the snapshot requests cannot be made back-to-back.

    Instead they need to be spaced about 30 seconds apart or Blink will throw a "System Busy.... " error.

    Mostly 30 seconds works, but every so often it bites The Big One.

    So I tried to add error trapping to the script – hoping to trap the error (which the trap sees as a 409) and then wait 30 seconds and re-issue the request for the same cam.

    It actually seems like it might be working, but I do not know enough about the PS environment  or Blink to be 100% sure.

    What I am hoping for is Somebody Who Knows to take a look at the code and tell me if it, at least, looks like it should wait N seconds and then re-try the same cam

    Here's the code; scroll down to function TakeSnapshotFromOneCamera to see the attempted error trapping.

    # PURPOSE: To force a snapshot from each camera in the system every 10 minutes
    #
    #   NOTES: Code copied from Ryan's(@naryk) much larger, much more comprehensive script.
    #
    # CHANGES: 2019 04-09: - Modified the Win 7 box thusly:
    #                        * Downloaded/installed Windows Management Framework 5.1
    #                        * Downloaded/installed .NET Framework 4.7.2 DevPack FROM https://dotnet.microsoft.com/download
    #                      - Carved away almost all of Andrew's code leaving just snapshots
    #          2019 04-12: - Fixed incorrect references to email and password
    #          2019 04-12  - Added error trapping to TakeSnapshotFromOneCamera for "System is busy... code :307", although
    #                        the trapping seems to see "409) Conflict" instead. 
    #          2019 04-14  - Modified error trapping
    
    # ----------------------------------
    # Blink Credentials for your system:
    
    $blinkAccountEmail = "x@y.com"
    $blinkAccountPassword = "xxx"
    
    # ----------------------------------
    # Determine how many seconds we want to 
    # wait between individual snapshots.
    # If we try too soon, we get a "System Busy"
    # error - which comes back to error trapping
    # as a 409 error.
    
    $secondsBetweenSnapshots = 30
    
    # ----------------------------------
    # Determine how many times we want to re-try
    # telling a given cam to take a snspshot in 
    # event of above-mentioned 409 error.
    
    $numberOfSnapshotRetries = 3
    
    
    # ----------------------------------
    # Specify Blink's API Server, this is the URL you are 
    # directed to when you are prompted for IFTTT Integration 
    # to "Grant Access".
    # You can verify this yourself to make sure you are sending 
    # the data where you expect it to be
    
    $blinkAPIServer = 'prod.immedia-semi.com'
    
    # Use the server below if you are in Germany
    #$blinkAPIServer = 'prde.immedia-semi.com'
    
    
    # ----------------------------------
    # Concoct headers to send to Blink's 
    # server for authentication
    
    $authenticationHeaders = 
       @{
        "Host" = "$blinkAPIServer"
        "Content-Type" = "application/json"
        }
    
    
    # ----------------------------------
    # Concoct credential data
    
    $credentials = 
       @{
        "email" = $blinkAccountEmail
        "password" = $blinkAccountPassword
        } | ConvertTo-Json
    
    
    # ----------------------------------
    # Specify login URL of Blink API
    
    $BlinkLoginURL = "https://$blinkAPIServer/login"
    
    
    # ----------------------------------
    # Authenticate credentials with Blink 
    # Server and get our token for future requests
    
    $response = Invoke-RestMethod -UseBasicParsing $BlinkLoginURL -Method Post -Headers $authenticationHeaders -Body $credentials
    if(-not $response)
        {
        echo "Invalid Blink credentials provided. Please verify email and password in this script's code."
        exit
        }
    
    
    # ----------------------------------
    # Get the object data
    
    $region = $response.region.psobject.properties.name
    $authToken = $response.authtoken.authtoken
    
    
    # ----------------------------------
    # Concoct headers to send to Blink's
    # server after authentication with our token
    
    $workingHeaders = 
       @{
        "Host" = "$blinkAPIServer"
        "TOKEN_AUTH" = "$authToken"
        }
    
    
    # ----------------------------------------------------------------------------------------------------
    function TakeSnapshotFromOneCamera
    {
    # PURPOSE: To force one camera to take one snapshot
    #   NOTES: 1) Sometimes we do not allow enough time between snapshots
    #             and the system is busy.  To deal with that, we allow 
    #             up to N attempts to take the snapshot before reporting an error.
     param (
            [Parameter(Mandatory=$true)]
            [string]$NetworkId,
            [string]$CameraId,
            [string]$CameraName
            )
     $finished = $false
     $retryCount = 0
     
     While (-not $finished)
        {
        Try
           {
           $curURL = 'https://rest-'+ $region +".immedia-semi.com/network/$NetworkId/camera/$CameraId/thumbnail"
      
           $response = Invoke-RestMethod -UseBasicParsing $curURL -Method Post -Headers $workingHeaders -ErrorAction Stop
            
           # Get list of cameras
           $curURL = 'https://rest-'+ $region +".immedia-semi.com/network/$NetworkId/camera/$cameraId"    
           $response = Invoke-RestMethod -UseBasicParsing $curURL -Method Get -Headers $workingHeaders -ErrorAction Stop
           #$cameraThumbnail = $response.camera_status.thumbnail
           $finished = $true 
           }
       
        Catch
           {   
           if ($retryCount -ge $numberOfSnapshotRetries)
              {
              $curTimeStamp = Get-Date -DisplayHint DateTime
              $curLineNumber = $_.InvocationInfo.ScriptLineNumber
              $curFailedItem = $_.Exception.ItemName  
              $curExceptionMessage = $_.Exception.Message
              $curInnerExceptionMessage = $_.Exception.InnerException
              Write-Host $curTimeStamp "Line" $curLineNumber $cameraName 
              Write-Host "                  " $curFailedItem $curExceptionMessage
              #Write-Host "                   " $curInnerExceptionMessage
              throw
              }
           else
              {
              if ($retryCount -gt 0)
                 {
                 write-Host "$CameraName Retries=$retryCount"
                 }
              Start-Sleep -s $secondsBetweenSnapshots
              $retryCount++
              }
           }
        }
    }
    
    
    # ----------------------------------------------------------------------------------------------------
    function TakeSnapshotFromEachCamera
    {
     $curURL = 'https://rest-'+ $region +".immedia-semi.com/api/v1/camera/usage"
     $sync_units = Invoke-RestMethod -UseBasicParsing $curURL -Method Get -Headers $workingHeaders
    
     foreach($network in $sync_units.networks)
        {
         $cameras = $network.cameras
         $curNetwork_id = $network.network_id 
         $count = 1
    
         foreach($camera in $cameras)
           {                       
            $curCamera_id = $camera.id
            $curCameraName = $camera.name
            #echo "$curCameraName"
            $count += 1
            TakeSnapshotFromOneCamera -NetworkId $curNetwork_id -CameraId $curCamera_id -CameraName $curCameraName
                       
            # ------------------------------------------------------------
            # We need to wait at least a certain number of seconds between
            # snapshots to avoid "System is busy, please wait","code":307}
    
            Start-Sleep -s $secondsBetweenSnapshots
           }
        }
     }
    
    
    # ======================================================================
    # MAIN PROCEDURE: Force a snapshot from each camera every 10 minutes
    #
    # Sleep seconds were strictly trial-and-error to get to a 10 min
    # interval between snapshots for the cams - including the seconds
    # between snaps to avoid "System is Busy..." errors.
    
    
    do{   
       $totalCount +=1
       $curTimeStamp = Get-Date -DisplayHint DateTime
       #Write-Host " "
       Write-Host "Count=$totalCount $curTimeStamp"
       #Write-Host "-----------------------------"
       TakeSnapshotFromEachCamera 
       Start-Sleep -s 138
      } while (1)
    
    # ========================= End of Code =================================
  • #151568

    Participant
    Topics: 2
    Replies: 442
    Points: 918
    Helping Hand
    Rank: Major Contributor

    Yeah, this will work. I'd be inclined to adjust the methodology a bit there, though. I like the idea of having an attempts counter so that it doesn't retry indefinitely (maybe have the error handling in the catch{} block check that, and if there's 3 or more in that value you can handle differently, provide a notification that this camera might be down/broken somehow. If not, just increment the value).

    But in terms of skipping that on success, it's probably just simpler to break out of the loop explicitly. 🙂

  • #151574

    Participant
    Topics: 1
    Replies: 2
    Points: 16
    Rank: Member

    Yeah, this will work. I'd be inclined to adjust the methodology a bit there, though. I like the idea of having an attempts counter so that it doesn't retry indefinitely (maybe have the error handling in the catch{} block check that, and if there's 3 or more in that value you can handle differently, provide a notification that this camera might be down/broken somehow. If not, just increment the value).

    But in terms of skipping that on success, it's probably just simpler to break out of the loop explicitly. 🙂

    Thanks.

    I tweaked the code and re-pasted into the OP.

    Dropped the time between snaps to 20 seconds to force errors and am running a test now.

  • #151620

    Participant
    Topics: 8
    Replies: 371
    Points: 423
    Helping Hand
    Rank: Contributor
    # https://powershell.org/forums/topic/does-this-error-trapping-do-what-i-want/
    
    #region Input
        $blinkAccountEmail     = 'confirm@fatbelly.com'
        $blinkAccountPassword  = 'Suedog999'
        $blinkAPIServer        = 'prod.immedia-semi.com'
        $secondsBetweenSnaps   = 600 # PURPOSE: To take a snapshot from each camera in the system every 10 minutes
    #endregion
    
    
    #region Initialize, Authenticate
    $authenticationHeaders = @{
        Host           = $blinkAPIServer
        'Content-Type' = 'application/json'
    }
    $credentials = @{
        email    = $blinkAccountEmail
        password = $blinkAccountPassword
    } | ConvertTo-Json
    $BlinkLoginURL = "https://$blinkAPIServer/login"
    $response = Invoke-RestMethod -UseBasicParsing $BlinkLoginURL -Method Post -Headers $authenticationHeaders -Body $credentials
    if($response) {
        Write-Output "Successfully authenticated to $blinkAPIServer"
    } else {
        Write-Output "Invalid Blink credentials provided. Please verify email and password in this script's code."
        exit
    }
    $region    = $response.region.psobject.properties.name
    $authToken = $response.authtoken.authtoken
    $curURL    = "https://rest-$region.immedia-semi.com/api/v1/camera/usage"
    $workingHeaders = @{
        Host       = $blinkAPIServer
        TOKEN_AUTH = $authToken
    }
    $sync_units   = Invoke-RestMethod -UseBasicParsing $curURL -Method Get -Headers $workingHeaders
    #endregion
    
    
    do{ 
        $curTimeStamp = Get-Date -DisplayHint DateTime
     
        foreach($network in $sync_units.networks) {
            $null = Start-Job -ScriptBlock { # using jobs so that cams on one network don't have to wait for cams on the next network
                $network = $Using:network
                foreach($camera in $network.cameras) { 
                    $curURL = "https://rest-$Using:region.immedia-semi.com/network/$($network.network_id)/camera/$($camera.id)/thumbnail"
                    $Done   = $false
                    do {
                        Try {
                            $response = Invoke-RestMethod -UseBasicParsing $curURL -Method Post -Headers $Using:workingHeaders -ErrorAction Stop
                            "$(Get-Date) - Successfully took snapshot - camera: $($camera.name)"
                            $Done = $true
                        } Catch { 
                            "$(Get-Date) Camera $($camera.name) not ready - waiting 30 sec.."
                            Start-Sleep -Seconds 30
                            $Done = $false
                        } 
                    } while (-not $Done)
                } # foreach $camera
            } # job
        } # foreach $network
    
        while ((Get-Job).HasMoreData -ne $false) { Get-Job | Receive-Job }
    
        $secondsUsed = (New-TimeSpan -Start $curTimeStamp -End (Get-Date)).TotalSeconds
        $secondsToWait = $secondsBetweenSnaps - $secondsUsed
        "Done - waiting $secondsToWait seconds.."
        Start-Sleep -Seconds $secondsToWait
        ' '
        '###################################################################################'
    } while ($true)
    

    Output..

    You need to change that pwd..

  • #152102

    Participant
    Topics: 1
    Replies: 2
    Points: 16
    Rank: Member

    I amended the OP, but the paste into your post remains.

    How about deleting ir?

  • #152174

    Participant
    Topics: 23
    Replies: 143
    Points: 285
    Helping Hand
    Rank: Contributor

    You need to reset the pw, no matter if the post gets deleted.

    You should consider that password burned, and exposed to the entire world.

You must be logged in to reply to this topic.