Building an automated Microsoft Teams status light – Part 2

Teams status light

In “Building an automated Microsoft Teams status light – Part 1”, I outlined the very basic method of how I wired up a NeoPixel LED to an ESP8266 and connected it to HomeAssistant. Any RGB smart bulb connected to HomeAssistant will achieve the same goal, I just wanted something that can sit on the bookshelf that sits outside my makeshift office.

In this part, I will be showing how to connect to your online teams presence to retrieve your current status.

Set up your Azure Active Directory

The first step is to create an AAD application and grant the appropriate rights. In order to achieve this, you will need the “Application Developer” role if “Users can register applications” has been set to “No” in your AAD. I set up my initial registration as follows:

Register an application

Once registered, I then needed to set up the permissions for the application to query presence information. The application requires the following permissions:

  • Presence.Read
  • User.Read

As I was also toying with some calendar information, I added calendar.read rights as well. The last step was to create a secret for the application:

Now that this is all complete, record the following information:

  • Tenant ID
  • Client ID
  • Client secret

These are all required for PowerShell to collect your presence information.

Query AAD for presence information with PowerShell

For this piece of code, I will be using the PSMSGraph module to get the presence information.

# Import PSMSGraph
Import-Module PSMSGraph

Using the information recorded earlier, create the following variables:

# Tenant and Client IDs
$tenantID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$clientID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# Create Secret
$clientSecret = (ConvertTo-SecureString "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -AsPlainText -Force)

With all of the required ID’s and secrets set, I now call the Graph application and get the access tokens. This will prompt for you to log in with your O365 credentials.

# Call the Graph App
$GraphApp = New-GraphApplication -Name "presence-app" -Tenant $tenantID -ClientCredential $creds -RedirectUri "http://localhost/" 

# This will prompt you to log in with your O365/Azure credentials and authorise access
$AuthCode = $GraphApp | Get-GraphOauthAuthorizationCode
$GraphAccessToken = $AuthCode | Get-GraphOauthAccessToken -Resource 'https://graph.microsoft.com'

Now that I have an access token, I am able to make a REST call to get the presence information:

$presence = Invoke-RestMethod -Headers @{Authorization = "Bearer $($graphaccesstoken.GetAccessToken())" } -Uri 'https://graph.microsoft.com/beta/me/presence' -method Get

We can now see the presence information returned:

PS C:\> $presence


@odata.context      : https://graph.microsoft.com/beta/$metadata#users('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')/presence/$entity
id                  : xxxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxxxxxx
availability        : Available
activity            : Available
outOfOfficeSettings : @{message=; isOutOfOffice=False}

We can see two properties on the object:

  • availability
  • activity

The following information is what I’m using. Availability is the primary control I’m using for the light. Activity is allowing me to link an additional light that activates the webcam ring light when I join a video call:

AvailabilityAvailable
Busy
Away
DoNotDisturb
ActivityAvailable
InACall
InAConferenceCall

Now that I have the presence information, I can loop with a delay to get this information, however the access token will eventually expire. If we look at the access token properties we can see the following:

PS C:\> $graphaccesstoken


GUID            : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
RequestedDate   : 8/03/2022 8:04:25 PM
LastRequestDate : 8/03/2022 8:04:25 PM
IsExpired       : False
Expires         : 8/03/2022 9:18:17 PM
ExpiresUTC      : 8/03/2022 10:18:17 AM
NotBefore       : 8/03/2022 7:59:27 PM
NotBeforeUTC    : 8/03/2022 8:59:27 AM
Scope           : {Calendars.Read, Presence.Read, User.Read}
Resource        : https://graph.microsoft.com
IsRefreshable   : True
Application     : Guid: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Name: presence-app

From the properties, we can see “IsExpired” and “IsRefreshable”. When the token expires, we can update the token without the need for re-authentication:

    if ($GraphAccessToken.IsExpired)
    {
        $GraphAccessToken | Update-GraphOAuthAccessToken -Verbose    
    }

Putting this all together, my code looks like:

# Import PSMSGraph
Import-Module PSMSGraph

# Tenant and Client IDs
$tenantID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$clientID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# Create Secret
$clientSecret = (ConvertTo-SecureString "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -AsPlainText -Force)

# Create credentials
$creds = [pscredential]::new($clientID, $clientSecret)

# Call the Graph App
$GraphApp = New-GraphApplication -Name "presence-app" -Tenant $tenantID -ClientCredential $creds -RedirectUri "http://localhost/" 

# This will prompt you to log in with your O365/Azure credentials and authorise access
$AuthCode = $GraphApp | Get-GraphOauthAuthorizationCode
$GraphAccessToken = $AuthCode | Get-GraphOauthAccessToken -Resource 'https://graph.microsoft.com'


while ($true)
{
    $presence = Invoke-RestMethod -Headers @{Authorization = "Bearer $($graphaccesstoken.GetAccessToken())" } -Uri 'https://graph.microsoft.com/beta/me/presence' -method Get
    write-host "Availability -" $presence.availability
    Write-Host "Activity -" $presence.activity
    Write-Host "`n"

    Start-Sleep -Seconds 2
    if ($GraphAccessToken.IsExpired)
    {
        $GraphAccessToken | Update-GraphOAuthAccessToken -Verbose    
    }
}

In the next post, I will outline how to update the teams status light in HomeAssistant.

One thought on “Building an automated Microsoft Teams status light – Part 2”

Comments are closed.