OneWheel - adding status of BLE device + charging to smart plug

I have a OneWheel, which is a bloody amazing piece of machinery, practically snowboarding uphill, on concrete, year round - or on trails, thing is amazing. Anyhow it exposes the battery and other settings via BLE. I’ve setup HA to have a view that shows the battery % and if it hits 100% turn off the smart plug attached. Scripts and configuration below, likely not the best way to do it, but works for me. Could be adapted to work with any BLE device and pull information into a HA sensor.

This is on a Raspberry Pi (Zero W with Raspian Stretch Lite) and HA All-In-One Installer.

#!/usr/bin/env python3
import argparse,subprocess

text = 'This program returns stats from an Onewheel BLE device'
parser = argparse.ArgumentParser(description = text)
parser.add_argument("address",help="mac address of device")
parser.add_argument("--battery", help="get battery level",action="store_true")
parser.add_argument("--total_miles", help="get total miles",action="store_true")
parser.add_argument("--firmware_version", help="get firmware version",action="store_true")
parser.add_argument("--hardware_revision", help="get hardware revision",action="store_true")
parser.add_argument("--riding_mode", help="get current riding mode",action="store_true")

args = parser.parse_args()


if __name__ == "__main__":
    if args.battery:
        handle = "0x0021"
    elif args.total_miles:
        handle = "0x0079"
    elif args.hardware_revision:
        handle = "0x0075"
    elif args.firmware_version:
        handle = "0x0059"
    elif args.riding_mode:
        handle = "0x001d"
    else:
        handle = "0x0021"

    p = subprocess.Popen("/usr/bin/gatttool -b {0} --char-read --handle={1}".format(args.address,handle), stdout=subprocess.PIPE, shell=True)
    try:
        (output, err) = p.communicate(timeout=10)
        p_status = p.wait()
        p_out = output.decode('ascii').split()
        if len(p_out) > 0:
            r = '{0}{1}'.format(p_out[2],p_out[3])
            print(int(r,16))
        else:
            print(p_out)
    except subprocess.TimeoutExpired:
        print('n/a')

And OW sensors from configuration.yaml:

sensor:
  - platform: command_line
    name: "OneWheel Battery Level"
    command: "/home/homeassistant/.homeassistant/tools/onewheel_stats.py 50:65:83:A1:C2:53 --battery"
    scan_interval: 60
    unit_of_measurement: "%"
  - platform: command_line
    name: "OneWheel Total Miles"
    command: "/home/homeassistant/.homeassistant/tools/onewheel_stats.py 50:65:83:A1:C2:53 --total_miles"
    scan_interval: 1000

I’ve also got a smart plug that turns off when the OW hits 100%:

- action:
  - alias: turn on onewheel smart plug
    data:
      entity_id: switch.onewheel_smart_plug
    service: switch.turn_on
  alias: 'Turn on OW charger when less than 100% '
  condition: []
  trigger:
  - above: 0
    below: 100
    entity_id: sensor.onewheel_battery_level
    platform: numeric_state
- action:
  - alias: turn off onewheel smart plug
    data:
      entity_id: switch.onewheel_smart_plug
    service: switch.turn_off
  alias: Turn off OW charger when at 100%
  condition:
  - condition: state
    entity_id: switch.onewheel_smart_plug
    state: 'on'
  trigger:
  - entity_id: sensor.onewheel_battery_level
    platform: state
    to: '100'
1 Like

I was messing with the idea of a somewhat related project for my Onewheel XR, so I was going to roll something quick with my RPi3 and some Python to see if I could get all the data I need that way. However, I seem to only be getting back double 00 bytes from attempts to read values such as the battery (0x0021, or its associated UUID).

So having stumbled on your above post here, I thought I would try your solution of just using gatttool… but that still gives me the same 0 result.

I can connect to the board, I can get a list of characteristics back from it via gatt, but my char reads always give me 0… I am at the limits of my sanity here.

Sorry to necro bump this post a year later, but I am hoping you or someone else with some experience with a Pi and the Onewheel, or even just better BLE/GATT knowledge than me, might have some idea what is going on.

Well, turns out I am not alone.

The Gemini firmware update seems to introduced a secure handshake of some sort to hinder 3rd party connections even reading gatt characteristics.

Here is a link to a discussion of the issue via ponewheel on github.

@kariudo just catching up, yeah, there is a link to another python script based off what we did at the link you have on github… and just noticed it was yours, well done.

Is there anything that works to get the newer Onewheel boards communicating with Home Assistant? I have a couple of Onewheels that I would love to monitor the charge process using Home Assistant. It seems like FM have really locked everything down since 2017.

Thanks
Sorry to revive an old thread, this is the only post talking about HA and OW.