#!/usr/bin/python from __future__ import absolute_import, print_function, unicode_literals ''' Cycling Speed and Cadence test script ''' from optparse import OptionParser, make_option import sys import dbus import dbus.service import dbus.mainloop.glib try: from gi.repository import GObject except ImportError: import gobject as GObject import bluezutils BUS_NAME = 'org.bluez' CYCLINGSPEED_MANAGER_INTERFACE = 'org.bluez.CyclingSpeedManager1' CYCLINGSPEED_WATCHER_INTERFACE = 'org.bluez.CyclingSpeedWatcher1' CYCLINGSPEED_INTERFACE = 'org.bluez.CyclingSpeed1' class MeasurementQ: def __init__(self, wrap_v): self._now = [None, None] self._prev = [None, None] self._wrap_v = wrap_v def can_calc(self): return ((self._now[0] is not None) and (self._now[1] is not None) and (self._prev[0] is not None) and (self._prev[1] is not None)) def delta_v(self): delta = self._now[0] - self._prev[0] if (delta < 0) and (self._wrap_v): delta = delta + 65536 return delta def delta_t(self): delta = self._now[1] - self._prev[1] if delta < 0: delta = delta + 65536 return delta def put(self, data): self._prev = self._now self._now = data class Watcher(dbus.service.Object): _wheel = MeasurementQ(False) _crank = MeasurementQ(True) _circumference = None def enable_calc(self, v): self._circumference = v @dbus.service.method(CYCLINGSPEED_WATCHER_INTERFACE, in_signature="oa{sv}", out_signature="") def MeasurementReceived(self, device, measure): print("Measurement received from %s" % device) rev = None evt = None if "WheelRevolutions" in measure: rev = measure["WheelRevolutions"] print("WheelRevolutions: ", measure["WheelRevolutions"]) if "LastWheelEventTime" in measure: evt = measure["LastWheelEventTime"] print("LastWheelEventTime: ", measure["LastWheelEventTime"]) self._wheel.put( [rev, evt] ) rev = None evt = None if "CrankRevolutions" in measure: rev = measure["CrankRevolutions"] print("CrankRevolutions: ", measure["CrankRevolutions"]) if "LastCrankEventTime" in measure: evt = measure["LastCrankEventTime"] print("LastCrankEventTime: ", measure["LastCrankEventTime"]) self._crank.put( [rev, evt] ) if self._circumference is None: return if self._wheel.can_calc(): delta_v = self._wheel.delta_v() delta_t = self._wheel.delta_t() if (delta_v >= 0) and (delta_t > 0): speed = delta_v * self._circumference * 1024 / delta_t # mm/s speed = speed * 0.0036 # mm/s -> km/h print("(calculated) Speed: %.2f km/h" % speed) if self._crank.can_calc(): delta_v = self._crank.delta_v() delta_t = self._crank.delta_t() if delta_t > 0: cadence = delta_v * 1024 / delta_t print("(calculated) Cadence: %d rpm" % cadence) def properties_changed(interface, changed, invalidated): if "Location" in changed: print("Sensor location: %s" % changed["Location"]) if __name__ == "__main__": dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) bus = dbus.SystemBus() option_list = [ make_option("-i", "--adapter", action="store", type="string", dest="adapter"), make_option("-b", "--device", action="store", type="string", dest="address"), make_option("-c", "--circumference", action="store", type="int", dest="circumference"), ] parser = OptionParser(option_list=option_list) (options, args) = parser.parse_args() if not options.address: print("Usage: %s [-i ] -b [-c ] [cmd]" % (sys.argv[0])) print("Possible commands:") print("\tShowSupportedLocations") print("\tSetLocation ") print("\tSetCumulativeWheelRevolutions ") sys.exit(1) managed_objects = bluezutils.get_managed_objects() adapter = bluezutils.find_adapter_in_objects(managed_objects, options.adapter) adapter_path = adapter.object_path device = bluezutils.find_device_in_objects(managed_objects, options.address, options.adapter) device_path = device.object_path cscmanager = dbus.Interface(bus.get_object(BUS_NAME, adapter_path), CYCLINGSPEED_MANAGER_INTERFACE) watcher_path = "/test/watcher" watcher = Watcher(bus, watcher_path) if options.circumference: watcher.enable_calc(options.circumference) cscmanager.RegisterWatcher(watcher_path) csc = dbus.Interface(bus.get_object(BUS_NAME, device_path), CYCLINGSPEED_INTERFACE) bus.add_signal_receiver(properties_changed, bus_name=BUS_NAME, path=device_path, dbus_interface="org.freedesktop.DBus.Properties", signal_name="PropertiesChanged") device_prop = dbus.Interface(bus.get_object(BUS_NAME, device_path), "org.freedesktop.DBus.Properties") properties = device_prop.GetAll(CYCLINGSPEED_INTERFACE) if "Location" in properties: print("Sensor location: %s" % properties["Location"]) else: print("Sensor location is not supported") if len(args) > 0: if args[0] == "ShowSupportedLocations": if properties["MultipleLocationsSupported"]: print("Supported locations: ", properties["SupportedLocations"]) else: print("Multiple sensor locations not supported") elif args[0] == "SetLocation": if properties["MultipleLocationsSupported"]: device_prop.Set(CYCLINGSPEED_INTERFACE, "Location", args[1]) else: print("Multiple sensor locations not supported") elif args[0] == "SetCumulativeWheelRevolutions": if properties["WheelRevolutionDataSupported"]: csc.SetCumulativeWheelRevolutions(dbus.UInt32(args[1])) else: print("Wheel revolution data not supported") else: print("Unknown command") sys.exit(1) mainloop = GObject.MainLoop() mainloop.run()