Beispiel #1
0
    def test(self):

        cfc = CompoundFunctionContainer(13)

        t0 = {"source": "initial", "target": "s1"}
        t1 = {
            "trigger": "a",
            "source": "s1",
            "function": cfc.compound,
            "targets": "s2 s3",
        }
        t2 = {"trigger": "b", "source": "s2", "target": "final"}
        t3 = {"trigger": "b", "source": "s3", "target": "final"}

        stm = Machine(name="stm", transitions=[t0, t1, t2, t3], obj=None)

        _ = stmpy.get_graphviz_dot(stm)

        driver = Driver()
        driver.add_machine(stm)
        driver.start(keep_active=False)
        driver.send("a", "stm", args=["hi"], kwargs={"b1": "bbb"})
        driver.send("b", "stm")

        driver.wait_until_finished()
Beispiel #2
0
    def test(self):
        terminate = Terminate()
        t0 = {"source": "initial", "target": "s_1"}
        t1 = {
            "trigger": "t",
            "source": "s_1",
            "target": "s_2",
            "effect": "action"
        }
        stm_terminate = Machine(name="stm_terminate",
                                transitions=[t0, t1],
                                obj=terminate)
        terminate.stm = stm_terminate

        scheduler = Driver()
        scheduler.add_machine(stm_terminate)
        scheduler.start(max_transitions=2, keep_active=False)
        scheduler.send("t", "stm_terminate")

        scheduler.wait_until_finished()

        _ = stmpy.get_graphviz_dot(stm_terminate)
        _ = scheduler.print_status()

        self.assertTrue(True)
Beispiel #3
0
    def __init__(self, driver: Driver, serverAPI: ServerAPI,
                 py_audio: PyAudio):
        self.logger = logging.getLogger("WalkieTalkie")
        self.players = {}  # userID -> audio player object
        self.serverAPI = serverAPI
        self.driver = driver
        self.py_audio = py_audio
        self.queue = []
        self.max_current_priority = -1

        MQTT_BROKER = 'mqtt.item.ntnu.no'
        MQTT_PORT = 1883

        # create MQTT client
        self.logger.info(
            f'Connecting to MQTT broker {MQTT_BROKER} at port {MQTT_PORT}')
        self.mqtt_client = mqtt.Client()
        self.mqtt_client.on_connect = self.on_connect
        self.mqtt_client.on_message = self.on_message
        self.mqtt_client.connect(MQTT_BROKER, MQTT_PORT)
        self.mqtt_client.loop_start()
        self.update_subscriptions()

        # Create state machine
        self.state_machine = Machine(name="queue_manager",
                                     transitions=self._get_transitions(),
                                     states=self._get_states(),
                                     obj=self)
        driver.add_machine(self.state_machine)
Beispiel #4
0
    def test(self):
        tick1 = EntryExitSelfLogic()
        t0 = {"source": "initial", "target": "s1"}
        t1 = {
            "trigger": "b",
            "source": "s1",
            "target": "s1",
            "effect": "add('b')"
        }
        t2 = {
            "trigger": "done",
            "source": "s1",
            "target": "final",
            "effect": "add('c')",
        }

        s1 = {"name": "s1", "do": "do_action('a')"}

        stm = Machine(name="stm",
                      transitions=[t0, t1, t2],
                      states=[s1],
                      obj=tick1)
        tick1.stm = stm

        _ = stmpy.get_graphviz_dot(stm)

        driver = Driver()
        driver.add_machine(stm)
        driver.start()

        driver.wait_until_finished()
Beispiel #5
0
    def test(self):
        t0 = {
            "source": "initial",
            "target": "s1",
            "effect": "start_timer('t1', 1000)",
        }
        t1 = {
            "trigger": "a",
            "source": "s1",
            "target": "s1",
            "effect": "stop_timer('t1')",
        }
        t2 = {"trigger": "b", "source": "s1", "target": "final"}

        stm = Machine(name="stm", transitions=[t0, t1, t2], obj=None)

        _ = stmpy.get_graphviz_dot(stm)

        driver = Driver()
        driver.add_machine(stm)
        driver.start(keep_active=False)
        driver.send("a", "stm")
        driver.send("b", "stm")

        driver.wait_until_finished()
Beispiel #6
0
    def test(self):
        print(__name__)
        debug_level = logging.DEBUG
        logger = logging.getLogger(__name__)
        logger.setLevel(debug_level)
        ch = logging.StreamHandler()
        ch.setLevel(debug_level)
        formatter = logging.Formatter(
            "%(asctime)s - %(name)-12s - %(levelname)-8s - %(message)s")
        ch.setFormatter(formatter)
        logger.addHandler(ch)

        # terminate = Terminate()
        t0 = {"source": "initial", "target": "s1"}
        t1 = {"trigger": "b", "source": "s1", "target": "s2"}
        t2 = {"trigger": "a", "source": "s2", "target": "final"}
        s1 = {"name": "s1", "a": "defer", "a2": "defer", "a3": "defer"}
        s2 = {"name": "s2", "a2": "defer", "a3": "defer"}

        stm_terminate = Machine(name="stm",
                                transitions=[t0, t1, t2],
                                states=[s1, s2],
                                obj=None)
        # terminate.stm = stm_terminate

        _ = stmpy.get_graphviz_dot(stm_terminate)
        print(_)

        def unwrap(queue):
            s = []
            if queue is None:
                return s
            for event in queue:
                if event is not None:
                    s.append(event["id"])
            return s

        driver = Driver()
        driver.add_machine(stm_terminate)
        driver.start(max_transitions=30, keep_active=False)
        driver.send("a", "stm")
        driver.send("a2", "stm")
        driver.send("a3", "stm")

        print("Events {}".format(unwrap(driver._event_queue.queue)))
        print(stm_terminate.state)
        print("Defers {}".format(unwrap(stm_terminate._defer_queue)))
        print(driver._max_transitions)

        driver.send("b", "stm")

        print("Events {}".format(unwrap(driver._event_queue.queue)))
        print(stm_terminate.state)
        print("Defers {}".format(unwrap(stm_terminate._defer_queue)))
        print(driver._max_transitions)

        driver.wait_until_finished()
        print(stm_terminate.state)
        self.assertTrue(True)
Beispiel #7
0
 def __init__(self, driver: Driver, py_audio: PyAudio):
     self.logger = logging.getLogger("WalkieTalkie")
     self.py_audio = py_audio
     self.state_machine = Machine(
         name="audio_player_" +
         str(id(self)),  # Unique identifier for each audio player object
         transitions=self._get_transitions(),
         states=self._get_states(),
         obj=self)
     driver.add_machine(self.state_machine)
Beispiel #8
0
    def __init__(self, mqttAPI: MqttAPI, driver: Driver, py_audio: PyAudio,
                 serverAPI: ServerAPI):
        self.logger = logging.getLogger("WalkieTalkie")
        self.serverAPI = serverAPI

        # Define private variables
        self._recording = False

        # Save references
        self.mqttAPI = mqttAPI
        self.py_audio = py_audio

        # Create state machine
        self.state_machine = Machine(name="audio_recorder",
                                     transitions=self._get_transitions(),
                                     states=self._get_states(),
                                     obj=self)
        driver.add_machine(self.state_machine)
Beispiel #9
0
    def test(self):
        busy = Busy()
        t0 = {"source": "initial", "target": "s_busy", "effect": "on_busy"}
        t1 = {
            "trigger": "busy",
            "source": "s_busy",
            "target": "s_busy",
            "effect": "on_busy",
        }
        stm_busy = Machine(name="busy", transitions=[t0, t1], obj=busy)
        busy.stm = stm_busy

        scheduler = Driver()
        scheduler.add_machine(stm_busy)
        scheduler.start(max_transitions=5)
        scheduler.wait_until_finished()

        self.assertTrue(True)
Beispiel #10
0
    def test(self):
        t0 = {"source": "initial", "target": "s1"}
        t1 = {
            "trigger": "a",
            "source": "s1",
            "function": self.compound,
            "targets": "final",
        }

        stm = Machine(name="stm", transitions=[t0, t1], obj=None)

        _ = stmpy.get_graphviz_dot(stm)

        driver = Driver()
        driver.add_machine(stm)
        driver.start(keep_active=False)
        driver.send("a", "stm", args=["hi"], kwargs={"b1": "bbb"})

        driver.wait_until_finished()
Beispiel #11
0
    def test(self):
        two = TwoMethods()
        t0 = {"source": "initial", "target": "s_1"}
        t1 = {
            "trigger": "t",
            "source": "s_1",
            "target": "s_2",
            "effect": "m1;m2"
        }
        stm_two = Machine(name="stm_two", transitions=[t0, t1], obj=two)
        two.stm = stm_two

        scheduler = Driver()
        scheduler.add_machine(stm_two)
        scheduler.start(max_transitions=2)
        print("scheduler started")
        scheduler.send("t", "stm_two")

        scheduler.wait_until_finished()

        self.assertTrue(True)
Beispiel #12
0
    def test(self):
        tick1 = EntryExitSelfLogic()
        t0 = {"source": "initial", "target": "s1"}
        t1 = {
            "trigger": "b",
            "source": "s1",
            "target": "s1",
            "effect": "add('b')"
        }
        t2 = {
            "trigger": "c",
            "source": "s1",
            "target": "final",
            "effect": "add('c')"
        }

        s1 = {
            "name": "s1",
            "a": "add('a')",
            "entry": "add('entry')",
            "exit": "add('exit')",
        }

        stm = Machine(name="stm",
                      transitions=[t0, t1, t2],
                      states=[s1],
                      obj=tick1)
        tick1.stm = stm

        _ = stmpy.get_graphviz_dot(stm)

        driver = Driver()
        driver.add_machine(stm)
        driver.start(max_transitions=30, keep_active=False)
        driver.send("a", "stm")
        driver.send("b", "stm")
        driver.send("c", "stm")

        driver.wait_until_finished()
Beispiel #13
0
def test_tick():

    logger = logging.getLogger("stmpy.Driver")
    logger.setLevel(logging.INFO)
    ch = logging.StreamHandler()
    ch.setLevel(logging.INFO)
    formatter = logging.Formatter(
        "%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    ch.setFormatter(formatter)
    logger.addHandler(ch)

    scheduler = Driver()
    tick = Tick()

    t0 = {"source": "initial", "target": "s_tick", "effect": "on_init"}
    t1 = {
        "trigger": "tick",
        "source": "s_tick",
        "target": "s_tock",
        "effect": "on_tick",
    }
    t2 = {
        "trigger": "tock",
        "source": "s_tock",
        "target": "s_tick",
        "effect": "on_tock",
    }

    stm_tick = Machine(name="stm_tick", transitions=[t0, t1, t2], obj=tick)

    # the object may need the stm to add events and control timers
    tick.stm = stm_tick

    scheduler.add_machine(stm_tick)
    scheduler.start(max_transitions=3)
    scheduler.wait_until_finished()
raspi = RasPi()

#TRANSITIONS

#To the state  where RasPi listens for signals from Beacon
t0 = {'source': 'initial', 'target': 'receiver'}

t1 = {'trigger': 't', 'source': 'receiver', 'target': 'transmitter'}

t2 = {'trigger': 't', 'source': 'transmitter', 'target': 'receiver'}

#STATES

#The receiver state where RasPi listens for signals
receiver = {'name': 'receiver', 'entry': 'listen'}

#The transmitter state where RasPi transmit message to the mqtt-broker
transmitter = {'name': 'transmitter', 'entry': 'send'}

#STATE MACHINE
machine = Machine(name='raspi',
                  transitions=[t0, t1, t2],
                  obj=raspi,
                  states=[receiver, transmitter])
raspi.stm = machine

#Setting up and starting the driver
driver = Driver()
driver.add_machine(machine)
driver.start()
Beispiel #15
0
class WalkieTalkie:
    def __init__(self, transitions, states, debug):
        self.payload = {}
        self._logger = logging.getLogger(__name__)
        self._logger.info('logging under name {}.'.format(__name__))
        self._logger.info('Starting Component')
        self.debug = debug
        self.app = None
        self.lock = Lock()
        self.recorder = Recorder(self)
        self.text_to_speech = Speaker()
        self.overwrote_last = False

        self.uuid = uuid4().hex
        if self.debug:
            self.uuid = "122ec9e8edda48f8a6dd290747acfa8c"
        self.channel = "{server}{uuid}".format(server=MQTT_TOPIC_BASE,uuid=self.uuid)

        self.name = "jonas"
        stm_walkie_talkie_name = "{}_walkie_talkie".format(self.name)
        walkie_talkie_machine = Machine(transitions=transitions, states=states, obj=self, name=stm_walkie_talkie_name)
        self.stm = walkie_talkie_machine

        recognizer_stm = get_state_machine('stm_recognizer', [stm_walkie_talkie_name])

        self.stm_driver = Driver()
        self.stm_driver.add_machine(walkie_talkie_machine)
        self.stm_driver.add_machine(recognizer_stm)
        self.stm_driver.start()
        self._logger.debug('Component initialization finished')

    def create_gui(self):
        self.app = gui("Walkie Talkie", "320x568", bg='yellow')
        self.app.setStretch("both")
        self.app.setSticky("")
        self.app.setBgImage("images/bg.gif")

        if self.debug == True:
            self.app.setInPadding([30,40])
            self.app.setPadding([0,50])
        self.app.addLabel("status", "State: STATUS", 0, 0)
        self.app.setLabelBg("status", "#3e3e3e")
        self.app.setLabelFg("status", "white")

        def on_button_pressed_start(label):
            label = label.lower()
            command = label
            if 'stop' in label:
                self.stop_recording()
                command = "stop"
            elif 'send <' in label:
                self.stm.send("send", kwargs={'action': 'send', 'argument': 'bob ross'})
                command = "send"
            elif 'replay <' in label:
                self.stm.send("replay", kwargs={'action': 'replay', 'argument': 'bob ross'})
                command = "replay"
            elif 'replay' in label:
                self.stm.send("replay")
                command = "replay"
            elif 'next' in label:
                self.stm.send("next") 
                command = "next"
            elif 'play' in label:
                self.stm.send("play")
                command = "play"
            print("[ACTION]:", command)
            print("[STATE]:", self.stm.state)
        
        if self.debug == True:
            self.app.setPadding([0,0])
            self.app.setInPadding([60,40])
            self.app.startLabelFrame("Debug panel",1,0)
            self.app.setStretch("both")
            self.app.setSticky("news")
            self.app.addButton('Send <name>', on_button_pressed_start)
            self.app.addButton('Stop recording', on_button_pressed_start)
            self.app.addButton('Play', on_button_pressed_start)
            self.app.addButton('Replay', on_button_pressed_start)
            self.app.addButton('Next', on_button_pressed_start)
            self.app.addButton('Replay <name>', on_button_pressed_start)
            self.app.stopLabelFrame()
        else:
            self.app.addLabel("padding", "", 1, 0)
        self.update_led(False)
        self.update_status('LISTENING')
        self.app.go()

    def on_init(self):
        # Create and start MQTT client on init
        client = MQTT_Client(self)
        self.mqtt_client = client.client # for publishing/subscribing to broker
        client.stm = self.stm
        client.start(MQTT_BROKER, MQTT_PORT)

        self.mqtt_client.subscribe(self.channel)
        print("{uuid}: listening on channel {channel}".format(uuid=self.uuid, channel=self.channel))

        # Create GUI in a new thread
        th = Thread(target=self.create_gui)
        th.start()
    
    # Text-to-speech
    def tts(self, text):
        th = Thread(target=self.text_to_speech.speak, args=[str(text)])
        th.start()
        self._logger.debug(text)

    def force_stop(self):
        if self.recorder.playing:
            self.recorder.force_stop()
            while not self.recorder.terminated:
                pass

    def register(self):
        msg = {
            "command":"register",
            "uuid":self.uuid,
            "name":self.name
        }
        json_msg = json.dumps(msg)
        self.mqtt_client.publish(MQTT_TOPIC_OUTPUT, json_msg)
        print(self.uuid)

    def query_server(self, **kwargs): # check if recipient/sender is registered
        if kwargs.get("argument") and kwargs.get("action"):
            msg = {
                "command":"query",
                "device_id_from":self.uuid,
                "recipient_name": kwargs.get("argument")
            }
            json_msg = json.dumps(msg)
            self.mqtt_client.publish(MQTT_TOPIC_OUTPUT, json_msg)
        else:
            self.stm.send("time_out")

        '''
        request:
        {"device_id_from": uuid, "recipient_name": name, "command" : "query" }
 
        response:
        {"device_id_from": sender, "recipient_name": name, "exists": true/false}
        '''

    def start_recording(self):
        self.update_status("RECORDING")
        self.recorder.record()

    def stop_recording(self):
        self.update_status("STOP RECORDING")
        self.recorder.stop()
    
    # Parses server responses
    def parse_message(self, payload):
        if payload.get('command') == "message":
            self.stm.send("save_message", args=[payload])
        elif payload.get('exists') == True: # if recipient exists
            self.recipient = payload.get("recipient_name")
            self.stm.send("query_ok")
        elif payload.get('exists') == False: # if recipient does not exists
            self.stm.send("query_not_found")
        elif payload.get('data'):
            self.stm.send('replay_save_message', args=[payload])
    
    def threaded_save(self, lock, payload):
        lock.acquire()
        try:
            sender_name = payload.get('device_owner_name_from')
            self.tts(f"Received message from {sender_name}")
            # Retreive message from payload
            wf = payload.get('data')
            data = base64.b64decode(wf)
            # Get queue length and saves message in the FIFO order
            queue_number = len(os.listdir("message_queue"))
            with open(f'message_queue/{queue_number}.wav', 'wb') as fil:
                fil.write(data)
                self._logger.debug(f'Message saved to /message_queue/{queue_number}.wav')
        except:
            self._logger.error(f'Payload could not be read!')
        lock.release()
        self.iterate_queue(False)

    def save_message(self, payload):
        th = Thread(target=self.threaded_save, args=[self.lock,payload])
        th.start()
        th.join()

    def play_replay_message(self, payload):
        try:
            # Retreive message from payload
            wf = payload.get('data')
            data = base64.b64decode(wf)
            with open(f'replay_message.wav', 'wb') as fil:
                fil.write(data)
                self._logger.debug(f'Message saved to replay_message.wav')
            self.recorder.play("replay_message.wav")
            self.stm.send("replay_finished")
        except: # Should never happen, but added as insurance so the program doesn't throw an error and stops
            self._logger.error(f'Payload could not be read!')
            self.stm.send("replay_finished")

    def print_timer(self):
        print(self.stm.get_timer('time_out'))

    def play_message(self):
        self.update_status("PLAYING")
        self.overwrote_last = False

        # Check queue length
        queue_folder = "message_queue"
        queue_length = len(os.listdir(queue_folder))
        if self.check_message_queue(1):
            self._logger.info(f'Playing message 1/{queue_length}!')
            self.recorder.play(f"{queue_folder}/1.wav")
            if not self.overwrote_last:
                self.stm.send('message_played')
                self.update_led(False, 1)
        else:
            self.stm.send("queue_empty")
    
    def load_next_message_in_queue(self):
        # Iterates queue in FIFO order deleting the first file and shifting the filenames to the left
        if self.check_message_queue(2):  # if there are more than 2, it is safe to iterate
            self.iterate_queue(True, True)
        else:
            self.iterate_queue(True, True)
            self.stm.send("queue_empty")

    def check_message_queue(self, i): # returns true if there are more than i messages left in queue
        if len(os.listdir("message_queue")) > i:
            return True
        return False
    
    def threaded_iterate(self, lock, remove):
        lock.acquire()
        queue_folder = "message_queue"
        num = 1
        listdir = os.listdir(queue_folder)
        listdir.sort()
        for filename in listdir:
            if filename.split(".")[0] == "1" and num == 1 and remove:
                os.remove(f"{queue_folder}/{filename}")
            else:
                if filename != ".gitkeep":
                    os.rename(f"{queue_folder}/{filename}", f"{queue_folder}/{num}.wav")
                    num += 1
        self.update_led(False)
        lock.release()

    def iterate_queue(self, remove, force=False):
        if force:
            self.overwrite_current_playing()
        th = Thread(target=self.threaded_iterate, args=[self.lock, remove])
        th.start()
        th.join()

    # Request replay message from the server
    def get_latest_user_message(self):
        self.update_status("REPLAYING")
        name = self.recipient
        uuid = self.uuid
        msg = {
            "device_id_from": uuid,
            "device_owner_name_to": name,
            "command":"replay",
        }
        json_msg = json.dumps(msg)
        self.mqtt_client.publish(MQTT_TOPIC_OUTPUT, json_msg)

    def send_data(self):
        filename = self.recorder.filename
        byte_data = open(filename, 'rb')
        data = base64.b64encode(byte_data.read())
        msg = {
            "device_id_from":self.uuid,
            "device_owner_name_to": self.recipient,
            "command": "message",
            "data": data.decode()
        }
        json_msg = json.dumps(msg)
        self.mqtt_client.publish(MQTT_TOPIC_OUTPUT,json_msg)
     
    def update_status(self, text):
        if self.app != None:
            label = "State:"+text
            self.app.setLabel("status", label)

    def update_led(self, is_error, queue_pad=0):
        if self.app != None:
            if is_error:
                self.app.setBgImage("images/bg_red.gif")
            else:
                if self.check_message_queue(1+queue_pad): # check if there are more than 1 messages in queue
                    self.app.setBgImage("images/bg_green.gif")
                else:
                    self.app.setBgImage("images/bg.gif")

    def vibrate(self):
        self.recorder.play("vibrate.wav")
        self._logger.debug("Walkie goes brrrrrr...")

    def stop(self):
        # stop the MQTT client
        self.mqtt_client.loop_stop()
        # stop the state machine Driver
        self.stm_driver.stop()

    def overwrite_current_playing(self):
        self.overwrote_last = True
        self.force_stop()
Beispiel #16
0
logger.setLevel(debug_level)
ch = logging.StreamHandler()
ch.setLevel(debug_level)
formatter = logging.Formatter(
    "%(asctime)s - %(name)-12s - %(levelname)-8s - %(message)s")
ch.setFormatter(formatter)
logger.addHandler(ch)

print(stmpy.__version__)
speaker = Speaker()

t0 = {"source": "initial", "target": "ready"}
t1 = {"trigger": "speak", "source": "ready", "target": "speaking"}
t2 = {"trigger": "done", "source": "speaking", "target": "ready"}

s1 = {"name": "speaking", "do": "speak(*)", "speak": "defer"}

stm = Machine(name="stm", transitions=[t0, t1, t2], states=[s1], obj=speaker)
speaker.stm = stm

driver = Driver()
driver.add_machine(stm)
driver.start()

driver.send("speak", "stm", args=["My first sentence."])
driver.send("speak", "stm", args=["My second sentence."])
driver.send("speak", "stm", args=["My third sentence."])
driver.send("speak", "stm", args=["My fourth sentence."])

driver.wait_until_finished()
Beispiel #17
0
    def __init__(self, plant_name, treshhold):
        self.sense = SenseHat()
        self._logger = logging.getLogger(__name__)
        logging.basicConfig(level=logging.INFO)
        print('logging under name {}.'.format(__name__))
        self._logger.info('Starting humiditychecker')
        self.plant_name = plant_name
        self.treshhold = treshhold
        self.watering_machine = WateringMachine(plant_name, self)
        self.sense.show_message("Hello<3", text_colour=green)

        t0 = {'source': 'initial', 'target': 'check_idle'}
        t1 = {
            'trigger': 't',
            'source': 'check_idle',
            'function': self.water_checking
        }
        t2 = {
            'trigger': 'watering_done',
            'source': 'watering_plant',
            'effect': 'stop_timer("fallback");logg("Watering done"); ',
            'target': 'check_idle'
        }
        t3 = {
            'trigger': 'fallback',
            'source': 'watering_plant',
            'effedt': 'logg("State: check_idle");',
            'target': 'check_idle'
        }

        check_idle = {'name': 'check_idle', 'entry': 'start_timer("t",4000);'}
        watering_plant = {
            'name':
            'watering_plant',
            'entry':
            'start_timer("fallback",20000);sendToDriver("water","Watering");logg("State: watering_plant")'
        }

        humidity_machine = Machine(transitions=[t0, t1, t2, t3],
                                   obj=self,
                                   states=[check_idle, watering_plant],
                                   name='humidityCheck')

        self.stm = humidity_machine
        broker, port = MQTT_BROKER, MQTT_PORT
        driver = Driver()
        driver.add_machine(self.stm)
        self.driver = driver
        myclient = MQTT_Client_1(driver, self, MQTT_BROKER, MQTT_PORT,
                                 self.plant_name)
        self.mqtt = myclient
        self.mqtt_client = myclient.client
        myclient.stm = self.stm
        myclient.stm_driver = driver
        self.driver.add_machine(self.watering_machine.stm)

        self.airhumid = AirHumidity(self.plant_name, self.mqtt)
        self.driver.add_machine(self.airhumid.stm)

        driver.start()
        myclient.start(broker, port)
Beispiel #18
0
class AudioHelper:
    def __init__(self):

        self.recorder = Recorder()

        t0_r = {'source': 'initial', 'target': 'ready'}
        t1_r = {
            'trigger': 'start_recording',
            'source': 'ready',
            'target': 'recording'
        }
        t2_r = {'trigger': 'done', 'source': 'recording', 'target': 'ready'}
        s_ready = {'name': 'ready'}
        s_recording = {
            'name': 'recording',
            'do': 'record()',
            "stop": "stop_recording()"
        }
        self.stm_recording = Machine(name='stm_recording',
                                     transitions=[t0_r, t1_r, t2_r],
                                     states=[s_ready, s_recording],
                                     obj=self.recorder)
        self.recorder.stm = self.stm_recording

        self.speaker = Speaker()
        t0_s = {'source': 'initial', 'target': 'ready'}
        t1_s = {'trigger': 'speak', 'source': 'ready', 'target': 'speaking'}
        t2_s = {'trigger': 'done', 'source': 'speaking', 'target': 'ready'}

        s1_s = {'name': 'speaking', 'do': 'speak(*)', 'speak': 'defer'}

        self.stm_speaker = Machine(name='stm_speaker',
                                   transitions=[t0_s, t1_s, t2_s],
                                   states=[s1_s],
                                   obj=self.speaker)
        self.speaker.stm = self.stm_speaker

        self.driver = Driver()
        self.driver.add_machine(self.stm_recording)
        self.driver.add_machine(self.stm_speaker)
        self.driver.start()
        print('Audio Module ready')

    def play_audio_noStm(self, filename):
        # Open the sound file
        wf = wave.open(filename, 'rb')

        # Create an interface to PortAudio
        p = pyaudio.PyAudio()

        # Open a .Stream object to write the WAV file to
        # 'output = True' indicates that the sound will be played rather than recorded
        stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                        channels=wf.getnchannels(),
                        rate=wf.getframerate(),
                        output=True)

        # Read data in chunks
        data = wf.readframes(CHUNK)
        #self.playing = True
        # Play the sound by writing the audio data to the stream
        while (data != b''):  #and self.playing:
            stream.write(data)
            data = wf.readframes(CHUNK)
        # Close and terminate the stream
        stream.close()
        p.terminate()

    def start_recording(self):
        #print("driver started")
        self.last_record = []
        self.stm_recording.send('start_recording')

    def stop_recording(self):
        self.stm_recording.send("stop")

    def get_tmp_filename(self):
        #Returns the filename that is used for temp storage
        return FILENAME

    def get_recorded_samples(self):
        return b''.join(self.stm_recording._obj.getFrames())

    def text_to_speech(self, text):
        self.stm_speaker.send('speak', args=[text])
Beispiel #19
0
class WalkieTalkie:

    t0 = {'source': 'initial', 'target': 'idle'}

    t1 = {'trigger': 'message', 'source': 'idle', 'target': 'play_message'}

    t2 = {
        'trigger': 'cancel_btn',
        'source': 'play_message',
        'target': 'idle',
        'effect': 'stop_playing()'
    }

    t3 = {
        'trigger': 'message_played',
        'source': 'play_message',
        'target': 'idle',
    }

    t4 = {
        'trigger': 'join_btn',
        'source': 'idle',
        'target': 'join_group',
        'effect': 'join_group_f(*)'
    }

    t5 = {
        'trigger': 'error_message',
        'source': 'join_group',
        'target': 'error',
    }

    t6 = {
        'trigger': 'subscribed',
        'source': 'join_group',
        'target': 'idle',
    }

    t7 = {
        'trigger': 'leave_btn',
        'source': 'idle',
        'target': 'leave_group',
        'effect': 'leave_group_f(*)'
    }

    t8 = {
        'trigger': 'error_message',
        'source': 'leave_group',
        'target': 'error',
    }

    t9 = {
        'trigger': 'unsubscribed',
        'source': 'leave_group',
        'target': 'idle',
    }

    t10 = {
        'trigger': 'recipient_btn',
        'source': 'idle',
        'target': 'select_group',
        'effect': 'choose_recipient_group(*)'
    }

    t11 = {
        'trigger': 'leave_recipient_btn',
        'source': 'idle',
        'target': 'select_group',
        'effect': 'remove_recipient_group(*)'
    }

    t12 = {
        'trigger': 't1',
        'source': 'select_group',
        'target': 'idle',
    }

    t13 = {
        'trigger': 'cancel_btn',
        'source': 'select_group',
        'target': 'idle',
    }

    t14 = {
        'trigger': 'record_btn',
        'source': 'idle',
        'target': 'record_message',
    }

    t15 = {
        'trigger': 'cancel_btn',
        'source': 'record_message',
        'target': 'idle',
    }

    t16 = {
        'trigger': 'record_btn',
        'source': 'select_group',
        'target': 'record_message',
    }

    t17 = {
        'trigger': 'recording_saved',
        'source': 'record_message',
        'target': 'send_message',
    }

    t18 = {
        'trigger': 'message_sent',
        'source': 'send_message',
        'target': 'idle',
    }

    t19 = {
        'trigger': 'error_message',
        'source': 'idle',
        'target': 'error',
    }

    t20 = {
        'trigger': 'error_message',
        'source': 'select_group',
        'target': 'error',
    }
    t21 = {
        'trigger': 'error_message',
        'source': 'record_message',
        'target': 'error',
    }
    t22 = {
        'trigger': 'error_message',
        'source': 'send_message',
        'target': 'error',
    }

    t24 = {
        'trigger': 'connection_ok',
        'source': 'error',
        'target': 'idle',
    }

    t25 = {
        'trigger': 't2',
        'source': 'error',
        'target': 'error',
    }

    t23 = {
        'trigger': 'error_message',
        'source': 'play_message',
        'target': 'error',
    }

    #states

    idle = {'name': 'idle', 'entry': 'idle_state'}

    play_message = {
        'name': 'play_message',
        'entry': 'play_message_f',
        'message': 'defer',
    }

    join_group = {'name': 'join_group', 'message': 'defer'}

    leave_group = {'name': 'leave_group', 'message': 'defer'}

    select_group = {
        'name': 'select_group',
        'entry': 'start_timer("t1", 1000)',
        'message': 'defer'
    }

    record_message = {
        'name': 'record_message',
        'entry': 'record_message_f',
        'message': 'defer',
    }

    send_message = {
        'name': 'send_message',
        'entry': 'send_message_f',
        'message': 'defer'
    }

    error = {
        'name': 'error',
        'entry': 'test_connection; start_timer("t2", 3000)'
    }

    def __init__(self):

        #MQTT
        self.MQTT_BROKER = 'mqtt.item.ntnu.no'
        self.MQTT_PORT = 1883
        self.topic_output = 'ttm4115/team_12/file'
        self.group_topics_base = 'ttm4115/team_12/groups/'
        self.voice_file_name = 'output.wav'
        self.message_file_name_base = 'input.wav'
        self.joined_groups = []
        self.recipient_groups = []
        self.all_groups = {
            "Doctors": False,
            "Nurses": False,
            "Surgeons": False,
            "Head Surgeon": False,
            "Janitors": False
        }

        self.recording = False

        #State machine
        self.stm = Machine(name='stm',
                           transitions=[
                               self.t0, self.t1, self.t2, self.t3, self.t4,
                               self.t5, self.t6, self.t7, self.t8, self.t9,
                               self.t10, self.t11, self.t12, self.t13,
                               self.t14, self.t15, self.t16, self.t17,
                               self.t18, self.t19, self.t20, self.t21,
                               self.t21, self.t22, self.t23, self.t24, self.t25
                           ],
                           states=[
                               self.idle, self.play_message, self.join_group,
                               self.leave_group, self.select_group,
                               self.record_message, self.send_message,
                               self.error
                           ],
                           obj=self)
        self.driver = Driver()
        self.driver.add_machine(self.stm)
        self.driver.start()

        #Voice recording
        self.Recorder = Recorder(self.driver)

        #Message playing
        self.player = Player(self.driver)

        #File sending
        self.FileSender = FileSenderComponent(self.driver, self.MQTT_BROKER,
                                              self.MQTT_PORT)

        #File receiving
        self.FileReceiver = FileReceiverComponent(self.driver,
                                                  self.MQTT_BROKER,
                                                  self.MQTT_PORT)

        #Errors
        self.error_message = 'ERROR: Connection lost'

        self.message_index = 0

        self.create_gui()

    def create_gui(self):
        self.app = gui()
        self.app.setSize(600, 620)
        self.app.setBg('white', override=False, tint=False)

        self.app.startFrame("record", row=0, column=0)
        self.app.startLabelFrame('Record Message')
        self.app.addButton('Record', self.record_button)
        self.app.addButton('Save and Send recording', self.stop_recording)
        self.app.stopLabelFrame()
        self.app.stopFrame()

        self.app.startFrame("cancel", row=0, column=1)
        self.app.startLabelFrame('Cancel')
        self.app.addButton('Cancel', self.cancel_button)
        self.app.stopLabelFrame()
        self.app.stopFrame()

        self.app.startFrame("join_groups", row=20, column=0)
        self.app.startLabelFrame('Join Groups')
        self.app.addButton('Join Doctors', self.on_button_pressed_join_groups)
        self.app.addButton('Join Nurses', self.on_button_pressed_join_groups)
        self.app.addButton('Join Surgeons', self.on_button_pressed_join_groups)
        self.app.addButton('Join Important Information',
                           self.on_button_pressed_join_groups)
        self.app.addLabel("joined_groups_title", "Joined Groups")
        self.app.addLabel("No Joined Groups")
        self.app.stopLabelFrame()
        self.app.stopFrame()

        self.app.startFrame("choose_recipient", row=40, column=0)
        self.app.startLabelFrame('Choose Recipient Group')
        self.app.addButton('Send to Doctors',
                           self.on_button_pressed_recipient_group)
        self.app.addButton('Send to Nurses',
                           self.on_button_pressed_recipient_group)
        self.app.addButton('Send to Surgeons',
                           self.on_button_pressed_recipient_group)
        self.app.addButton('send to Important',
                           self.on_button_pressed_recipient_group)
        self.app.addLabel("recipient_groups_title", "Recipient Groups")
        self.app.addLabel("No Recipient Groups")
        self.app.stopLabelFrame()
        self.app.stopFrame()

        self.app.startFrame("leave_group", row=20, column=1)
        self.app.startLabelFrame('Leave Groups')
        self.app.addButton('Leave Doctors',
                           self.on_button_pressed_leave_groups)
        self.app.addButton('Leave Nurses', self.on_button_pressed_leave_groups)
        self.app.addButton('Leave Surgeons',
                           self.on_button_pressed_leave_groups)
        self.app.addButton(' Leave Important information',
                           self.on_button_pressed_leave_groups)
        self.app.stopLabelFrame()
        self.app.stopFrame()

        self.app.startFrame("remove_recipient", row=40, column=1)
        self.app.startLabelFrame('Remove Recipient Groups')
        self.app.addButton('Remove Doctors',
                           self.on_button_pressed_remove_groups)
        self.app.addButton('Remove Nurses',
                           self.on_button_pressed_remove_groups)
        self.app.addButton('Remove Surgeons',
                           self.on_button_pressed_remove_groups)
        self.app.addButton('Remove Important Information',
                           self.on_button_pressed_remove_groups)
        self.app.stopLabelFrame()
        self.app.stopFrame()

        self.app.startFrame("error_display", row=60, column=1)
        self.app.startLabelFrame('Error Display')
        self.app.addLabel("error_label", "No errors")
        self.app.addButton('Simulate connection lost',
                           self.simulate_connection_lost)
        self.app.stopLabelFrame()
        self.app.stopFrame()

        self.app.go()

    def record_button(self):
        if len(self.recipient_groups) == 0:
            print("No recipient groups to send to")
            return
        self.recording = True
        self.driver.send('record_btn', 'stm')

    def cancel_button(self):
        #self.player.stop_playing_sound()
        self.driver.send('cancel_btn', 'stm')

    def stop_playing(self):
        self.player.stop_playing_sound()

    def on_button_pressed_join_groups(self, buttonTitle):
        group_name = buttonTitle.lower()
        if 'doctors' in group_name:
            group_name = 'doctors'
        elif 'nurses' in group_name:
            group_name = 'nurses'
        elif 'surgeons' in group_name:
            group_name = 'surgeons'
        elif 'important' in group_name:
            group_name = 'important'
        #self.join_group(group_name)
        if group_name not in self.joined_groups:
            self.driver.send('join_btn', 'stm', args=[group_name])
        else:
            pass

    def on_button_pressed_leave_groups(self, buttonTitle):
        group_name = buttonTitle.lower()
        if 'doctors' in group_name:
            group_name = 'doctors'
        elif 'nurses' in group_name:
            group_name = 'nurses'
        elif 'surgeons' in group_name:
            group_name = 'surgeons'
        elif 'important' in group_name:
            group_name = 'important'
        #self.leave_group(group_name)
        if group_name in self.joined_groups:
            self.driver.send('leave_btn', 'stm', args=[group_name])
        else:
            pass

    def on_button_pressed_recipient_group(self, buttonTitle):
        group_name = buttonTitle.lower()
        if 'doctors' in group_name:
            group_name = 'doctors'
        elif 'nurses' in group_name:
            group_name = 'nurses'
        elif 'surgeons' in group_name:
            group_name = 'surgeons'
        elif 'important' in group_name:
            group_name = 'important'
        #self.choose_recipient_group(group_name)
        self.driver.send('recipient_btn', 'stm', args=[group_name])

    def on_button_pressed_remove_groups(self, buttonTitle):
        group_name = buttonTitle.lower()
        if 'doctors' in group_name:
            group_name = 'doctors'
        elif 'nurses' in group_name:
            group_name = 'nurses'
        elif 'surgeons' in group_name:
            group_name = 'surgeons'
        elif 'important' in group_name:
            group_name = 'important'
        #self.remove_recipient_group(group_name)
        self.driver.send('leave_recipient_btn', 'stm', args=[group_name])

    def set_record_button_text(self):
        if self.recording:
            self.app.setButton('Record', 'Stop and Send')
        else:
            self.app.setButton('Record', 'Record')

    def simulate_connection_lost(self):
        print('Simulating connection lost')
        self.FileSender.disconnect()

    def play_message_f(self):
        print("Main state: Play message")
        next_file_name = 'input{}.wav'.format(self.message_index)
        self.player.play_sound_file(next_file_name)
        self.message_index += 1

    def record_message_f(self):
        print("Main state: Record message")
        self.Recorder.start_recording()

    def idle_state(self):
        print("Main state: Idle")
        if self.recording:
            self.Recorder.stop_recording()
            self.recording = False
            self.set_record_button_text()

    def send_message_f(self):
        print("Main state: Send message")
        for group in self.recipient_groups:
            group_topic = '{0}{1}'.format(self.group_topics_base, group)
            self.FileSender.send_file(self.voice_file_name, group_topic)

    def stop_recording(self):
        self.Recorder.stop_recording()
        self.recording = False
        self.set_record_button_text()

    def join_group_f(self, groupName):
        if not groupName in self.joined_groups:
            print("joining group: {}".format(groupName))
            self.FileReceiver.subscribe_to_topic('{0}{1}'.format(
                self.group_topics_base, groupName))
            self.joined_groups.append(groupName)
            self.app.setLabel("No Joined Groups",
                              ', '.join(self.joined_groups))

    def choose_recipient_group(self, groupName):
        if not groupName in self.recipient_groups:
            self.recipient_groups.append(groupName)
            print("Choosing new recipient group: {}".format(groupName))
            self.app.setLabel("No Recipient Groups",
                              ', '.join(self.recipient_groups))

    def remove_recipient_group(self, groupName):
        if groupName in self.recipient_groups:
            print("Removing group: {}".format(groupName))
            self.recipient_groups.remove(groupName)
            self.app.setLabel("No Recipient Groups",
                              ', '.join(self.recipient_groups))

    def leave_group_f(self, groupName):
        if groupName in self.joined_groups:
            print("Leaving group: {}".format(groupName))
            self.FileReceiver.unsubscribe_from_topic('{0}{1}'.format(
                self.group_topics_base, groupName))
            self.joined_groups.remove(groupName)
            self.app.setLabel("No Joined Groups",
                              ', '.join(self.joined_groups))

    def test_connection(self):
        print('Testing connection')
        if self.FileReceiver.connected and self.FileSender.connected:
            self.driver.send('connection_ok', 'stm')
            self.app.setLabel("error_label", 'No errors')
            self.app.setLabelBg("error_label", 'white')
            print('Connection ok')
        else:
            self.app.setLabel("error_label", self.error_message)
            self.app.setLabelBg("error_label", 'red')
            print('Connection lost, resetting components and reconnecting')
            self.FileReceiver = FileReceiverComponent(self.driver,
                                                      self.MQTT_BROKER,
                                                      self.MQTT_PORT)
            self.FileSender = FileSenderComponent(self.driver,
                                                  self.MQTT_BROKER,
                                                  self.MQTT_PORT)
Beispiel #20
0
class BikeRack:
    def __init__(self, name, mqtt_broker, mqtt_port):
        """
        Start the component.
        ## Start of MQTT
        We subscribe to the topic(s) the component listens to.
        The client is available as variable `self.client` so that subscriptions
        may also be changed over time if necessary.
        The MQTT client reconnects in case of failures.
        ## State Machine driver
        We create a single state machine driver for STMPY. This should fit
        for most components. The driver is available from the variable
        `self.driver`. You can use it to send signals into specific state
        machines, for instance.
        """

        # TODO Make the mqtt topics into bike/$name/command (input) and bike/$name (output).
        # Something wrong happened trying to do so.
        self.MQTT_TOPIC_INPUT = 'bike/'  #, name, '/command'
        self.MQTT_TOPIC_OUTPUT = 'bike/'  #, name

        # Get the logger object for the component
        self._logger = logging.getLogger(__name__)
        print('Logging under name {}.'.format(__name__))

        # ::: DEBUGGING :::
        # logging.DEBUG: Most fine-grained logging, printing everything
        # logging.INFO:  Only the most important informational log items
        # logging.WARN:  Show only warnings and errors.
        # logging.ERROR: Show only error messages.
        debug_level = logging.DEBUG
        logger = logging.getLogger(__name__)
        logger.setLevel(debug_level)
        ch = logging.StreamHandler()
        ch.setLevel(debug_level)
        formatter = logging.Formatter(
            '%(asctime)s - %(name)-12s - %(levelname)-8s - %(message)s')
        ch.setFormatter(formatter)
        logger.addHandler(ch)
        # END DEBUGGING

        self._logger.info('Starting Component')

        # Create a new MQTT client
        self._logger.debug('Connecting to MQTT broker {} at port {}'.format(
            mqtt_broker, mqtt_port))
        self.mqtt_client = mqtt.Client()

        # Callback methods
        self.mqtt_client.on_connect = self.on_connect
        self.mqtt_client.on_message = self.on_message

        # Connect to the broker
        self.mqtt_client.connect(mqtt_broker, mqtt_port)

        # Subscribe to proper topic(s) of your choice
        self.mqtt_client.subscribe(self.MQTT_TOPIC_INPUT)

        # Start the internal loop to process MQTT messages
        self.mqtt_client.loop_start()

        # We start the stmpy driver, without any state machines for now
        self.driver = Driver()
        self.driver.start(keep_active=True)

        self._logger.debug('Component initialization finished')

        # Active machines
        self.active_machines = {}
        self.name = name

        # Add test_lock
        lock_name = "en"
        self._logger.debug(f'Create machine with name: {lock_name}')
        lock_stm = BikeLock(self.driver, self, lock_name)

        self.driver.add_machine(lock_stm.stm)
        self.active_machines[lock_name] = lock_name

        self._logger.debug("Start driver")
        self.driver.start()
        # TEST END

    def stop(self):
        """
        Stop the component.
        """
        # Stop the MQTT client
        self.mqtt_client.loop_stop()
        # Stop the state machine Driver
        self.driver.stop()

    def on_connect(self, client, userdata, flags, rc):
        # We just log that we are connected
        self._logger.debug('MQTT connected to {}'.format(client))

    def check_available(self):
        for name in self.active_machines:
            if self.driver._stms_by_id[name].state == "available":
                return True

    def on_message(self, client, userdata, msg):
        """
        Processes incoming MQTT messages.
        We assume the payload of all received MQTT messages is an UTF-8 encoded
        string, which is formatted as a JSON object. The JSON object contains
        a field called `command` which identifies what the message should achieve.
        As a reaction to a received message, we can for example do the following:
        * create a new state machine instance to handle the incoming messages,
        * route the message to an existing state machine session,
        * handle the message right here,
        * throw the message away.
        """
        self._logger.debug('Incoming message to topic {}'.format(msg.topic))

        payload = json.loads(msg.payload)
        command = payload.get('command')
        self._logger.debug(f"Have detected this command: {command}")

        if command == "check_driver":
            self._logger.debug(f"State Machine: {self.driver.print_status()}")
            if self.check_available():
                self.mqtt_client.publish(self.MQTT_TOPIC_OUTPUT,
                                         self.driver.print_status())

        # Assumes payload with ``lock_name`` and ``nfc_tag``
        elif command == "reserve":
            for name in self.active_machines:
                if self.driver._stms_by_id[name].state == "available":
                    self._logger.debug(f"Reserving lock with id: {name}")
                    kwargs = {"nfc_tag": payload.get("value")}
                    self.driver.send(message_id='reserve',
                                     stm_id=name,
                                     kwargs=kwargs)
                    self.mqtt_client.publish(
                        self.MQTT_TOPIC_OUTPUT,
                        f'Reserved lock with name {name}')
                    self.mqtt_client.publish(
                        self.get_stm_by_name(name)._obj.get_nfc_tag())
                    self._logger.debug(
                        self.get_stm_by_name(name)._obj.get_nfc_tag())
                    return
            self._logger.debug("No locks available in this rack")
            self.mqtt_client.publish(self.MQTT_TOPIC_OUTPUT,
                                     f'No locks available')

        elif command == "add_lock":
            lock_name = payload.get("lock_name")
            self._logger.debug(f"Add lock with name: {lock_name}")
            lock_stm = BikeLock(self.driver, self, lock_name)
            self.driver.add_machine(lock_stm.stm)
            self.active_machines[lock_name] = lock_name

        # Assumes payload with``nfc_tag`` and ``lock_name``
        elif command == "nfc_det":
            self._logger.debug("running nfc_det")
            self.nfc_det(nfc_tag=payload.get("value"),
                         lock_name=payload.get("lock_name"))

        elif command == "check_state":
            name = payload.get("name")
            self._logger.debug(
                f"Machine: {name}, is in state: {self.get_stm_by_name(name).state}"
            )
            self.mqtt_client.publish(
                self.MQTT_TOPIC_OUTPUT,
                f"Machine: {name}, is in state: {self.get_stm_by_name(name).state}"
            )

        # Catch message without handler
        else:
            self._logger.debug(f"Command: {command} does not have a handler")

    def res_expired(self, nfc_tag):
        self.mqtt_client.publish(self.MQTT_TOPIC_OUTPUT,
                                 f'Reservetion timed out for {nfc_tag}')

    def nfc_det(self, nfc_tag, lock_name):
        self._logger.debug(
            f"Detected NFC-tag with value: {nfc_tag} presented to lock: {lock_name}"
        )
        self._logger.debug(self.get_stm_by_name(lock_name).state)
        kwargs = {"nfc_tag": nfc_tag}
        self.driver.send(message_id='nfc_det', stm_id=lock_name, kwargs=kwargs)

    # Getter for stm_by name
    def get_stm_by_name(self, stm_name):
        if self.driver._stms_by_id[stm_name]:
            self._logger.debug(f"Getting stm with name: {stm_name}")
            return self.driver._stms_by_id[stm_name]
        # Did not find machine with ``stm_name``
        self._logger.error(f"Error: did not find stm with name: {stm_name}")
        return None
Beispiel #21
0
    def test(self):

        # print(stmpy.__version__)

        logger = logging.getLogger("stmpy")
        logger.setLevel(logging.DEBUG)
        ch = logging.StreamHandler()
        ch.setLevel(logging.DEBUG)
        formatter = logging.Formatter(
            "%(asctime)s - %(name)s - %(levelname)s - %(message)s")
        ch.setFormatter(formatter)
        logger.addHandler(ch)

        tick1 = Tick()
        t0 = {
            "source": "initial",
            "target": "active",
            "effect": "start_timer('tick', 1000); print('initial1')",
        }
        #'effect': 'print("initial1")'}
        t1 = {
            "trigger": "tick",
            "source": "active",
            "target": "active",
            "effect": "start_timer('tick', 1000); print('timeout1')",
        }
        #'effect': 'print("timeout1")'}
        stm_tick_1 = Machine(name="stm_tick_1",
                             transitions=[t0, t1],
                             obj=tick1)
        tick1.stm = stm_tick_1

        tick2 = Tick()
        t0 = {
            "source": "initial",
            "target": "active",
            "effect": "start_timer('tick', 2000); print('initial2')",
        }
        #'effect': 'print("initial2")'}
        t1 = {
            "trigger": "tick",
            "source": "active",
            "target": "active",
            "effect": "start_timer('tick', 1000); print('timeout2')",
        }
        stm_tick_2 = Machine(name="stm_tick_2",
                             transitions=[t0, t1],
                             obj=tick2)
        tick2.stm = stm_tick_2

        driver1 = Driver()

        driver1.start(max_transitions=6, keep_active=True)

        print("driver state: active {} and thread alive {} ".format(
            driver1._active, driver1.thread.is_alive()))

        driver1.add_machine(stm_tick_1)
        print(driver1.print_status())
        driver1.add_machine(stm_tick_2)
        print(driver1.print_status())
        driver1._wake_queue()
        print("driver state: active {} and thread alive {} ".format(
            driver1._active, driver1.thread.is_alive()))
        # driver1.start(max_transitions=6, keep_active=True)
        print(driver1.print_status())

        # driver2 = Driver()
        # driver1.add_machine(stm_tick_2)
        # driver2.start(max_transitions=10)

        driver1.wait_until_finished()
class WalkieTalkie:
    """
    The component to send and receive voice messages.
    """

    def __init__(self):
        # setting the standard channel as 0 and ID as default
        self.channel = 0
        self.ID = "default"

        # the output dir is where received recordings are stored
        self.output_dir = "../player/"
        self.record_dir = "../recordings/"
        self.channel_dir = self.output_dir + str(self.channel)
        self.fileNameList = []
        self.messageList = []

        # cleaing the player list
        self.create_channel_folder(self.output_dir, self.record_dir)

        #Burde vi ha create_player_folder for konsistent??
        self.clear_player_folder(self.output_dir)

        # get the logger object for the component
        self._logger = logging.getLogger(__name__)
        print('logging under name {}.'.format(__name__))
        self._logger.info('Starting Component')


        # create a new MQTT client
        self._logger.debug('Connecting to MQTT broker {} at port {}'.format(MQTT_BROKER, MQTT_PORT))
        self.mqtt_client = mqtt.Client()
        # callback methods
        self.mqtt_client.on_connect = self.on_connect
        self.mqtt_client.on_message = self.on_message
        self.mqtt_client.on_disconnect = self.on_disconnect


        # Connect to the broker
        try:
            self.mqtt_client.connect(MQTT_BROKER, MQTT_PORT)

        except:
            print("Connection fails")
            sys.exit(1)


        self.mqtt_client.loop_start()

        '''
        #Testing the on_disconnect function
        time.sleep(10)
        self.mqtt_client.disconnect() # disconnect gracefully
        self.mqtt_client.loop_stop() # stops network loop
        time.sleep(5)
        self.mqtt_client.connect()
        '''


        # recorder
        recorder = Recorder.create_machine('stm_recorder', self)
        self.recorder = recorder
        stm_recorder = recorder.stm

        # player
        player = Player.create_machine('stm_player', self)
        self.player = player
        stm_player = player.stm

        # creating driver, attaching machines
        self.driver = Driver()
        self.driver.add_machine(stm_recorder)
        self.driver.add_machine(stm_player)

        # starting driver
        self.driver.start(keep_active = True)
        self.create_gui()
        print("Bye!")


    def create_channel_folder(self, output_dir, record_dir):
        if not os.path.exists(output_dir): os.mkdir(output_dir)
        if not os.path.exists(record_dir): os.mkdir(record_dir)
        for i in range(MAX_CHANNELS):
            path = output_dir + str(i)
            if not os.path.exists(path):
                os.mkdir(path)

    def clear_player_folder(self, output_dir):
        for i in range(MAX_CHANNELS):
            for f in os.listdir(output_dir + str(i)):
                if f.endswith(".wav"):
                    os.remove(os.path.join(output_dir+str(i), f))

    def set_channel_path(self):
        self.channel_dir=self.output_dir +str(self.channel)


    def on_connect(self, client, userdata, flags, rc):
        print(mqtt.connack_string(rc))
        if(rc == 0):
            self.mqtt_client.subscribe(MQTT_TOPIC_INPUT + str(self.channel))
            self.mqtt_client.subscribe(MQTT_TOPIC_INPUT+ str(self.channel)+"/ACK")
            self._logger.debug('MQTT connected to {}'.format(client))
            self.client_id = client
        else:
            print(mqtt.connack_string(rc))

    def on_disconnect(self, client, userdata, rc):
        if(rc == 0):
            print("Disconnected gracefully.")
        else:
            print("Unexpected disconnection.")
            self.app.setLabel("delivered", text = "Connection lost: Waiting to reconnect \n and resend latest message")


    # Runs when WalkieTalkie receives a message
    def on_message(self, client, userdata, msg):
        print("A message is received")
        self._logger.debug('Incoming message to topic {}'.format(msg.topic))


        #message_payload_received = json.load(io.BytesIO(msg.payload))
        if(msg.payload):
            message_payload_received = json.loads(msg.payload)
            # Check correct channel
            if(str(msg.topic) == MQTT_TOPIC_OUTPUT + str(self.channel) and message_payload_received):
                dataToByteArray = base64.b64decode(bytearray(bytes(message_payload_received['data'], "utf-8")))

                print("client_id: " + message_payload_received['ID'])

                # Check that message is not sent to self
                if (message_payload_received['ID'] != self.ID):
                    temp_file = message_payload_received['ID'] + str(strftime(" %Y-%m-%d %H-%M-%S", gmtime())) + ".wav"
                    self.temp_file = temp_file
                    f = open(os.path.join(self.channel_dir, self.temp_file), 'wb')
                    f.write(dataToByteArray)
                    print("Data written to file")
                    f.close()
                    self.driver.send('start', 'stm_player', args=[os.path.join(self.channel_dir, self.temp_file)])
                    time.sleep(1)
                    self.messageList  = [ Message(path) for path in os.listdir(self.channel_dir) if path.endswith(".wav") ]
                    self.fileNameList = [ m.path for m in self.messageList]
                    print(self.fileNameList)
                    self.app.changeOptionBox("Choose message", self.fileNameList)

                    # Sending ack
                    package_ack = {'message_id': message_payload_received['Msg_ID'], 'sender': message_payload_received['ID']}
                    payload_ack = json.dumps(package_ack)
                    self.mqtt_client.publish(str(msg.topic)+"/ACK", payload_ack, qos=2)


            # Checks for ACK
            if (str(msg.topic) == MQTT_TOPIC_INPUT+ str(self.channel)+"/ACK"):
                if(message_payload_received['message_id'] == self.recorder.get_latest_file()):
                    if(message_payload_received['sender'] == self.ID):
                        print("Message delivered with ID: "+ message_payload_received['message_id'] + " and sender: " + message_payload_received['sender'])
                        self.app.setLabel("delivered","Message delivered")
                        self.app.setLabelFg("delivered","green")




    def send_message(self):
        print("Sending a new message")
        #self.mqtt_client.connect(MQTT_BROKER, MQTT_PORT)
        path = self.recorder.get_latest_file()
        f = open(path, "rb")
        imagestring = f.read()
        f.close()
        imageByteArray = bytearray(imagestring)
        imageByteArrayString = str(base64.b64encode(imageByteArray), "utf-8")
        package = {'ID': self.ID, 'data': imageByteArrayString, 'Msg_ID': path}
        payload = json.dumps(package)
        mqtt_msg = self.mqtt_client.publish(MQTT_TOPIC_OUTPUT + str(self.channel), payload, qos = 2)
        timestamp = time.time()
        print("Sending the message took: {} ".format(time.time()-timestamp))

        self.app.setLabel("delivered",text = "Sending")
        self.app.setLabelFg("delivered","orange")
        time.sleep(1)
        # catching the exception thrown by mqtt when no acc is given.
        ## TODO: Her kan vi kanskje ha Message failed rød tekst? Hvis Catch error.


    # Creates the appJar GUI
    def create_gui(self):
        BUTTON_WIDTH = 30
        self.app = gui("Walkie-Talkie", "300x500")


        #set username
        def on_button_name(title):
            self.ID = self.app.getEntry("NameEntry")
            self.app.setLabel("NameLabel", "User: "******"User ID changed")

        #channel up
        def on_button_pressed_increase(title):
            self.mqtt_client.unsubscribe(MQTT_TOPIC_INPUT + str(self.channel))
            self.mqtt_client.unsubscribe(MQTT_TOPIC_INPUT+ str(self.channel)+"/ACK")
            self.channel = (self.channel + 1)% MAX_CHANNELS
            self.set_channel_path()
            self.mqtt_client.subscribe(MQTT_TOPIC_INPUT + str(self.channel))
            self.mqtt_client.subscribe(MQTT_TOPIC_INPUT+ str(self.channel)+"/ACK")
            self.app.setLabel("Channel",text="Connected to channel: {}".format(self.channel))

        #channel up
        def on_button_pressed_decrease(title):
            self.mqtt_client.unsubscribe(MQTT_TOPIC_INPUT + str(self.channel))
            self.mqtt_client.unsubscribe(MQTT_TOPIC_INPUT+ str(self.channel)+"/ACK")
            self.channel = (self.channel - 1) % MAX_CHANNELS
            self.set_channel_path()
            self.mqtt_client.subscribe(MQTT_TOPIC_INPUT + str(self.channel))
            self.mqtt_client.subscribe(MQTT_TOPIC_INPUT+ str(self.channel)+"/ACK")
            self.app.setLabel("Channel",text="Connected to channel: {}".format(self.channel))


        #start recording
        def on_button_pressed_start(title):
            self.driver.send('start', 'stm_recorder')
            print("Start recording")

        #Stop recording and send message
        def on_button_pressed_stop(title):
            self.driver.send('stop', 'stm_recorder')
            time.sleep(1)
            self.send_message()
            print("Stop recording")

        #resend latest message
        def on_button_pressed_resend(title):
            if os.listdir(self.record_dir) != []:
                self.send_message()
            else:
                print("You have no messages. ")

        #Replay chosen message
        def on_button_pressed_replay(title):
            play_list = self.fileNameList
            if play_list:
                tmp = self.app.getOptionBox('Choose message')
                self.driver.send('replay', 'stm_player', args=[os.path.join(self.channel_dir, tmp)])
            else:
                print("You have no messages. ")


        def voiceToText(title):
            play_list = self.fileNameList
            if play_list:
                tmp = self.app.getOptionBox('Choose message')
                r = sr.Recognizer()

                lyd=sr.AudioFile(os.path.join(self.channel_dir, tmp))
                with lyd as source:
                    audio = r.record(source)
                try:
                    s = r.recognize_google(audio)
                    self.app.setLabel("message","Message: " + s)
                except Exception as e:
                    print("Exception: "+str(e))
            else:
                print("You have no messages. ")



        # Choose ID
        self.app.addLabel("NameLabel", "User: "******"Names")

        self.app.addLabel("NameEntryLabel", "Name: ", 1, 0)

        self.app.addEntry("NameEntry", 1, 1)
        self.app.setEntrySubmitFunction("NameEntry", on_button_name)
        self.app.stopLabelFrame()


        # Choose channel
        self.app.startLabelFrame('Change channel:')
        self.app.addLabel("Channel",text="Connected to channel: {}".format(self.channel), colspan=2)
        self.app.setLabelWidth('Channel', int(BUTTON_WIDTH*(5/3)))

        self.app.addButton('Increase', on_button_pressed_increase, 1, 0)
        self.app.setButtonWidth('Increase', BUTTON_WIDTH)

        self.app.addButton('Decrease', on_button_pressed_decrease, 1 , 1)
        self.app.setButtonWidth('Decrease', BUTTON_WIDTH)
        self.app.stopLabelFrame()

        # Start and stop recording
        self.app.startLabelFrame('Send messages')

        self.app.addButton('Start recording', on_button_pressed_start, 1, 0)
        self.app.setButtonWidth("Start recording", BUTTON_WIDTH)

        self.app.addButton('Stop and send', on_button_pressed_stop, 1, 1)
        self.app.setButtonWidth('Stop and send', BUTTON_WIDTH)

        #resend and exit button
        self.app.addButton('Resend', on_button_pressed_resend, colspan=2)
        self.app.setButtonWidth('Resend', BUTTON_WIDTH*2)
        self.app.addButton('Exit system', sys.exit, colspan=3)
        self.app.setButtonWidth('Exit system', BUTTON_WIDTH*2)


        self.app.addLabel("delivered", "")
        self.app.stopLabelFrame()


        # Replay last received message
        self.app.startLabelFrame('Replay message:')
        self.app.addOptionBox("Choose message", self.fileNameList, colspan=2)
        self.app.setOptionBoxWidth('Choose message', BUTTON_WIDTH)

        self.app.addButton('Replay', on_button_pressed_replay, 1, 0)
        self.app.setButtonWidth('Replay', BUTTON_WIDTH)
        self.app.addButton('Text Message', voiceToText, 1, 1)
        self.app.setButtonWidth('Text Message', BUTTON_WIDTH)
        self.app.stopLabelFrame()



        #Voice to text
        self.app.startFrame("message frame")
        self.app.setBg("white")
        self.app.addLabel("message", "No message data...")
        self.app.stopFrame()
        self.app.go()
        self.stop()


    def stop(self):
        """
        Stop the component.
        """
        self.mqtt_client.loop_stop()
        # Stop the state machine Driver
        self.driver.stop()