I’m rubbishing at remembering to charge my Bluetooth headsets, and up until recently Android has been a pretty poor at letting you know the battery level. In Android 8.1 this improved somewhat, but you still have to open the list of Bluetooth devices to see the level
.Originally I thought this a job for Tasker on my phone but I then realised Home Assistant would be even better.
A post I made on Reddit gave me the hard bit (thanks /u/JustRollWithIt ) and after I received a message asking for details I thought this might be useful for some other Home Assistant fans…
So now to put the pieces together
- Have Tasker run a script on Battery Level changes when connected to my phone
- The last step of this task is to run some PHP on my webspace to save a JSON file with all the information
- In Home Assistant I then add a REST sensor for each Headset polling the JSON File on my server
- I then have an Automation which triggers when I turn my bedroom TV on (between 07:00 and 22:10 - as it turns on as far as HASS is concerned in the early hours to update I didn’t want a trigger while sleeping) - if the battery level of any Bluetooth headset is low it generates a message containing the details of all the devices which need charging and my Google Home Mini then speaks all this out.
Limitations
- If the Bluetooth battery level changes when I have no internet connection Tasker is unable to talk to my web space. Not a massive problem as EE has such rock solid coverage round here.
- When you charge the headset you’ll keep getting messages spoken by Hey Google until you turn the headset on again. I now take the headset off charge, turn it on, wait until it says “Connected” (all mine have voice feedback), wait a couple of seconds, and then turn off.
- It’s a bit convoluted to setup!
- The battery level reported by the devices is on a pretty poor scale - IME 60% is effectively 0%, you’ll soon be getting low battery warning - therefore anything below 80% is treated by me as < 50% left so time to charge - This shows the log it generated, it powered off as it hit 20%
Tasker XML Profile (note you’ll need to change the URL)
This triggers on a Bluetooth Battery level state change, then calls my PHP (see next step) with three parameters
- m = The MAC Address of the Headset
- l = The battery level
- d = The friendly device name in Android
<TaskerData sr="" dvi="1" tv="5.1m">
<Profile sr="prof26" ve="2">
<cdate>1524766321046</cdate>
<edate>1525082086982</edate>
<id>26</id>
<mid0>45</mid0>
<nme>Bluetooth Battery</nme>
<Event sr="con0" ve="2">
<code>599</code>
<Str sr="arg0" ve="3">android.bluetooth.device.action.BATTERY_LEVEL_CHANGED</Str>
<Int sr="arg1" val="0"/>
<Int sr="arg2" val="0"/>
<Str sr="arg3" ve="3"/>
<Str sr="arg4" ve="3"/>
</Event>
</Profile>
<Task sr="task45">
<cdate>1520784385563</cdate>
<edate>1524926567515</edate>
<id>45</id>
<nme>BT Battery</nme>
<pri>100</pri>
<Action sr="act0" ve="7">
<code>664</code>
<Str sr="arg0" ve="3">adapter</Str>
<Str sr="arg1" ve="3">BluetoothAdapter</Str>
<Str sr="arg2" ve="3">getDefaultAdapter {BluetoothAdapter} ()</Str>
<Str sr="arg3" ve="3"/>
<Str sr="arg4" ve="3"/>
<Str sr="arg5" ve="3"/>
<Str sr="arg6" ve="3"/>
<Str sr="arg7" ve="3"/>
<Str sr="arg8" ve="3"/>
<Str sr="arg9" ve="3"/>
</Action>
<Action sr="act1" ve="7">
<code>664</code>
<Str sr="arg0" ve="3">device</Str>
<Str sr="arg1" ve="3">adapter</Str>
<Str sr="arg2" ve="3">getRemoteDevice {BluetoothDevice} (String)</Str>
<Str sr="arg3" ve="3">%android_bluetooth_device_extra_device</Str>
<Str sr="arg4" ve="3"/>
<Str sr="arg5" ve="3"/>
<Str sr="arg6" ve="3"/>
<Str sr="arg7" ve="3"/>
<Str sr="arg8" ve="3"/>
<Str sr="arg9" ve="3"/>
</Action>
<Action sr="act2" ve="7">
<code>664</code>
<Str sr="arg0" ve="3">%devicename</Str>
<Str sr="arg1" ve="3">device</Str>
<Str sr="arg2" ve="3">getName {String} ()</Str>
<Str sr="arg3" ve="3"/>
<Str sr="arg4" ve="3"/>
<Str sr="arg5" ve="3"/>
<Str sr="arg6" ve="3"/>
<Str sr="arg7" ve="3"/>
<Str sr="arg8" ve="3"/>
<Str sr="arg9" ve="3"/>
</Action>
<Action sr="act3" ve="7">
<code>523</code>
<Str sr="arg0" ve="3">Dev %devicename, Level %android_bluetooth_device_extra_battery_level</Str>
<Str sr="arg1" ve="3">%android_bluetooth_device_extra_battery_level</Str>
<Img sr="arg2" ve="2"/>
<Int sr="arg3" val="0"/>
<Int sr="arg4" val="0"/>
<Int sr="arg5" val="3"/>
</Action>
<Action sr="act4" ve="7">
<code>116</code>
<Str sr="arg0" ve="3">https://www.example.com</Str>
<Str sr="arg1" ve="3">/battery.php</Str>
<Str sr="arg2" ve="3">m=%android_bluetooth_device_extra_device
l=%android_bluetooth_device_extra_battery_level
d=%devicename</Str>
<Str sr="arg3" ve="3"/>
<Str sr="arg4" ve="3"/>
<Int sr="arg5" val="10"/>
<Str sr="arg6" ve="3"/>
<Str sr="arg7" ve="3"/>
<Int sr="arg8" val="0"/>
</Action>
</Task>
</TaskerData>
The PHP On my Web Server
This processes the request made by tasker and simply writes those parameters as a JSON Object to a file on the server - this file is named the MD5 hash of the devices MAC Address. For security you will want to validate the MAC is a known good one.
Based on the tasker example above this would be accessible at
https://www.example.com/battery.php
<?php
$param = array();
$param['device'] = isset($_REQUEST['d']) ? $_REQUEST['d'] : false;
$param['status'] = isset($_REQUEST['l']) ? $_REQUEST['l'] : false;
$param['mac'] = isset($_REQUEST['m']) ? $_REQUEST['m'] : false;
$param['update'] = date('Y-m-d H:i:s');
if($param['status'] >= 0)
{
$json = json_encode($param);
file_put_contents("states/" . md5($param['mac']).".txt",$json);
echo $json;
}
?>
This would right to a file which would be accessible at a URL along the lines of
https://www.example.com/states/aaaaaaaaaaaaaaaaaaaaaaaaaaaa.txt
This file would contain JSON similar to the following
{"device":"WM2015AV02","status":"90","mac":"FF:FF:FF:AA:BB:CC","update":"2018-05-01 06:17:33"}
Home Assistant States Sensors
Now to create the REST sensor in Home Assistant
sensor bt_bathroom_speaker:
- platform: rest
name: BT - Bathroom Speaker
json_attributes:
- device
- update
- mac
resource: https://www.example.com/states/aaaaaaaaaaaaaaaaaaaaaaaaaaaa.txt
value_template: '{{ value_json.status }}'
unit_of_measurement: "%"
You’d repeat for each of the Headsets you have.
Home Assistant Automation
And now for the Automation
Then in Home Assistant I have the following Automation
- id: kev_home_bt
alias: Bluetooth Low Battery Alert
trigger:
platform: state
entity_id: media_player.kevs_bedroom_lg_tv
from: 'off'
to: 'playing'
condition:
condition: and
conditions:
- condition: time
after: '07:00:00'
before: '22:10:00'
- condition: or
conditions:
- condition: numeric_state
entity_id: sensor.bt__trekz_titanium_headset
below: '80'
- condition: numeric_state
entity_id: sensor.bt__bathroom_speaker
below: '80'
- condition: numeric_state
entity_id: sensor.bt__slimbuds_blue
below: '80'
- condition: numeric_state
entity_id: sensor.bt__slimbuds_red
below: '80'
action:
- service: tts.google_say
data_template:
entity_id: media_player.kevs_home_mini
message: >
Hey Kev, the batteries on your blue tooth devices are getting low
{% if states.sensor.bt__trekz_titanium_headset.state | float < 80 %}
Trekz Titanium is at {{ states.sensor.bt__trekz_titanium_headset.state }}
{% endif %}
{% if states.sensor.bt__bathroom_speaker.state | float < 80 %}
Bathroom Speaker is at {{ states.sensor.bt__bathroom_speaker.state }}
{% endif %}
{% if states.sensor.bt__slimbuds_blue.state | float < 80 %}
Slim Buds Blue is at {{ states.sensor.bt__slimbuds_blue.state }}
{% endif %}
{% if states.sensor.bt__slimbuds_red.state | float < 80 %}
Slimbuds Red is at {{ states.sensor.bt__slimbuds_red.state }}
{% endif %}
At a glance view in the Hass dashboard
And the history of a device throughout the day…
Enjoy!