# cPy - qt gui application communicating with Esp32 through USB
# Copyright by Anthony Vogelaar, Perth Scotland
# rev 0.10  2026-04-02  initial release

import  subprocess;         subprocess.run('clear')
import	time, json
import	datetime			as		dt
from	serial	            import	Serial
from    PySide6.QtWidgets   import  (QApplication, QWidget, QTextEdit)
from    PySide6.QtGui       import  QTextCursor

# ============================ UsbSerial ===============================

class UsbSerial:
    
    def __init__(self, port='/dev/ttyUSB0', baud=115200):
        self.comm    = Serial(port=port, baudrate=baud, timeout=0, exclusive=True)
        self.buff_rx = b''
        
        
    # write string s <LF> terminated
    def writeLn(self, s):
        if s[-1] != '\n': s += '\n'
        self.comm.write(s.encode())
        
        
    # return received line as string or None
    def readLn(self):
        res = None
        while ch := self.comm.read():
            if ch == b'\r': continue
            if ch == b'\n':
                if self.buff_rx: 
                    res, self.buff_rx = self.buff_rx,b''
                    return res.decode()
            else: self.buff_rx += ch

# ============================= Qt GUI ===============================
#             
class Gui(QWidget):

    # GUI setup
    def __init__(self):
        self.app = QApplication()                       # Qt framework
        super().__init__()                              # instantiate QWidget = GUI
        self.resize(200, 200)
        self.memo = QTextEdit(self)
        self.memo.setGeometry(10, 10, 180, 180)
        self.memo.setReadOnly(True)
        self.memo.setStyleSheet('background-color: MediumAquamarine')
        self.show()


    # add string s to memo
    def memoAdd(self, s):
        txt = self.memo.toPlainText()
        if txt: txt += '\n'
        self.memo.setText(txt + s)
        self.memo.moveCursor(QTextCursor.End)


    # refresh Qt loop, call @ 20 Hz
    def refresh(self):
        self.app.processEvents()

# ============================= main ================================

def interpret(s):
    try:
        cmd = json.loads(s)
        for k, v in cmd.items():
            if k == 'btn':
                if   v == 'red'   : loc = 'Amsterdam'; time =  2		# utc+2
                elif v == 'yellow': loc = 'London';    time =  1
                elif v == 'green' : loc = 'New York';  time = -4
                elif v == 'blue'  : loc = 'Sidney';    time = 10
                else: continue
                time = dt.datetime.now(dt.timezone(dt.timedelta(hours=time)))
                time = time.strftime('%H:%M:%S')
        return f'{loc}\n{time}'
    except: print('Exception in interpret()')


# present string received from Esp32 on kit's LCD, Qt GUI and in Shell
def main():
    comm = UsbSerial()
    gui = Gui()
    while True:
        if s_rx := comm.readLn():
            gui.memoAdd(s_rx)                       # show s_rx in GUI
            res = interpret(s_rx)
            gui.memoAdd(res)                        # show  res in GUI
            comm.writeLn(res)						# write res to Esp32
            print(res)                              # show  res in shell
        gui.refresh()                               # refresh Qt loop
        time.sleep(0.05)                            # 20 Hz loop
    
    
main()

# ============================== end ================================
