Exemplo n.º 1
0
class XBeeFrameBase(Block):
    """ Generate or interpret XBee frames

    Parameters:
        escaped (bool): True uses API mode 2 
        digimesh (bool): Use DigiMesh protocol rather than XBee (IEEE 802.15.4)
    """

    version = VersionProperty(version='1.0.0')
    escaped = BoolProperty(title='Escaped characters? (API mode 2)',
                           default=True)
    digimesh = BoolProperty(title='DigiMesh', default=False)

    def __init__(self):
        super().__init__()
        self._xbee = None
        self._serial = None
        self._protocol = xbee.XBee

    def configure(self, context):
        super().configure(context)
        if self.digimesh():
            self._protocol = xbee.DigiMesh
        self._connect()

    def process_signals(self, signals):
        for signal in signals:
            pass

    def stop(self):
        try:
            self.logger.debug('Halting XBee callback thread')
            self._xbee.halt()
            self.logger.debug('XBee halted')
        except:
            self.logger.exception('Exception while halting xbee')
        super().stop()

    def _connect(self):
        ''' Establish XBee serial connection '''
        try:
            self._serial = serial.Serial(None)
            self.logger.debug('Escaped is' ': {}'.format(self.escaped()))
            try:
                self._xbee = self._protocol(self._serial,
                                            escaped=self.escaped())
            except:
                self.logger.exception('An exception occurred')
        except:
            self.logger.exception('An failure occurred')

    def _API_frame_packer(self, data):
        return xbee.frame.APIFrame(data, self.escaped()).output()

    def _API_frame_unpacker(self, data):
        frame = xbee.frame.APIFrame(escaped=self.escaped())
        for byte in data:
            frame.fill(bytes([byte]))
        frame.parse()
        return self._xbee._split_response(frame.data)
Exemplo n.º 2
0
class XBeeParseFrame(XBeeFrameBase):
    """Parse Frame.

    Take a XBee Frame as an input signal and output a signal composed of the
    individual frame components.

    Parameters:
        data: An XBee frame with a start byte and checksum
            *TODO: allow only the data packet* 
    """

    version = VersionProperty(version='1.0.0')
    data = Property(title="Data", default="{{ $ }}")

    def process_signals(self, signals):
        for signal in signals:
            if isinstance(self.data(signal), bytes):
                data_encoded = self.data(signal)
            else:
                data_encoded = "{}".format(self.data(signal)).encode()
            try:
                frame = self._API_frame_unpacker(data_encoded)
                self.notify_signals([Signal(frame)])
            except:
                self.logger.exception("Failed to parse frame")
class XBeeDigiMeshTXFrame(XBeeFrameBase):
    """Generate TX_LONG_ADDR command frame

    This block generates an XBee 0x10 digimesh tx long frame.

    Parameters:
        dest_addr: 8 byte address of remote xbee to send AT command to.
            Default value when left blank is "FF FF" which sends a broadcast.
        data: Data to send, default is 100 bytes
        frame_id: Hidden property that can be used to order data.
    """

    version = VersionProperty(version='1.0.0')
    data = Property(title="Data", default="{{ $.to_dict() }}")
    dest_addr = Property(title='Destination Address \
                         (8 bytes hex, ex: "01 23 45 67 89 AA 00 05")',
                         default='',
                         allow_none=True)
    frame_id = Property(title='Frame id',
                        default="{{ $frame_id }}",
                        hidden=True)

    def configure(self, context):
        super().configure(context)
        self._protocol = xbee.DigiMesh
        self._connect()

    def process_signals(self, signals):
        for signal in signals:
            data_encoded = "{}".format(self.data(signal)).encode()
            dest_addr = \
                binascii.unhexlify(self.dest_addr(signal).replace(" ", "")) \
                if self.dest_addr(signal) else None
            try:
                frame_id = binascii.unhexlify(self.frame_id(signal))
                self.logger.debug("Frame ID = {}".format(frame_id))
            except:
                frame_id = None
            self.logger.debug('Creating frame, data: {}'.format(data_encoded))
            # tx_long_addr: 0x10 "Tx (Transmit) Request: 64-bit address"
            # frame_id: 0x01
            # dest_addr: 0xFFFF is the broadcast address
            # data: RF data bytes to be transmitted
            #
            # frame_id is an arbitrary value, 1 hex byte, used to associate
            # sent packets with their responses. If set to 0 no response will
            # be sent. Could be a block property.

            packet = self._xbee._build_command(
                'tx',
                id=b'\x10',
                frame_id=frame_id or b'\x01',
                dest_addr=dest_addr or b'\x00\x00\x00\x00\x00\x00\xFF\xFF',
                data=data_encoded,
                reserved=b'\xFF\xFE',
                broadcast_radius=b'\x00',
                options=b'\x00')
            self.notify_signals(
                [Signal({"frame": self._API_frame_packer(packet)})])
Exemplo n.º 4
0
class XBeeTX(XBeeBase):

    """Execute TX Command.

    XBee sends the serialized version of each input signal to thie block. It is
    sent to the configured "Distnation Address" of the XBee. That destination
    XBee will receive that serialized signal. If that block is connected to nio
    then the block will notify the signal.

    Parameters:
        dest_addr: 2 or 8 byte address of remote xbee to send AT command to.
            must be 8 bytes when using digimesh.
            Default value when left blank is "FF FF" which sends a broadcast.
    """

    version = VersionProperty(version='0.2.1')
    data = Property(title="Data", default="{{ $.to_dict() }}")
    dest_addr = Property(title='Destination Address \
                         (2 or 8 bytes hex, ex: "00 05")',
                         default='',
                         allow_none=True)

    def process_signals(self, signals):
        for signal in signals:
            data_encoded = "{}".format(self.data(signal)).encode()
            dest_addr = \
                binascii.unhexlify(self.dest_addr(signal).replace(" ", "")) \
                if self.dest_addr(signal) else None
            self.logger.debug('Sending data: {}'.format(data_encoded))
            # tx: 0x01 "Tx (Transmit) Request: 16-bit address"
            # tx: 0x10 "Tx (Transmit) Request: 64-bit address", DigiMesh
            # frame_id: 0x01
            # dest_addr: 0xFFFF appears to make it so that it sends to the
            # configured "Destination Address" on the XBee
            # data: RF data bytes to be transmitted
            #
            # frame_id is an arbitrary value, 1 hex byte, used to associate
            # sent packets with their responses. If set to 0 no response will
            # be sent. Could be a block property.
            if self.digimesh():
                # pass all arguments to work around bug in
                # python-xbee/xbee/digimesh.py where default values are not
                # bytes
                self._xbee.send(
                    'tx',
                    id=b'\x10',
                    frame_id=b'\x01',
                    dest_addr=dest_addr or b'\x00\x00\x00\x00\x00\x00\xFF\xFF',
                    reserved=b'\xFF\xFE',
                    broadcast_radius=b'\x00',
                    options=b'\x00',
                    data=data_encoded
                )
            else:
                self._xbee.send('tx',
                                frame_id=b'\x01',
                                dest_addr=dest_addr or b'\xFF\xFF',
                                data=data_encoded)
class XBeeATCommandFrame(XBeeFrameBase):
    """ Generate AT commands frames
    Parameters:
        command: The command to execute, ex. 'D0', WR'
        parameter: The command parameter, ex. '05' for 'D0' command
           to set pin high
        frame_id: Hidden parameter to specify frame_id
    """

    version = VersionProperty(version='1.0.0')
    command = Property(title='AT Command (ascii)', default='ID')
    parameter = Property(title='Command Parameter (hex, ex: "05")', default='')
    frame_id = Property(title='Frame id',
                        default="{{ $frame_id }}",
                        hidden=True)

    def process_signals(self, signals):
        for signal in signals:
            try:
                command = self.command(signal)
                parameter = self.parameter(signal).replace(" ", "")
                try:
                    frame_id = binascii.unhexlify(self.frame_id(signal))
                    self.logger.debug("Frame ID = {}".format(frame_id))
                except:
                    frame_id = None
                self._at(command, parameter, frame_id)
            except:
                self.logger.exception("Failed to execute at command")

    def _at(self, command, parameter, frame_id):
        command = command.encode('ascii')
        parameter = binascii.unhexlify(parameter)
        self.logger.debug(
            "Executing AT command: {}, with parameter: {}".format(
                command, parameter))
        # at: 0x08 "AT Command"
        # frame_id: 0x01
        # data: RF data bytes to be transmitted
        # command: The command to execute, ex. 'D0', WR'
        # parameter: The command parameter, ex. b'\x05' for 'D0' command
        #    to set pin high
        #
        # frame_id is an arbitrary value, 1 hex byte, used to associate sent
        # packets with their responses. If set to 0 no response will be sent.
        # Could be a block property.
        packet = self._xbee._build_command('at',
                                           frame_id=frame_id or b'\x01',
                                           command=command,
                                           parameter=parameter)
        self.notify_signals(
            [Signal({"frame": self._API_frame_packer(packet)})])
Exemplo n.º 6
0
class TrendAnalysis(Block):


    data = Property(title='Data Set', default='')
    version = VersionProperty('0.1.0')
    
    def process_signals(self, signals):
        # Create empty list of signals to notify
        signals_to_notify = []
        for signal in signals:
            if (isinstance(self.data(signal), list) and
                    len(self.data(signal)) > 1):
                # Make sure input is a list with at least two values
                dd = self.data(signal)
                # Plot trend line
                trend,trend_start = self.linreg(range(len(dd)),dd)
                trend_d = [
                        trend * index + trend_start for index in range(len(dd))
                        ]
                trend_end = trend_d[len(dd)-1]
                # Calculate standard error
                error = [abs(trend_d - dd) for trend_d, dd in zip(trend_d, dd)]
                std_error = statistics.stdev(error)
                # Create new signal attributes
                signal.trend = trend
                signal.trend_start = trend_start
                signal.trend_end = trend_end
                signal.std_error = std_error
                # Append signal to list signals_to_notify
                signals_to_notify.append(signal)
            else:
                # Raise exception, do not append signals_to_notify
                self.logger.error(
                        "Data Set must be a list with length > 1"
                        )
        self.notify_signals(signals_to_notify)

    def linreg(self, X, Y):
        # Perform least-squares-fit of linear regression to a list of numeric
        # values
        N = len(X)
        Sx = Sy = Sxx = Syy = Sxy = 0.0
        for x, y in zip(X, Y):
            Sx = Sx + x
            Sy = Sy + y
            Sxx = Sxx + x*x
            Syy = Syy + y*y
            Sxy = Sxy + x*y
        det = Sxx * N - Sx * Sx
        return (Sxy * N - Sy * Sx)/det, (Sxx * Sy - Sx * Sxy)/det
Exemplo n.º 7
0
class XBeeTXFrame(XBeeFrameBase):

    """Generate TX command frame

    Parameters:
        dest_addr: 2 byte hex address of remote xbee to send AT command to.
            Default value when left blank is "FF FF" which sends a broadcast.
        data: Data to send, default maximum is 100 bytes
        frame_id: Hidden parameter to set frame_id
    """

    version = VersionProperty(version='1.0.0')
    data = Property(title="Data", default="{{ $.to_dict() }}")
    dest_addr = Property(title='Destination Address \
                         (2 bytes hex, ex: "00 05")',
                         default='',
                         allow_none=True)
    frame_id = Property(title='Frame id', 
                        default="{{ $frame_id }}", 
                        hidden=True)

    def process_signals(self, signals):
        for signal in signals:
            data_encoded = "{}".format(self.data(signal)).encode()
            dest_addr = \
                binascii.unhexlify(self.dest_addr(signal).replace(" ", "")) \
                if self.dest_addr(signal) else None
            try:
                frame_id = binascii.unhexlify(self.frame_id(signal))
                self.logger.debug("Frame ID = {}".format(frame_id))
            except:
                frame_id = None
            self.logger.debug('Creating frame, data: {}'.format(data_encoded))
            # tx: 0x01 "Tx (Transmit) Request: 16-bit address"
            # frame_id: 0x01
            # dest_addr: 0xFFFF is the broadcast address
            # data: RF data bytes to be transmitted
            #
            # frame_id is an arbitrary value, 1 hex byte, used to associate
            # sent packets with their responses. If set to 0 no response will
            # be sent. Could be a block property.
            packet = self._xbee._build_command('tx',
                        frame_id=frame_id or b'\x01',
                        dest_addr=dest_addr or b'\xFF\xFF',
                        data=data_encoded)
            self.notify_signals([Signal( { "frame" :
                        self._API_frame_packer(packet)
                        } )])
Exemplo n.º 8
0
class XBeeATCommand(XBeeBase):

    """ Execute AT commands
    Parameters:
        command: The command to execute, ex. 'D0', WR'
        parameter: The command parameter, ex. '05' for 'D0' command
           to set pin high
    """

    version = VersionProperty(version='0.1.0')
    command = Property(title='AT Command (ascii)',
                       default='ID')
    parameter = Property(title='Command Parameter (hex, ex: "05")', default='')

    def process_signals(self, signals):
        for signal in signals:
            try:
                command = self.command(signal)
                parameter = self.parameter(signal).replace(" ", "")
                self._at(command, parameter)
            except:
                self.logger.exception("Failed to execute at command")

    def _at(self, command, parameter):
        command = command.encode('ascii')
        parameter = binascii.unhexlify(parameter)
        self.logger.debug(
            "Executing AT command: {}, with parameter: {}".format(
                command, parameter)
        )
        # at: 0x08 "AT Command"
        # frame_id: 0x01
        # data: RF data bytes to be transmitted
        # command: The command to execute, ex. 'D0', WR'
        # parameter: The command parameter, ex. b'\x05' for 'D0' command
        #    to set pin high
        #
        # frame_id is an arbitrary value, 1 hex byte, used to associate sent
        # packets with their responses. If set to 0 no response will be sent.
        # Could be a block property.
        self._xbee.send('at',
                        frame_id=b'\x01',
                        command=command,
                        parameter=parameter)
Exemplo n.º 9
0
class IdentityIntervalSimulator(MultipleSignals, IdentityGenerator,
                                IntervalTrigger, GeneratorBlock):

    version = VersionProperty('1.2.0')
Exemplo n.º 10
0
class CounterSafeSimulator(CounterGenerator, SafeTrigger, GeneratorBlock):

    version = VersionProperty('1.1.0')
class StateBase(Persistence, GroupBy, Block):

    """ A base block mixin for keeping track of state """

    state_expr = Property(
        title='State ', default='{{ $state }}', allow_none=True, order=0)
    initial_state = Property(
        title='Initial State', default='{{ None }}', allow_none=True, order=1)
    version = VersionProperty('0.1.0')

    def __init__(self):
        super().__init__()
        self._initial_state = None
        self._state_locks = defaultdict(Lock)
        self._safe_lock = Lock()
        self._states = {}

    def persisted_values(self):
        """Persist states using block mixin."""
        return ["_states"]

    def configure(self, context):
        super().configure(context)
        # Store a cached copy of what a new state should look like
        self._initial_state = self.initial_state(Signal())

    def get_state(self, group):
        """ Return the current state for a group.

        If the state has not been set yet, this function will return the
        initial state configured for the block. It will also set that as the
        state.
        """
        if group not in self._states:
            self._states[group] = copy(self._initial_state)
        return self._states[group]

    def process_signals(self, signals, input_id=None):
        """ Process incoming signals.

        This block is a helper, it will just call _process_group and
        notify any signals that get appeneded to the to_notify list.

        Most likely, _process_group will be overridden in subclasses instead
        of this method.
        """
        self.logger.debug(
            "Ready to process {} incoming signals".format(len(signals)))
        signals_to_notify = defaultdict(list)
        with self._safe_lock:
            group_result = self.for_each_group(
                self._process_group, signals, input_id=input_id,
                signals_to_notify=signals_to_notify)
            if group_result:
                signals_to_notify[None] = group_result
        for output_id in signals_to_notify:
            if output_id:
                self.notify_signals(signals_to_notify[output_id],
                                    output_id=output_id)
            else:
                self.notify_signals(signals_to_notify[output_id])

    def _process_group(self, signals, group, input_id, signals_to_notify=None):
        """ Implement this method in subclasses to process signals in a group.

        Return:
            list or dict(list): The list of signals to be nofified. If
                notifying to a non-default input, return a dict with the key
                as the output id.
        """
        pass

    def _process_state(self, signal, group):
        """ Changes state based on a signal and a group.

        If the signal cannot be processed, the state remains unchanged.

        Returns:
            Tuple: (prev_sate, new_state) if the state was changed
            None - if the state did not change
        """
        with self._state_locks[group]:
            prev_state = self.get_state(group)
            new_state = self.state_expr(signal)

            if new_state != prev_state:
                # notify signal if there was a prev_state and
                # the state has changed.
                self.logger.debug(
                    "Changing state from {} to {} for group {}".format(
                        prev_state, new_state, group))
                self._states[group] = new_state

                return (prev_state, new_state)

    def current_state(self, group):
        """ Command that returns the current state of a group """
        if group is None:
            return_list = []
            with self._safe_lock:
                for group in self._states:
                    return_list.append({"group": group,
                                        "state": self._states[group]})
            return return_list
        if group in self._states:
            return {"group": group,
                    "state": self._states[group]}
        else:
            raise HTTPNotFound()
Exemplo n.º 12
0
class HostSpecs(Block):

    version = VersionProperty("0.1.0")
    menu = ObjectProperty(Menu, title='Menu', default=Menu())

    def __init__(self):
        super().__init__()
        self._retry_count = 0

    def process_signals(self, signals):
        plat = self.platform()
        self.notify_signals([Signal(plat)])

    def platform(self):
        '''Returns platform data
        '''
        keys = []
        out = {}

        if self.menu().machine():
            keys.append('machine')
        if self.menu().os_version():
            keys.append('version')
        if self.menu().platform():
            keys.append('platform')
        if self.menu().dist():
            keys.append('dist')
        if self.menu().system():
            keys.append('system')
        if self.menu().node():
            keys.append('node')
        if len(keys) > 0:
            out = {key: getattr(platform, key)() for key in tuple(keys)}
        if self.menu().python():
            out['python'] = {
                key: getattr(platform, "python_" + key)()
                for key in ('implementation', 'compiler', 'version')
            }
            out['python']['architecture'] = \
                int(ctypes.sizeof(ctypes.c_voidp) * 8)
        if self.menu().processor():
            out['processor'] = self._get_processor()
            out['cores'] = len(psutil.cpu_percent(percpu=True))
        if self.menu().mac():
            out['MAC'] = hex(get_mac())[2:].upper()

        return out

    def _get_processor(self):
        '''Get type of processor
        http://stackoverflow.com/questions/4842448/
        getting-processor-information-in-python
        '''
        out = None
        if platform.system() == "Windows":
            out = platform.processor()
        elif platform.system() == "Darwin":
            path = os.environ['PATH']
            os.environ['PATH'] = os.environ['PATH'] + os.pathsep + '/usr/sbin'
            try:
                command = "sysctl -n machdep.cpu.brand_string"
                out = subprocess.check_output(command, shell=True)\
                    .strip().decode()
            finally:
                os.environ['PATH'] = path
        elif platform.system() == "Linux":
            command = "cat /proc/cpuinfo"
            all_info = subprocess.check_output(command, shell=True)\
                .strip().decode()
            for line in all_info.split("\n"):
                if "model name" in line:
                    out = re.sub(".*model name.*:", "", line, 1)
            if "Hz" not in out:
                command_add = "lscpu | grep MHz"
                clock_info = subprocess.check_output(command_add, shell=True)\
                    .strip().decode()
                out = out + ' ' + \
                    [n for n in clock_info.split('\n')][0].split()[3] + "MHz"

        if out is None:
            return platform.processor()
        else:
            return out
Exemplo n.º 13
0
class ControlBands(GroupBy, Persistence, Block):

    band_interval = TimeDeltaProperty(default={"days": 1},
                                      title="Band Interval")
    value_expr = Property(default="{{ $value }}", title="Value")
    version = VersionProperty("1.0.2")

    def __init__(self):
        super().__init__()
        self._band_values = defaultdict(list)
        self._signals_lock = Lock()

    def process_signals(self, signals, input_id='default'):
        sigs_out = self.for_each_group(self.record_values, signals)
        if sigs_out:
            self.notify_signals(sigs_out)

    def persisted_values(self):
        """ Overridden from persistence mixin """
        return ['_band_values']

    def record_values(self, signals, group):
        """ Save the time and the list of signals for each group.

        This will return signals with the mean/band data included on them """
        sigs_out = []

        with self._signals_lock:
            ctime = _time()
            # First get rid of the old values
            self.trim_old_values(group, ctime)

            prev_values = self._get_current_values(group)
            self.logger.debug(
                "Previous values for group: {}".format(prev_values))
            # Start off a new band data using the latest value from the
            # previous band data objects
            new_values = BandData(prev_values.last_val)

            for sig in signals:
                try:
                    # the value must be a floating point value
                    value = float(self.value_expr(sig))

                    # Add the moving range data to the signal and add it to
                    # the list of signals to notify
                    sigs_out.append(
                        self._enrich_signal(sig, prev_values + new_values,
                                            value))

                    # Now account for the latest value in the moving range data
                    new_values.register_value(value)
                except:
                    self.logger.exception(
                        "Unable to determine value for signal {}".format(sig))

            # Archive the new values
            if new_values.count_items:
                self._band_values[group].append((ctime, new_values))

        return sigs_out

    def _enrich_signal(self, signal, band_data, value):
        """ Add relevant band data to the signal.

        Args:
            signal: The signal that we should add data to
            band_data (BandData): A single BandData object containing the
                current moving range information
            value: The value this signal contributed to the band data. This is
                used to determine how many deviations from the mean it is.

        Returns:
            The signal with updated data
        """
        range_mean = band_data.get_mean()
        range_deviation = band_data.get_range()
        if range_deviation != 0:
            deviations = (value - range_mean) / range_deviation
        else:
            deviations = 0

        class BandSignalData():
            def __init__(self, value, mean, deviation, deviations):
                self.value = value
                self.mean = mean
                self.deviation = deviation
                self.deviations = deviations

            def to_dict(self):
                """represent all BandSignalData attributes as a dict"""
                return self.__dict__

        setattr(
            signal, 'band_data',
            BandSignalData(value, range_mean, range_deviation,
                           deviations).to_dict())

        return signal

    def _get_current_values(self, group):
        """ Returns a single BandData object for a group.

        This will make use of the __add__ function in the BandData class to
        sum together all of the current data points in the group. The result
        will be a single BandData object with all of the previously saved
        points accounted for. """
        cur_values = self._band_values[group]
        if len(cur_values) > 1:
            # Sum every BandData (after the first), using the first one as
            # the starting point
            return sum([data[1] for data in cur_values[1:]], cur_values[0][1])
        elif len(cur_values) == 1:
            return cur_values[0][1]
        else:
            return BandData()

    def trim_old_values(self, group, ctime):
        """ Remove any "old" saved values for a given group """
        group_values = self._band_values[group]
        self.logger.debug("Trimming old values - had {} items".format(
            len(group_values)))
        group_values[:] = [
            data for data in group_values
            if data[0] > ctime - self.band_interval().total_seconds()
        ]
        self.logger.debug("Now has {} items".format(len(group_values)))
Exemplo n.º 14
0
class XBeeRemoteATFrame(XBeeFrameBase):

    """Generate Remote AT command frame

    Parameters:
        command: The command to execute, ex. 'D0', WR'
        parameter: The command parameter, ex. '05' for 'D0' command
           to set pin high
        dest_addr: 2 or 8 byte address of remote xbee to send AT command to.
            must be 8 bytes when using digimesh.
            Default value when left blank is "FF FF" which sends a broadcast.
        frame_id: Hidden parameter to set frame_id
    """

    version = VersionProperty(version='1.0.0')
    command = Property(title='AT Command (ascii)', default='ID')
    parameter = Property(title='Command Parameter (hex, ex: "05")', default='')
    dest_addr = Property(title='Destination Address \
                         (2 or 8 bytes hex, ex: "00 05")',
                         default='',
                         allow_none=True)
    frame_id = Property(title='Frame id', 
                        default="{{ $frame_id }}", 
                        hidden=True)

    def process_signals(self, signals):
        for signal in signals:
            try:
                command = self.command(signal).encode('ascii')
                parameter = \
                    binascii.unhexlify(self.parameter(signal).replace(" ", ""))
                dest_addr = \
                    binascii.unhexlify(
                        self.dest_addr(signal).replace(" ", "")) \
                        if self.dest_addr(signal) else None
                try:
                    frame_id = binascii.unhexlify(self.frame_id(signal))
                    self.logger.debug("Frame ID = {}".format(frame_id))
                except:
                    frame_id = None
                self._remote_at(command, parameter, dest_addr, frame_id)
            except:
                self.logger.exception("Failed to execute remote at command")

    def _remote_at(self, command, parameter, dest_addr, frame_id):
        self.logger.debug(
            "Executing Remote AT command: {}, with parameter: {}".format(
                command, parameter))
        # remote_at: 0x17 "Remote AT Command"
        # frame_id: 0x01
        # dest_addr: 0xFFFF broadcasts to all XBees
        # data: RF data bytes to be transmitted
        # command: The command to execute, ex. 'D0', WR'
        # parameter: The command parameter, ex. b'\x05' for 'D0' command
        #    to set pin high
        #
        # frame_id is an arbitrary value, 1 hex byte, used to associate sent 
        # packets with their responses. If set to 0 no response will be sent.
        # Could be a block property.
        if dest_addr is not None and len(dest_addr) == 8:
            packet = self._xbee._build_command('remote_at',
                    frame_id=frame_id or b'\x01',
                    dest_addr_long=dest_addr or 
                        b'\x00\x00\x00\x00\x00\x00\xFF\xFF',
                    command=command,
                    parameter=parameter)
        else:
            packet = self._xbee._build_command('remote_at',
                    frame_id=frame_id or b'\x01',
                    dest_addr=dest_addr or b'\xFF\xFF',
                    command=command,
                    parameter=parameter)
        self.notify_signals([Signal( { "frame" :
                    self._API_frame_packer(packet)
                    } )])
Exemplo n.º 15
0
class CounterIntervalSimulator(MultipleSignals, CounterGenerator,
                               IntervalTrigger, GeneratorBlock):

    version = VersionProperty("0.2.0")
Exemplo n.º 16
0
class FileIntervalSimulator(MultipleSignals, FileGenerator, IntervalTrigger,
                            GeneratorBlock):

    version = VersionProperty('1.3.0')
Exemplo n.º 17
0
class IdentityCronSimulator(MultipleSignals, IdentityGenerator, CronTrigger,
                            GeneratorBlock):

    version = VersionProperty('0.1.0')
Exemplo n.º 18
0
class XBeeRemoteAT(XBeeBase):
    """Execute Remote AT commands.

    Parameters:
        command: The command to execute, ex. 'D0', WR'
        parameter: The command parameter, ex. '05' for 'D0' command
           to set pin high
        dest_addr: 2 or 8 byte address of remote xbee to send AT command to.
            must be 8 bytes when using digimesh.
            Default value when left blank is "FF FF" which sends a broadcast.
    """

    version = VersionProperty(version='0.1.0')
    command = Property(title='AT Command (ascii)', default='ID')
    parameter = Property(title='Command Parameter (hex, ex: "05")', default='')
    dest_addr = Property(title='Destination Address \
                         (2 or 8 bytes hex, ex: "00 05")',
                         default='',
                         allow_none=True)

    def process_signals(self, signals):
        for signal in signals:
            try:
                command = self.command(signal).encode('ascii')
                parameter = binascii.unhexlify(
                    self.parameter(signal).replace(" ", ""))
                dest_addr = binascii.unhexlify(
                    self.dest_addr(signal).replace(" ", "")) if \
                    self.dest_addr(signal) else None
                self._remote_at(command, parameter, dest_addr)
            except:
                self.logger.exception("Failed to execute remote at command")

    def _remote_at(self, command, parameter, dest_addr):
        self.logger.debug(
            "Executing Remote AT command: {}, with parameter: {}".format(
                command, parameter))
        # remote_at: 0x17 "Remote AT Command"
        # frame_id: 0x01
        # dest_addr: 0xFFFF broadcasts to all XBees
        # data: RF data bytes to be transmitted
        # command: The command to execute, ex. 'D0', WR'
        # parameter: The command parameter, ex. b'\x05' for 'D0' command
        #    to set pin high
        #
        # frame_id is an arbitrary value, 1 hex byte, used to associate sent
        # packets with their responses. If set to 0 no response will be sent.
        # Could be a block property.
        if self.digimesh():
            # pass all arguments to work around bug in
            # python-xbee/xbee/digimesh.py where default values are not bytes
            self._xbee.send('remote_at',
                            id=b'\x17',
                            frame_id=b'\x01',
                            dest_addr_long=dest_addr
                            or b'\x00\x00\x00\x00\x00\x00\xFF\xFF',
                            reserved=b'\xFF\xFE',
                            options=b'\x02',
                            command=command,
                            parameter=parameter)
        else:
            self._xbee.send('remote_at',
                            frame_id=b'\x01',
                            dest_addr=dest_addr or b'\xFF\xFF',
                            command=command,
                            parameter=parameter)