From 26c6b7cdc86c63c0c73022c42f4732a24048e60b Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 12 Jul 2021 15:03:52 -0700 Subject: [PATCH] AWS IoT | Python MQTT Client for Multiple ESP32CAM --- ESP32_MQTT/3_Python_MQTT_Client_App/main.py | 120 ++++++++++++++++++ .../3_Python_MQTT_Client_App/requirements.txt | 3 + 2 files changed, 123 insertions(+) create mode 100644 ESP32_MQTT/3_Python_MQTT_Client_App/main.py create mode 100644 ESP32_MQTT/3_Python_MQTT_Client_App/requirements.txt diff --git a/ESP32_MQTT/3_Python_MQTT_Client_App/main.py b/ESP32_MQTT/3_Python_MQTT_Client_App/main.py new file mode 100644 index 0000000..9ebf8ae --- /dev/null +++ b/ESP32_MQTT/3_Python_MQTT_Client_App/main.py @@ -0,0 +1,120 @@ +import io +import queue +import traceback + +import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT +import PySimpleGUI as sg +from PIL import Image + + +class Application: + def __init__(self): + self.myAWSIoTMQTTClient = None + self.gui_queue = queue.Queue() + + middle_font = ('Helvetica', 14) + context_font = ('Helvetica', 12) + sg.theme('DarkGrey14') + + col1 = [[sg.Column([ + [sg.Frame('MQTT Panel', [[sg.Column([ + [sg.Text('Client Id:', font=middle_font)], + [sg.Input('Python_Client', key='_CLIENTID_IN_', size=(19, 1), font=context_font), + sg.Button('Connect', key='_CONNECT_BTN_', font=context_font)], + [sg.Text('Notes:', font=middle_font)], + [sg.Multiline(key='_NOTES_', autoscroll=True, size=(26, 34), font=context_font, )], + ], size=(235, 640), pad=(0, 0))]], font=middle_font)], ], pad=(0, 0), element_justification='c')]] + + col2 = [[sg.Column([[sg.Frame('CAM {}'.format((row + col)), [ + [sg.Image(key='_ESP32/CAM_{}_'.format((row + col)), size=(480, 320))], + ], font=middle_font) for row in range(0, 3, 2)]], pad=(0, 0), element_justification='c')] for col in range(2)] + + layout = [[ + sg.Column(col1), sg.Column(col2) + ]] + + self.window = sg.Window('Python MQTT Client - AWS IoT -', layout) + + while True: + event, values = self.window.Read(timeout=5) + if event is None or event == 'Exit': + break + + if event == '_CONNECT_BTN_': + if self.window[event].get_text() == 'Connect': + + if len(self.window['_CLIENTID_IN_'].get()) == 0: + self.popup_dialog('Client Id is empty', 'Error', context_font) + else: + self.window['_CONNECT_BTN_'].update('Disconnect') + self.aws_connect(self.window['_CLIENTID_IN_'].get()) + + else: + self.window['_CONNECT_BTN_'].update('Connect') + self.aws_disconnect() + try: + message = self.gui_queue.get_nowait() + except queue.Empty: + message = None + if message is not None: + _target_ui = message.get("Target_UI") + _image = message.get("Image") + self.window[_target_ui].update(data=_image) + + self.window.Close() + + def aws_connect(self, client_id): + ENDPOINT = "xxxxxxxxxxxxxx-ats.iot.us-west-1.amazonaws.com" + PATH_TO_CERT = "" + PATH_TO_KEY = "" + PATH_TO_ROOT = "" + + self.myAWSIoTMQTTClient = AWSIoTPyMQTT.AWSIoTMQTTClient(client_id) + self.myAWSIoTMQTTClient.configureEndpoint(ENDPOINT, 8883) + self.myAWSIoTMQTTClient.configureCredentials(PATH_TO_ROOT, PATH_TO_KEY, PATH_TO_CERT) + + try: + if self.myAWSIoTMQTTClient.connect(): + self.add_note('[MQTT] Connected') + for i in range(4): + self.mqtt_subscribe('esp32/cam_{}'.format(i)) + + else: + self.add_note('[MQTT] Cannot Access AWS IOT') + except Exception as e: + tb = traceback.format_exc() + sg.Print(f'An error happened. Here is the info:', e, tb) + + def aws_disconnect(self): + if self.myAWSIoTMQTTClient is not None: + self.myAWSIoTMQTTClient.disconnect() + self.add_note('[MQTT] Successfully Disconnected!') + + def mqtt_subscribe(self, topic): + if self.myAWSIoTMQTTClient.subscribe(topic, 0, lambda client, userdata, message: { + + self.gui_queue.put({"Target_UI": "_{}_".format(str(message.topic).upper()), + "Image": self.byte_image_to_png(message)}) + }): + self.add_note('[MQTT] Topic: {}\n-> Subscribed'.format(topic)) + else: + self.add_note('[MQTT] Cannot subscribe\nthis Topic: {}'.format(topic)) + + def add_note(self, note): + note_history = self.window['_NOTES_'].get() + self.window['_NOTES_'].update(note_history + note if len(note_history) > 1 else note) + + def byte_image_to_png(self, message): + bytes_image = io.BytesIO(message.payload) + picture = Image.open(bytes_image) + + im_bytes = io.BytesIO() + picture.save(im_bytes, format="PNG") + return im_bytes.getvalue() + + def popup_dialog(self, contents, title, font): + sg.Popup(contents, title=title, keep_on_top=True, font=font) + + +if __name__ == '__main__': + Application() diff --git a/ESP32_MQTT/3_Python_MQTT_Client_App/requirements.txt b/ESP32_MQTT/3_Python_MQTT_Client_App/requirements.txt new file mode 100644 index 0000000..033a951 --- /dev/null +++ b/ESP32_MQTT/3_Python_MQTT_Client_App/requirements.txt @@ -0,0 +1,3 @@ +pysimplegui +AWSIoTPythonSDK +Pillow \ No newline at end of file