コード例 #1
0
class MessageHandler():
    '''
    This handler just displays IFS IR events as they arrive.
    '''
    def __init__(self, level):
        super().__init__()
        self._counter = itertools.count()
        self._log = Logger("queue", Level.INFO)
        self._ir = ['PSID', 'PORT', 'CNTR', 'STBD', 'SSID']
        self._log.info('ready.')

    # ......................................................
    def handle(self, message):
        self._log.debug('handle message #{}: priority {}: {}'.format(
            message.number, message.priority, message.description))
        _event = message.event
        self._ir[
            0] = Fore.RED + Style.BRIGHT + 'PSID' if _event is Event.INFRARED_PORT_SIDE else Fore.BLACK + Style.DIM + '....'
        self._ir[
            1] = Fore.RED + Style.NORMAL + 'PORT' if _event is Event.INFRARED_PORT else Fore.BLACK + Style.DIM + '....'
        self._ir[
            2] = Fore.BLUE + Style.BRIGHT + 'CNTR' if _event is Event.INFRARED_CNTR else Fore.BLACK + Style.DIM + '....'
        self._ir[
            3] = Fore.GREEN + Style.NORMAL + 'STBD' if _event is Event.INFRARED_STBD else Fore.BLACK + Style.DIM + '....'
        self._ir[
            4] = Fore.GREEN + Style.BRIGHT + 'SSID' if _event is Event.INFRARED_STBD_SIDE else Fore.BLACK + Style.DIM + '....'
        print('{} '.format(self._ir[0])    \
               + '{} '.format(self._ir[1]) \
               + '{} '.format(self._ir[2]) \
               + '{} '.format(self._ir[3]) \
               + '{} '.format(self._ir[4]) + Style.RESET_ALL, end='\n')
コード例 #2
0
class MessageBus():
    '''
    Message Bus description.
    '''
    def __init__(self, level=Level.INFO):
        self._log = Logger('bus', level)
        self._log.debug('initialised...')
        self._subscriptions = set()
        self._log.debug('ready.')

    # ..........................................................................
    @property
    def subscriptions(self):
        '''
        Return the current set of Subscriptions.
        '''
        return self._subscriptions

    # ..........................................................................
    async def publish_to_bus(self, message: Message):
        '''
        Publishes the Message to all Subscribers.
        '''
        self._log.info(Style.BRIGHT + 'publish message: eid: {}; event: {}'.format(message.eid, message.event.name))
        for queue in self._subscriptions:
            queue.put_nowait(message)
コード例 #3
0
class Toggle(object):
    '''
    Returns a boolean value indicating the state of a toggle switch connected
    to the specified GPIO pin. The pin is pulled high in software by default
    ("off") and returns False, and connected to ground when switched "on",
    returning True.

    :param pin:       the BCM pin to which the switch is connected
    :param level:     log level
    '''
    def __init__(self, pin, level):
        self._log = Logger("toggle", level)
        self._log.info('configuring toggle on pin {}'.format(pin))
        self._pin = pin
        # The GPIO pin is set up as an input, pulled up to avoid false
        # detection. The pin is wired to connect to GND on button press.
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(self._pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
        self._log.info('ready.')

    # ......................................................
    @property
    def state(self):
        '''
        Returns True when the toggle switch is turned on (connected to ground).
        '''
        _state = False if GPIO.input(self._pin) else True
        self._log.debug('state on pin {}: {}'.format(self._pin, _state))
        return _state

    # ......................................................
    def close(self):
        GPIO.cleanup()  # clean up GPIO on normal exit
        self._log.info('closed.')
コード例 #4
0
ファイル: gamepad.py プロジェクト: SiChiTong/ros-1
class GamepadScan(object):
    '''
    Returns the device with the most recently changed status from /dev/input/event{n}
    This can help you figure out which device is your gamepad, if if was connected
    after everything else in the system had settled.
    '''
    def __init__(self, config, level):
        self._log = Logger("gamepad-scan", level)
        if config is None:
            raise ValueError("no configuration provided.")
        _config = config['ros'].get('gamepad')
        self._device_path = _config.get('device_path')
        self._log.debug('device path: {}'.format(self._device_path))
        self._log.info('ready')

    # ..........................................................................
    def _get_ctime(self, path):
        try:
            _device_stat = os.stat(path)
            return _device_stat.st_ctime
        except OSError:
            return -1.0

    # ..........................................................................
    def get_latest_device(self):
        '''
        Build a dictionary of available devices, return the one with the
        most recent status change.
        '''
        _dict = {}
        for i in range(10):
            _path = '/dev/input/event{}'.format(i)
            try:
                _device_stat = os.stat(_path)
                _ctime = _device_stat.st_ctime
            except OSError:
                break
            self._log.debug('device: {}'.format(_path) + Fore.BLUE + Style.NORMAL + '\tstatus changed: {}'.format(dt.datetime.fromtimestamp(_ctime)))
            _dict[_path] = _ctime
        # find most recent by sorting the dictionary on ctime
        _sorted = sorted(_dict.items(), key=lambda x:x[1])
        _latest_devices = _sorted[len(_sorted)-1]
        _latest_device = _latest_devices[0]
        self._log.info('device path:        {}'.format(self._device_path))
        self._log.info('most recent device: {}'.format(_latest_device))
        return _latest_device

    # ..........................................................................
    def check_gamepad_device(self):
        '''
        Checks that the configured device matches the device with the most
        recently changed status, returning True if matched.
        '''
        _latest_device = self.get_latest_device()
        if self._device_path == _latest_device:
            self._log.info(Style.BRIGHT + 'matches:            {}'.format(self._device_path))
            return True
        else:
            self._log.info(Style.BRIGHT + 'does not match:     {}'.format(_latest_device))
            return False
コード例 #5
0
class ConfigLoader():
    '''
        Has just one method: configure() reads a YAML file.
    '''
    def __init__(self, level):
        self._log = Logger('configloader', level)
        self._log.info('ready.')

    # ..........................................................................
    def configure(self, filename='config.yaml'):
        '''
        Read and return configuration from the specified YAML file.

        Pretty-prints the configuration object if the log level is set to DEBUG.
        '''
        self._log.info(
            'reading from yaml configuration file {}...'.format(filename))
        _config = yaml.safe_load(open(filename, 'r'))
        if self._log.level == Level.DEBUG:
            self._log.debug('YAML configuration as read:')
            print(Fore.BLUE)
            pp = pprint.PrettyPrinter(width=80, indent=2)
            pp.pprint(_config)
            print(Style.RESET_ALL)
        self._log.info('configuration read.')
        return _config
コード例 #6
0
class FlaskWrapperService(threading.Thread):
    def __init__(self):
        global g_queue
        super().__init__()
        self._log = Logger('flask.wrapper', Level.INFO)
        g_queue = MockMessageQueue()
        threading.Thread.__init__(self)
        self._thread = None
        self._log.debug('ready')

    # ..........................................................................
    def run(self):
        global app
        self._log.info('starting flask wrapper...')
        # suppress console log messages (this doesn't actually work)
        _flask_log = logging.getLogger('werkzeug')
        _flask_log.setLevel(logging.ERROR)
        _flask_log.disabled = True
        #       socketio.run(app)
        self._thread = threading.Thread(target=app.run(
            host='0.0.0.0', port=8085, debug=False, use_reloader=False))
        self._thread.start()
        #       app.run(host='0.0.0.0', port=8085, debug=False, use_reloader=False)
        self._log.info('ended flask thread.')

    # ..........................................................................
    def close(self):
        self._log.info('closing flask.')
        if self._thread != None:
            self._thread.join(timeout=1.0)
            self._log.info('flask app thread joined.')
        self._log.info('closed flask.')
コード例 #7
0
ファイル: i2c_scanner.py プロジェクト: bopopescu/ros
class I2CScanner():
    '''
        Scans the I2C bus returning a list of addresses.
    '''

    def __init__(self, level):
        super().__init__()
        self._log = Logger('i2cscan', level)
        self._log.debug('initialising...')
        self.hex_list = []
        try:
            import smbus
            bus_number = 1  # 1 indicates /dev/i2c-1
            self._bus = smbus.SMBus(bus_number)
            self._log.info('ready.')
        except ImportError:
            self._log.warning('initialised. This script requires smbus. Will operate without but return an empty result.')
            self._bus = None


    def getHexAddresses(self):
        '''
            Returns a hexadecimal version of the list. This is only populated after calling getAddresses().
        '''
        return self.hex_list


    def getIntAddresses(self):
        '''
            Returns an integer version of the list. This is only populated after calling getAddresses().
        '''
        return self._int_list


    def getAddresses(self):
        self._int_list = []
        device_count = 0
        if self._bus is not None:
            for address in range(3, 128):
                try:
                    self._bus.write_byte(address, 0)
                    self._log.debug('found {0}'.format(hex(address)))
                    self._int_list.append(address)
                    self.hex_list.append(hex(address))
                    device_count = device_count + 1
                except IOError as e:
                    if e.errno != errno.EREMOTEIO:
                        self._log.error('Error: {0} on address {1}'.format(e, hex(address)))
                except Exception as e: # exception if read_byte fails
                    self._log.error('Error unk: {0} on address {1}'.format(e, hex(address)))
        
            self._bus.close()
            self._bus = None
            self._log.info("found {0} device(s)".format(device_count))
        else:
            self._log.info("found no devices (no smbus available)")
        return self._int_list
コード例 #8
0
def main():

    signal.signal(signal.SIGINT, signal_handler)

    _log = Logger("scanner", Level.INFO)
    _log.info(Fore.CYAN + Style.BRIGHT + ' INFO  : starting test...')
    _log.info(Fore.YELLOW + Style.BRIGHT + ' INFO  : Press Ctrl+C to exit.')

    try:
        _i2c_scanner = I2CScanner(Level.WARN)
        _addresses = _i2c_scanner.getAddresses()
        hexAddresses = _i2c_scanner.getHexAddresses()
        _addrDict = dict(
            list(map(lambda x, y: (x, y), _addresses, hexAddresses)))
        for i in range(len(_addresses)):
            _log.debug(Fore.BLACK + Style.DIM +
                       'found device at address: {}'.format(hexAddresses[i]))

        vl53l1x_available = (0x29 in _addresses)
        ultraborg_available = (0x36 in _addresses)

        if not vl53l1x_available:
            raise OSError('VL53L1X hardware dependency not available.')
        elif not ultraborg_available:
            raise OSError('UltraBorg hardware dependency not available.')

        _log.info('starting scan...')
        #       _player = Player(Level.INFO)

        _loader = ConfigLoader(Level.INFO)
        filename = 'config.yaml'
        _config = _loader.configure(filename)

        _lidar = Lidar(_config, Level.INFO)
        _lidar.enable()
        values = _lidar.scan()

        _angle_at_min = values[0]
        _min_mm = values[1]
        _angle_at_max = values[2]
        _max_mm = values[3]
        _log.info(
            Fore.CYAN + Style.BRIGHT +
            'min. distance at {:>5.2f}°:\t{}mm'.format(_angle_at_min, _min_mm))
        _log.info(
            Fore.CYAN + Style.BRIGHT +
            'max. distance at {:>5.2f}°:\t{}mm'.format(_angle_at_max, _max_mm))
        time.sleep(1.0)
        _lidar.close()
        _log.info(Fore.CYAN + Style.BRIGHT + 'test complete.')

    except Exception:
        _log.info(traceback.format_exc())
        sys.exit(1)
コード例 #9
0
def main():

    _log = Logger("cat-scan test", Level.INFO)

    _log.info('starting test...')
    _log.info(Fore.YELLOW + Style.BRIGHT + ' INFO  : Press Ctrl+C to exit.')

    try:

        _i2c_scanner = I2CScanner(Level.WARN)
        _addresses = _i2c_scanner.getAddresses()
        hexAddresses = _i2c_scanner.getHexAddresses()
        _addrDict = dict(list(map(lambda x, y:(x,y), _addresses, hexAddresses)))
        for i in range(len(_addresses)):
            _log.debug(Fore.BLACK + Style.DIM + 'found device at address: {}'.format(hexAddresses[i]) + Style.RESET_ALL)
        ultraborg_available = ( 0x36 in _addresses )
    
        if not ultraborg_available:
            raise OSError('UltraBorg hardware dependency not available.')

        _log.info('starting cat scan...')

        _loader = ConfigLoader(Level.INFO)
        filename = 'config.yaml'
        _config = _loader.configure(filename)

        _queue = MockMessageQueue(Level.INFO)
        _catscan = CatScan(_config, _queue, Level.INFO)
        _catscan.enable()

        _catscan.set_mode(True)

        _count = 0
        while not _queue.is_complete():
            if _count % 5 == 0:
                _log.info('waiting for cat... ' + Fore.BLACK + Style.DIM + '({:d} sec)'.format(_count))
            time.sleep(1.0)
            _count += 1

        time.sleep(9.0)

        _catscan.close()
        _log.info('test complete.')

    except KeyboardInterrupt:
        if _catscan:
            _catscan.close()

    except Exception:
        _log.info(traceback.format_exc())

    finally:
        if _catscan:
            _catscan.close()
コード例 #10
0
ファイル: follower_test.py プロジェクト: bopopescu/ros
def main():

    signal.signal(signal.SIGINT, signal_handler)

    print('follower test     :' + Fore.CYAN + Style.BRIGHT + ' INFO  : starting test...' + Style.RESET_ALL)
    print('follower test     :' + Fore.YELLOW + Style.BRIGHT + ' INFO  : Press Ctrl+C to exit.' + Style.RESET_ALL)

    _log = Logger("follower", Level.INFO)

    try:

        _i2c_scanner = I2CScanner(Level.WARN)
        _addresses = _i2c_scanner.getAddresses()
        hexAddresses = _i2c_scanner.getHexAddresses()
        _addrDict = dict(list(map(lambda x, y:(x,y), _addresses, hexAddresses)))
        for i in range(len(_addresses)):
            _log.debug(Fore.BLACK + Style.DIM + 'found device at address: {}'.format(hexAddresses[i]) + Style.RESET_ALL)
        vl53l1x_available = ( 0x29 in _addresses )
        ultraborg_available = ( 0x36 in _addresses )
    
        if not vl53l1x_available:
            raise OSError('VL53L1X hardware dependency not available.')
        elif not ultraborg_available:
            raise OSError('UltraBorg hardware dependency not available.')

        _log.info('starting wall follower...')

        _loader = ConfigLoader(Level.INFO)
        filename = 'config.yaml'
        _config = _loader.configure(filename)

        _follower = WallFollower(_config, Level.INFO)
        _follower.enable()

        _follower.set_position(Orientation.PORT)
        time.sleep(1.5)

        _follower.set_position(Orientation.STBD)
        time.sleep(1.5)

#       for i in range(10):
#           mm = _follower.scan()
#           time.sleep(1.0)

        

        _follower.close()
        print('follower test     :' + Fore.CYAN + Style.BRIGHT + ' INFO  : test complete.' + Style.RESET_ALL)


    except Exception:
        _log.info(traceback.format_exc())
        sys.exit(1)
コード例 #11
0
class OutputSplitter(object):
    '''
        An output (as far as picamera is concerned), is just a filename or an object
        which implements a write() method (and optionally the flush() and close() methods)

        If the filename parameter is None no file is written.
    '''
    def __init__(self, filename):
        self.frame = None
        self.buffer = io.BytesIO()
        self._log = Logger('output', Level.INFO)
        self._filename = filename
        if self._filename:
            self._output_file = io.open(filename, 'wb')
            self._log.info(Fore.MAGENTA + 'output file: {}'.format(filename))
        else:
            self._output_file = None
            self._log.info(Fore.MAGENTA +
                           'no output file generated from video.')
        self._condition = Condition()
        self._log.info('ready.')

    def get_filename(self):
        return self._filename

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # new frame, copy existing buffer's content and notify all clients it's available
            self.buffer.truncate()
            with self._condition:
                self.frame = self.buffer.getvalue()
                self._condition.notify_all()
            self.buffer.seek(0)
        if self._output_file and not self._output_file.closed:
            self._output_file.write(buf)
        return self.buffer.write(buf)

    def flush(self):
        self._log.debug('flushing...')
        if self._output_file and not self._output_file.closed:
            self._output_file.flush()
        if not self.buffer.closed:
            self.buffer.flush()
        self._log.debug('flushed.')

    def close(self):
        self._log.info('closing...')
        if self._output_file and not self._output_file.closed:
            self._output_file.close()
        if not self.buffer.closed:
            self.buffer.close()
        self._log.info('closed.')
コード例 #12
0
ファイル: repostinator.py プロジェクト: blejdfist/NeuBot
 def event_url(self, params):
     (url, irc) = params;
     Logger.info("RepostinatorPlugin: Got url '%s' from urlcatcher" % params[0])
     if irc.server.get_current_nick() == irc.message.destination:
         Logger.debug("Got url in priv ignoring")
         return
     key = "%s_%s_%s" % (irc.message.destination, irc.get_ircnet_name(), url)
     data = self.store.get(key);
     if(data):
         irc.reply('This url was first posted in this channel by %s @ %s' % (data[0], data[2]))
     else:
         data = [irc.message.source.nick,  irc.message.destination, time.ctime()]
         self.store.put(key, data);
コード例 #13
0
class MockMessageBus():
    '''
    This message queue just displays filtered, clock-related events as they arrive.
    '''
    def __init__(self, level):
        super().__init__()
        self._counter = itertools.count()
        self._log = Logger("queue", Level.INFO)
        self._start_time = dt.now()
        self._last_time = self._start_time
        self._log.info('ready.')

    # ......................................................
    def set_clock(self, clock):
        self._clock = clock

    # ......................................................
    def add(self, message):
        global tock_count
        message.number = next(self._counter)
        self._log.debug('added message {:06d}: priority {}: {}'.format(
            message.number, message.priority, message.description))
        _event = message.event
        _value = message.value

        _now = dt.now()
        _delta = _now - self._start_time
        _elapsed_ms = (_now - self._last_time).total_seconds() * 1000.0
        _process_delta = _now - message.timestamp
        _elapsed_loop_ms = _delta.total_seconds() * 1000.0
        _process_ms = _process_delta.total_seconds() * 1000.0
        _total_ms = _elapsed_loop_ms + _process_ms

        if SHOW_STATS:
            if _event is Event.CLOCK_TICK:
                #               self._log.info(Fore.YELLOW + Style.NORMAL + 'CLOCK_TICK: {}; value: {}'.format(_event.description, _value))
                self._log.info(Fore.BLACK  + Style.DIM + 'event: {}; proc time: {:8.5f}ms; tick loop: {:5.2f}ms; total: {:5.2f}ms; '.format(\
                        _event.description, _process_ms, _elapsed_loop_ms, _total_ms) + Fore.WHITE + Style.NORMAL \
                        + ' elapsed: {:6.3f}ms; trim: {:7.4f}'.format(_elapsed_ms, self._clock.trim))
            elif _event is Event.CLOCK_TOCK:
                self._log.info(Fore.YELLOW + Style.DIM + 'event: {}; proc time: {:8.5f}ms; tock loop: {:5.2f}ms; total: {:6.3f}ms; '.format(\
                        _event.description, _process_ms, _elapsed_loop_ms, _total_ms) + Fore.WHITE + Style.NORMAL \
                        + ' elapsed: {:6.3f}ms; trim: {:7.4f}'.format(_elapsed_ms, self._clock.trim))
                self._start_time = _now
                tock_count += 1
            else:
                self._log.info(Fore.BLACK + Style.BRIGHT +
                               'other event: {}'.format(_event.description))

        self._last_time = _now
コード例 #14
0
class Lux():
    '''
    Uses the Pimoroni LTR-559 Light and Proximity Sensor to return a lux value.
    '''
    def __init__(self, level):
        self._log = Logger("lux", level)
        self._ltr559 = LTR559()
        self._log.info('ready.')

    def get_value(self):
        self._ltr559.update_sensor()
        _lux = self._ltr559.get_lux()
        self._log.debug("lux: {:06.2f}".format(_lux))
        return _lux
コード例 #15
0
ファイル: tof.py プロジェクト: bopopescu/ros
class TimeOfFlight():
    '''
        This is based on Pimoroni's VL53L1X Time of Flight (ToF) Breakaway Garden board,
        which has a 4-400cm range (27° field of view), up to 50Hz ranging frequency, and
        an accuracy of +/-25mm (+/-20mm in the dark).

    '''
    def __init__(self, range_value, level):
        self._log = Logger("tof", level)
        self._range = range_value
        #       self._tof = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29)
        self._tof = VL53L1X.VL53L1X()
        self._tof.open()
        # Optionally set an explicit timing budget. These values are measurement time
        # in microseconds, and inter-measurement time in milliseconds. If you uncomment
        # the line below to set a budget you should use `self._tof.start_ranging(0)`
        # self._tof.set_timing(66000, 70)

        # lower timing budgets allow for faster updates, but sacrifice accuracy
        if self._range is Range.PERFORMANCE:
            self._tof.set_timing(UPDATE_TIME_MICROS,
                                 INTER_MEASUREMENT_PERIOD_MILLIS)

        self._log.info('ready.')

    # ..........................................................................
    def read_distance(self):
        '''
            Return the range in mm. This function will block until a reading is returned.
        '''
        distance_in_mm = self._tof.get_distance()
        self._log.debug('distance: {:d}mm'.format(distance_in_mm))
        return distance_in_mm

    # ..........................................................................
    def enable(self):
        if self._range is Range.PERFORMANCE:
            self._tof.start_ranging(Range.UNCHANGED.value)
            self._log.info('enabled with high performance.')
        else:
            self._tof.start_ranging(self._range.value)
            self._log.info('enabled with {} range.'.format(self._range.name))

    # ..........................................................................
    def disable(self):
        self._tof.stop_ranging()
        self._log.info('disabled.')
コード例 #16
0
ファイル: plugincontroller.py プロジェクト: blejdfist/NeuBot
    def load_plugin(self, name, search_dir = None):
        name = name.strip()
        import_name = None

        if self._loaded_plugins.has_key(name):
            raise PluginLoadError("Plugin is already loaded")

        import_name = self.find_plugin(name, search_dir)

        if not import_name:
            raise PluginLoadError("No such plugin")

        basename = import_name.rpartition(".")[2]

        try:
            mod = __import__(import_name)
            cls = getattr(mod, basename)
        except Exception as e:
            # Remove the system-entry
            if import_name and sys.modules.has_key(import_name):
                del sys.modules[import_name]

            Logger.log_traceback(self)
            raise PluginLoadError("Failed to load " + import_name)

        # Find the plugin entry point
        for objname in dir(cls):
            obj = getattr(cls, objname)
            if objname != 'Plugin' and type(obj) == types.ClassType and issubclass(obj, Plugin):
                Logger.debug("Plugin entry is '%s'" % objname)
                instance = new.instance(obj)

                # Initialize plugin instance
                instance.store  = DatastoreController().get_store(basename)
                instance.event  = self._eventcontroller
                instance.config = self._config
                instance.nets   = IRCNetsController()
                instance.plugin = self
                instance.__init__()

                self._loaded_plugins[basename.lower()] = (basename, instance, import_name)

                return True

        del sys.modules[import_name]
        raise PluginLoadError("Unable to find entry point")
コード例 #17
0
def main():

    signal.signal(signal.SIGINT, signal_handler)

    print('uscanner_test      :' + Fore.CYAN + Style.BRIGHT +
          ' INFO  : starting test...' + Style.RESET_ALL)
    print('uscanner_test      :' + Fore.YELLOW + Style.BRIGHT +
          ' INFO  : Press Ctrl+C to exit.' + Style.RESET_ALL)

    _log = Logger("uscanner", Level.INFO)
    try:
        _scanner = I2CScanner(Level.WARN)
        _int_addresses = _scanner.get_int_addresses()
        _hex_addresses = _scanner.get_hex_addresses()
        _addrDict = dict(
            list(map(lambda x, y: (x, y), _int_addresses, _hex_addresses)))
        for i in range(len(_int_addresses)):
            _log.debug(
                Fore.BLACK + Style.DIM +
                'found device at address: {}'.format(_hex_addresses[i]) +
                Style.RESET_ALL)
        ultraborg_available = (0x36 in _int_addresses)

        if ultraborg_available:
            _log.info('starting ultrasonic scan...')

            _loader = ConfigLoader(Level.INFO)
            filename = 'config.yaml'
            _config = _loader.configure(filename)

            _scanner = UltrasonicScanner(_config, Level.INFO)
            _scanner.enable()
            values = _scanner.scan()
            time.sleep(1.0)
            _scanner.close()
        else:
            _log.error('required hardware dependencies not available.')

        print('uscanner_test      :' + Fore.CYAN + Style.BRIGHT +
              ' INFO  : test complete.' + Style.RESET_ALL)

    except Exception:
        _log.info(traceback.format_exc())
        sys.exit(1)
コード例 #18
0
ファイル: front_test.py プロジェクト: bopopescu/ros
class MockMessageQueue():
    '''
        This message queue waits for one CAT_SCAN event.
    '''
    def __init__(self, level):
        super().__init__()
        self._log = Logger("mock-queue", Level.INFO)
        self._counter = itertools.count()
        self._experienced_event = False

    # ......................................................
    def add(self, message):
        message.set_number(next(self._counter))
        self._log.debug('added message #{}: priority {}: {}'.format(
            message.get_number(), message.get_priority(),
            message.get_description()))
        event = message.get_event()
        if event is Event.INFRARED_STBD_SIDE:
            self._log.info(Fore.GREEN + Style.BRIGHT +
                           'event: {};\tvalue: {:d}'.format(
                               event.description, message.get_value()))
        elif event is Event.INFRARED_STBD:
            self._log.info(Fore.GREEN + Style.BRIGHT +
                           'event: {};\tvalue: {:d}'.format(
                               event.description, message.get_value()))
        elif event is Event.INFRARED_CENTER:
            self._log.info(Fore.BLUE + Style.BRIGHT +
                           'event: {};\tvalue: {:d}'.format(
                               event.description, message.get_value()))
        elif event is Event.INFRARED_PORT:
            self._log.info(Fore.RED + Style.BRIGHT +
                           'event: {};\tvalue: {:d}'.format(
                               event.description, message.get_value()))
        elif event is Event.INFRARED_PORT_SIDE:
            self._log.info(Fore.RED + Style.BRIGHT +
                           'event: {};\tvalue: {:d}'.format(
                               event.description, message.get_value()))
        else:
            self._log.info(Fore.RED +
                           'other event: {}'.format(event.description))

    # ......................................................
    def is_complete(self):
        return self._experienced_event
コード例 #19
0
class TickHandler(object):
    def __init__(self, ifs, level):
        super().__init__()
        self._ifs = ifs
        self._log = Logger('tick-hand', level)
        self._log.info('ready.')

    # ..........................................................................
    def tick(self, message):
        #       self._log.info(Fore.GREEN + 'th.rx tick: {}::{}'.format(message.description, message.value))
        #       self._ifs.add(message)
        pass

    # ..........................................................................
    def tock(self, message):
        self._log.debug(
            Fore.GREEN + Style.BRIGHT +
            'th.rx tock: {}::{}'.format(message.description, message.value))
        pass
コード例 #20
0
def test_moth():
    '''
    Test the basic functionality of the Moth sensor's various outputs.
    The test is entirely visual, i.e., something to be looked at, tested
    with a bright light source.
    '''
    _log = Logger("test", Level.INFO)
    # read YAML configuration
    _loader = ConfigLoader(Level.INFO)
    filename = 'config.yaml'
    _config = _loader.configure(filename)
    _moth = Moth(_config, None, Level.INFO)

    _rgbmatrix = RgbMatrix(Level.INFO)
    _rgbmatrix.set_display_type(DisplayType.SOLID)

#   for i in range(50):
    while True:
        # orientation and bias .............................
        _orientation = _moth.get_orientation()
        _bias = _moth.get_bias()
        _log.debug('bias: {}; orientation: {}'.format(type(_bias), _orientation))
        if _orientation is Orientation.PORT:
            _rgbmatrix.show_color(Color.BLACK, Orientation.STBD)
            _rgbmatrix.show_color(Color.RED, Orientation.PORT)
            _log.info(Fore.RED    + Style.BRIGHT + '{}\t {:<6.3f}'.format(_orientation.name, _bias[0]))
        elif _orientation is Orientation.STBD:
            _rgbmatrix.show_color(Color.BLACK, Orientation.PORT)
            _rgbmatrix.show_color(Color.GREEN, Orientation.STBD)
            _log.info(Fore.GREEN  + Style.BRIGHT + '{}\t {:<6.3f}'.format(_orientation.name, _bias[1]))
        else:
            _rgbmatrix.show_color(Color.YELLOW, Orientation.PORT)
            _rgbmatrix.show_color(Color.YELLOW, Orientation.STBD)
            _log.info(Fore.YELLOW + '{}\t {:6.3f}|{:6.3f}'.format(_orientation.name, _bias[0], _bias[1]))
        # int values .......................................
        _int_values = _moth.get_int_values()
        _log.info(Fore.RED   + '{:d}\t'.format(_int_values[0]) + Fore.GREEN + '{:d}\t'.format(_int_values[1]) )
        # float values .....................................
        _values = _moth.get_values()
        _log.info(Fore.RED   + '{:<6.3f}\t'.format(_values[0]) + Fore.GREEN + '{:<6.3f}\t'.format(_values[1]) )
#       time.sleep(1.0)
        time.sleep(0.1)
コード例 #21
0
class Publisher(ABC):
    '''
    Abstract publisher, subclassed by any classes that publish to a MessageBus.
    '''
    def __init__(self, message_factory, message_bus, level=Level.INFO):
        self._log = Logger('pub', level)
        self._log.info(Fore.MAGENTA + 'Publisher: create.')
        self._message_factory = message_factory
        self._message_bus = message_bus
        self._counter = itertools.count()
        self._log.debug('ready.')

    # ..........................................................................
    def get_message_of_type(self, event, value):
        '''
        Provided an Event type and a message value, returns a Message
        generated from the MessageFactory.
        '''
        return self._message_factory.get_message(event, value)

    def get_random_event_type(self):
        types = [ Event.STOP, Event.INFRARED_PORT, Event.INFRARED_STBD, Event.FULL_AHEAD, Event.ROAM, Event.EVENT_R1 ]
        return types[random.randint(0, len(types)-1)]

    # ..........................................................................
    @abstractmethod
    async def publish(self, iterations):
        '''
        DESCRIPTION.
        '''
        self._log.info(Fore.MAGENTA + Style.BRIGHT + 'Publish called.')
        for x in range(iterations):
            self._log.info(Fore.MAGENTA + 'Publisher: I have {} subscribers now'.format(len(self._message_bus.subscriptions)))
            _uuid = str(uuid.uuid4())
            _message = self.get_message_of_type(self.get_random_event_type(), 'msg_{:d}-{}'.format(x, _uuid))
            _message.number = next(self._counter)
            self._message_bus.publish(_message)
            await asyncio.sleep(1)
    
        _shutdown_message = self.get_message_of_type(Event.SHUTDOWN, 'shutdown')
        self._message_bus.publish(_shutdown_message)
コード例 #22
0
ファイル: config_loader.py プロジェクト: SiChiTong/ros-1
class ConfigLoader():
    '''
        Has just one method: configure() reads a YAML file.
    '''
    def __init__(self, level):
        self._log = Logger('configloader', level)
        self._log.info('ready.')

    # ..........................................................................
    def configure(self, filename):
        '''
            Read and return configuration from the specified YAML file.
        '''
        self._log.info(
            'reading from yaml configuration file {}...'.format(filename))
        _config = yaml.safe_load(open(filename, 'r'))
        for key, value in _config.items():
            self._log.debug('config key: {}; value: {}'.format(
                key, str(value)))
        self._log.info('configuration read.')
        return _config
コード例 #23
0
    def send(self, data):
        params = data.split()
        if len(params) == 0:
            return

        cmd = params[0]

        if cmd == "JOIN":
            self.server_user_response("JOIN", ":" + params[1])
            self.server_user_response(ircdef.RPL_ENDOFNAMES, "%s :/End of /NAMES list." % params[1])
        elif cmd == "WHO":
            self.server_response(ircdef.RPL_WHOREPLY, "%s %s %s %s %s %s H :0 %s" % (
                self.bot_nick,
                params[1],
                self.bot_ident,
                self.bot_host,
                self.server_name,
                self.bot_nick,
                "The NeuBot"))

            self.server_response(ircdef.RPL_ENDOFWHO, "%s %s :End of /WHO list." % (self.bot_nick, params[1],))

        elif cmd == "PRIVMSG":
            match = re.match("PRIVMSG (.*?) :(.*)", data)
            channel, message = match.groups()

            print "\033[1;37m[%s:PRIVMSG %s]\033[0m %s" % (self.bot_nick, channel, message)

        elif cmd == "NOTICE":
            match = re.match("NOTICE (.*?) :(.*)", data)
            channel, message = match.groups()

            print "\033[1;35m<%s:NOTICE %s>\033[0m %s" % (self.bot_nick, channel, message)

        elif cmd == "PING":
            match = re.match("PING (.*)", data)
            self.server_response("PONG", match.group(1))

        else:
            Logger.debug("Unhandled: " + data.strip())
コード例 #24
0
class Selector(object):

    def __init__(self, config, level):
        if config is None:
            raise ValueError('no configuration provided.')
        self._log = Logger("selector", level)
        self._rot = RotaryEncoder(config, i2c_address=0x0F, level=Level.WARN)
        self._rot.increment = 8
        self._last_value    = 0
        self._colors = [ Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE, Color.MAGENTA ]
        self._log.info('ready.')

    # ..........................................................................
    def read(self):
        _value = self._rot.read(False) % 360
        if _value != self._last_value:
            _color = self.get_color_for_heading(_value)
            self._rot.set_led((int(_color.red), int(_color.green), int(_color.blue)))
            self._log.info('returned value: {:d}; color: {}'.format(_value, _color))
        self._last_value = _value
        return _value

    # ..........................................................................
    def get_color_for_heading(self, degrees):
        '''
        Provided a heading in degrees return a color.
        '''
        _value = round(((degrees-30.0) / 60.0) + 0.5)
        _index = (_value % 6)
        _color = self._colors[_index]
        self._log.debug('{}°; value: {}; index: {}; color: {}'.format(degrees, _value, _index, _color))
        return _color

    # ..........................................................................
    def reset(self):
        _color = Color.BLACK
        self._rot.set_led((int(_color.red), int(_color.green), int(_color.blue)))
        self._rot.reset()
        self._log.info('reset.')
コード例 #25
0
ファイル: clock_test.py プロジェクト: SiChiTong/ros-1
class MockMessageQueue():
    '''
        This message queue just displays filtered, clock-related events as they arrive.
    '''
    def __init__(self, level):
        super().__init__()
        self._counter = itertools.count()
        self._log = Logger("queue", Level.INFO)
        self._start_time = dt.now()
        self._log.info('ready.')

    # ......................................................
    def add(self, message):
        message.number = next(self._counter)
        self._log.debug('added message {:06d}: priority {}: {}'.format(
            message.number, message.priority, message.description))
        _event = message.event
        _value = message.value

        _delta = dt.now() - self._start_time
        _elapsed_ms = _delta.total_seconds() * 1000
        _process_delta = dt.now() - message.timestamp
        _process_ms = _process_delta.total_seconds() * 1000
        _total_ms = _elapsed_ms + _process_ms

        if _event is Event.CLOCK_TICK:
            self._log.info(
                Fore.YELLOW + Style.NORMAL +
                'CLOCK_TICK: {}; value: {}'.format(_event.description, _value))

        elif _event is Event.CLOCK_TOCK:
            self._log.info(Fore.GREEN + Style.NORMAL + 'event: {}; value: {}; processing time: {:6.3f}ms; loop: {:6.3f}ms elapsed; total: {:6.3f}ms'.format(\
                    _event.description, _value, _process_ms, _elapsed_ms, _total_ms))
            self._start_time = dt.now()
        else:
            self._log.info(Fore.BLACK + Style.BRIGHT +
                           'other event: {}'.format(_event.description))
コード例 #26
0
class Subscription():
    '''
    A subscription on the MessageBus.
    '''
    def __init__(self, message_bus, level=Level.WARN):
        self._log = Logger('subscription', level)
        self._log.debug('__init__')
        self._message_bus = message_bus
        self.queue = asyncio.Queue()

    def __enter__(self):
        self._log.debug('__enter__')
        self._message_bus._subscriptions.add(self.queue)
        return self.queue

    def __exit__(self, type, value, traceback):
        self._log.debug('__exit__')
        self._message_bus._subscriptions.remove(self.queue)
コード例 #27
0
class I2cMaster():
    '''
        A Raspberry Pi Master for a corresponding Arduino Slave.

        Parameters:
          device_id:  the I²C address over which the master and slave communicate
          level:      the log level, e.g., Level.INFO
    '''
    def __init__(self, config, level):
        super().__init__()
        if config is None:
            raise ValueError('no configuration provided.')
        self._config = config['ros'].get('i2c_master')
        self._device_id = self._config.get(
            'device_id'
        )  # i2c hex address of slave device, must match Arduino's SLAVE_I2C_ADDRESS
        self._channel = self._config.get('channel')

        self._log = Logger('i²cmaster-0x{:02x}'.format(self._device_id), level)
        self._log.info('initialising...')
        self._counter = itertools.count()
        self._loop_count = 0  # currently only used in testing
        self._thread = None
        self._enabled = False
        self._closed = False
        self._i2c = SMBus(self._channel)
        self._log.info(
            'ready: imported smbus2 and obtained I²C bus at address 0x{:02X}...'
            .format(self._device_id))

    # ..........................................................................
    def enable(self):
        self._enabled = True
        self._log.info('enabled.')

    # ..........................................................................
    def disable(self):
        self._enabled = False
        self._log.info('disabled.')

    # ..............................................................................
    def read_i2c_data(self):
        '''
            Read a byte from the I²C device at the specified handle, returning the value.

            ## Examples:
            int.from_bytes(b'\x00\x01', "big")        # 1
            int.from_bytes(b'\x00\x01', "little")     # 256
        '''
        with SMBus(self._channel) as bus:
            _byte = bus.read_byte_data(self._device_id, 0)
            time.sleep(0.01)
        return _byte

    # ..........................................................................
    def write_i2c_data(self, data):
        '''
            Write a byte to the I²C device at the specified handle.
        '''
        with SMBus(self._channel) as bus:
            bus.write_byte(self._device_id, data)
            time.sleep(0.01)

    # ..........................................................................
    def get_input_from_pin(self, pin):
        '''
            Sends a message to the pin, returning the result as a byte.
        '''
        self.write_i2c_data(pin)
        #       time.sleep(0.2)
        _received_data = self.read_i2c_data()
        #       time.sleep(0.2)
        self._log.debug('received response from pin {:d} of {:08b}.'.format(
            pin, _received_data))
        return _received_data

    # ..........................................................................
    def in_loop(self):
        '''
            Returns true if the main loop is active (the thread is alive).
        '''
        return self._thread != None and self._thread.is_alive()

    # ..........................................................................
    def _front_sensor_loop(self, loop_delay_sec, callback):
        self._log.info('starting event loop...\n')
        while self._enabled:

            _count = next(self._counter)
            print(CLEAR_SCREEN)

            # pin 1: analog infrared sensor ................
            _received_data = self.get_input_from_pin(1)
            #           self._log.info('[{:04d}] ANALOG IR ({:d}):       \t'.format(_count, 1) + ( Fore.RED if ( _received_data > 100.0 ) else Fore.YELLOW ) \
            #                   + Style.BRIGHT + '{:d}'.format(_received_data) + Style.DIM + '\t(analog value 0-255)')
            callback(1, PinType.ANALOG_INPUT, _received_data)

            # pin 2: analog infrared sensor ................
            _received_data = self.get_input_from_pin(2)
            #           self._log.info('[{:04d}] ANALOG IR ({:d}):       \t'.format(_count, 2) + ( Fore.RED if ( _received_data > 100.0 ) else Fore.YELLOW ) \
            #                   + Style.BRIGHT + '{:d}'.format(_received_data) + Style.DIM + '\t(analog value 0-255)')
            callback(2, PinType.ANALOG_INPUT, _received_data)

            # pin 3: analog infrared sensor ................
            _received_data = self.get_input_from_pin(3)
            #           self._log.info('[{:04d}] ANALOG IR ({:d}):       \t'.format(_count, 3) + ( Fore.RED if ( _received_data > 100.0 ) else Fore.YELLOW ) \
            #                   + Style.BRIGHT + '{:d}'.format(_received_data) + Style.DIM + '\t(analog value 0-255)')
            callback(3, PinType.ANALOG_INPUT, _received_data)

            # pin 4: analog infrared sensor ................
            _received_data = self.get_input_from_pin(4)
            #           self._log.info('[{:04d}] ANALOG IR ({:d}):       \t'.format(_count, 4) + ( Fore.RED if ( _received_data > 100.0 ) else Fore.YELLOW ) \
            #                   + Style.BRIGHT + '{:d}'.format(_received_data) + Style.DIM + '\t(analog value 0-255)')
            callback(4, PinType.ANALOG_INPUT, _received_data)

            # pin 5: analog infrared sensor ................
            _received_data = self.get_input_from_pin(5)
            #           self._log.info('[{:04d}] ANALOG IR ({:d}):       \t'.format(_count, 5) + ( Fore.RED if ( _received_data > 100.0 ) else Fore.YELLOW ) \
            #                   + Style.BRIGHT + '{:d}'.format(_received_data) + Style.DIM + '\t(analog value 0-255)')
            callback(5, PinType.ANALOG_INPUT, _received_data)

            # pin 9: digital bumper sensor .................
            _received_data = self.get_input_from_pin(9)
            #           self._log.info('[{:04d}] DIGITAL IR ({:d}):      \t'.format(_count, 9) + Fore.GREEN + Style.BRIGHT  + '{:d}'.format(_received_data) \
            #                   + Style.DIM + '\t(displays digital pup value 0|1)')
            callback(9, PinType.DIGITAL_INPUT_PULLUP, _received_data)

            # pin 10: digital bumper sensor ................
            _received_data = self.get_input_from_pin(10)
            #           self._log.info('[{:04d}] DIGITAL IR ({:d}):      \t'.format(_count, 10) + Fore.GREEN + Style.BRIGHT  + '{:d}'.format(_received_data) \
            #                   + Style.DIM + '\t(displays digital pup value 0|1)')
            callback(10, PinType.DIGITAL_INPUT_PULLUP, _received_data)

            # pin 11: digital bumper sensor ................
            _received_data = self.get_input_from_pin(11)
            #           self._log.info('[{:04d}] DIGITAL IR ({:d}):      \t'.format(_count, 11) + Fore.GREEN + Style.BRIGHT  + '{:d}'.format(_received_data) \
            #                   + Style.DIM + '\t(displays digital pup value 0|1)')
            callback(11, PinType.DIGITAL_INPUT_PULLUP, _received_data)

            time.sleep(loop_delay_sec)

        # we never get here if using 'while True:'
        self._log.info('exited event loop.')

    # ..........................................................................
    def start_front_sensor_loop(self, loop_delay_sec, callback):
        '''
            This is the method to call to actually start the loop.
        '''
        if not self._enabled:
            raise Exception(
                'attempt to start front sensor event loop while disabled.')
        elif not self._closed:
            if self._thread is None:
                enabled = True
                self._thread = threading.Thread(
                    target=I2cMaster._front_sensor_loop,
                    args=[self, loop_delay_sec, callback])
                self._thread.start()
                self._log.info('started.')
            else:
                self._log.warning('cannot enable: process already running.')
        else:
            self._log.warning('cannot enable: already closed.')

    # ..........................................................................
    def close(self):
        '''
            Close the instance.
        '''
        self._log.debug('closing I²C master.')
        if not self._closed:
            try:
                if self._thread != None:
                    self._thread.join(timeout=1.0)
                    self._log.debug('front sensor loop thread joined.')
                    self._thread = None
                self._closed = True
                #               self._pi.i2c_close(self._handle) # close device
                self._log.debug('I²C master closed.')
            except Exception as e:
                self._log.error('error closing master: {}'.format(e))
        else:
            self._log.debug('I²C master already closed.')
コード例 #28
0
class Servo():
    '''
    Provided with configuration this permits setting of the center position offset.

    The UltraBorg supports four servos, numbered 1-4.
    '''
    def __init__(self, config, number, level):
        self._number = number
        self._log = Logger("servo-{:d}".format(number), level)
        self._config = config
        if self._config:
            self._log.info('configuration provided.')
            _config = self._config['ros'].get('servo{:d}'.format(number))
            self._center_offset = _config.get('center_offset')
        else:
            self._log.warning('no configuration provided.')
            self._center_offset = 0.0
        self._log.info('center offset: {:>3.1f}'.format(self._center_offset))

        self._UB = UltraBorg(level)    # create a new UltraBorg object
        self._UB.Init()                # initialise the board (checks it is connected)
        # settings .......................................................................
        self._min_angle = -90.1        # Smallest position to use (n/90)
        self._max_angle = +90.1        # Largest position to use (n/90)
        self._startup_delay = 0.5      # Delay before making the initial move
        self._step_delay = 0.05        # Delay between steps
        self._rate_start = 0.05        # Step distance for all servos during initial move
        self._step_distance = 1.0      # Step distance for servo #1
        self._enabled = False
        self._closed = False
        self._log.info('ready.')

    # ..........................................................................
    def get_min_angle(self):
        '''
        Return the configured minimum servo angle.
        '''
        return self._min_angle

    # ..........................................................................
    def get_max_angle(self):
        '''
        Return the configured maximum servo angle.
        '''
        return self._max_angle

    # ..........................................................................
    def is_in_range(self, degrees):
        '''
        A convenience method that returns true if the argument is within the
        minimum and maximum range (inclusive of endpoints) of the servo.
        '''
        return degrees >= self._min_angle and degrees <= self._max_angle

    # ..........................................................................
    def set_position(self, position):
        '''
        Set the position of the servo to a value between -90.0 and 90.0 degrees.
        Values outside this range set to their respective min/max.

        This adjusts the argument by the value of the center offset.
        '''
        self._log.debug('set servo position to: {:+5.2f}° (center offset {:+5.2f}°)'.format(position, self._center_offset))
        position += self._center_offset
        if position < self._min_angle:
            self._log.warning('cannot set position {:+5.2f}° less than minimum {:+5.2f}°'.format(position, self._min_angle))
            position = self._min_angle
        if position > self._max_angle:
            self._log.warning('cannot set position {:+5.2f}° greater than maximum {:+5.2f}°'.format(position, self._max_angle))
            position = self._max_angle
        # values for servo range from -1.0 to 1.0
        _value = position / 90.0
        if self._number == 1:
            self._UB.SetServoPosition1(_value)
        elif self._number == 2:
            self._UB.SetServoPosition2(_value)
        elif self._number == 3:
            self._UB.SetServoPosition3(_value)
        elif self._number == 4:
            self._UB.SetServoPosition4(_value)

    # ..........................................................................
    def get_position(self, defaultValue):
        '''
        Get the position of the servo. If unavailable return the default.
        '''
        if self._number == 1:
            _position = self._UB.GetServoPosition1()
        elif self._number == 2:
            _position = self._UB.GetServoPosition2()
        elif self._number == 3:
            _position = self._UB.GetServoPosition3()
        elif self._number == 4:
            _position = self._UB.GetServoPosition4()
        if _position is None:
            return defaultValue
        else:
            return ( _position * 90.0 ) + self._center_offset

    # ..........................................................................
    def get_distance(self, retry_count, useRawDistance):
        '''
        Gets the filtered distance for the ultrasonic module in millimeters.
        Parameters:
            retry_count: how many times to attempt to read from the sensor
                         before giving up (this value is ignored when
                         useRawDistance is True)
            useRawDistance: if you need a faster response use this instead
                         (no filtering) e.g.:
                             0     -> No object in range
                             25    -> Object 25 mm away
                             1000  -> Object 1000 mm (1 m) away
                             3500  -> Object 3500 mm (3.5 m) away

        Returns 0 for no object detected or no ultrasonic module attached.

        This admittedly is not a servo function but since we have an UltraBorg
        supporting this servo, this becomes a convenience method. The ultrasonic
        sensor should be connected to the same number as the servo.
        '''
        if self._number == 1:
            if useRawDistance:
                return self._UB.GetRawDistance1()
            else:
                return self._UB.GetWithRetry(self._UB.GetDistance1, retry_count)
        elif self._number == 2:
            if useRawDistance:
                return self._UB.GetRawDistance2()
            else:
                return self._UB.GetWithRetry(self._UB.GetDistance2, retry_count)
        elif self._number == 3:
            if useRawDistance:
                return self._UB.GetRawDistance3()
            else:
                return self._UB.GetWithRetry(self._UB.GetDistance3, retry_count)
        elif self._number == 4:
            if useRawDistance:
                return self._UB.GetRawDistance4()
            else:
                return self._UB.GetWithRetry(self._UB.GetDistance4, retry_count)

    # ..........................................................................
    def sweep(self):
        '''
        Repeatedly sweeps between minimum and maximum until disabled.
        '''
        self._log.info('press CTRL+C to quit.')
        try:

            self._log.info('move to center position.')
            position = 0.0
            self.set_position(position)
            # wait to be sure the servo has caught up
            time.sleep(self._startup_delay)

            self._log.info('sweep to start position.')
            while position > self._min_angle:
                position -= self._rate_start
                if position < self._min_angle:
                    position = self._min_angle
                self.set_position(position)
                time.sleep(self._step_delay)

            self._log.info('sweep through the range.')
            while self._enabled:
                position += self._step_distance
                # check if too large, if so wrap to the over end
                if position > self._max_angle:
                    position -= (self._max_angle - self._min_angle)
                self.set_position(position)
                time.sleep(self._step_delay)

        except KeyboardInterrupt:
            self.close()
            self._log.info('done.')

    # ..........................................................................
    def get_ultraborg(self):
        '''
        Return the UltraBorg supporting this Servo.
        '''
        return self._UB

    # ..........................................................................
    def enable(self):
        self._enabled = True
        self._log.info('enabled.')

    # ..........................................................................
    def disable(self):
        self._enabled = False
        self._log.info('disabled.')

    # ..........................................................................
    def reset(self):
        if self._number == 1:
            self._UB.SetServoPosition1(0.0)
        elif self._number == 2:
            self._UB.SetServoPosition2(0.0)
        elif self._number == 3:
            self._UB.SetServoPosition3(0.0)
        elif self._number == 4:
            self._UB.SetServoPosition4(0.0)
        self._log.info('reset position.')

    # ..........................................................................
    def close(self):
        '''
        Close the servo. If it has not already been disabled its position
        will reset to zero.
        '''
        if self._enabled:
            self.reset()
        if not self._closed:
            self._closed = True
            self.disable()
            self._log.info('closed.')
コード例 #29
0
class I2CScanner():
    '''
    Scans the I²C bus, returning a list of devices.
    '''
    def __init__(self, level):
        super().__init__()
        self._log = Logger('i2cscan', level)
        self._log.debug('initialising...')
        self._int_list = []
        self._hex_list = []
        try:
            import smbus
            bus_number = 1  # 1 indicates /dev/i2c-1
            self._bus = smbus.SMBus(bus_number)
            self._log.info('ready.')
        except ImportError:
            self._log.warning('initialised. This script requires smbus. Will operate without but return an empty result.')
            self._bus = None

    # ..........................................................................
    def get_hex_addresses(self):
        '''
        Returns a hexadecimal version of the list.
        '''
        self._scan_addresses()
        return self._hex_list

    # ..........................................................................
    def get_int_addresses(self):
        '''
        Returns an integer version of the list.
        '''
        self._scan_addresses()
        return self._int_list

    # ..........................................................................
    def has_address(self, addresses):
        '''
        Performs the address scan (if necessary) and returns true if a device
        is available at any of the specified addresses.
        '''
        self._scan_addresses()
        for address in addresses:
            if address in self._int_list:
                return True
        return False

    # ..........................................................................
    def _scan_addresses(self):
        '''
        Scans the bus and returns the available device addresses. After being
        called and populating the int and hex lists, this closes the connection
        to smbus.
        '''
        if len(self._int_list) == 0:
            device_count = 0
            if self._bus is not None:
                for address in range(3, 128):
                    try:
                        self._bus.write_byte(address, 0)
                        self._log.debug('found I²C device at 0x{:02X}'.format(address))
                        self._int_list.append(address)
                        self._hex_list.append(hex(address))
                        device_count = device_count + 1
                    except IOError as e:
                        if e.errno != errno.EREMOTEIO:
                            self._log.error('Error: {0} on address {1}'.format(e, hex(address)))
                    except Exception as e: # exception if read_byte fails
                        self._log.error('Error unk: {0} on address {1}'.format(e, hex(address)))
                self._bus.close()
                self._bus = None
                self._log.info("found {:d} device(s).".format(device_count))
            else:
                self._log.info("found no devices (no smbus available).")
        return self._int_list
コード例 #30
0
class RgbMatrix(Feature):
    '''
        This class provides access to a pair of Pimoroni 5x5 RGB LED Matrix displays,
        labeled port and starboard. It also includes several canned demonstrations,
        which can be used to indicate behaviours in progress.
    '''
    def __init__(self, level):
        global enabled
        self._log = Logger("rgbmatrix", level)
        self._rgbmatrix5x5_PORT = RGBMatrix5x5(address=0x77)
        self._log.info('port rgbmatrix at 0x77.')
        self._rgbmatrix5x5_PORT.set_brightness(0.8)
        self._rgbmatrix5x5_PORT.set_clear_on_exit()
        self._rgbmatrix5x5_STBD = RGBMatrix5x5(address=0x74)
        self._log.info('starboard rgbmatrix at 0x74.')
        self._rgbmatrix5x5_STBD.set_brightness(0.8)
        self._rgbmatrix5x5_STBD.set_clear_on_exit()
        self._height = self._rgbmatrix5x5_PORT.height
        self._width = self._rgbmatrix5x5_PORT.width
        self._thread_PORT = None
        self._thread_STBD = None
        enabled = False
        self._closing = False
        self._closed = False
        self._display_type = DisplayType.DARK  # default
        self._log.info('ready.')

    # ..........................................................................
    def name(self):
        return 'RgbMatrix'

    # ..........................................................................
    def _get_target(self):
        if self._display_type is DisplayType.RAINBOW:
            return RgbMatrix._rainbow
        elif self._display_type is DisplayType.BLINKY:
            return RgbMatrix._blinky
        elif self._display_type is DisplayType.RANDOM:
            return RgbMatrix._random
        elif self._display_type is DisplayType.SCAN:
            return RgbMatrix._scan
        elif self._display_type is DisplayType.SWORL:
            return RgbMatrix._sworl
        elif self._display_type is DisplayType.DARK:
            return RgbMatrix._dark

    # ..........................................................................
    def enable(self):
        global enabled
        if not self._closed and not self._closing:
            if self._thread_PORT is None and self._thread_STBD is None:
                enabled = True
                self._thread_PORT = threading.Thread(
                    target=self._get_target(),
                    args=[self, self._rgbmatrix5x5_PORT])
                self._thread_PORT.start()
                self._thread_STBD = threading.Thread(
                    target=self._get_target(),
                    args=[self, self._rgbmatrix5x5_STBD])
                self._thread_STBD.start()
                self._log.debug('enabled.')
            else:
                self._log.warning('cannot enable: process already running.')
        else:
            self._log.warning('cannot enable: already closed.')

    # ..........................................................................
    def clear(self):
        self._clear(self._rgbmatrix5x5_PORT)
        self._clear(self._rgbmatrix5x5_STBD)

    # ..........................................................................
    def is_disabled(self):
        global enabled
        return not enabled

    # ..........................................................................
    def disable(self):
        global enabled
        self._log.debug('disabling...')
        enabled = False
        self._clear(self._rgbmatrix5x5_PORT)
        self._clear(self._rgbmatrix5x5_STBD)
        if self._thread_PORT != None:
            self._thread_PORT.join(timeout=1.0)
            self._log.debug('port rgbmatrix thread joined.')
            self._thread_PORT = None
        if self._thread_STBD != None:
            self._thread_STBD.join(timeout=1.0)
            self._log.debug('starboard rgbmatrix thread joined.')
            self._thread_STBD = None
        self._log.debug('disabled.')

    # ..........................................................................
    def _rainbow(self, rgbmatrix5x5):
        '''
            Display a rainbow pattern.
        '''
        global enabled
        self._log.info('starting rainbow...')
        _spacing = 360.0 / 5.0
        _hue = 0
        while enabled:
            for x in range(self._width):
                for y in range(self._height):
                    _hue = int(time.time() * 100) % 360
                    offset = (x * y) / 25.0 * _spacing
                    h = ((_hue + offset) % 360) / 360.0
                    r, g, b = [
                        int(c * 255) for c in colorsys.hsv_to_rgb(h, 1.0, 1.0)
                    ]
                    rgbmatrix5x5.set_pixel(x, y, r, g, b)
#                   r, g, b = [int(c * 255) for c in colorsys.hsv_to_rgb(h + 0.5, 1.0, 1.0)]
#                   rainbow2.set_pixel(x, y, r, g, b)
                if not enabled:
                    break
            rgbmatrix5x5.show()
            #           rainbow2.show()
            time.sleep(0.0001)
        self._clear(rgbmatrix5x5)
        self._log.info('rainbow ended.')

    # ..........................................................................
    def _sworl(self, rgbmatrix5x5):
        '''
            Display a sworl pattern, whatever that is.
        '''
        global enabled
        self._log.info('starting sworl...')

        target = Color.LIGHT_BLUE
        self.set_color(target)

        #       for r in numpy.arange(0.0, target.red):
        #           for g in numpy.arange(0.0, target.green):
        #               for b in numpy.arange(0.0, target.blue):
        #                   rgbmatrix5x5.set_all(r, g, b)
        #                   rgbmatrix5x5.show()
        #                   time.sleep(0.01)
        #           if not enabled:
        #               break

        #       for r in numpy.arange(target.red, 0.0, -1.0):
        #           for g in numpy.arange(target.green, 0.0, -1.0):
        #               for b in numpy.arange(target.blue, 0.0, -1.0):
        #                   rgbmatrix5x5.set_all(r, g, b)
        #                   rgbmatrix5x5.show()
        #                   time.sleep(0.01)
        #           if not enabled:
        #               break

        self._clear(rgbmatrix5x5)
        self._log.info('sworl ended.')

    # ..........................................................................
    def _dark(self, rgbmatrix5x5):
        '''
            Display a dark static color.
        '''
        global enabled
        self._log.info('starting dark...')
        self.set_color(Color.BLACK)
        while enabled:
            time.sleep(0.2)

    # ..........................................................................
    @staticmethod
    def make_gaussian(fwhm):
        x = numpy.arange(0, 5, 1, float)
        y = x[:, numpy.newaxis]
        x0, y0 = 2, 2
        fwhm = fwhm
        gauss = numpy.exp(-4 * numpy.log(2) * ((x - x0)**2 + (y - y0)**2) /
                          fwhm**2)
        return gauss

    # ..........................................................................
    def _blinky(self, rgbmatrix5x5):
        '''
            Display a pair of blinky spots.
        '''
        global enabled
        self._log.info('starting blinky...')
        if self._height == self._width:
            _delta = 0
        else:
            _delta = 2

        while enabled:
            for i in range(3):
                for z in list(range(1, 10)[::-1]) + list(range(1, 10)):
                    fwhm = 5.0 / z
                    gauss = RgbMatrix.make_gaussian(fwhm)
                    start = time.time()
                    for y in range(self._height):
                        for x in range(self._width):
                            h = 0.5
                            s = 0.8
                            if self._height <= self._width:
                                v = gauss[x, y]
#                               v = gauss[x, y + _delta]
                            else:
                                v = gauss[x, y]
#                               v = gauss[x + _delta, y]
                            rgb = colorsys.hsv_to_rgb(h, s, v)
                            r = int(rgb[0] * 255.0)
                            g = int(rgb[1] * 255.0)
                            b = int(rgb[2] * 255.0)
                            rgbmatrix5x5.set_pixel(x, y, r, g, b)
                    rgbmatrix5x5.show()
                    end = time.time()
                    t = end - start
                    if t < 0.04:
                        time.sleep(0.04 - t)
                        pass
                if not enabled:
                    break
        self._clear(rgbmatrix5x5)
        self._log.info('blinky ended.')

    # ..........................................................................
    def _scan(self, rgbmatrix5x5):
        '''
            KITT- or Cylon-like eyeball scanning.
        '''
        global enabled
        self._log.info('starting scan...')

        r = int(255.0)
        g = int(64.0)
        b = int(0.0)
        #       start = time.time()
        #       for x in range(self._width):
        x = 2
        _delay = 0.25

        while enabled:
            #           for i in range(count):
            for y in range(0, self._height):
                rgbmatrix5x5.clear()
                rgbmatrix5x5.set_pixel(x, y, r, g, b)
                rgbmatrix5x5.show()
                time.sleep(_delay)
            for y in range(self._height - 1, 0, -1):
                rgbmatrix5x5.clear()
                rgbmatrix5x5.set_pixel(x, y, r, g, b)
                rgbmatrix5x5.show()
                time.sleep(_delay)
            if not enabled:
                break
        self._clear(rgbmatrix5x5)
        self._log.debug('scan ended.')

    # ..........................................................................
    def _random(self, rgbmatrix5x5):
        '''
            Display an ever-changing random pattern.
        '''
        global enabled
        self._log.info('starting random...')
        count = 0
        while enabled:
            rand_hue = numpy.random.uniform(0.1, 0.9)
            rand_mat = numpy.random.rand(self._width, self._height)
            for y in range(self._height):
                for x in range(self._width):
                    #                   h = 0.1 * rand_mat[x, y]
                    h = rand_hue * rand_mat[x, y]
                    s = 0.8
                    v = rand_mat[x, y]
                    rgb = colorsys.hsv_to_rgb(h, s, v)
                    r = int(rgb[0] * 255.0)
                    g = int(rgb[1] * 255.0)
                    b = int(rgb[2] * 255.0)
                    rgbmatrix5x5.set_pixel(x, y, r, g, b)
            if not enabled:
                break
            rgbmatrix5x5.show()
            time.sleep(0.01)
        self._clear(rgbmatrix5x5)
        self._log.info('random ended.')

    # ..........................................................................
    def set_color(self, color):
        '''
            Set the color of both RGB Matrix displays.
        '''
        self._set_color(self._rgbmatrix5x5_PORT, color)
        self._set_color(self._rgbmatrix5x5_STBD, color)

    # ..........................................................................
    def _set_color(self, rgbmatrix5x5, color):
        '''
            Set the color of the RGB Matrix.
        '''
        rgbmatrix5x5.set_all(color.red, color.green, color.blue)
        rgbmatrix5x5.show()

    # ..........................................................................
    def _clear(self, rgbmatrix5x5):
        '''
            Clears the RGB Matrix by setting its color to black.
        '''
        self._set_color(rgbmatrix5x5, Color.BLACK)

    # ..........................................................................
    def set_display_type(self, display_type):
        self._display_type = display_type

    # ..........................................................................
    def close(self):
        if self._closing:
            self._log.warning('already closing.')
            return
        self._closing = True
        self.disable()
        self._closed = True
        self._log.info('closed.')
コード例 #31
0
ファイル: ThunderBorg3.py プロジェクト: SiChiTong/ros-1
class ThunderBorg:
    """
This module is designed to communicate with the ThunderBorg

busNumber               I²C bus on which the ThunderBorg is attached (Rev 1 is bus 0, Rev 2 is bus 1)
bus                     the smbus object used to talk to the I²C bus
i2cAddress              The I²C address of the ThunderBorg chip to control
foundChip               True if the ThunderBorg chip can be seen, False otherwise
printFunction           Function reference to call when printing text, if None "print" is used
    """

    # Shared values used by this class
    busNumber = 1  # Check here for Rev 1 vs Rev 2 and select the correct bus
    i2cAddress = I2C_ID_THUNDERBORG  # I²C address, override for a different address
    foundChip = False
    printFunction = None
    i2cWrite = None
    i2cRead = None

    def __init__(self, level):
        super().__init__()
        self._log = Logger('thunderborg', level)
        self._log.info('ready.')

    def RawWrite(self, command, data):
        """
RawWrite(command, data)

Sends a raw command on the I2C bus to the ThunderBorg
Command codes can be found at the top of ThunderBorg.py, data is a list of 0 or more byte values

Under most circumstances you should use the appropriate function instead of RawWrite
        """
        rawOutput = [command]
        rawOutput.extend(data)
        rawOutput = bytes(rawOutput)
        self.i2cWrite.write(rawOutput)

    def RawRead(self, command, length, retryCount=3):
        """
RawRead(command, length, [retryCount])

Reads data back from the ThunderBorg after sending a GET command
Command codes can be found at the top of ThunderBorg.py, length is the number of bytes to read back

The function checks that the first byte read back matches the requested command
If it does not it will retry the request until retryCount is exhausted (default is 3 times)

Under most circumstances you should use the appropriate function instead of RawRead
        """
        while retryCount > 0:
            self.RawWrite(command, [])
            rawReply = self.i2cRead.read(length)
            reply = []
            for singleByte in rawReply:
                reply.append(singleByte)
            if command == reply[0]:
                break
            else:
                retryCount -= 1
        if retryCount > 0:
            return reply
        else:
            raise IOError('I2C read for command %d failed' % (command))

    def InitBusOnly(self, busNumber, address):
        """
InitBusOnly(busNumber, address)

Prepare the I2C driver for talking to a ThunderBorg on the specified bus and I2C address
This call does not check the board is present or working, under most circumstances use Init() instead
        """
        self.busNumber = busNumber
        self.i2cAddress = address
        self.i2cRead = io.open("/dev/i2c-" + str(self.busNumber),
                               "rb",
                               buffering=0)
        fcntl.ioctl(self.i2cRead, I2C_SLAVE, self.i2cAddress)
        self.i2cWrite = io.open("/dev/i2c-" + str(self.busNumber),
                                "wb",
                                buffering=0)
        fcntl.ioctl(self.i2cWrite, I2C_SLAVE, self.i2cAddress)

    def Print(self, message):
        """
Print(message)

Wrapper used by the ThunderBorg instance to print(messages, will call printFunction if set, print otherwise)
        """
        self._log.info(message)
#       if self.printFunction == None:
#           print(message)
#       else:
#           self.printFunction(message)

    def NoPrint(self, message):
        """
NoPrint(message)

Does nothing, intended for disabling diagnostic printout by using:
TB = ThunderBorg.ThunderBorg()
TB.printFunction = TB.NoPrint
        """
        pass

    def Init(self, tryOtherBus=False):
        """
Init([tryOtherBus])

Prepare the I2C driver for talking to the ThunderBorg

If tryOtherBus is True, this function will attempt to use the other bus if the ThunderBorg devices can not be found on the current busNumber
    This is only really useful for early Raspberry Pi models!
        """
        self.Print('Loading ThunderBorg on bus %d, address %02X' %
                   (self.busNumber, self.i2cAddress))

        # Open the bus
        self.i2cRead = io.open("/dev/i2c-" + str(self.busNumber),
                               "rb",
                               buffering=0)
        fcntl.ioctl(self.i2cRead, I2C_SLAVE, self.i2cAddress)
        self.i2cWrite = io.open("/dev/i2c-" + str(self.busNumber),
                                "wb",
                                buffering=0)
        fcntl.ioctl(self.i2cWrite, I2C_SLAVE, self.i2cAddress)

        # Check for ThunderBorg
        try:
            i2cRecv = self.RawRead(COMMAND_GET_ID, I2C_MAX_LEN)
            if len(i2cRecv) == I2C_MAX_LEN:
                if i2cRecv[1] == I2C_ID_THUNDERBORG:
                    self.foundChip = True
                    self.Print('Found ThunderBorg at %02X' % (self.i2cAddress))
                else:
                    self.foundChip = False
                    self.Print(
                        'Found a device at %02X, but it is not a ThunderBorg (ID %02X instead of %02X)'
                        % (self.i2cAddress, i2cRecv[1], I2C_ID_THUNDERBORG))
            else:
                self.foundChip = False
                self.Print('Missing ThunderBorg at %02X' % (self.i2cAddress))
        except KeyboardInterrupt:
            raise
        except:
            self.foundChip = False
            self.Print('Missing ThunderBorg at %02X' % (self.i2cAddress))

        # See if we are missing chips
        if not self.foundChip:
            self.Print('ThunderBorg was not found')
            if tryOtherBus:
                if self.busNumber == 1:
                    self.busNumber = 0
                else:
                    self.busNumber = 1
                self.Print('Trying bus %d instead' % (self.busNumber))
                self.Init(False)
            else:
                self.Print(
                    'Are you sure your ThunderBorg is properly attached, the correct address is used, and the I2C drivers are running?'
                )
                self.bus = None
        else:
            self.Print('ThunderBorg loaded on bus %d' % (self.busNumber))

    def SetMotor2(self, power):
        """
SetMotor2(power)

Sets the drive level for motor 2, from +1 to -1.
e.g.
SetMotor2(0)     -> motor 2 is stopped
SetMotor2(0.75)  -> motor 2 moving forward at 75% power
SetMotor2(-0.5)  -> motor 2 moving reverse at 50% power
SetMotor2(1)     -> motor 2 moving forward at 100% power
        """
        if power < 0:
            # Reverse
            command = COMMAND_SET_B_REV
            pwm = -int(PWM_MAX * power)
            if pwm > PWM_MAX:
                pwm = PWM_MAX
        else:
            # Forward / stopped
            command = COMMAND_SET_B_FWD
            pwm = int(PWM_MAX * power)
            if pwm > PWM_MAX:
                pwm = PWM_MAX

        try:
            self.RawWrite(command, [pwm])
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed sending motor 2 drive level!')

    def GetMotor2(self):
        """
power = GetMotor2()

Gets the drive level for motor 2, from +1 to -1.
e.g.
0     -> motor 2 is stopped
0.75  -> motor 2 moving forward at 75% power
-0.5  -> motor 2 moving reverse at 50% power
1     -> motor 2 moving forward at 100% power
        """
        try:
            i2cRecv = self.RawRead(COMMAND_GET_B, I2C_MAX_LEN)
        except KeyboardInterrupt:
            raise
        except:
            #           self.Print('Failed reading motor 2 drive level!')
            self._log.debug('failed reading motor 2 drive level.')
            return None

        power = float(i2cRecv[2]) / float(PWM_MAX)

        if i2cRecv[1] == COMMAND_VALUE_FWD:
            return power
        elif i2cRecv[1] == COMMAND_VALUE_REV:
            return -power
        else:
            return

    def SetMotor1(self, power):
        """
SetMotor1(power)

Sets the drive level for motor 1, from +1 to -1.
e.g.
SetMotor1(0)     -> motor 1 is stopped
SetMotor1(0.75)  -> motor 1 moving forward at 75% power
SetMotor1(-0.5)  -> motor 1 moving reverse at 50% power
SetMotor1(1)     -> motor 1 moving forward at 100% power
        """
        if power < 0:
            # Reverse
            command = COMMAND_SET_A_REV
            pwm = -int(PWM_MAX * power)
            if pwm > PWM_MAX:
                pwm = PWM_MAX
        else:
            # Forward / stopped
            command = COMMAND_SET_A_FWD
            pwm = int(PWM_MAX * power)
            if pwm > PWM_MAX:
                pwm = PWM_MAX

        try:
            self.RawWrite(command, [pwm])
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed sending motor 1 drive level!')

    def GetMotor1(self):
        """
power = GetMotor1()

Gets the drive level for motor 1, from +1 to -1.
e.g.
0     -> motor 1 is stopped
0.75  -> motor 1 moving forward at 75% power
-0.5  -> motor 1 moving reverse at 50% power
1     -> motor 1 moving forward at 100% power
        """
        try:
            i2cRecv = self.RawRead(COMMAND_GET_A, I2C_MAX_LEN)
        except KeyboardInterrupt:
            raise
        except:
            #           self.Print('Failed reading motor 1 drive level!')
            self._log.debug('failed reading motor 1 drive level.')
            return None

        power = float(i2cRecv[2]) / float(PWM_MAX)

        if i2cRecv[1] == COMMAND_VALUE_FWD:
            return power
        elif i2cRecv[1] == COMMAND_VALUE_REV:
            return -power
        else:
            return

    def SetMotors(self, power):
        """
SetMotors(power)

Sets the drive level for all motors, from +1 to -1.
e.g.
SetMotors(0)     -> all motors are stopped
SetMotors(0.75)  -> all motors are moving forward at 75% power
SetMotors(-0.5)  -> all motors are moving reverse at 50% power
SetMotors(1)     -> all motors are moving forward at 100% power
        """
        if power < 0:
            # Reverse
            command = COMMAND_SET_ALL_REV
            pwm = -int(PWM_MAX * power)
            if pwm > PWM_MAX:
                pwm = PWM_MAX
        else:
            # Forward / stopped
            command = COMMAND_SET_ALL_FWD
            pwm = int(PWM_MAX * power)
            if pwm > PWM_MAX:
                pwm = PWM_MAX

        try:
            self.RawWrite(command, [pwm])
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed sending all motors drive level!')

    def MotorsOff(self):
        """
MotorsOff()

Sets all motors to stopped, useful when ending a program
        """
        try:
            self.RawWrite(COMMAND_ALL_OFF, [0])
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed sending motors off command!')

    def SetLed1(self, r, g, b):
        """
SetLed1(r, g, b)

Sets the current colour of the ThunderBorg LED. r, g, b may each be between 0 and 1
e.g.
SetLed1(0, 0, 0)       -> ThunderBorg LED off
SetLed1(1, 1, 1)       -> ThunderBorg LED full white
SetLed1(1.0, 0.5, 0.0) -> ThunderBorg LED bright orange
SetLed1(0.2, 0.0, 0.2) -> ThunderBorg LED dull purple
        """
        levelR = max(0, min(PWM_MAX, int(r * PWM_MAX)))
        levelG = max(0, min(PWM_MAX, int(g * PWM_MAX)))
        levelB = max(0, min(PWM_MAX, int(b * PWM_MAX)))

        try:
            self.RawWrite(COMMAND_SET_LED1, [levelR, levelG, levelB])
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed sending colour for the ThunderBorg LED!')

    def GetLed1(self):
        """
r, g, b = GetLed1()

Gets the current colour of the ThunderBorg LED. r, g, b may each be between 0 and 1
e.g.
0, 0, 0       -> ThunderBorg LED off
1, 1, 1       -> ThunderBorg LED full white
1.0, 0.5, 0.0 -> ThunderBorg LED bright orange
0.2, 0.0, 0.2 -> ThunderBorg LED dull purple
        """
        try:
            i2cRecv = self.RawRead(COMMAND_GET_LED1, I2C_MAX_LEN)
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed reading ThunderBorg LED colour!')
            return

        r = i2cRecv[1] / float(PWM_MAX)
        g = i2cRecv[2] / float(PWM_MAX)
        b = i2cRecv[3] / float(PWM_MAX)
        return r, g, b

    def SetLed2(self, r, g, b):
        """
SetLed2(r, g, b)

Sets the current colour of the ThunderBorg Lid LED. r, g, b may each be between 0 and 1
e.g.
SetLed2(0, 0, 0)       -> ThunderBorg Lid LED off
SetLed2(1, 1, 1)       -> ThunderBorg Lid LED full white
SetLed2(1.0, 0.5, 0.0) -> ThunderBorg Lid LED bright orange
SetLed2(0.2, 0.0, 0.2) -> ThunderBorg Lid LED dull purple
        """
        levelR = max(0, min(PWM_MAX, int(r * PWM_MAX)))
        levelG = max(0, min(PWM_MAX, int(g * PWM_MAX)))
        levelB = max(0, min(PWM_MAX, int(b * PWM_MAX)))

        try:
            self.RawWrite(COMMAND_SET_LED2, [levelR, levelG, levelB])
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed sending colour for the ThunderBorg Lid LED!')

    def GetLed2(self):
        """
r, g, b = GetLed2()

Gets the current colour of the ThunderBorg Lid LED. r, g, b may each be between 0 and 1
e.g.
0, 0, 0       -> ThunderBorg Lid LED off
1, 1, 1       -> ThunderBorg Lid LED full white
1.0, 0.5, 0.0 -> ThunderBorg Lid LED bright orange
0.2, 0.0, 0.2 -> ThunderBorg Lid LED dull purple
        """
        try:
            i2cRecv = self.RawRead(COMMAND_GET_LED2, I2C_MAX_LEN)
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed reading ThunderBorg Lid LED colour!')
            return

        r = i2cRecv[1] / float(PWM_MAX)
        g = i2cRecv[2] / float(PWM_MAX)
        b = i2cRecv[3] / float(PWM_MAX)
        return r, g, b

    def SetLeds(self, r, g, b):
        """
SetLeds(r, g, b)

Sets the current colour of both LEDs. r, g, b may each be between 0 and 1
e.g.
SetLeds(0, 0, 0)       -> Both LEDs off
SetLeds(1, 1, 1)       -> Both LEDs full white
SetLeds(1.0, 0.5, 0.0) -> Both LEDs bright orange
SetLeds(0.2, 0.0, 0.2) -> Both LEDs dull purple
        """
        levelR = max(0, min(PWM_MAX, int(r * PWM_MAX)))
        levelG = max(0, min(PWM_MAX, int(g * PWM_MAX)))
        levelB = max(0, min(PWM_MAX, int(b * PWM_MAX)))

        try:
            self.RawWrite(COMMAND_SET_LEDS, [levelR, levelG, levelB])
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed sending colour for both LEDs!')

    def SetLedShowBattery(self, state):
        """
SetLedShowBattery(state)

Sets the system to enable or disable the LEDs showing the current battery level
If enabled the LED colours will be ignored and will use the current battery reading instead
This sweeps from fully green for maximum voltage (35 V) to fully red for minimum voltage (7 V)
        """
        if state:
            level = COMMAND_VALUE_ON
        else:
            level = COMMAND_VALUE_OFF

        try:
            self.RawWrite(COMMAND_SET_LED_BATT_MON, [level])
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed sending LED battery monitoring state!')

    def GetLedShowBattery(self):
        """
state = GetLedShowBattery()

Gets if the system is using the LEDs to show the current battery level, true for enabled, false for disabled
If enabled the LED colours will be ignored and will use the current battery reading instead
This sweeps from fully green for maximum voltage (35 V) to fully red for minimum voltage (7 V)
        """
        try:
            i2cRecv = self.RawRead(COMMAND_GET_LED_BATT_MON, I2C_MAX_LEN)
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed reading LED battery monitoring state!')
            return

        if i2cRecv[1] == COMMAND_VALUE_OFF:
            return False
        else:
            return True

    def SetCommsFailsafe(self, state):
        """
SetCommsFailsafe(state)

Sets the system to enable or disable the communications failsafe
The failsafe will turn the motors off unless it is commanded at least once every 1/4 of a second
Set to True to enable this failsafe, set to False to disable this failsafe
The failsafe is disabled at power on
        """
        if state:
            level = COMMAND_VALUE_ON
        else:
            level = COMMAND_VALUE_OFF

        try:
            self.RawWrite(COMMAND_SET_FAILSAFE, [level])
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed sending communications failsafe state!')

    def GetCommsFailsafe(self):
        """
state = GetCommsFailsafe()

Read the current system state of the communications failsafe, True for enabled, False for disabled
The failsafe will turn the motors off unless it is commanded at least once every 1/4 of a second
        """
        try:
            i2cRecv = self.RawRead(COMMAND_GET_FAILSAFE, I2C_MAX_LEN)
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed reading communications failsafe state!')
            return

        if i2cRecv[1] == COMMAND_VALUE_OFF:
            return False
        else:
            return True

    def GetDriveFault1(self):
        """
state = GetDriveFault1()

Reads the motor drive fault state for motor #1, False for no problems, True for a fault has been detected
Faults may indicate power problems, such as under-voltage (not enough power), and may be cleared by setting a lower drive power
If a fault is persistent, it repeatably occurs when trying to control the board, this may indicate a wiring problem such as:
    * The supply is not powerful enough for the motors
        The board has a bare minimum requirement of 6V to operate correctly
        A recommended minimum supply of 7.2V should be sufficient for smaller motors
    * The + and - connections for motor #1 are connected to each other
    * Either + or - is connected to ground (GND, also known as 0V or earth)
    * Either + or - is connected to the power supply (V+, directly to the battery or power pack)
    * One of the motors may be damaged
Faults will self-clear, they do not need to be reset, however some faults require both motors to be moving at less than 100% to clear
The easiest way to check is to put both motors at a low power setting which is high enough for them to rotate easily, such as 30%
Note that the fault state may be true at power up, this is normal and should clear when both motors have been driven
For more details check the website at www.piborg.org/thunderborg and double check the wiring instructions
        """
        try:
            i2cRecv = self.RawRead(COMMAND_GET_DRIVE_A_FAULT, I2C_MAX_LEN)
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed reading the drive fault state for motor #1!')
            return

        if i2cRecv[1] == COMMAND_VALUE_OFF:
            return False
        else:
            return True

    def GetDriveFault2(self):
        """
state = GetDriveFault2()

Reads the motor drive fault state for motor #2, False for no problems, True for a fault has been detected
Faults may indicate power problems, such as under-voltage (not enough power), and may be cleared by setting a lower drive power
If a fault is persistent, it repeatably occurs when trying to control the board, this may indicate a wiring problem such as:
    * The supply is not powerful enough for the motors
        The board has a bare minimum requirement of 6V to operate correctly
        A recommended minimum supply of 7.2V should be sufficient for smaller motors
    * The + and - connections for motor #2 are connected to each other
    * Either + or - is connected to ground (GND, also known as 0V or earth)
    * Either + or - is connected to the power supply (V+, directly to the battery or power pack)
    * One of the motors may be damaged
Faults will self-clear, they do not need to be reset, however some faults require both motors to be moving at less than 100% to clear
The easiest way to check is to put both motors at a low power setting which is high enough for them to rotate easily, such as 30%
Note that the fault state may be true at power up, this is normal and should clear when both motors have been driven
For more details check the website at www.piborg.org/thunderborg and double check the wiring instructions
        """
        try:
            i2cRecv = self.RawRead(COMMAND_GET_DRIVE_B_FAULT, I2C_MAX_LEN)
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed reading the drive fault state for motor #2!')
            return

        if i2cRecv[1] == COMMAND_VALUE_OFF:
            return False
        else:
            return True

    def GetBatteryReading(self):
        """
voltage = GetBatteryReading()

Reads the current battery level from the main input.
Returns the value as a voltage based on the 3.3 V rail as a reference.
        """
        try:
            i2cRecv = self.RawRead(COMMAND_GET_BATT_VOLT, I2C_MAX_LEN)
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed reading battery level!')
            return

        raw = (i2cRecv[1] << 8) + i2cRecv[2]
        level = float(raw) / float(COMMAND_ANALOG_MAX)
        level *= VOLTAGE_PIN_MAX
        return level + VOLTAGE_PIN_CORRECTION

    def SetBatteryMonitoringLimits(self, minimum, maximum):
        """
SetBatteryMonitoringLimits(minimum, maximum)

Sets the battery monitoring limits used for setting the LED colour.
The values are between 0 and 36.3 V.
The colours shown range from full red at minimum or below, yellow half way, and full green at maximum or higher.
These values are stored in EEPROM and reloaded when the board is powered.
        """
        levelMin = minimum / float(VOLTAGE_PIN_MAX)
        levelMax = maximum / float(VOLTAGE_PIN_MAX)
        levelMin = max(0, min(0xFF, int(levelMin * 0xFF)))
        levelMax = max(0, min(0xFF, int(levelMax * 0xFF)))

        try:
            self.RawWrite(COMMAND_SET_BATT_LIMITS, [levelMin, levelMax])
            time.sleep(0.2)  # Wait for EEPROM write to complete
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed sending battery monitoring limits!')

    def GetBatteryMonitoringLimits(self):
        """
minimum, maximum = GetBatteryMonitoringLimits()

Reads the current battery monitoring limits used for setting the LED colour.
The values are between 0 and 36.3 V.
The colours shown range from full red at minimum or below, yellow half way, and full green at maximum or higher.
        """
        try:
            i2cRecv = self.RawRead(COMMAND_GET_BATT_LIMITS, I2C_MAX_LEN)
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed reading battery monitoring limits!')
            return

        rawMin = i2cRecv[1]
        rawMax = i2cRecv[2]
        levelMin = float(rawMin) / float(0xFF)
        levelMax = float(rawMax) / float(0xFF)
        levelMin *= VOLTAGE_PIN_MAX
        levelMax *= VOLTAGE_PIN_MAX
        return levelMin, levelMax

    def WriteExternalLedWord(self, b0, b1, b2, b3):
        """
WriteExternalLedWord(b0, b1, b2, b3)

Low level serial LED word writing.
Bytes are written MSB first starting from b0
e.g.
WriteExtermnalLedWord(255, 64, 1, 0)
will write out:
11111111 01000000 00000001 00000000
to the LEDs.
        """
        b0 = max(0, min(PWM_MAX, int(b0)))
        b1 = max(0, min(PWM_MAX, int(b1)))
        b2 = max(0, min(PWM_MAX, int(b2)))
        b3 = max(0, min(PWM_MAX, int(b3)))

        try:
            self.RawWrite(COMMAND_WRITE_EXTERNAL_LED, [b0, b1, b2, b3])
        except KeyboardInterrupt:
            raise
        except:
            self.Print('Failed sending word for the external LEDs!')

    def SetExternalLedColours(self, colours):
        """
SetExternalLedColours([[r, g, b], ..., [r, g, b]])

Takes a set of RGB triples to set each LED to.
Each call will set all of the LEDs
e.g.
SetExternalLedColours([[1.0, 1.0, 0.0]])
will set a single LED to full yellow.
SetExternalLedColours([[1.0, 0.0, 0.0], [0.5, 0.0, 0.0], [0.0, 0.0, 0.0]])
will set LED 1 to full red, LED 2 to half red, and LED 3 to off.
        """
        # Send the start marker
        self.WriteExternalLedWord(0, 0, 0, 0)

        # Send each colour in turn
        for r, g, b in colours:
            self.WriteExternalLedWord(255, 255 * b, 255 * g, 255 * r)

    def Help(self):
        """
Help()

Displays the names and descriptions of the various functions and settings provided
        """
        funcList = [
            ThunderBorg.__dict__.get(a) for a in dir(ThunderBorg)
            if isinstance(ThunderBorg.__dict__.get(a), types.FunctionType)
        ]
        funcListSorted = sorted(funcList,
                                key=lambda x: x.func_code.co_firstlineno)

        print(self.__doc__)
        print
        for func in funcListSorted:
            print('=== %s === %s' % (func.func_name, func.func_doc))
コード例 #32
0
class RgbMatrix(Feature):
    '''
    This class provides access to a pair of Pimoroni 5x5 RGB LED Matrix displays,
    labeled port and starboard. It also includes several canned demonstrations,
    which can be used to indicate behaviours in progress.

    The port side display requires cutting of the ADDR trace on the board to alter
    its I2C address to 0x77, so that two boards can be used. The starboard display
    is at the default address of 0x74 and hence is required, the port optional.
    '''
    def __init__(self, level):
        global enabled
        self._log = Logger("rgbmatrix", level)
        _i2c_scanner = I2CScanner(Level.WARN)
        _addresses = _i2c_scanner.get_int_addresses()
        self._rgbmatrix5x5_PORT = RGBMatrix5x5(
            address=0x77) if (0x77 in _addresses) else None
        #       self._rgbmatrix5x5_PORT = RGBMatrix5x5(address=0x77)
        if self._rgbmatrix5x5_PORT:
            self._log.info('port rgbmatrix at 0x77.')
            self._rgbmatrix5x5_PORT.set_brightness(0.8)
            self._rgbmatrix5x5_PORT.set_clear_on_exit()
        else:
            self._log.info('no port rgbmatrix found.')
        self._rgbmatrix5x5_STBD = RGBMatrix5x5(address=0x74)
        self._log.info('starboard rgbmatrix at 0x74.')
        self._rgbmatrix5x5_STBD.set_brightness(0.8)
        self._rgbmatrix5x5_STBD.set_clear_on_exit()

        self._height = self._rgbmatrix5x5_STBD.height
        self._width = self._rgbmatrix5x5_STBD.width
        self._log.info('rgbmatrix width,height: {},{}'.format(
            self._width, self._height))
        self._thread_PORT = None
        self._thread_STBD = None
        self._color = Color.RED  # used by _solid
        enabled = False
        self._closing = False
        self._closed = False
        self._display_type = DisplayType.DARK  # default
        # color used by wipe display
        self._wipe_color = Color.WHITE  # default
        # used by _cpu:
        self._max_value = 0.0  # TEMP
        self._buf = numpy.zeros(
            (self._rgbmatrix5x5_STBD._width, self._rgbmatrix5x5_STBD._height))
        self._colors = [
            Color.GREEN, Color.YELLOW_GREEN, Color.YELLOW, Color.ORANGE,
            Color.RED
        ]
        self._log.info('ready.')

    # ..........................................................................
    def name(self):
        return 'RgbMatrix'

    # ..........................................................................
    def _get_target(self):
        if self._display_type is DisplayType.BLINKY:
            return [RgbMatrix._blinky, None]
        elif self._display_type is DisplayType.CPU:
            return [RgbMatrix._cpu, None]
        elif self._display_type is DisplayType.DARK:
            return [RgbMatrix._dark, None]
        elif self._display_type is DisplayType.RAINBOW:
            return [RgbMatrix._rainbow, None]
        elif self._display_type is DisplayType.RANDOM:
            return [RgbMatrix._random, None]
        elif self._display_type is DisplayType.SCAN:
            return [RgbMatrix._scan, None]
        elif self._display_type is DisplayType.SOLID:
            return [RgbMatrix._solid, None]
        elif self._display_type is DisplayType.SWORL:
            return [RgbMatrix._sworl, None]
        elif self._display_type is DisplayType.WIPE_LEFT:
            return [RgbMatrix._wipe, WipeDirection.LEFT]

    # ..........................................................................
    def enable(self):
        global enabled
        if not self._closed and not self._closing:
            if self._thread_PORT is None and self._thread_STBD is None:
                enabled = True
                _target = self._get_target()
                if self._rgbmatrix5x5_PORT:
                    self._thread_PORT = Thread(
                        name='rgb-port',
                        target=_target[0],
                        args=[self, self._rgbmatrix5x5_PORT, _target[1]])
                    self._thread_PORT.start()
                self._thread_STBD = Thread(
                    name='rgb-stbd',
                    target=_target[0],
                    args=[self, self._rgbmatrix5x5_STBD, _target[1]])
                self._thread_STBD.start()
                self._log.debug('enabled.')
            else:
                self._log.warning('cannot enable: process already running.')
        else:
            self._log.warning('cannot enable: already closed.')

    # ..........................................................................
    def clear(self):
        if self._rgbmatrix5x5_PORT:
            self._clear(self._rgbmatrix5x5_PORT)
        self._clear(self._rgbmatrix5x5_STBD)

    # ..........................................................................
    def is_disabled(self):
        global enabled
        return not enabled

    # ..........................................................................
    def disable(self):
        global enabled
        self._log.debug('disabling...')
        enabled = False
        if self._rgbmatrix5x5_PORT:
            self._clear(self._rgbmatrix5x5_PORT)
        self._clear(self._rgbmatrix5x5_STBD)
        if self._thread_PORT != None:
            self._thread_PORT.join(timeout=1.0)
            self._log.debug('port rgbmatrix thread joined.')
            self._thread_PORT = None
        if self._thread_STBD != None:
            self._thread_STBD.join(timeout=1.0)
            self._log.debug('starboard rgbmatrix thread joined.')
            self._thread_STBD = None
        self._log.debug('disabled.')

    # ..........................................................................
    def _cpu(self, rgbmatrix5x5, arg):
        '''
        A port of the CPU example from the Matrix 11x7.

        For some reasoon the output needs to be rotated 90 degrees to work properly.
        '''
        self._log.info('starting cpu...')
        i = 0
        cpu_values = [0] * self._width
        while enabled:
            try:
                cpu_values.pop(0)
                cpu_values.append(psutil.cpu_percent())

                #               # display cpu_values and max (turns out to be 50.0)
                #               for i in range(0, len(cpu_values)-1):
                #                   self._max_value = max(self._max_value, cpu_values[i])
                #               self._log.info(Fore.BLUE + 'cpu_values: {}, {}, {}, {}, {}; '.format(cpu_values[0], cpu_values[1], cpu_values[2], cpu_values[3], cpu_values[4]) \
                #                       + Style.BRIGHT + '\tmax: {:5.2f}'.format(self._max_value))

                self._set_graph(rgbmatrix5x5, cpu_values, low=0.0,
                                high=50.0)  # high was 25
                rgbmatrix5x5.show()
                time.sleep(0.2)
            except KeyboardInterrupt:
                self._clear(rgbmatrix5x5)
                self._log.info('cpu ended.')
                sys.exit(0)

    # ......................................................
    def _set_graph(self, rgbmatrix5x5, values, low=None, high=None, x=0, y=0):
        '''
        Plot a series of values into the display buffer.
        '''
        global enabled
        # def set_graph(self, values, low=None, high=None, brightness=1.0, x=0, y=0, width=None, height=None):
        #       x=0
        #       y=0
        _width = self._width - 1
        _height = self._height + 0
        if low is None:
            low = min(values)
        if high is None:
            high = max(values)
        self._buf = self._grow_buffer(x + _width, y + _height)
        span = high - low
        for p_y in range(0, _height):
            try:
                _value = values[p_y]
                _value -= low
                _value /= float(span)
                _value *= _width * 10.0
                _value = min(_value, _height * 12.0)
                _value = max(_value, 0.0)
                if _value > 5.0:
                    _value = 50.0
#               self._log.info(Fore.MAGENTA + 'p_y={}; _value: {}'.format(p_y, _value) + Style.RESET_ALL)
                for p_x in range(0, _width):
                    _r = self._colors[p_x].red
                    _g = self._colors[p_x].green
                    _b = self._colors[p_x].blue
                    if _value <= 10.0:
                        _r = (_value / 10.0) * _r
                        _g = (_value / 10.0) * _g
                        _b = (_value / 10.0) * _b
                    _x = x + (_width - p_x)
                    _y = y + p_y
                    self._log.info(Fore.YELLOW +
                                   'setting pixel x={}/{}, y={}/{};'.format(
                                       _x, _width, _y, _height) +
                                   Fore.MAGENTA +
                                   '\tvalue: {:>5.2f}'.format(_value) +
                                   Style.RESET_ALL)
                    rgbmatrix5x5.set_pixel(_x, _y, _r, _g, _b)
                    _value -= 10.0
                    if _value < 0.0:
                        _value = 0.0
                print('')
            except IndexError:
                return

    # ......................................................
    def _grow_buffer(self, x, y):
        '''
        Grows a copy of the buffer until the new shape fits inside it.

        :param x: Minimum x size
        :param y: Minimum y size
        '''
        x_pad = max(0, x - self._buf.shape[0])
        y_pad = max(0, y - self._buf.shape[1])
        return numpy.pad(self._buf, ((0, x_pad), (0, y_pad)), 'constant')

    # ..........................................................................
    def _rainbow(self, rgbmatrix5x5, arg):
        '''
        Display a rainbow pattern.
        '''
        global enabled
        self._log.info('starting rainbow...')
        _spacing = 360.0 / 5.0
        _hue = 0
        while enabled:
            for x in range(self._width):
                for y in range(self._height):
                    _hue = int(time.time() * 100) % 360
                    offset = (x * y) / 25.0 * _spacing
                    h = ((_hue + offset) % 360) / 360.0
                    r, g, b = [
                        int(c * 255) for c in colorsys.hsv_to_rgb(h, 1.0, 1.0)
                    ]
                    rgbmatrix5x5.set_pixel(x, y, r, g, b)
#                   r, g, b = [int(c * 255) for c in colorsys.hsv_to_rgb(h + 0.5, 1.0, 1.0)]
#                   rainbow2.set_pixel(x, y, r, g, b)
                if not enabled:
                    break
            rgbmatrix5x5.show()
            #           rainbow2.show()
            time.sleep(0.0001)
        self._clear(rgbmatrix5x5)
        self._log.info('rainbow ended.')

    # ..........................................................................
    def _sworl(self, rgbmatrix5x5, arg):
        '''
        Display a sworl pattern, whatever that is.
        '''
        global enabled
        self._log.info('starting sworl...')

        try:
            for r in range(0, 10, 1):
                rgbmatrix5x5.set_all(r, 0, 0)
                rgbmatrix5x5.show()
                time.sleep(0.003)
            for i in range(0, 5):
                for r in range(10, 250, 10):
                    _blue = r - 128 if r > 128 else 0
                    rgbmatrix5x5.set_all(r, _blue, 0)
                    rgbmatrix5x5.show()
                    time.sleep(0.01)
                if not enabled:
                    break
                for r in range(250, 10, -10):
                    _blue = r - 128 if r > 128 else 0
                    rgbmatrix5x5.set_all(r, _blue, 0)
                    rgbmatrix5x5.show()
                    time.sleep(0.01)
                if not enabled:
                    break
            self._log.info('sworl ended.')
        except KeyboardInterrupt:
            self._log.info('sworl interrupted.')
        finally:
            self.set_color(Color.BLACK)

    # ..........................................................................
    def _wipe(self, rgbmatrix5x5, direction):
        '''
        Display a wipe in the specified direction.
        '''
        if direction is WipeDirection.LEFT or direction is WipeDirection.RIGHT:
            self._wipe_horizontal(rgbmatrix5x5, direction)
        if direction is WipeDirection.UP or direction is WipeDirection.DOWN:
            self._wipe_vertical(rgbmatrix5x5, direction)

    # ..........................................................................
    def _wipe_horizontal(self, rgbmatrix5x5, direction):
        '''
        Note: not implemented yet.
        '''
        global enabled
        raise NotImplementedError()

    # ..........................................................................
    def set_wipe_color(self, color):
        self._wipe_color = color

    # ..........................................................................
    def _wipe_vertical(self, rgbmatrix, direction):
        '''
        Note: UP has not been implemented yet.
        '''
        global enabled
        if not rgbmatrix:
            self._log.debug('null RGB matrix argument.')
            return
        if direction is WipeDirection.DOWN:
            self._log.info('starting wipe DOWN...')
        elif direction is WipeDirection.UP:
            raise NotImplementedError('wipe UP not implemented.')
        else:
            raise ValueError('unrecognised direction argument.')
        _delay = 0.05
        self.set_color(Color.BLACK)
        #       self._set_color(rgbmatrix, Color.BLACK)
        time.sleep(0.1)
        xra = [[0, self._width, 1], [self._width - 1, -1, -1]]
        yra = [[0, self._height, 1], [self._height - 1, -1, -1]]
        colors = [self._wipe_color, Color.BLACK]
        try:
            for i in range(0, 2):
                xr = xra[i]
                yr = yra[i]
                r, g, b = colors[i].rgb
                for x in range(xr[0], xr[1], xr[2]):
                    for y in range(yr[0], yr[1], yr[2]):
                        rgbmatrix.set_pixel(x, y, r, g, b)
                    rgbmatrix.show()
                    time.sleep(_delay)
            self._log.info('wipe ended.')
        except KeyboardInterrupt:
            self._log.info('wipe interrupted.')
        finally:
            self.set_color(Color.BLACK)

    # ..........................................................................
    def set_solid_color(self, color):
        self._color = color

    # ..........................................................................
    def show_color(self, color, orientation):
        self.set_solid_color(color)
        if orientation is Orientation.PORT or orientation is Orientation.BOTH and self._rgbmatrix5x5_PORT:
            self._set_color(self._rgbmatrix5x5_PORT, self._color)
        if orientation is Orientation.STBD or orientation is Orientation.BOTH:
            self._set_color(self._rgbmatrix5x5_STBD, self._color)

    # ..........................................................................
    def get_rgbmatrix(self, orientation):
        '''
        Return the port or starboard RGB matrix.
        '''
        if orientation is Orientation.PORT:
            return self._rgbmatrix5x5_PORT
        if orientation is Orientation.STBD:
            return self._rgbmatrix5x5_STBD
        else:
            return None

    # ..........................................................................
    def show_hue(self, hue, orientation):
        '''
        Set the color of the display to the hue specified as a value from 0.0 - 1.0.

        Not sure this works, abandoned for now.
        '''
        rgb = colorsys.hsv_to_rgb(abs(hue), 1.0, 1.0)
        r = int(rgb[0] * 255.0)
        g = int(rgb[1] * 255.0)
        b = int(rgb[2] * 255.0)
        if orientation is Orientation.PORT or orientation is Orientation.BOTH and self._rgbmatrix5x5_PORT:
            self._rgbmatrix5x5_PORT.set_all(r, g, b)
            self._rgbmatrix5x5_PORT.show()
        if orientation is Orientation.STBD or orientation is Orientation.BOTH:
            self._rgbmatrix5x5_STBD.set_all(r, g, b)
            self._rgbmatrix5x5_STBD.show()

    # ..........................................................................
    def _solid(self, rgbmatrix5x5, arg):
        '''
        Display a specified static, solid color on only the starboard display.
        '''
        global enabled
        #       self.set_color(self._color)
        #       self._set_color(self._rgbmatrix5x5_PORT, self._color)
        self._set_color(self._rgbmatrix5x5_STBD, self._color)
        self._log.info('starting solid color to {}...'.format(
            str.lower(self._color.name)))
        while enabled:
            time.sleep(0.2)

    # ..........................................................................
    def _dark(self, rgbmatrix5x5, arg):
        '''
        Display a dark static color.
        '''
        global enabled
        self._log.info('starting dark...')
        self.set_color(Color.BLACK)
        while enabled:
            time.sleep(0.2)

    # ..........................................................................
    @staticmethod
    def make_gaussian(fwhm):
        x = numpy.arange(0, 5, 1, float)
        y = x[:, numpy.newaxis]
        x0, y0 = 2, 2
        fwhm = fwhm
        gauss = numpy.exp(-4 * numpy.log(2) * ((x - x0)**2 + (y - y0)**2) /
                          fwhm**2)
        return gauss

    # ..........................................................................
    def _blinky(self, rgbmatrix5x5, arg):
        '''
        Display a pair of blinky spots.
        '''
        global enabled
        self._log.info('starting blinky...')
        if self._height == self._width:
            _delta = 0
        else:
            _delta = 2

        while enabled:
            for i in range(3):
                for z in list(range(1, 10)[::-1]) + list(range(1, 10)):
                    fwhm = 5.0 / z
                    gauss = RgbMatrix.make_gaussian(fwhm)
                    start = time.time()
                    for y in range(self._height):
                        for x in range(self._width):
                            h = 0.5
                            s = 0.8
                            if self._height <= self._width:
                                v = gauss[x, y]
#                               v = gauss[x, y + _delta]
                            else:
                                v = gauss[x, y]
#                               v = gauss[x + _delta, y]
                            rgb = colorsys.hsv_to_rgb(h, s, v)
                            r = int(rgb[0] * 255.0)
                            g = int(rgb[1] * 255.0)
                            b = int(rgb[2] * 255.0)
                            rgbmatrix5x5.set_pixel(x, y, r, g, b)
                    rgbmatrix5x5.show()
                    end = time.time()
                    t = end - start
                    if t < 0.04:
                        time.sleep(0.04 - t)
                        pass
                if not enabled:
                    break
        self._clear(rgbmatrix5x5)
        self._log.info('blinky ended.')

    # ..........................................................................
    def _scan(self, rgbmatrix5x5, arg):
        '''
        KITT- or Cylon-like eyeball scanning.
        '''
        global enabled
        self._log.info('starting scan...')

        r = int(255.0)
        g = int(64.0)
        b = int(0.0)
        #       start = time.time()
        #       for x in range(self._width):
        x = 2
        _delay = 0.25

        while enabled:
            #           for i in range(count):
            for y in range(0, self._height):
                rgbmatrix5x5.clear()
                rgbmatrix5x5.set_pixel(x, y, r, g, b)
                rgbmatrix5x5.show()
                time.sleep(_delay)
            for y in range(self._height - 1, 0, -1):
                rgbmatrix5x5.clear()
                rgbmatrix5x5.set_pixel(x, y, r, g, b)
                rgbmatrix5x5.show()
                time.sleep(_delay)
            if not enabled:
                break
        self._clear(rgbmatrix5x5)
        self._log.debug('scan ended.')

    # ..........................................................................
    def _random(self, rgbmatrix5x5, arg):
        '''
        Display an ever-changing random pattern.
        '''
        global enabled
        self._log.info('starting random...')
        count = 0
        while enabled:
            rand_hue = numpy.random.uniform(0.1, 0.9)
            rand_mat = numpy.random.rand(self._width, self._height)
            for y in range(self._height):
                for x in range(self._width):
                    #                   h = 0.1 * rand_mat[x, y]
                    h = rand_hue * rand_mat[x, y]
                    s = 0.8
                    v = rand_mat[x, y]
                    rgb = colorsys.hsv_to_rgb(h, s, v)
                    r = int(rgb[0] * 255.0)
                    g = int(rgb[1] * 255.0)
                    b = int(rgb[2] * 255.0)
                    rgbmatrix5x5.set_pixel(x, y, r, g, b)
            if not enabled:
                break
            rgbmatrix5x5.show()
            time.sleep(0.01)
        self._clear(rgbmatrix5x5)
        self._log.info('random ended.')

    # ..........................................................................
    def set_color(self, color):
        '''
        Set the color of both RGB Matrix displays.
        '''
        if self._rgbmatrix5x5_PORT:
            self._set_color(self._rgbmatrix5x5_PORT, color)
        self._set_color(self._rgbmatrix5x5_STBD, color)

    # ..........................................................................
    def _set_color(self, rgbmatrix5x5, color):
        '''
        Set the color of the RGB Matrix.
        '''
        rgbmatrix5x5.set_all(color.red, color.green, color.blue)
        rgbmatrix5x5.show()

    # ..........................................................................
    def _clear(self, rgbmatrix5x5):
        '''
        Clears the RGB Matrix by setting its color to black.
        '''
        self._set_color(rgbmatrix5x5, Color.BLACK)

    # ..........................................................................
    def set_display_type(self, display_type):
        self._display_type = display_type

    # ..........................................................................
    def close(self):
        if self._closing:
            self._log.warning('already closing.')
            return
        self.set_color(Color.BLACK)
        self._closing = True
        self.disable()
        self._closed = True
        self._log.info('closed.')
コード例 #33
0
class JobQueueManager():
    """ Handles the monitoring of the JobQueue and runs jobs """

    def __init__(self, config, verbose, daemon=True):
        """ Parse config file and setup the logging """

        self.config = config
        self.verbose = verbose
        self.daemon = daemon

        self.running = True

        self.logger = Logger(self.config.DAEMON.log_name,
                             self.config.DAEMON.log_dir).get_logger()

        self.pidfile = self.config.DAEMON.pid_file

        self.api_manager = FrontendApiManager(self.config.API, logger=self.logger)
        self.sync_manager = SyncManager(self.api_manager, logger=self.logger)

    def daemonize(self):
        """ Turn this running process into a deamon """
        # Perform first fork
        try:
            pid = os.fork()
            if pid > 0:
                self.logger.error('First fork returned but was >0, exiting')
                sys.exit(1)
            self.logger.debug('First fork worked')
        except OSError as e:
            self.logger.error('First fork failed ({0})'.format(e))
            raise Exception(e)

        # Escape out of where we started
        os.chdir(self.config.DAEMON.working_dir)
        os.umask(self.config.DAEMON.umask)
        os.setsid()

        # Perform second fork
        try:
            pid = os.fork()
            if pid > 0:
                self.logger.error('Second fork returned but was >0, exiting')
                sys.exit(1)
        except OSError as e:
            self.logger.error('Second fork failed ({0})'.format(e))
            raise Exception(e)

        # Close off the stdXXX
        self.logger.debug('Closing file descriptors')
        sys.stdout.flush()
        sys.stderr.flush()
        si = open(os.devnull, 'r')
        so = open(os.devnull, 'a+')
        se = open(os.devnull, 'a+')

        os.dup2(si.fileno(), sys.stdin.fileno())
        os.dup2(so.fileno(), sys.stdout.fileno())
        os.dup2(se.fileno(), sys.stderr.fileno())

        # Register the pid file deletion
        atexit.register(self.on_exit)

        # Write the PID to file
        pid = str(os.getpid())
        with open(self.pidfile, 'w+') as f:
            f.write(pid + '\n')
        self.logger.debug("Written PID of '{0}' into file '{1}'".format(pid, self.pidfile))

    def on_exit(self):
        """ Delete the PID file """
        os.remove(self.pidfile)
        self.logger.debug('Removed the pid file ({0})'.format(self.pidfile))

    def run(self):
        """ Main worker loop """
        while self.running:
            # Loop over the job queue and handle any jobs that we are not processing yet
            job_queue = self.api_manager.get_job_queue()

            if not job_queue:
                self.logger.info('Job queue empty')

            for job in job_queue:
                try:
                    self.sync_manager.handle(job)
                    self.logger.info('Starting job {0}'.format(job['name']))
                except self.sync_manager.AlreadyWorkingOnException:
                    self.logger.debug('Already working on job {0}'.format(job['name']))
                except self.sync_manager.ActionAlreadyWorkingOnException:
                    self.logger.debug("action='{0}' job='{1}' message='action already working on'".format(
                        job['action'], job['name']))

            # Go over all queued jobs and complete any finished ones, report on what jobs we finished off
            for job in self.sync_manager.complete_jobs():
                self.logger.info('Removed finished job {0}'.format(job))

            # Sleep for a set time before checking the queue again
            sleep_time = float(self.config.DAEMON.sleep)
            self.logger.debug('Sleeping for {0} seconds'.format(sleep_time))
            time.sleep(sleep_time)

        if not self.running:
            # Good-ish place to be in
            self.logger.warning('Main loop was stopped (running = False)')
            return True
        else:
            # Bad place to be in
            self.logger.warning('Main loop broke without us saying (running = True)')
            return False

    def start(self):
        """ Start the daemon """
        # Check for a pidfile to see if the daemon already runs
        try:
            with open(self.pidfile, 'r') as pf:
                pid = int(pf.read().strip())
        except IOError:
            if not os.path.isdir(os.path.dirname(self.pidfile)):
                print('ERROR: PID folder does not exist: {0}'.format(os.path.dirname(self.pidfile)))
                sys.exit(1)
            pid = None

        if pid:
            # pidfile exists, bail
            message = 'pidfile {0} already exists. Daemon already running?'
            self.logger.error(message.format(self.pidfile))
            sys.exit(1)
        
        # Turn into a daemon if we are told to
        if self.daemon:
            self.daemonize()
            message = 'We are now a daemon, all stdout/stderr redirected'
            self.logger.debug(message)
        else:
            print('INFO: Skipping daemon mode')
            print('INFO: Log file: {0}'.format(self.logger.log_file))

        # Work our magic
        self.run()

        # Finishing up properly
        self.logger.info('Finished successfully, bye bye!')
        return True

    def stop(self):
        """ Stop the daemon, kill off all jobs """
        # Check for a pidfile to see if the daemon already runs
        try:
            with open(self.pidfile, 'r') as pf:
                pid = int(pf.read().strip())
        except IOError:
            if not os.path.isdir(os.path.dirname(self.pidfile)):
                message = 'ERROR: PID folder does not exist: {0}'
                print(message.format(os.path.dirname(self.pidfile)))
                sys.exit(1)
            pid = None

        if not pid:
            message = 'pidfile {0} does not exist. Daemon not running?'
            self.logger.error(message.format(self.pidfile))
            sys.exit(1)

        # Go over all queued jobs and close off any finished ones, report on the number we finished off
        for job in self.sync_manager.complete_jobs():
            self.logger.info('Removed finished job {0}'.format(job))

        # Go over all currently running jobs, report on them and then kill them.
        for process in self.sync_manager.processing_queue:
            self.logger.info('Still processing job {0}'.format(process.name))

            # We now kill off the process, upon restart the job should restart again
            self.logger.warning('Killing job {0}'.format(process.name))
            process.terminate()

        self.running = False
コード例 #34
0
ファイル: plugincontroller.py プロジェクト: blejdfist/NeuBot
 def find_plugin(self, name, search_dir = None):
     for path, candidate_name in self.plugin_candidates(search_dir):
         if candidate_name.lower() == name.lower():
             module_name = path + "." + candidate_name
             Logger.debug("Candidate plugin '%s'" % module_name)
             return module_name
コード例 #35
0
ファイル: jsonnd.py プロジェクト: SiChiTong/ros-1
class JsonNdParser(object):
    def __init__(self, delim, level, include_datatype=True):
        self._log = Logger("jnp", level)
        self._delim = delim
        self._log.info('delimiter: \'{}\''.format(delim))
        self._include_datatype = include_datatype
        self._log.info('include datatype: {}'.format(self._include_datatype))
        csv.register_dialect("csv-vbar", delimiter=self._delim)
        self._log.info('ready.')

    #...........................................................................
    def parse_file(self, filename):
        '''
           Parse the CSV file to a List of JSON strings.
        '''
        _list = []
        try:
            with open(filename) as csv_file:
                _header = []
                csv_reader = csv.reader(csv_file, delimiter='|')
                _line_count = 0
                for _row_data in csv_reader:
                    if _line_count == 0:  # then reada header
                        self._log.debug('raw column names are: {}'.format(
                            ', '.join(_row_data)))
                        for i in range(len(_row_data) - 1):
                            if i == 0:
                                _header.append('@timestamp')
                            elif i == 1:
                                _header.append('row')
                            else:
                                _value = _row_data[i].strip()
                                _header.append(_value)
                        self._log.info('header field names:\n' + Fore.YELLOW +
                                       '{}'.format(', '.join(_header)))
                        _line_count += 1
                    else:
                        _json_row = self._parse_row(_header, _row_data,
                                                    _line_count)
                        _list.append(_json_row)
                        _line_count += 1
            self._log.info('processed {} lines.'.format(_line_count))
        except Exception as e:
            raise JsonNdParserException(
                'error parsing CSV to JSON: {}\n{}'.format(
                    e, traceback.format_exc()))

        self._log.info('returning list of {} elements.'.format(len(_list)))
        return _list

    #...........................................................................
    def _parse_row(self, header, row, line_count):
        '''
           Parse the row, returning it as a JSON string. 
           This uses the header to provide field names.
        '''
        _row_dict = OrderedDict()
        self._log.debug('processing row {}...'.format(line_count))
        for i in range(len(row) - 1):
            _value = row[i].strip()
            if i == 0:
                _datatype = 'date'
            elif i == 1:
                _datatype = 'integer'
                _value = line_count
            elif '.' in _value:
                _datatype = 'float'
                _value = float(_value)
            else:
                _datatype = 'integer'
                _value = int(_value)
            if self._include_datatype:
                self._log.debug(Fore.MAGENTA +
                                '[{}] datatype: {}; value: \'{}\''.format(
                                    i, _datatype, _value))
                _row_dict['{}:{}'.format(header[i], _datatype)] = _value
            else:
                _row_dict['{}'.format(header[i])] = _value

        _json_row = json.dumps(_row_dict)
        self._log.debug(Fore.BLUE + 'JSON:\n{}'.format(_json_row) +
                        Style.RESET_ALL)
        self._log.info('processed row {}.'.format(line_count))
        return _json_row
コード例 #36
0
ファイル: ftpstore.py プロジェクト: tussock/Vault
    import paramiko
else:
    from ftplib import FTP, FTP_TLS


from storebase import *
from lib import utils
from lib import const


#    Do this last!
from lib.logger import Logger

log = Logger("io")

log.debug("Use Paramiko: ", "yes" if use_paramiko else "no")


class FTPStreamer(Thread):
    def __init__(self, ftp, path, mode):
        Thread.__init__(self, name="FTPWorker")
        log.trace("FTPStreamer init", ftp, path, mode)
        self.ftp = ftp
        self.path = path
        self.mode = mode

        self.lock = RLock()
        self.buffer = []
        self.bufsize = 0
        self.done = False
        self.error = None