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¶
-
Find the name of your device. Open PowerShell and list all Bluetooth devices:
Look in the
FriendlyNamecolumn. In my case the mouse is called MX Anywhere 2. -
List all properties of that device to find the battery value:
Look for the property whose
Datais a number between 0 and 100. ItsKeyNameis what you need. For me it was:Mind the space
The space before the
2is part of the key name. -
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 DataKeep this command at hand; you'll use it in the script.
2. Prepare Home Assistant¶
-
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. -
Create a Number helper to hold the value. Go to Settings → Devices & services → Helpers → Create helper → Number and use:
Setting Value Name Mouse batteryMinimum / Maximum 0/100Display 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:
$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¶
-
Open Task Scheduler and choose Create Task (not Create Basic Task).
-
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.
-
On the Triggers tab, add a trigger that starts at logon (or at a fixed time) and repeats every 10 minutes indefinitely.
-
On the Actions tab, add Start a program:
Field Value Program/script powershell.exeArguments -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.