示例#1
0
文件: antnode.py 项目: cecob/ant-fan
class AntNode:
    deviceManager: [DeviceManager] = []

    def __init__(self):
        os.system("usbreset 0fcf:1008")
        self.node = Node(driver.USB2Driver())
        self.network = Network(key=NETWORK_KEY_ANT_PLUS, name='N:ANT+')

    def add_heart_rate_monitor(self, sensor: Sensor, on_data_received):
        device = DeviceManager(
            HeartRate(self.node, self.network,
                      {'onHeartRateData': on_data_received}),
            sensor.ant_channel_id)
        self.deviceManager.append(device)

    def start(self):
        try:
            self.node.start()
            self.node.setNetworkKey(NETWORK_NUMBER_PUBLIC, self.network)
            logger.info('ANT started. Connecting to devices...')
            for profile in self.deviceManager:
                profile.open()
        except ANTException as err:
            logger.info(f'Could not start ANT.\n{err}')

    # ya you better call these or you may have to unplug the antnode+ stick
    def shutdown(self):
        for profile in self.deviceManager:
            profile.close()
        self.node.stop()
示例#2
0

#-------------------------------------------------#
#  Initialization                                 #
#-------------------------------------------------#

try:
    reset_USB_Device()
except Exception as ex:
    print(ex)

antnode = Node(driver.USB2Driver(log=LOG, debug=DEBUG, idProduct=0x1008))
try:
    antnode.start()
    network = Network(key=NETWORK_KEY_ANT_PLUS, name='N:ANT+')
    antnode.setNetworkKey(NETWORK_NUMBER_PUBLIC, network)
    myTrainer = bikeTrainer(
        antnode, network, {
            'onDevicePaired': device_paired,
            'onSearchTimeout': search_timed_out,
            'onChannelClosed': channel_closed,
            'onBikeTrainer': bike_Trainer
        })
    # Unpaired, search:
    myTrainer.open()
    print('ANT started. Connecting to devices...')
except ANTException as err:
    print(f'Could not start ANT.\n{err}')

#######################################################################################
示例#3
0
def main():
    global mainloop
    idProduct = prepare_usb("ANTUSB")

    device = driver.USB2Driver(log=LOG, debug=DEBUG, idProduct=idProduct)
    antnode = Node(device)
    antnode.start()
    network = Network(key=NETWORK_KEY_ANT_PLUS, name='N:ANT+')
    antnode.setNetworkKey(NETWORK_NUMBER_PUBLIC, network)

    POWER_SENSOR_ID = id_from_serial(1)
    #POWER_SENSOR_ID = 12345
    print("Start power meter ID %d" % POWER_SENSOR_ID)
    pm = PowerMeterTx(antnode, network, POWER_SENSOR_ID)

    def device_found(self, channelID):
        print("Detect %s" % str(channelID))

    def updatePower(self, cadence, accPower, power):
        pm.update(cadence, accPower, power)

    def heartrate_data(computed_heartrate, event_time_ms, rr_interval_ms):
        if HR_DEBUG:
            if rr_interval_ms is not None:
                print(
                    "Heart rate: %d, event time(ms): %d, rr interval (ms): %d"
                    % (computed_heartrate, event_time_ms, rr_interval_ms))
            else:
                print("Heart rate: %d" % (computed_heartrate, ))
        ble_hrm_update_hr(computed_heartrate)

    hr = HeartRate(antnode,
                   network,
                   callbacks={
                       'onDevicePaired': device_found,
                       'onHeartRateData': heartrate_data
                   })

    fe = FitnessEquipment(antnode,
                          network,
                          callbacks={
                              'onDevicePaired': device_found,
                              'onPowerUpdated': updatePower
                          })

    # Unpaired, search:
    hr.open()
    pm.open()
    fe.open()
    # Paired to a specific device:
    #fe.open(ChannelID(53708, 17, 37))
    #hr.open(ChannelID(21840, 120 ,81))

    print("++++++++++++++++++++++++++++++++++")
    monitor = None
    mainloop = GLib.MainLoop()
    ble_hrm_start()
    #while True:
    #    try:
    #        time.sleep(1)
    #    except KeyboardInterrupt:
    #        break

    try:
        mainloop.run()
    except KeyboardInterrupt:
        print("KeyboardInterrupt")
    ble_hrm_stop()

    print("+++++++++++++++++++---------------")
    fe.close()
    pm.close()
    hr.close()
    antnode.stop()
示例#4
0
class AntSensors():
    """
    ANT+ Heartrate and Power Meter sensor handler
    """
    class SensorStatus():
        """
        Tracks the status of a sensor device, whether it's connected
        and if its data is fresh.
        """
        class State(Enum):
            """
            State of an ANT+ sensor
            """
            NOTCONNECTED = 1
            CONNECTED = 2
            STALE = 3

        def __init__(self, fresh_time_s=15):
            self._connected = False
            self._last_seen_time = None
            self._fresh_time_s = fresh_time_s

        def make_fresh(self):
            """ Marks the sensor as connected and makes last seen time now"""
            self._connected = True
            self._last_seen_time = dt.now()

        def make_disconnected(self):
            """ Marks the sensor as disconnceted"""
            self._connected = False

        @property
        def state(self):
            """ Returns the state of the sensor
            Returns:
                SensorStatus.State representing current state
            """
            if not self._connected:
                _s = self.State.NOTCONNECTED
            elif (self._last_seen_time
                  and (dt.now() - self._last_seen_time).total_seconds() >
                  self._fresh_time_s):
                _s = self.State.STALE
            else:
                _s = self.State.CONNECTED
            return _s

    class SensorError(Exception):
        """
        Exceptions for ANT+ sensors.
        """
        class ErrorType(Enum):
            """
            Type of ANT+ sensor error
            """
            UNKNOWN = 1
            USB = 2
            NODE = 3
            TIMEOUT = 4

        def __init__(self,
                     expression=None,
                     message="",
                     err_type=ErrorType.UNKNOWN):
            super().__init__(message)
            self.expression = expression
            self.message = message
            self.err_type = err_type

    def __init__(self, search_timeout_sec=120):
        """
        Create Ant+ node, network, and initialize all attributes
        """
        self.search_timeout_sec = search_timeout_sec
        self.device = driver.USB2Driver()
        self.antnode = Node(self.device)
        self.network = Network(key=NETWORK_KEY_ANT_PLUS, name='N:ANT+')

        # Start search for sensors and register callbacks:
        self.device_power_meter = BicyclePower(self.antnode,
                                               self.network,
                                               callbacks={
                                                   'onDevicePaired':
                                                   self._on_device_found,
                                                   'onPowerData':
                                                   self._on_power_data,
                                                   'onChannelClosed':
                                                   self._on_channel_closed,
                                                   'onSearchTimeout':
                                                   self._on_search_timeout
                                               })
        self._power_meter_status = AntSensors.SensorStatus(fresh_time_s=2)
        self.device_heart_rate = HeartRate(self.antnode,
                                           self.network,
                                           callbacks={
                                               'onDevicePaired':
                                               self._on_device_found,
                                               'onHeartRateData':
                                               self._on_heartrate_data,
                                               'onChannelClosed':
                                               self._on_channel_closed,
                                               'onSearchTimeout':
                                               self._on_search_timeout
                                           })
        self._heart_rate_status = AntSensors.SensorStatus(fresh_time_s=2)
        self._reconnect = True
        # Heartrate fields
        self._heartrate_bpm = None
        self._rr_interval_ms = None
        self._hr_event_time_ms = None
        # Power meter fields
        self._instantaneous_power_watts = None
        self._cadence_rpm = None
        self._accumulated_power_watts = None
        self._power_event_count = None

    def connect(self):
        """
        Attaches to the ANT+ dongle and begins search for heartrate
        and power meter sensors.
        """
        try:
            self.antnode.start()
            self.antnode.setNetworkKey(NETWORK_NUMBER_PUBLIC, self.network)
        except exceptions.DriverError as e:
            raise AntSensors.SensorError(
                message=e.args[0],
                err_type=AntSensors.SensorError.ErrorType.USB)
        except exceptions.NodeError as e:
            raise AntSensors.SensorError(
                message=e.args[0],
                err_type=AntSensors.SensorError.ErrorType.NODE)

        # Reinitialize all data fields
        self._heartrate_bpm = None
        self._rr_interval_ms = None
        self._hr_event_time_ms = None
        self._instantaneous_power_watts = None
        self._cadence_rpm = None
        self._accumulated_power_watts = None
        self._power_event_count = None
        # Open device and start searching
        self.device_heart_rate.open(searchTimeout=self.search_timeout_sec)
        self.device_power_meter.open(searchTimeout=self.search_timeout_sec)

    def close(self):
        """
        Safely closes down the dongle interface and releases resources
        prior to exit.
        """
        self._reconnect = False
        if (self.device_heart_rate.state
                and self.device_heart_rate.state != ChannelState.CLOSED):
            self.device_heart_rate.close()
        if (self.device_power_meter.state
                and self.device_power_meter.state != ChannelState.CLOSED):
            self.device_power_meter.close()
        try:
            self.antnode.stop()
        except (exceptions.NodeError, exceptions.DriverError):
            pass

    def _on_device_found(self, device, ch_id):
        #TODO: make the device number available
        print("Found a {:s} device".format(device.name))
        print(
            "device number: {:d} device type {:d}, transmission type: {:d}\r\n"
            .format(ch_id.deviceNumber, ch_id.deviceType,
                    ch_id.transmissionType))

    def _on_channel_closed(self, device):
        if device == self.device_heart_rate:
            self._heart_rate_status.make_disconnected()
        elif device == self.device_power_meter:
            self._power_meter_status.make_disconnected()
        else:
            print("Unknown device channel closed!")
        print("Channel closed for {:s}".format(device.name))
        # TODO - figure out why re-open doesn't work - returns USB Driver error,
        #        perhaps something wasn't properly freed on close?
        #if self._reconnect == True:
        #    print("Attempting re-connect...")
        #    device.open()

    def _on_search_timeout(self, device):
        raise AntSensors.SensorError(
            message="Timed out searching for device: {}".format(device.name),
            err_type=AntSensors.SensorError.ErrorType.TIMEOUT)

    def _on_heartrate_data(self, computed_heartrate, event_time_ms,
                           rr_interval_ms):
        self._heartrate_bpm = computed_heartrate
        self._rr_interval_ms = rr_interval_ms
        if (not self._hr_event_time_ms
            ) or event_time_ms > self._hr_event_time_ms:
            self._hr_event_time_ms = event_time_ms
            self._heart_rate_status.make_fresh()

    def _on_power_data(self, event_count, _, cadence_rpm,
                       accumulated_power_watts, instantaneous_power_watts):
        self._instantaneous_power_watts = instantaneous_power_watts
        self._cadence_rpm = cadence_rpm
        self._accumulated_power_watts = accumulated_power_watts
        if (not self._power_event_count
            ) or event_count != self._power_event_count:
            self._power_event_count = event_count
            self._power_meter_status.make_fresh()

    @property
    def heartrate_bpm(self):
        """
        Returns heartrate in beats per minute (BPM) or None if heartrate data are not
        available or fresh.
        """
        #TODO: check for stale data (if no update in xx sec, return None)
        return self._heartrate_bpm

    @property
    def power_watts(self):
        """
        Returns power in Watts if available, or None if not available or fresh.
        """
        #TODO: return calculated power from accumulated power if there are event_count gaps
        #TODO: check for stale data (if no update in xx sec, return None)
        return self._instantaneous_power_watts

    @property
    def cadence_rpm(self):
        """
        Returns cadence in RPM if available or None if not available or fresh.
        """
        #TODO: check for stale data (if no update in xx sec, return None)
        return self._cadence_rpm

    @property
    def heart_rate_status(self):
        """
        Returns status of heart rate sensor.
        """
        return self._heart_rate_status.state

    @property
    def power_meter_status(self):
        """
        Returns status of power meter sensor.
        """
        return self._power_meter_status.state