neon.ninja

Sharing enlightening moments of home automation

Working from Home – Teams Availability

In this post I am going to explain how I make my status in Microsoft Teams running on my work laptop available in Home Assistant.

I have been working from home for more than six months now and have my work area in a fairly good and functional shape now – large desk, comfy chair, second monitor, good lighting, etc. However, there is one thing that has been a little bit out of my control: My desk is in a large open space in our house and it is close to the kitchen. And every now and then I find myself in the middle of a conference call while the family is turning on the kettle or cleaning the dishes in the background. If only there was a way to make it more obvious that I am in the middle of a call…

We are heavily using Microsoft Teams in our organisation, so my solution focuses on the presence concept of Teams. And if you have been reading my blog for some time now, you would be aware that I am a long time user of Home Assistant, so of course I want to represent my presence in there. This will give me all the flexibility to not only remote control a status light, but maybe other things, too, like for example turn off the radio when a meeting starts.

One thing that really caught my eye and kicked off this whole investigation was a recent post on the Home Assistant subreddit.

So now that we now what the vision for this integration is, let’s see how we can get there.

Access presence status from Teams

The first thing I tried was Microsoft’s Graph API. To play around with the various API calls you can try the Graph Explorer. The key API call for this integration is probably https://graph.microsoft.com/beta/me/presence which returns the availability and activity status.

The biggest challenge here is security. Of course security is important, especially with personal information such as whether you are working or not. However, multi-factor authentication and tokens make it hard to use this API on the server-side.

Luckily someone in the HA community forum pointed me to an app called PresenceLight. This app takes care of the authentication and authorisation process with the Graph API and actually provides a bit of a shortcut if you are not using Home Assistant – it can directly control Philips Hue, Yeelight or LIFX lights and change the colour based on your status. However it also contains a custom API option where you can define a URL to POST to – the perfect integration point for Home Assistant’s webhooks.

Installing PresenceLight

I installed PresenceLight from the Microsoft Store on my Windows 10 work laptop (Update: If you are not using a Windows machine, you can now also run PresenceLight as a Docker container). Administrator permissions for the installation were not required in my case – your experience may be different depending on the security constraints implemented by your organisation.

PresenceLight Microsoft Store

Authorisation Process

As part of the initial startup of the app you are being guided through the authorisation process that will allow PresenceLight to access your Teams status. The experience may be slightly different depending on whether or not your organisation has Multi-factor authentication (MFA) enabled, and whether or not you are already logged on to Office 365. After the successful authentication, the app shows the current Teams status on the first tab.

PresenceLight First Start
PresenceLight Sign-in – Pick an Account
PresenceLight Sign-in – Permissions requested

Note: If instead at this step you get a message “Need admin approval”, then you will need to ask your friendly IT department to help you with the installation and authorisation.

Autostart PresenceLight

Because Teams has become such an essential part of my workday it is automatically starting up when I start Windows. Hence it makes sense to also start PresenceLight automatically.

In Windows 10 you can for example do that by opening Windows Explorer and go to %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup. Now you can drag and drop the PresenceLight icon from the start menu into that folder and Windows automatically creates a link.

Windows 10 Create Startup Link

Shortcut if you are not using Home Assistant

If you are not using Home Assistant and either have a Philips Hue, Yeelight or LIFX lamp in your local network then have a look at the other tabs in the app. You can connect a lamp and change the colour depending on your status in Teams. I haven’t actually tried these options myself, because all my smart lights are integrated into Home Assistant and my work laptop is in a separate VLAN that has little access to the rest of my network.

If however you want to use the full power of Home Assistant then please continue reading.

Home Assistant Configuration

There are a couple of things to know and prepare for this integration. I decided to create 2 input selects – one for availability and one for activity. Each input select simply stores the actual value provided by the PresenceLight app. I decided to store a more human-readable form of the status instead of the original values used in the Graph API without spaces.

Next we need two automations that each use a webhook trigger. The webhook ID does not need to be defined separately and is just extracted from the URL that we will configure in PresenceLight. The action in each automation extracts a query parameter status and sets the value on the corresponding input select entity.

Instead of YAML configuration, this time I am only using a UI based configuration hence the screenshots below. To create an input select entity, go to Configuration -> Helpers -> Add Helper -> Dropdown.

Availability Input Select

Input Select – Availability

Availability Webhook Automation

Webhook Automation – Availability

Activity Input Select

Input Select – Activity

Activity Webhook Automation

Webhook Automation – Activity

Network Access Considerations

Let’s quickly talk about the network setup and access to Home Assistant:

  • If Home Assistant and your computer running Teams are in the same local network then the setup should be fairly easy.
  • However, if you are frequently using a VPN to dial into the corporate network, all traffic is routed through the VPN and local access to Home Assistant is not available anymore.
  • If your Home Assistant instance is already accessible from outside your local network then make sure you can access its URL from inside your local network as well as through the corporate VPN.
  • An alternative is to use Nabu Casa’s webhook capability. After creating the automations above, go to Configuration -> Home Assistant Cloud and scroll down to the Webhooks section as shown below, find the new webhooks, activate them and use the URL displayed as your base URL in the PresenceLight configuration.
Webhooks via Nabu Casa

PresenceLight Configuration

On the Configure Custom API tab in PresenceLight you have to tick the checkbox at the top and then fill in all the details.

  • The API Method must be set to POST because that is the only method that the Home Assistant webhooks support.
  • The base URL of course depends on how you have set up your Home Assistant and how it is accessible from the computer running PresenceLight.
  • The path is /api/webhook/[webhook ID] where the webhook ID must correspond with the one configured in the automation triggers above.
  • If you decided to use Nabu Casa’s webhook integration the whole public URL including path is provided on the Home Assistant Cloud page. If you have already activated the webhook you can click on “Manage” to copy the public URL.
  • Finally I added a URL parameter status that carries the value, and which of course must correspond with the input select options.
    The format for the first URL parameter is ?status=[value] appended to the URL without a space. This works with both the direct approach where your Home Assistant instance is publicly accessible as well as with the Nabu Casa webhook integration.
PresenceLight – Configure Custom API

Originally I thought about using just a single webhook ID, but that approach revealed a couple of challenges. While only a single automation would have been required, I had to use different URL parameters to distinguish availability and activity and thus the action would have become a bit more complicated to distinguish the two. Also, PresenceLight typically sends the two API calls very quickly in a row, so the automation mode would need to change to Queued or Parallel to correctly process both of them.

Now each time the presence status changes in Teams – whether manually or automatically – PresenceLight should call the corresponding webhook and update the status in Home Assistant. In my tests this typically happens in less than 5 seconds.

Home Assistant Panel

The following glance panel shows the current state of the two input select entities.

Presence Status Panel

And now that the status information is available in Home Assistant you can start creating automations based on state changes.

Outlook

In the next part of this series I am going to show a simple configuration of a light based on the Teams status. And in the meantime I am going to think about how my final status light is going to look like and what components I will need for that.

Another area of research could be finding out the status of the microphone – muted or unmuted. This information is something that Teams itself via the Graph API does not expose, so I will need to look for something else.

Compatibility

At the time of writing this post, I used:

  • Home Assistant 0.115.6 with Python 3.7.5 (please note that there appears to be an issue in 0.116.0 with the Nabu Casa webhook integration)
  • Microsoft Teams 1.3.00.13565 on Windows 10
  • PresenceLight 3.0.43.0

Update 17/03/2021

My PresenceLight was just updated to version 4.0.1.0 then 4.0.26.0, and I noticed that all the webhooks were gone from its configuration. Adding the webhooks back in did not work and they were not saved into the configuration file. This issue was reported and can be solved by manually deleting the configuration file and letting the application recreate it at startup.

Just in case you are wondering how I found the configuration file: In the PresenceLight application I went to tab Logs -> Log Files -> Click on a log file name and Windows Explorer opens up -> Go 3 folders up and find file settings.json.

Also, over the last couple of weeks I noticed that PresenceLights occasionally appears to stop reporting back to Home Assistant. I tracked this down to me frequently going on and off the corporate VPN. The only solution I have found was to sign out and sign back in on the PresenceLight application. This issue may be related to the split tunnel setup of the VPN, but that is currently out of my control.

Update 07/03/2023

In the meantime I moved from Windows 10 to macOS and can no longer run PresenceLight on my work laptop. The good news is that in the meantime the application is also available as a Docker container. I recently migrated my PresenceLight installation to Docker and explain the prerequisites and steps in a new post.

Working from home series

  1. Working from Home – Teams Availability
  2. Working from Home – Migrate to Docker
  3. Working from Home – Native macOS app

Comments

12 responses to “Working from Home – Teams Availability”

  1. Adam Avatar
    Adam

    I have been trying to do something similar, but ran into the blocker than my organisation requires admin approval for accessing the Graph API, and blocks almost all apps in the Microsoft Store – therefore I have been unable to install PresenceLight and even if I could, would not easily be able to get approval to use the Graph API. I expect this will be a common limitation for many organisations, particularly large ones, who have tightly controlled security. I haven’t bothered to ask permission – as I know that it will be too hard. (I really wish Teams would also expose something locally to the machine that an app could read, as Skype for Business does).

    While it’s far from ideal, the solution I have put in place is to use AutoHotKey to look for the Teams icon in my system tray and depending on the icon, send a webhook to Home Assistant. This has some significant limitations, including needing to be visible on my screen to work, and I can only distinguish between Available/Busy/DND/Away as those are the only icon distinctions.

    For those in a similar situation as me, I have put my AHK solution up on GitHub here: https://github.com/ajobbins/AHK-Teams-Presence

    To your point about mic in use, I’ve also looked into this and there is no great solution. I’d also like to know if my camera is on. I am working on an update to my AHK script above to look at the screen to see the status of both the mic and video icons in the Teams UI and update accordingly. I’ve got a partially working solution already, but needs some cleanup before I publish to GitHub.

    1. malte Avatar
      malte

      Thanks very much for the details, Adam.
      I was actually positively surprised that my organisation did allow me to install the app and access the Graph API, but you are right, there will be many organisations who won’t. The approach you are taking is quite smart, just looking at icons or other information available on the screen. I have seen some people who looked at using DLLs to locally access the Teams status but that all required custom code.

  2. Bo Avatar
    Bo

    Great post, this will really help keeping my home office ‘zen’ while working.
    But during testing I noticed an error when updating my status, logging says the following when updating:
    Invalid option: {{ trigger.query[“status”] }} (possible options: Available, Busy…

    Do you have an idea?
    This is the service data I have configured:
    option: ‘{{ trigger.query[“status”] }}’
    entity_id: entity_id: input_select.home_office_presence_bo_activity

    1. malte Avatar
      malte

      Thanks for your feedback, Bo.

      First of all, your configuration appears to contain entity_id twice. Is that a copy&paste issue into the comment? If not, that line should only read entity_id: input_select.home_office_presence_bo_activity.

      That error message you are getting indicates that the expression '{{ trigger.query["status"] }}' is not recognised as a template, but instead the automation literally tries to set that string as option. If I had to make a guess I would say that the single-quote or double-quotes may not be quite right. I just copied and pasted the configuration snippet from your comment into a text editor and that shows different single-quote/double-quote characters.

      Not sure if it’s going to work, but try to copy&paste this into the service data field:
      option: '{{ trigger.query["status"] }}' entity_id: input_select.home_office_presence_bo_activity

  3. Wayne Avatar
    Wayne

    Maybe I’m missing something, but how does one create an input select in the GUI? This will be the first time I’m creating one.

  4. WAYNE SEPEGA Avatar
    WAYNE SEPEGA

    Config –> Helpers –> Add –> Dropdown

    As always next search after asking returned the info.

    1. malte Avatar
      malte

      Good point, Wayne. I added this hint to the above.

  5. WAYNE SEPEGA Avatar
    WAYNE SEPEGA

    Thank you for great instructions, now for the next step figuring out if I get a lamp with a color change bulb, or an LED strip for the door frame.

    1. malte Avatar
      malte

      No worries. Let us know which way you go. My own lights are still work in progress.

  6. Brett Avatar
    Brett

    This worked great for me! However, I did encounter an issue with the query parameter value including spaces, like “Be Right Back”. It seems that including spaces in the status value causes the webhook to fail in my case. I used apitester.com and these are my results.

    I tested:
    https://hass.org/api/webhook/ms_teams_availability?status=Be Right Back

    Response Headers:
    HTTP/1.0 400 Bad Request
    Content-Type: text/plain; charset=utf-8
    Content-Length: 23
    Date: Wed, 17 Feb 2021 18:08:21 GMT
    Server: Python/3.8 aiohttp/3.7.3

    Response Body:
    invalid constant string

    Then I removed the spaces from the status value:
    https://hass.org/api/webhook/ms_teams_availability?status=BeRightBack

    Response Headers:
    HTTP/1.1 200 OK
    Content-Length: 0
    Content-Type: application/octet-stream
    Date: Wed, 17 Feb 2021 18:11:41 GMT
    Server: Python/3.8 aiohttp/3.7.3

    Response Body:
    *blank*

    1. malte Avatar
      malte

      Thanks for the feedback, Brett.
      I just tested my webhooks with apitester.com and get the same result when the status value contains whitespace. However, from within PresenceLight, the same URL with the same status value works just fine.
      I’d say that when using apitester.com something goes wrong with encoding the URL parameters. When you manually encoded the spaces with %20 then it works just fine, i.e. “…?status=Be%20Right%20Back”.
      For testing purposes I usually use Chrome plug-in “Tabbed Postman – REST Client”.

  7. Caio Avatar
    Caio

    Very nice! Thank you for sharing such a detailed explanation!

    I will try to implement in my HA.

    Cheers

    Caio

Leave a Reply

Your email address will not be published. Required fields are marked *