Esempio n. 1
0
    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))
Esempio n. 2
0
 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))
Esempio n. 3
0
 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))
Esempio n. 4
0
    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)
Esempio n. 5
0
    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)
Esempio n. 6
0
 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
Esempio n. 7
0
    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)
Esempio n. 8
0
    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
Esempio n. 9
0
    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()
Esempio n. 10
0
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)
Esempio n. 11
0
    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)
Esempio n. 12
0
    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)
Esempio n. 13
0
    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)