Skip to content

Send Bluetooth battery levels to Home Assistant

Every time my keyboard or mouse needed charging, I found out too late, in the middle of work. So I wanted a notification on my phone when the battery drops below, say, 10%. Windows already knows the battery level of most Bluetooth devices; this guide reads that value with PowerShell and pushes it to Home Assistant every 10 minutes.

What you need: a Windows PC with the Bluetooth device paired, and a Home Assistant instance reachable from that PC.

1. Read the battery level with PowerShell

  1. Find the name of your device. Open PowerShell and list all Bluetooth devices:

    Get-PnpDevice -Class 'Bluetooth'
    

    Look in the FriendlyName column. In my case the mouse is called MX Anywhere 2.

  2. List all properties of that device to find the battery value:

    Get-PnpDevice -Class 'Bluetooth' -FriendlyName 'MX Anywhere 2' | Get-PnpDeviceProperty
    

    Look for the property whose Data is a number between 0 and 100. Its KeyName is what you need. For me it was:

    {104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2
    

    Mind the space

    The space before the 2 is part of the key name.

  3. Test the full command. It should print just the battery percentage:

    Get-PnpDevice -Class 'Bluetooth' -FriendlyName 'MX Anywhere 2' |
      Get-PnpDeviceProperty -KeyName '{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2' |
      Select-Object -ExpandProperty Data
    

    Keep this command at hand; you'll use it in the script.

2. Prepare Home Assistant

  1. Create a long-lived access token. In Home Assistant, click your name at the bottom left, open the Security tab and scroll down to Long-lived access tokens. Create a token, give it a name (for example PowerShell) and copy the code. You only get to see it once.

  2. Create a Number helper to hold the value. Go to Settings → Devices & services → Helpers → Create helper → Number and use:

    Setting Value
    Name Mouse battery
    Minimum / Maximum 0 / 100
    Display mode Input field
    Unit of measurement %

    Home Assistant gives it an entity ID like input_number.mouse_battery.

3. Write the script

Save the following as bluetooth-battery.ps1, for example in C:\Scripts\, and fill in your own values:

C:\Scripts\bluetooth-battery.ps1
$deviceName = '<friendly name from step 1>'
$batteryKey = '<key name from step 1>'
$haUrl      = '<your Home Assistant URL, e.g. http://homeassistant.local:8123>'
$entityId   = 'input_number.mouse_battery'
$token      = '<your long-lived access token>'

$battery = Get-PnpDevice -Class 'Bluetooth' -FriendlyName $deviceName |
  Get-PnpDeviceProperty -KeyName $batteryKey |
  Select-Object -ExpandProperty Data

$body = @{
  state      = "$battery"
  attributes = @{ unit_of_measurement = '%'; mode = 'box' }
} | ConvertTo-Json

Invoke-RestMethod -Method Post -Uri "$haUrl/api/states/$entityId" -Headers @{
  Authorization  = "Bearer $token"
  'Content-Type' = 'application/json'
} -Body $body | Out-Null

Note

The Authorization header must start with the literal word Bearer, followed by a space and your token. It does not depend on what you named the token.

Run the script once by hand and check that the helper in Home Assistant shows the right percentage.

4. Run it automatically

  1. Open Task Scheduler and choose Create Task (not Create Basic Task).

  2. On the General tab, give it a name and select Run whether user is logged on or not. That way you won't see a PowerShell window pop up.

  3. On the Triggers tab, add a trigger that starts at logon (or at a fixed time) and repeats every 10 minutes indefinitely.

  4. On the Actions tab, add Start a program:

    Field Value
    Program/script powershell.exe
    Arguments -ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Scripts\bluetooth-battery.ps1"

Done

The battery level of your device now lands in Home Assistant every 10 minutes. From here you can build an automation on input_number.mouse_battery, for example a notification to your phone when it drops below 10%:

triggers:
  - trigger: numeric_state
    entity_id: input_number.mouse_battery
    below: 10
actions:
  - action: notify.mobile_app_<your_phone>
    data:
      message: "Mouse battery is at {{ states('input_number.mouse_battery') | int }}%. Time to charge!"

Track a keyboard too

Duplicate the helper and add a second block to the script with the keyboard's name and key.