Skip to content

Undesireable behavior in XBeeDevice.read_data_from #315

@btingle

Description

@btingle

Hi there,
I've been using this library to create a coordinated radio network of xbee devices. One device acts as a coordinator and the rest as nodes. I record statistics for the time to transmit/receive messages to each node.

I noticed that my receive times were curiously always in a multiple of 100ms- which is odd. None of my configuration settings on the XBee itself would have caused this, so I began digging through the code in this repository, which is where I traced the execution path to this function, in https://github.com/digidotcom/xbee-python/blob/master/digi/xbee/reader.py#L2021:

def get_by_remote(self, remote, timeout=None):
        """
        Returns the first element of the queue that had been sent by
        `remote`, if there is some in the specified timeout.

        If timeout is `None`, this method is non-blocking. In this case, if
        there is not any packet sent by `remote` in the queue, it returns
        `None`, otherwise it returns an :class:`.XBeeAPIPacket`.

        Args:
            remote (:class:`.RemoteXBeeDevice`): Remote XBee to get its first
                element from queue.
            timeout (Integer, optional, default=`None`): Timeout in seconds.

        Returns:
            :class:`.XBeeAPIPacket`: If there is any packet available before
                the timeout expires. If timeout is `None`, the returned value
                may be `None`.

        Raises:
            TimeoutException: If timeout is not `None` and there is not any
                packet available that was sent by `remote` before the timeout
                expires.
        """
        if timeout is None:
            with self.mutex:
                for packet in self.queue:
                    if self.__remote_device_match(packet, remote):
                        self.queue.remove(packet)
                        return packet
            return None

        packet = self.get_by_remote(remote)
        dead_line = time.time() + timeout
        while packet is None and dead_line > time.time():
            time.sleep(0.1)
            packet = self.get_by_remote(remote)
        if packet is None:
            raise TimeoutException()

        return packet

time.sleep(0.1) in a loop... Who thought this was a good idea?! I have sidestepped the issue by calling the read_data_remote function without a timeout and using my own timeout loop with an increment smaller than 100ms.

This problem could be avoided entirely by instantiating a separate data queue for each remote device and thus being able to use the builtin queue.get with the appropriate timeout, like in the get() method just above the offending function.

But if you don't want to do all that, just make the increment smaller than 100ms (I chose 10ms) to make it more tolerable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions