def onMessage(self, payload, isBinary): if isBinary: logger.warning( "Binary message received ({} bytes): ignoring".format( len(payload))) return try: unicode_message = payload.decode('utf8') except UnicodeDecodeError: logger.exception("Cannot decode {}: ignoring".format(payload)) return try: message = json.loads(unicode_message) except json.JSONDecodeError: logger.exception( "Cannot load {}: ignoring".format(unicode_message)) return ok, warning = self.validate_message(message) if not ok: logger.info("Received {}".format(message)) logger.warning(warning) logger.info("Ignoring") else: logger.debug("Received {}".format(message)) self.log_message(message, to_server=False) self.factory.process_event(message[P.EVENT])
def play_pause_stop(self, action, method_name, delay): if not isinstance(delay, (int, float)): raise TypeError("Delay must be int or float (received={}): skipping".format(delay)) logger.info("{} video".format(action)) reactor.callLater(delay, getattr(self.player, method_name))
def eject_floppy(self, reader_index): logger.info("Remove floppy {} from reader index={}".format( self.floppy_readers[reader_index], reader_index)) self.floppy_readers[reader_index] = None if self.status != "playing": logger.debug("Game is not started yet: nothing to do") return animation_task = self.tasks.get("animation", None) if animation_task and animation_task.active(): animation_task.cancel() chrono_task = self.tasks.get("chrono", None) if chrono_task and chrono_task.active(): logger.debug( "Chrono is running: stopping chrono and running bad move animation" ) chrono_task.cancel() self.bad_move_failure_animation(reader_index) else: if all([floppy is None for floppy in self.floppy_readers]): logger.debug( "All floppies have been removed: restart the game") self.restart_game() else: logger.debug("Some floppies remain inserted: updating errors") self.display_inserted_floppies_errors_before_restart()
def cancel_tasks(self): logger.debug("Cancelling tasks") if self.led_task and self.led_task.active(): logger.info("Cancelling led task") self.led_task.cancel() if self.stop_motor_task and self.stop_motor_task.active(): logger.info("Cancelling stop motor task") self.stop_motor_task.cancel()
def position_down(self): if self.motor_up.is_active: logger.info( "Motor was in up position. Turning off the up position and sleeping for {} seconds" .format(self.up_down_minimum_delay)) self.motor_up.off() time.sleep(self.up_down_minimum_delay) logger.info("Setting the motor in down position") self.motor_down.on()
def connectionLost(self, reason): if self.client_type == P.CLIENT_ADMIN: identifier = self.name self.factory.unregister_admin(self) elif self.client_type == P.CLIENT_NODE: identifier = "{}@{}".format(self.name, self.channel) self.factory.unregister_node(self) else: identifier = self.peer logger.info("Lost connection with {}".format(identifier))
def play_pause_stop(self, action, method, track_id, delay=0): if not isinstance(delay, (int, float)): raise ValueError("Delay must be int or float (received={}): skipping".format(delay)) logger.info("{} track id={}".format(action, track_id)) track = self.tracks.get(track_id, None) if track is None: raise ValueError("Unknown track id={}: aborting".format(track_id)) reactor.callLater(delay, getattr(track, method))
def new_success_sequence(self): logger.debug("Loading a new success sequence (try counter={})".format( self.try_counters[self.round])) round_sequences = self.difficulties[self.difficulty][self.round] sequence_index = (self.try_counters[self.round] - 1) % len(round_sequences) self.success_sequence = round_sequences[sequence_index] logger.info("The new success sequence is {}".format( self.success_sequence))
def event_play(self, sound_id: str, delay=0): if not isinstance(delay, (int, float)): raise ValueError( "Delay must be int or float (received={}): skipping".format( delay)) logger.info("Playing sound id={}".format(sound_id)) sound = self.sounds.get(sound_id, None) if sound is None: raise ValueError("Unknown sound id={}: aborting".format(sound_id)) reactor.callLater(delay, self.sound_player, sound)
def check_myself(self): callLater(0, self.check_myself) is_activated = bool(self.device.value) if is_activated is self.last_state: return self.last_state = is_activated if is_activated: logger.info("Cell (pin={}) has been activated".format(self.pin)) self.on_activation() else: logger.info("Cell (pin={}) has been deactivated".format(self.pin)) self.on_deactivation()
def event_pause(self, video_id: str, delay=0): if not isinstance(delay, (int, float)): raise ValueError( "Delay must be int or float (received={}): skipping".format( delay)) if video_id not in self.videos: raise ValueError( "Video id={} is not configured: aborting".format(video_id)) if delay > 0: logger.info("Scheduling to pause video {} in {} seconds".format( video_id, delay)) reactor.callLater(delay, self.videos[video_id].pause)
def log_message(self, message, to_server=True): identifier = "{}@{}".format(self.name, self.channel) if to_server: from_ = identifier to = P.SERVER else: from_ = P.SERVER to = identifier type_ = message[P.MESSAGE_TYPE] content = message.get(P.EVENT, "") logger.info("[{} > {}] {} {}".format(from_, to, type_, content))
def event_set_slide(self, slide_index: int, chapter_id: str, delay=0): if not isinstance(delay, (int, float)): raise TypeError("Delay must be int or float (received={}): skipping".format(delay)) if slide_index >= len(self.player.slides): raise ValueError("Video has only {} slides ({} is out of range): skipping".format( len(self.player.slides), slide_index)) if chapter_id not in self.player.chapters: raise ValueError("Video has no chapter id={}: skipping".format( chapter_id)) logger.info("Setting chapter id={} in slide index={}".format( chapter_id, slide_index)) reactor.callLater(delay, self.player.set_slide, slide_index, chapter_id)
def event_reset(self): logger.info("Resetting") self.motor.position_up() logger.info("Turning off the led") self.led.off() self.cancel_tasks() logger.info("Scheduling the motor to stop after {} seconds".format( self.pull_delay)) self.stop_motor_task = callLater(self.pull_delay, self.motor.stop) logger.info("Starting to listen to the switch") if not self.check_switch_task.running: self.check_switch_task.start(1 / 25)
def event_down(self): logger.info("Pulling table down") self.motor.position_down() self.cancel_tasks() logger.info("Scheduling the led to turn on after {} seconds".format( self.pull_delay)) self.led_task = callLater(self.pull_delay, self.led.on) logger.info("Scheduling the motor to stop after {} seconds".format( self.pull_delay)) self.stop_motor_task = callLater(self.pull_delay, self.motor.stop) if self.check_switch_task.running: logger.info("Stop listening to the switch") self.check_switch_task.stop()
def insert_floppy(self, reader_index, floppy): logger.info("Insert floppy {} in reader index={}".format( floppy, reader_index)) self.floppy_readers[reader_index] = floppy if self.status != "playing": logger.debug("Game is not started yet: nothing to do") return animation_task = self.tasks.get("animation", None) if animation_task and animation_task.active(): animation_task.cancel() # Chrono has not started <=> game is not started chrono_task = self.tasks.get("chrono", None) if not chrono_task or not chrono_task.active(): logger.debug("Chrono is not running: updating errors") self.display_inserted_floppies_errors_before_restart() # The game has started else: expected_reader_index = 4 - self.floppy_readers.count(None) insert_in_expected_reader = reader_index == expected_reader_index good_insert = self.floppy_readers[ reader_index] == self.success_sequence[reader_index] if not insert_in_expected_reader or not good_insert: logger.debug( "Bad insert: stopping chrono and running bad move animation" ) chrono_task.cancel() self.bad_move_failure_animation(reader_index) else: if expected_reader_index == 4: logger.debug("Good insert in the last reader: victory!") self.status = "success" else: logger.debug("Good insert: running good move animation") self.good_move_animation(reader_index)
def event_up(self): logger.info("Pulling table up") self.motor.position_up() logger.info("Turning off the led") self.led.off() self.cancel_tasks() logger.info("Scheduling the motor to stop after {} seconds".format( self.pull_delay)) self.stop_motor_task = callLater(self.pull_delay, self.motor.stop)
def generate_success_sequence(self): logger.debug("Generating new success sequence") new_sequence = [] available_floppies = self.difficulties[ self.difficulty]["available_floppies"] if 6 > len(available_floppies): # The algorithm below might end up in a deadlock logger.error( "Please submit at least 6 available floppies: skipping sequence generation" ) return for i in range(5): valid_choice = False while not valid_choice: floppy = random.choice(available_floppies) if self.success_sequence[ i] != floppy and floppy not in new_sequence: new_sequence.append(floppy) valid_choice = True self.success_sequence = new_sequence logger.info("The new success sequence is {}".format( self.success_sequence))
def onConnect(self, response): logger.info("Connected to server: {}".format(response.peer))
def onOpen(self): logger.info("Node connected: {}".format(self.peer))
def check_switch(self): if self.switch.is_active: if not self.motor.is_position_up: logger.info("Switch is active and motor is in position up") self.event_down() self.check_switch_task.stop()
def stop(self): logger.info("Stopping the motor") self.motor_up.off() self.motor_down.off()
def onMessage(self, payload, isBinary): if isBinary: logger.warning( "Binary message received ({} bytes): ignoring".format( len(payload))) return try: unicode_message = payload.decode('utf8') except UnicodeDecodeError: logger.exception("Cannot load {}: ignoring".format(payload)) return try: message = json.loads(unicode_message) except json.JSONDecodeError: logger.exception( "Cannot load {}: ignoring".format(unicode_message)) return ok, warning = self.validate_message(message) if not ok: logger.info("Received {}".format(message)) logger.warning(warning) logger.info("Ignoring") else: logger.debug("Received {}".format(message)) self.log_message(message, to_server=True) if self.client_type == P.CLIENT_NODE: if message[P.MESSAGE_TYPE] == P.MESSAGE_TYPE_EVENT: event = message[P.EVENT] self.factory.process_event(self.name, self.channel, event) elif message[P.MESSAGE_TYPE] == P.MESSAGE_TYPE_LOG: level = message[P.LOG_LEVEL] content = message[P.LOG_CONTENT] if level == P.LOG_LEVEL_INFO: self.factory.send_log_info(content) elif level == P.LOG_LEVEL_ERROR: self.factory.send_log_error(content) elif self.client_type == P.CLIENT_ADMIN: room_id = message[P.ROOM_ID] if message[P.MESSAGE_TYPE] == P.MESSAGE_TYPE_RUN: self.factory.process_run_room(room_id) elif message[P.MESSAGE_TYPE] == P.MESSAGE_TYPE_HALT: self.factory.process_halt_room(room_id) elif message[P.MESSAGE_TYPE] == P.MESSAGE_TYPE_RESET: self.factory.process_reset_room(room_id) elif message[P.MESSAGE_TYPE] == P.MESSAGE_TYPE_SEND_EVENT_TO: node = message[P.SEND_EVENT_NODE] event_to_send = message[P.EVENT] self.factory.process_send_event_to(room_id, node, event_to_send) elif message[P.MESSAGE_TYPE] == P.MESSAGE_TYPE_SEND_EVENT_AS: node = message[P.SEND_EVENT_NODE] event_to_send = message[P.EVENT] self.factory.process_send_event_as(room_id, node, event_to_send) elif message[ P.MESSAGE_TYPE] == P.MESSAGE_TYPE_PRESSED_ADMIN_BUTTON: button_id = message[P.PRESSED_BUTTON_ID] self.factory.process_on_admin_button_pressed( room_id, button_id) else: self.process_i_am_message(message)
def event_stop(self): logger.info("Stopping the table") self.motor.stop()
def event_on(self, color): logger.info("Turning on {}".format(color)) self.colors[color].on()
def event_off(self, color): logger.info("Turning off {}".format(color)) self.colors[color].off()
def onClose(self, wasClean, code, reason): logger.info("WebSocket connection closed: {}".format(reason))
def onConnect(self, request): logger.info("Node connecting: {}".format(request.peer))
def display_sequence(self): logger.info("Displaying sequence") self.skip_skippable_animations() def pre_display_animation(): self.unskippable_animation_task = callLater(1.6, display_element) for ad in self.air_ducts.values(): ad.set_color("black") self.fluid_to_color( ad.led_index, "red", 0.1, "display_element", self.fluid_to_color, ad.led_index, "black", 0.1, "display_element", self.fluid_to_color, ad.led_index, "red", 0.1, "display_element", self.fluid_to_color, ad.led_index, "black", 0.1, "display_element", self.fluid_to_color, ad.led_index, "red", 0.1, "display_element", self.fluid_to_color, ad.led_index, "black", 0.1, "display_element", ) def display_element(index=0): if index < len(self.success_sequence): # For the last element of the sequence, this code saves a task in the unskippable_animation_task, # ensuring that the animation time lasts until the last led has turned black again. self.unskippable_animation_task = callLater( 2, display_element, index + 1) element = self.success_sequence[index] self.air_ducts[element["air_duct"]].fan.on() self.animation_tasks["fan"] = callLater( 1.4, self.air_ducts[element["air_duct"]].fan.off) self.fluid_to_color( self.air_ducts[element["air_duct"]].led_index, element["color"], 1, "display_element", self.fluid_to_color, self.air_ducts[element["air_duct"]].led_index, "black", 1, "display_element", ) pre_display_animation()
def process_event(self, event): logger.debug("Processing event '{}'".format(event)) if type(event) is not dict: logger.debug("Unknown event: skipping") return if "action" not in event: logger.debug("Event has no action: skipping") return if event["action"] == "calibrate": auto = event.get("auto", False) if auto: logger.info("Start an auto calibration") self.niryo.calibrate_auto() else: logger.info("Start a manual calibration") self.niryo.calibrate_manual() logger.info("Calibration finished") elif event["action"] == "configure": if "learning_mode" in event: if event["learning_mode"]: logger.info("Activate learning mode") self.niryo.activate_learning_mode(True) else: logger.info("Deactivate learning mode") self.niryo.activate_learning_mode(False) if "velocity" in event: velocity = int(event["velocity"]) assert 1 <= velocity <= 100, "Speed must be between 1 and 100" logger.info("Set velocity to {}".format(velocity)) self.niryo.set_arm_max_velocity(velocity) elif event["action"] == "move_position": position_name = str(event.get("position", "")) joints = self.get_joints_from_position_name(position_name) self.niryo.move_joints(joints) elif event["action"] == "move_joint": joint = int(event.get("joint", 0)) assert 0 <= joint <= 5, "Joint must be between 0 and 5" position_name = str(event.get("position", "")) position_joints = self.get_joints_from_position_name(position_name) joints = self.niryo.joints[:] joints[joint] = position_joints[joint] self.niryo.move_joints(joints) elif event["action"] == "open_gripper": self.niryo.open_gripper(TOOL_GRIPPER_1_ID, 350) elif event["action"] == "close_gripper": self.niryo.close_gripper(TOOL_GRIPPER_1_ID, 350) else: logger.debug("Unknown action type '{}': skipping".format(event["action"]))