Microsoft Teams Status

sensor:
  - platform: rest
    name: Teams_status
    value_template: "{{value_json.availability}}"
    resource: https://graph.microsoft.com/beta/me/presence
    headers:
      Authorization: !secret teams_token

get a token etc from: https://developer.microsoft.com/en-us/graph/graph-explorer

3 Likes

While this works for some time, the Graph API Explorer access token expires quite quickly. The status didn’t get updated anymore, so I tried to get the status via PowerShell:

My organization didn’t grant consent in Azure AD to read my Teams availability and activity, so I was hoping I could do something from an interactive user context to get and refresh the access token. Any ideas?

Yeah I ran into the same problem.

The current rest sensor implementation doesnt support refreshtokens, so you’d have to create an azure app with the correct rights, get a proper AD role and go through all your organizational hoops (currently)

Something I havent tried.

We were discussing this here:

probably best to follow up in that topic.

I might take a look into implementing refresh tokens for the rest sensor, but honestly I’m not sure when I can make time

1 Like

Thanks! I’ll follow that topic then :blush:

My organization will probably not allow me to create an app registration, because “you need a valid business justification, bla, bla,bla “, so it would be nice if I could leverage the permissions granted for the Graph API Explorer, which is allowed.

I discovered a really cool app by Isaac Levin called PresenceLight. It is in the Windows app store and it allows you to configure custom API URIs based on the different Teams presence status’. I had to download the latest nightly build in order to login successfully though. Using this app along with Node-Red, I was able to configure this to update a light bulb with the different status colors. It works great.

4 Likes

Thanks for pointing this out, been looking for a way to do this. I used webhooks in automations as I don’t have node red.

1 Like

Ok, this may not be the most decent solution, but I managed to update my Microsoft Teams status in Home Assistant via a PowerShell script that is running as a service on my machine. I needed to fix it this way, since my organization didn’t grant me consent on the Graph API. I’m posting this for people who are in the same boat as myself :slight_smile:

First, I created a binary sensor in Home Assistant’s configuration.yaml (please note the value isn’t updated correctly yet after a restart of HA - I’m working on this):

sensor:
  - platform: template
    sensors:
      teams_status:
        friendly_name: "Microsoft Teams"
        value_template: >-
          {% if selectattr('state', 'unavailable') -%}
            Offline
          {%- endif %}
        icon_template: >-
          {% if is_state('sensor.teams_status', 'state', 'unavailable') -%}
            mdi:microsoft-teams
          {%- endif %}
        unique_id: sensor.teams_status

Second, I created the script below. The script reads the last 20 rows in the logfile from the Microsoft Teams client every 2 seconds, where it will look for certain phrases and takes action if the status changes.

$headers = @{"Authorization"="<Insert token>";}
$Enable = 1
$CurrentState = "Offline"
DO {
$TeamsLog = Get-Content -Path "C:\Users\<UserName>\AppData\Roaming\Microsoft\Teams\logs.txt" -Tail 20 | Select-String -Pattern 'Setting the taskbar overlay icon - Available','Setting the taskbar overlay icon - Busy','Setting the taskbar overlay icon - Away','Setting the taskbar overlay icon - Do not disturb','Main window is closing','main window closed','Setting the taskbar overlay icon - On the phone','Setting the taskbar overlay icon - In a meeting','StatusIndicatorStateService: Added Busy','StatusIndicatorStateService: Added Available','StatusIndicatorStateService: Added InAMeeting','StatusIndicatorStateService: Added DoNotDisturb'

If ($TeamsLog -like "*Available*") {
    $TeamsStatus = "Available"

}
ElseIf ($TeamsLog -like "*Busy*") {
    $TeamsStatus = "Busy"

}
ElseIf ($TeamsLog -like "*Away*") {
    $TeamsStatus = "Away"

}
ElseIf ($TeamsLog -like "*Do not disturb*" -or $TeamsLog -like "*DoNotDisturb*") {
    $TeamsStatus = "Do not disturb"

}
ElseIf ($TeamsLog -like "*In a meeting*" -or $TeamsLog -like "*InAMeeting*") {
    $TeamsStatus = "In a meeting"

}
ElseIf ($TeamsLog -like "*On the phone*") {
    $TeamsStatus = "In a call"

}
ElseIf ($TeamsLog -like "*ain window*") {
    $TeamsStatus = "Offline"

}

If ($CurrentState -ne $TeamsStatus) {
    $CurrentState = $TeamsStatus
    Write-Host $CurrentState

    $params = @{
     "state"="$CurrentState";
     "attributes"= @{
        "friendly_name"="Microsoft Teams";
        "icon"="mdi:microsoft-teams";
        }
     }

    Invoke-RestMethod -Uri 'https://<ha url>/api/states/binary_sensor.teams_status' -Method POST -Headers $headers -Body ($params|ConvertTo-Json) -ContentType "application/json" 

}
    Sleep 2
} Until ($Enable -eq 0)

Please note you’ll need an access token generation in HA. I’ve saved the script to C:\Scripts as Get-TeamsStatus.ps1.

Step 3 is to download the Non-Sucking Service Manager (NSSM) via http://nssm.cc/ and after extracting the download ZIP, I’ve saved the nssm.exe for my OS architecture to C:\Scripts as well.

Start a elevated PowerShell prompt, browse to C:\Scripts and run the following command:

Start-Process -FilePath .\nssm.exe -ArgumentList 'install "Microsoft Teams Status Monitor" "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-command "& { . C:\Scripts\Get-TeamsStatus.ps1 }"" ' -NoNewWindow -Wait

Have a look in Services.msc and make sure the service is started. You may need to change the PowerShell Execution Policy to allow the script to run.

I’m using this solution for a couple of days now, and even since the script doesn’t do any error handling, my status is updated every time. The only ‘bug’ that I noticed is that when you change your status a lot (because of testing around for example), the last 20 lines of the logfile can contain multiple lines of status changes and the status is updated incorrect.

image
I’m using this solution in combination with a script that detects if I’m connected to the monitor in our home office, so Home Assistant can determine which Squeezebox needs to be muted when I join a call and if the electrical heater needs to be turned off:

9 Likes

This is quite amazing! I want to check this soon myself to let the family know whether I’m in a call or not. :grin:

Thanks a lot for sharing this.

Your welcome :slight_smile: I just updated the PowerShell code with some improvements, because I noticed the status wasn’t updated correctly when the overlay of the icon had a ‘NewActivity’ badge number.

@EBOOZ

What version of nssm are you using? The script executes great for me, but when I start the service I get this error: And my execution policy is unrestricted.

image

Executable details below:
image

You can check if you need to unblock the file by running

Unblock-File C:\Scripts\Get-TeamsStatus.ps1
1 Like

Wow, thanks. I had a typo in the filename… :man_facepalming:

This is good work and a cool script.

1 Like

Thanks!

For some reason I can’t get the sensor default to Offline after a restart of HA, so if anybody has some ideas on that topic… Otherwise I’ll just leave it like this. I don’t need to restart that often :slight_smile:

Nailed it :sunglasses:

[{"id":"756030c6.c02df","type":"server-events","z":"fd16fb23.980d08","name":"Home Assistant connection status","server":"b581a42a.f06ca8","event_type":"home_assistant_client","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"x":200,"y":4520,"wires":[["4f75c11e.71ca7"]]},{"id":"4f75c11e.71ca7","type":"switch","z":"fd16fb23.980d08","name":"HA started","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"connected","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":410,"y":4520,"wires":[["b6cc02a2.bfbc5","afd5a5c7.472b28"]]},{"id":"afd5a5c7.472b28","type":"ha-api","z":"fd16fb23.980d08","name":"Set Microsoft Teams status","server":"b581a42a.f06ca8","debugenabled":false,"protocol":"http","method":"post","path":"states/sensor.teams_status","data":"{\"state\":\"Offline\",\"attributes\":{\"friendly_name\":\"Microsoft Teams\",\"icon\":\"mdi:microsoft-teams\"}}","dataType":"json","location":"payload","locationType":"msg","responseType":"json","x":620,"y":4540,"wires":[[]]},{"id":"b581a42a.f06ca8","type":"server","name":"Home Assistant","addon":true}]

I also would love to use my Microsoft Teams status in HA. I looked at @EBOOZ solution and it looks promising. Only thing… I am on a Mac… Looked in the log files and check what happened if I change my status… It triggers an event logline but nothing I can get the status from… @EBOOZ. Do you have any idea how this should work on a Mac?

1 Like

This is how I am handling a binary call/not call sensor in node red.

[{"id":"72999742.1e366","type":"server-state-changed","z":"c4d6bab.33e1a48","name":"Teams Status","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"sensor.teams_status","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"x":290,"y":2280,"wires":[["3af2b85d.be56f"]]},{"id":"3af2b85d.be56f","type":"switch","z":"c4d6bab.33e1a48","name":"Last one is avail","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"In a call","vt":"str"},{"t":"eq","v":"In a meeting","vt":"str"},{"t":"eq","v":"Do not disturb","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":4,"x":500,"y":2280,"wires":[["513d746.8a68f0c"],["513d746.8a68f0c"],["513d746.8a68f0c"],["997590da.1841b8"]]},{"id":"513d746.8a68f0c","type":"change","z":"c4d6bab.33e1a48","name":"icon phone","rules":[{"t":"set","p":"data.attributes.icon","pt":"msg","to":"mdi:phone","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"on","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":730,"y":2260,"wires":[["bb241344.fbae88"]]},{"id":"bb241344.fbae88","type":"ha-entity","z":"c4d6bab.33e1a48","name":"On A Call","server":"a7f65844.c2f878","version":1,"debugenabled":false,"outputs":1,"entityType":"binary_sensor","config":[{"property":"name","value":"On A Call"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"icon","value":"data.attributes.icon","valueType":"msg"}],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":960,"y":2280,"wires":[[]]},{"id":"997590da.1841b8","type":"change","z":"c4d6bab.33e1a48","name":"icon phone-hangup","rules":[{"t":"set","p":"data.attributes.icon","pt":"msg","to":"mdi:phone-hangup","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"off","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":2300,"wires":[["bb241344.fbae88"]]}]

This is what i´m looking for :slight_smile:

But unfortunately I get this error in powershell:

Invoke-RestMethod : 401: Unauthorized
In Zeile:48 Zeichen:5
+     Invoke-RestMethod -Uri 'http://homeassistant:8123/api/states/bina ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

I created a long term access token and added it:
$headers = @{"Authorization"="eyJ0............";}

Am I missing something?

Ok, I found the issue…
the correct format is:

$headers = @{"Authorization"="Bearer eyJ0............";}

Thanks for your script! Makes Homeoffice much more comfortable.

1 Like

I’ve updated the script to use two different sensors (status and activity), because I noticed an issue when still in a call, while the status of Teams changed to ‘In a meeting’ for example. This turned on my music again, which I obviously want to happen when I’ve left the call.

Previously the script was reading the logfile every two seconds. I’ve set it now to every second.

The updated script is available on GitHub: EBOOZ/TeamsStatus (github.com)

1 Like

Works fine at a first test.
I suggest to variables for username, URL and the token.
This way you only have to change the values on top of the script. More comfortable to use :wink: