Boondock Battery Life

As a rule of thumb, the Boondock Echo current draws approximately 100 mA at 5 V. That means the energy consumption is approximately 0.5 Watts. How did we arrive at these numbers? How do you calculate how long a battery lasts? The answer to the first question is “Through testing!” and the answer to the second question is “With Math!” This article explains the process and allows you to confirm my experiment.

This adventure started when amateur radio operator N5RET asked how long a 2000 mAh battery should last. And truthfully, we hadn't tested the Boondock Echo's power consumption in a while. The power consumption depends on a variety of factors including number of processors active at any one time, whether wifi is active or not, the efficiency of each algorithm, the duty cycle of the audio, the wifi usage, etc. 

I had to know! So the adventure began with the purchase of a FNB58 Bluetooth USB Power meter plugged inline with the Boondock Echo. The onscreen display updates approximately twice per second. The packaging gave no indication that bluetooth was available, and the app wasn't present on FNIRSI's website at the time of writing (although it appears to have returned after an emailed complaint.)

Plan A

I did find a link to the Android .apk file on MediaFire and side-loaded it onto a test phone. But the app is, in my opinion, more or less useless, so I'm not going to provide the link. Try to find the scatterplot in the screen capture below. I dare you.


This screen capture shows the data from the android app.  As you can tell, the scatterplot is compressed to just a few pixels in the vertical direction, rendering it entirely useless.

With Bluetooth-to-phone not a viable option, my options now include Bluetooth-to-computer or USB-to-Computer for data offload. 

Plan B -- LLM

The quickest way to accomplish this programming task is to describe the situation to a Large Language Model and have it spit out code in the language of my choice.

I first went with the LLM -- and it produced quite a bit of perfectly executable code that allowed me to communicate over BLE well within 5 minutes of formulating the request.

To start out, I created a virtual environment on my computer -- this helps to keep different packages from interfering with one another or having to refactor code somewhere down the road. ChatGPT recommended the Bleak package

py -m venv fnrisi_venv
.\fnrisi_venv.\scripts\activate
cd fnrisi_venv
pip install bleak


First -- scan for nearby Bluetooth devices and display their address.

import asyncio
from bleak import BleakScanner
async def scan_for_devices():
print("Scanning for Bluetooth devices...")
devices = await BleakScanner.discover()
for device in devices:
print(f"Device: {device.name}, Address: {device.address}")

loop = asyncio.get_event_loop() loop.run_until_complete(scan_for_devices())

 

Python spit out some “deprecation warnings” but the code worked just fine, it just leaves problems for future Mark. Since I don’t plan to ever update this code, I couldn’t care less about changing anything.

Then, with the known bluetooth address, scan for services and characteristics

import asyncio
from bleak import BleakClient
# Replace with the Bluetooth address of your FNRISI FNB58
FNB58_BLUETOOTH_ADDRESS = "98:DA:B0:08:AA:88" # Insert the actual device address here
async def list_services_and_characteristics():
  print(f"Connecting to {FNB58_BLUETOOTH_ADDRESS}...")
  async with BleakClient(FNB58_BLUETOOTH_ADDRESS) as client:
    print(f"Connected: {client.is_connected}")
    services = await client.get_services()
    print("Listing services and characteristics...")
    for service in services:
      print(f"Service: {service.uuid}")
      for characteristic in service.characteristics:
        print(f" Characteristic: {characteristic.uuid}, Properties: {characteristic.properties}")
loop = asyncio.get_event_loop()
loop.run_until_complete(list_services_and_characteristics())
 
 

That works very well to produce device services and characteristics

And polling those devices is not a big deal either.

import asyncio
from bleak import BleakClient
# Replace with your FNRISI FNB58 Bluetooth address
FNB58_BLUETOOTH_ADDRESS = "98:DA:B0:08:AA:88" # Insert actual device address here
# Replace with the characteristic UUID for notifications
CHARACTERISTIC_UUID = "0000ffe4-0000-1000-8000-00805f9b34fb"
def notification_handler(sender, data):
  """Simple notification handler which prints the data received."""
  print(f"Data received from {sender}: {data}")
 
async def run():
  print(f"Connecting to {FNB58_BLUETOOTH_ADDRESS}...")
  async with BleakClient(FNB58_BLUETOOTH_ADDRESS) as client:
    print(f"Connected: {client.is_connected}")
    # Start notifications
  await client.start_notify(CHARACTERISTIC_UUID, notification_handler)
    print("Receiving notifications...")
    # Keep the connection open to continue receiving data
    await asyncio.sleep(30) # Adjust the time as needed or use a loop
    # Stop notifications when done
    await client.stop_notify(CHARACTERISTIC_UUID)
loop = asyncio.get_event_loop()
loop.run_until_complete(run())

 

Unfortunately, the device doesn’t produce an automated stream of data, which isn’t what I hoped for. More than likely, one of the “write” characteristic flags has to be set to enable or disable data streaming. The technique now would be to use the app and sniff the Bluetooth packets out of the air. That should be relatively easy to log, and then interpret with WireShark or another similar program. The trouble will be in determining which bits of streaming data correspond to each measurement -- the device likely returns a stream of data, and I’ll have to know which bits correspond to which measurements, the endianness, etc.

There is a way to log Bluetooth packet transfer on Android devices in the developer menu by tapping “Enable Bluetooth HCI snoop log” and then cycling Bluetooth off and on again. But the files aren’t where they are supposed to be in internal storage. Fortunately, a bit of sleuthing on the internet helped. On the dialer app, type *#9900# to enter a secret phone menu. Then tap “Run dumpstate/logcat”, allow it to fully process, and then run “Copy to sd card (include cp ramdump)” The files magically appear in the “my files” app under “internal storage>log>bluetooth>btsnooz_hci_xxxxxxxxxxxxxxx.cfa”

From there, open the btsnooz_hci_xxxxxxxxxxxxxxx.cfa file in Wireshark and use the following filter to just look at the mac address for the FNIRSI device. “Bluetooth.addr == 98:da:b0:08:aa:88 (change the bluetooth address as needed)


This wireshark file shows the bits of data transferred over bluetooth between my phone and the FNIRSI device. 0xAA840001 and 0xAA8100f4 appear to tell the device to start streaming data.  Unfortunately, without documentation or corresponding measurements, there’s no real way to know which parts of the received data string correspond to which particular measurements.  Only way to figure it out is through hard work.

If I continue down this path, I think I can very quickly determine how to control the device, however, I still have to interpret the binary or hexadecimal values, and my 15 minutes of fooling around with this idea was up. So this “minimal effort programming” adventure was at an end. But, to me, it’s seriously impressive that I made it this far without typing one line of original code.  

But, maybe I can still be a script-kiddie, maybe someone has done this work already. Time to find out!

Plan C [[Solved]]

Time to see what Github had to offer. And it didn’t take long to find this:

https://github.com/baryluk/fnirsi-usb-power-data-logger

And wouldn’t you know it, he included complete install instructions! Woohoo!

Except, I am Hard-Way Hughes, and I wasn’t about to do the easy thing and switch over to a linux machine. No, I always do things the hard way. So I installed Ubuntu using Windows Subsystem for Linux. Now I can run all this code in a linux environment, right? Wrong! 

 

Windows firewalls the USB ports from WSL. So now I have to go on a quick detour to figure out how to pass the USB devices through the firewall. Fortunately, the USBIPD-WIN project was written specifically to accomplish this task.

https://github.com/dorssel/usbipd-win

So off to PowerShell for shenanigans.

winget install --interactive --exact dorssel.usbipd-win

usbipd list

 

Here’s I’ve obviously already done a few more steps, specifically

Usbipd bind --busid 1-2
Usbipd attach --wsl --busid 1-2

 

The only real “gotcha” here is that I had to have two powershell windows open. One running wsl, and the other running these commands. But once those are typed in, everything is ready to go and we can start collecting data from the logger. And there are plenty of instructions over at the github page I don’t have to copy here for you.

 


Open wsl in one powershell window before running the usbipd bind and attach commands in a second powershell window

Then, just hop into the github distribution at https://github.com/dorssel/usbipd-win, activate a virtual environment, and run fnirsi_logger.py

Or if you want to get fancy about it, you can send the output to a text file.

fnirsi_logger.py > boondockEchoPowerLogs.py

From that point on, it becomes a data analysis exercise. I chose to use Mathematica for that since I’m more comfortable making pretty graphics using Mathematica than Python.

Experiment with Data!

First let me state that the Fnirsi device came from Amazon -- it doesn’t have a NIST traceable certification. So the data may or may or may not be precisely reproducible. But it’ll definitely get us in the ballpark. 

And for an experiment, I chose to spend 30 minutes in an idle state, and then 30 minutes recording/uploading audio. I took all the data and plotted it on two graphs: One that shows current over time and another that shows power consumption over time.

 

This graph of current consumption over time shows a marked change at t=1800 seconds where I plugged in a Uniden Bearcat B125 scanner.

And the graphic of the current draw isn’t too different from the graphic for power consumption.

The graph of Power Consumption over time is very similar to the graph of Current Consumption over time.

 

The data shows a few things. First, before t=1800 s (the 30 minute mark), the device is mostly idle, the data shows horizontal striations -- likely attributable to different software processes. Wifi connectivity, the circular audio buffer, etc. If we are able to correlate the consumption levels with specific bits of code, it may be possible to optimize the algorithms to minimize power consumption. For example, perhaps we can create an idle state when on battery power that extends the time between high-energy code calls, shifting the power consumption data points closer to the 0.35 W line. After t=1800s, when the device is receiving and transmitting audio files, the striations shift up. But, interestingly, so do the lowest possible measurements. What changed? Likely that is when the radio was connected to the Boondock Echo and power was lost due to differential ground reference levels between the Boondock Echo and the radio. Current flowed from the Boondock Echo to the radio. An interesting follow-up experiment might be to place an audio isolation transformer in-line to provide galvanic isolation between the Boondock Echo and the radio. 

 

Discarding the 20% lowest and 20% highest values, the mean current is 96 mA, and the overall average is 104 mA, so using 100 mA as a rule of thumb is quite reasonable. 

Summary

This article shows you how you can measure the Boondock Echo power consumption in a variety of operational states using a USB cable, or if you are looking for excitement, it shows you how to harvest bluetooth data which would then let you write a program that captures wireless data from the FNIRSI device.