def event_set_status(self, status: str): if self.success is False: if status in self.STATUSES: logger.info("Setting status to '{}'".format(status)) self.status = status if status == 'alarm': self.event_set_led_color( 'red', sum(led_strip for led_strip, led_color in self.leds.items() if led_color != 'black')) # If all cells are deactivated while an alarm has been raised. This case should not happen because # players are supposed to be walking on the floor to raise an alarm. But there might be corner cases # where a player extends their hand, is on a cell with no load sensor or if this event has been # triggered from the admin interface... if all(not c for c in self.cells): self.clear_alarm_task = reactor.callLater( self.clear_alarm_delay, self.event_set_status, "playing") elif status == 'playing': self.event_set_led_color( 'orange', sum(led_strip for led_strip, led_color in self.leds.items() if led_color != 'black')) self.notify_clear() else: logger.warning("Unknown status '{}': skipping".format(status)) else: logger.warning( "Node is in success mode: ignoring set status to '{}'".format( status))
def cancel_looping_task(self): logger.debug('Cancelling looping task') try: self.looping_task.cancel() except Exception as e: logger.warning( "Could not cancel looping task (reason={})".format(e))
def cancel_release_task(self): logger.debug('Cancelling release task') try: self.release_task.cancel() except Exception as e: logger.warning( "Could not cancel release task (reason={})".format(e))
def onMessage(self, payload, isBinary): if isBinary: logger.warning( "Binary message received ({} bytes): ignoring".format( len(payload))) return unicode_message = payload.decode('utf8', 'replace') try: message = json.loads(unicode_message) except json.JSONDecodeError: logger.exception( "Cannot load {}: ignoring".format(unicode_message)) return # message could be validated here with something like pydantic logger.debug("{} >>> {}".format(self, message)) try: if message["action"] == "publish": self.factory.publish(message["event"], message["channel"]) elif message["action"] == "subscribe": self.subscribe(message["channel"]) except Exception: logger.error( "Error while trying to process message={}: skipping".format( message), exc_info=True)
def status(self, value): if value not in self.STATUSES: logger.warning("Status {} not in {}: skipping".format( value, ", ".join(self.STATUSES))) return if value == self.status: logger.info("Status is already {}: skipping".format(value)) return logger.info("Setting status to {}".format(value)) self._status = value if self._status == "inactive": self.skip_skippable_animations() if self.unskippable_animation_task and self.unskippable_animation_task.active( ): self.unskippable_animation_task.cancel() self.on_inactive() elif self._status == "playing": self.skip_skippable_animations() if self.unskippable_animation_task and self.unskippable_animation_task.active( ): self.unskippable_animation_task.cancel() self.on_playing() elif self._status == "success": self.on_success() self.service.notify_status(self.status)
def difficulty(self, value): if value not in self.difficulties: logger.warning("Difficulty {} not in {}: skipping".format( value, ", ".join(self.difficulties))) else: logger.info("Setting difficulty to {}".format(value)) self._difficulty = value
def __init__(self, config=..., *args, **kwargs): self.config = config if config is not ... else {} self._name = self.config.get('name', 'default_name') self._default_publication_channel = self.config.get('default_publication_channel', 'default_channel') self._subscriptions = self.config.get('subscriptions', []) rpi_detected = False try: with open('/proc/cpuinfo', 'r') as f: rpi_detected = any(['Raspberry Pi' in line for line in f.readlines()]) except Exception: pass if not rpi_detected: logger.warning("The detected platform is not a raspberry pi: mocking gpiozero library pin interfaces") Device.pin_factory = MockFactory() Device.pin_factory.pin_class = MockPWMPin serials = self.config.get('serials', []) self._serials = {} for serial in serials: port = serial['port'] baud_rate = serial.get('baud_rate', 9600) buffering_interval = serial.get('buffering_interval', 0.1) self._serials[serial['port']] = Serial(port, baud_rate, buffering_interval) self._serials[serial['port']].process_event = self.process_event # magic self._first_connection = False EventFilterMixin.__init__(self) Node.__init__(self, *args, **kwargs)
def __init__(self, *args, **kwargs): super(MusicPlayer, self).__init__(*args, **kwargs) initial_master_volume = self.config.get('master_volume', None) master_volume_mixer = self.config.get('mixer', '') default_initial_volume = self.config.get('default_volume', 100) player = self.config.get('player', 'vlc') if player == 'vlc': track_handler = VLCSelfReleasingTrackPlayer looping_track_handler = VLCLoopingTrackPlayer elif player == 'pyglet': track_handler = PygletTrackPlayer looping_track_handler = PygletLoopingTrackPlayer loop = LoopingCall(self.pyglet_loop) loop.start(1 / 30) else: raise ValueError( "Bad player value ({}). Possible values are vlc or " "pyglet.".format(player)) try: self.master_volume = MasterVolume( initial_volume=initial_master_volume, mixer=master_volume_mixer, ) except Exception: logger.exception() logger.warning( "Unable to initialize the master volume controller. Further " "actions on the master volume will be ignored.") self.master_volume = None self.tracks = {} for track in self.config.get('tracks', []): id_ = track['id'] path = track['path'] volume = track.get('volume', default_initial_volume) mode = track.get('mode', 'one_shot') if mode == 'loop': loop_a = track['loop_a'] loop_b = track['loop_b'] handler = looping_track_handler( track_id=id_, media_path=path, loop_a=loop_a, loop_b=loop_b, pause_callback=self.pause_callback, stop_callback=self.stop_callback, resume_callback=self.resume_callback, loop_callback=self.loop_callback, initial_volume=volume, ) else: handler = track_handler( media_path=path, initial_volume=volume, ) self.tracks[id_] = handler
def load_printer_patterns(self): patterns_directory = self.config['printer_patterns_directory'] for filename in os.listdir(patterns_directory): path = os.path.join(patterns_directory, filename) if not os.path.isfile(path): logger.warning("{} is not a file: skipping".format(path)) continue with open(path, 'r') as fh: logger.info("Adding printer pattern {}".format(filename)) self.printer_patterns[filename] = fh.readlines()
class Cylinders(MagicNode): def __init__(self, *args, **kwargs): super(Cylinders, self).__init__(*args, **kwargs) self.success = False self.difficulty = 'normal' self.delay = self.config['delay'] self.index_mapping = self.config['index_mapping'] self.slots = {} for key, slot in self.config['slots'].items(): red_led = gpiozero.OutputDevice(slot['red_pin']) green_led = gpiozero.OutputDevice(slot['green_pin']) self.slots[key] = { 'current_tag': None, 'expected_tag': slot['expected_tag'], 'red_led': red_led, 'green_led': green_led, 'delayed_task': None, } @on_event(filter={ArduinoProtocol.CATEGORY: ArduinoProtocol.READ}) def serial_event_read(self, port, /, i: int, t): reader_index = i tag = t global_reader_index = self.index_mapping[port].get(reader_index, None) if global_reader_index is None: logger.warning("Undeclared local reader index '{}' for port {}: skipping".format(reader_index, port)) return if global_reader_index not in self.slots: logger.warning("Undeclared global reader index '{}': skipping".format(global_reader_index)) return serialized_tag = "-".join([str(byte) for byte in tag]) if tag else None self.slots[global_reader_index]['current_tag'] = serialized_tag if self.slots[global_reader_index]['delayed_task'] and self.slots[global_reader_index]['delayed_task'].active(): self.slots[global_reader_index]['delayed_task'].cancel() self.slots[global_reader_index]['delayed_task'] = reactor.callLater(self.delay, self.update_leds)
def status(self, value): if value not in self.STATUSES: logger.warning("Status not in {}: skipping".format( value, ", ".join(self.STATUSES))) return if value == self.status: logger.debug("Status is already {}: skipping".format(value)) return logger.debug("Setting status to {}".format(value)) self._status = value if self._status == "inactive": self.on_inactive() elif self._status == "playing": self.on_playing() self.service.notify_status(self.status)
def difficulty(self, value): if value not in self.difficulty_settings: logger.warning( "Unknown difficulty {} (must be one of {}): skipping".format( value, ", ".join(self.difficulty_settings.keys()))) return self._difficulty = value bitmask = self.get_bitmask(self.difficulty_settings[value]['lasers']) dynamic_bitmask = self.get_bitmask( self.difficulty_settings[value]['dynamic_lasers']) dynamic_downtime = self.difficulty_settings[value][ 'dynamic_laser_downtime'] dynamic_uptime = self.difficulty_settings[value][ 'dynamic_laser_uptime'] dynamic_incremental_offset = self.difficulty_settings[value][ 'dynamic_laser_incremental_offset'] self.event_laser_on(bitmask, dynamic_bitmask, dynamic_downtime, dynamic_uptime, dynamic_incremental_offset)
def onMessage(self, payload, isBinary): if isBinary: logger.warning("Binary message received ({} bytes): ignoring".format(len(payload))) return unicode_message = payload.decode('utf8', 'replace') try: message = json.loads(unicode_message) except json.JSONDecodeError: logger.warning("Cannot load {}: ignoring".format(unicode_message)) return # message could be validated here with something like pydantic try: logger.info("{} <<< {}".format(message['channel'], message['event'])) self.factory.process_event(message['event'], message['channel']) except Exception: logger.error("Error while trying to process message={}".format(message), exc_info=True)