#!/usr/bin/python3 # -*- coding: utf-8 -*- ######################################## # HXbot GUI # # EoF 2016 EoF@itphx.ru # ######################################## import socket import sys import struct import curses import time import HX import select from curses import wrapper class HXguiClass(): def __init__(self, stdscr): super(HXguiClass, self).__init__() # UDP Socket self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.s.settimeout(HX.SRV_TIMEOUT) # Init color pairs self.RED_ON_BLACK = 1 self.GREEN_ON_BLACK = 2 self.YELLOW_ON_BLACK = 3 self.BLUE_ON_BLACK = 4 self.BLACK_ON_RED = 5 curses.init_pair(self.RED_ON_BLACK, curses.COLOR_RED, curses.COLOR_BLACK) curses.init_pair(self.GREEN_ON_BLACK, curses.COLOR_GREEN, curses.COLOR_BLACK) curses.init_pair(self.YELLOW_ON_BLACK, curses.COLOR_YELLOW, curses.COLOR_BLACK) curses.init_pair(self.BLUE_ON_BLACK, curses.COLOR_BLUE, curses.COLOR_BLACK) curses.init_pair(self.BLACK_ON_RED, curses.COLOR_BLACK, curses.COLOR_RED) # Params self.power_online = False self.vcc = 0.0 self.vin = 0.0 self.vdc = 0.0 self.vbt = 0.0 self.vba = 0.0 self.vpf = 0.0 self.vzu = 0.0 self.abt = 0.0 self.aba = 0.0 self.ain = 0.0 self.ahx = 0.0 self.vcc_ok = False self.vcc_low = False self.vcc_high = False self.vin_ok = False self.vin_low = False self.vin_high = False self.vdc_ok = False self.vdc_low = False self.vdc_high = False self.vbt_ok = False self.vbt_low = False self.vbt_full = False self.vba_ok = False self.vba_low = False self.vba_full = False self.vpf_ok = False self.vpf_low = False self.vpf_high = False self.vzu_ok = False self.vzu_low = False self.vzu_high = False self.abt_ok = False self.abt_low = False self.abt_high = False self.aba_ok = False self.aba_low = False self.aba_high = False self.ain_ok = False self.ain_low = False self.ain_high = False self.adc_ok = False self.adc_low = False self.adc_high = False self.bt_enabled = False self.ba_enabled = False self.mv_enabled = False self.us_enabled = False self.in_plugged = False self.bt_blocked = False self.ba_blocked = False self.bt_full = False self.ba_full = False self.reflex_online = False self.joystick_online = False self.lcd_online = False self.main_cam_state = 0 self.rear_cam_state = 0 self.main_mic_state = 0 self.error_count = 0 self.connected = False # Init screen stdscr.clear() stdscr.refresh() def draw_interface(self): self.header_text = "-= HXbot console v0.4 =-" self.footer_text = "-= EoF 2016 =-" self.header = curses.newwin(1, curses.COLS, 0, 0) self.header.bkgd(' ', curses.A_REVERSE) self.header.addstr(0, (curses.COLS - len(self.header_text)) // 2, self.header_text, curses.A_REVERSE) self.footer = curses.newwin(1, curses.COLS, curses.LINES - 1, 0) self.footer.bkgd(' ', curses.A_REVERSE) self.footer.addstr(0, (curses.COLS - len(self.footer_text)) // 2, self.footer_text, curses.A_REVERSE) self.comline = curses.newwin(1, curses.COLS, curses.LINES - 2, 0) self.comline.bkgd(' ', curses.A_NORMAL) self.comline.addstr(0, 0, "COMMAND: ", curses.A_BOLD) self.mainwin = curses.newwin(curses.LINES - 3, curses.COLS, 1, 0) self.mainwin.border() # Draw tables self.mainwin.addstr(2, 3, "| Vcc | Vin | Vdc | Vbt | Vba " + "| Vpf | Vzu |", curses.A_REVERSE) self.mainwin.addstr(3, 3, "| | | | | " + "| | |", curses.A_NORMAL) self.mainwin.addstr(4, 3, "| | | | | " + "| | |", curses.A_NORMAL) self.mainwin.addstr(6, 3, "| Abt || Aba || Ain || Ahx |", curses.A_REVERSE) self.mainwin.addstr(7, 3, "| || || || |", curses.A_NORMAL) self.mainwin.addstr(8, 3, "| || || || |", curses.A_NORMAL) self.mainwin.addstr(10, 3, "| MAIN POWER || MOVE POWER |", curses.A_REVERSE) self.mainwin.addstr(11, 3, "| || |", curses.A_NORMAL) self.mainwin.addstr(12, 3, "| || |", curses.A_NORMAL) #self.mainwin.addstr(11, 41, "| OK |", #curses.A_REVERSE) #self.mainwin.addstr(12, 41, "| |", #curses.A_NORMAL) self.mainwin.addstr(2, 55, "| STATUS |", curses.A_REVERSE) self.mainwin.addstr(3, 55, "| |", curses.A_NORMAL) self.mainwin.addstr(4, 55, "| |", curses.A_NORMAL) self.mainwin.addstr(5, 55, "| |", curses.A_NORMAL) self.mainwin.addstr(6, 55, "| |", curses.A_NORMAL) self.mainwin.addstr(7, 55, "| |", curses.A_NORMAL) self.mainwin.addstr(8, 55, "| |", curses.A_NORMAL) self.mainwin.addstr(9, 55, "| |", curses.A_NORMAL) self.mainwin.addstr(6, 41, "| BT & BA |", curses.A_REVERSE) self.mainwin.addstr(7, 41, "| |", curses.A_NORMAL) self.mainwin.addstr(8, 41, "| |", curses.A_NORMAL) self.mainwin.addstr(9, 41, "| |", curses.A_NORMAL) self.mainwin.addstr(10, 41, "| |", curses.A_NORMAL) self.mainwin.addstr(11, 41, "| |", curses.A_NORMAL) # Add text windows # Voltage states self.vcc_st_win = curses.newwin(1, 5, 4, 5) self.vin_st_win = curses.newwin(1, 5, 4, 12) self.vdc_st_win = curses.newwin(1, 5, 4, 19) self.vbt_st_win = curses.newwin(1, 5, 4, 26) self.vba_st_win = curses.newwin(1, 5, 4, 33) self.vpf_st_win = curses.newwin(1, 5, 4, 40) self.vzu_st_win = curses.newwin(1, 5, 4, 47) # Voltage values self.vcc_win = curses.newwin(1, 5, 5, 5) self.vin_win = curses.newwin(1, 5, 5, 12) self.vdc_win = curses.newwin(1, 5, 5, 19) self.vbt_win = curses.newwin(1, 5, 5, 26) self.vba_win = curses.newwin(1, 5, 5, 33) self.vpf_win = curses.newwin(1, 5, 5, 40) self.vzu_win = curses.newwin(1, 5, 5, 47) # Current states self.abt_st_win = curses.newwin(1, 6, 8, 5) self.aba_st_win = curses.newwin(1, 6, 8, 14) self.ain_st_win = curses.newwin(1, 6, 8, 23) self.ahx_st_win = curses.newwin(1, 6, 8, 32) # Current values self.abt_win = curses.newwin(1, 6, 9, 5) self.aba_win = curses.newwin(1, 6, 9, 14) self.ain_win = curses.newwin(1, 6, 9, 23) self.ahx_win = curses.newwin(1, 6, 9, 32) # Status self.bt_st_win = curses.newwin(1, 14, 12, 5) self.ba_st_win = curses.newwin(1, 14, 13, 5) self.mv_st_win = curses.newwin(1, 14, 12, 23) self.us_st_win = curses.newwin(1, 14, 13, 23) # Online Status self.pw_online_win = curses.newwin(1, 19, 4, 57) self.rf_online_win = curses.newwin(1, 19, 5, 57) self.js_online_win = curses.newwin(1, 19, 6, 57) self.lc_online_win = curses.newwin(1, 19, 7, 57) self.mc_online_win = curses.newwin(1, 19, 8, 57) self.rc_online_win = curses.newwin(1, 19, 9, 57) self.mm_online_win = curses.newwin(1, 19, 10, 57) # BL & BA status self.bt_blocked_win = curses.newwin(1, 9, 8, 43) self.ba_blocked_win = curses.newwin(1, 9, 9, 43) self.in_status_win = curses.newwin(1, 9, 10, 43) self.bt_status_win = curses.newwin(1, 9, 11, 43) self.ba_status_win = curses.newwin(1, 9, 12, 43) # Error pad clr = curses.color_pair(self.RED_ON_BLACK) self.error_pad = curses.newpad(3, 20) self.error_pad.border() self.error_pad.addstr(1, 2, "Connection lost!", clr) self.header.refresh() self.footer.refresh() self.mainwin.refresh() def draw_data(self): # Set voltage states if self.vcc_ok: tst = " OK " clr = curses.color_pair(self.GREEN_ON_BLACK) if self.vcc_low: tst = "LOW " clr = curses.color_pair(self.YELLOW_ON_BLACK) elif self.vcc_high: tst = "HIGH" clr = curses.color_pair(self.YELLOW_ON_BLACK) else: tst = "FAIL" clr = curses.color_pair(self.RED_ON_BLACK) self.vcc_st_win.addstr(0, 0, tst, clr) self.vcc_st_win.refresh() if self.vin_ok: tst = " OK " clr = curses.color_pair(self.GREEN_ON_BLACK) if self.vin_low: tst = "LOW " clr = curses.color_pair(self.YELLOW_ON_BLACK) elif self.vin_high: tst = "HIGH" clr = curses.color_pair(self.YELLOW_ON_BLACK) else: tst = "FAIL" clr = curses.color_pair(self.RED_ON_BLACK) self.vin_st_win.addstr(0, 0, tst, clr) self.vin_st_win.refresh() if self.vdc_ok: tst = " OK " clr = curses.color_pair(self.GREEN_ON_BLACK) if self.vdc_low: tst = "LOW " clr = curses.color_pair(self.YELLOW_ON_BLACK) elif self.vdc_high: tst = "HIGH" clr = curses.color_pair(self.YELLOW_ON_BLACK) else: tst = "FAIL" clr = curses.color_pair(self.RED_ON_BLACK) self.vdc_st_win.addstr(0, 0, tst, clr) self.vdc_st_win.refresh() if self.vbt_ok: tst = " OK " clr = curses.color_pair(self.GREEN_ON_BLACK) if self.vbt_low: tst = "LOW " clr = curses.color_pair(self.YELLOW_ON_BLACK) elif self.vbt_full: tst = "FULL" clr = curses.color_pair(self.GREEN_ON_BLACK) else: tst = "FAIL" clr = curses.color_pair(self.RED_ON_BLACK) self.vbt_st_win.addstr(0, 0, tst, clr) self.vbt_st_win.refresh() if self.mv_enabled: if self.vpf_ok: tst = " OK " clr = curses.color_pair(self.GREEN_ON_BLACK) if self.vpf_low: tst = "LOW " clr = curses.color_pair(self.YELLOW_ON_BLACK) elif self.vpf_high: tst = "HIGH" clr = curses.color_pair(self.GREEN_ON_BLACK) else: tst = "FAIL" clr = curses.color_pair(self.RED_ON_BLACK) else: tst = "OFF " clr = curses.color_pair(self.BLUE_ON_BLACK) self.vpf_st_win.addstr(0, 0, tst, clr) self.vpf_st_win.refresh() if self.vba_ok: tst = " OK " clr = curses.color_pair(self.GREEN_ON_BLACK) if self.vba_low: tst = "LOW " clr = curses.color_pair(self.YELLOW_ON_BLACK) elif self.vba_full: tst = "FULL" clr = curses.color_pair(self.GREEN_ON_BLACK) else: tst = "FAIL" clr = curses.color_pair(self.RED_ON_BLACK) self.vba_st_win.addstr(0, 0, tst, clr) self.vba_st_win.refresh() if self.mv_enabled: if self.vzu_ok: tst = " OK " clr = curses.color_pair(self.GREEN_ON_BLACK) if self.vzu_low: tst = "LOW " clr = curses.color_pair(self.YELLOW_ON_BLACK) elif self.vzu_high: tst = "HIGH" clr = curses.color_pair(self.GREEN_ON_BLACK) else: tst = "FAIL" clr = curses.color_pair(self.RED_ON_BLACK) else: tst = "OFF " clr = curses.color_pair(self.BLUE_ON_BLACK) self.vzu_st_win.addstr(0, 0, tst, clr) self.vzu_st_win.refresh() if self.abt_ok: tst = " OK " clr = curses.color_pair(self.GREEN_ON_BLACK) if self.abt_low: tst = "LOW " clr = curses.color_pair(self.YELLOW_ON_BLACK) elif self.abt_high: tst = "HIGH" clr = curses.color_pair(self.YELLOW_ON_BLACK) else: tst = "FAIL" clr = curses.color_pair(self.RED_ON_BLACK) self.abt_st_win.addstr(0, 0, tst, clr) self.abt_st_win.refresh() if self.aba_ok: tst = " OK " clr = curses.color_pair(self.GREEN_ON_BLACK) if self.aba_low: tst = "LOW " clr = curses.color_pair(self.YELLOW_ON_BLACK) elif self.aba_high: tst = "HIGH" clr = curses.color_pair(self.YELLOW_ON_BLACK) else: tst = "FAIL" clr = curses.color_pair(self.RED_ON_BLACK) self.aba_st_win.addstr(0, 0, tst, clr) self.aba_st_win.refresh() if self.ain_ok: tst = " OK " clr = curses.color_pair(self.GREEN_ON_BLACK) if self.ain_low: tst = "LOW " clr = curses.color_pair(self.YELLOW_ON_BLACK) elif self.ain_high: tst = "HIGH" clr = curses.color_pair(self.YELLOW_ON_BLACK) else: tst = "FAIL" clr = curses.color_pair(self.RED_ON_BLACK) self.ain_st_win.addstr(0, 0, tst, clr) self.ain_st_win.refresh() if self.ahx_ok: tst = " OK " clr = curses.color_pair(self.GREEN_ON_BLACK) if self.ahx_low: tst = "LOW " clr = curses.color_pair(self.YELLOW_ON_BLACK) elif self.ahx_high: tst = "HIGH" clr = curses.color_pair(self.YELLOW_ON_BLACK) else: tst = "FAIL" clr = curses.color_pair(self.RED_ON_BLACK) self.ahx_st_win.addstr(0, 0, tst, clr) self.ahx_st_win.refresh() # Set voltage values try: self.vcc_win.addstr(0, 0, '{:1.2f}'.format(self.vcc), curses.A_NORMAL) self.vcc_win.refresh() self.vin_win.addstr(0, 0, '{:2.1f}'.format(self.vin), curses.A_NORMAL) self.vin_win.refresh() self.vdc_win.addstr(0, 0, '{:1.2f}'.format(self.vdc), curses.A_NORMAL) self.vdc_win.refresh() self.vbt_win.addstr(0, 0, '{:1.2f}'.format(self.vbt), curses.A_NORMAL) self.vbt_win.refresh() self.vba_win.addstr(0, 0, '{:2.1f}'.format(self.vba), curses.A_NORMAL) self.vba_win.refresh() self.vpf_win.addstr(0, 0, '{:1.2f}'.format(self.vpf), curses.A_NORMAL) self.vpf_win.refresh() self.vzu_win.addstr(0, 0, '{:1.2f}'.format(self.vzu), curses.A_NORMAL) self.vzu_win.refresh() self.abt_win.addstr(0, 0, '{:2.2f}'.format(self.abt), curses.A_NORMAL) self.abt_win.refresh() self.aba_win.addstr(0, 0, '{:2.2f}'.format(self.aba), curses.A_NORMAL) self.aba_win.refresh() self.ain_win.addstr(0, 0, '{:2.2f}'.format(self.ain), curses.A_NORMAL) self.ain_win.refresh() self.ahx_win.addstr(0, 0, '{:2.2f}'.format(self.ahx), curses.A_NORMAL) self.ahx_win.refresh() except curses.error: #comline.addstr(0, 0, str(vba), curses.A_NORMAL) #comline.refresh() pass # Set status if self.bt_enabled: tst = "BT Enabled " clr = curses.color_pair(self.GREEN_ON_BLACK) else: tst = "BT Disabled" clr = curses.color_pair(self.YELLOW_ON_BLACK) self.bt_st_win.addstr(0, 0, tst, clr) self.bt_st_win.refresh() if self.ba_enabled: tst = "BA Enabled " clr = curses.color_pair(self.GREEN_ON_BLACK) else: tst = "BA Disabled" clr = curses.color_pair(self.YELLOW_ON_BLACK) self.ba_st_win.addstr(0, 0, tst, clr) self.ba_st_win.refresh() if self.mv_enabled: tst = "MV Enabled " clr = curses.color_pair(self.GREEN_ON_BLACK) else: tst = "MV Disabled" clr = curses.color_pair(self.RED_ON_BLACK) self.mv_st_win.addstr(0, 0, tst, clr) self.mv_st_win.refresh() if self.us_enabled: tst = "US Enabled " clr = curses.color_pair(self.GREEN_ON_BLACK) else: tst = "US Disabled" clr = curses.color_pair(self.RED_ON_BLACK) self.us_st_win.addstr(0, 0, tst, clr) self.us_st_win.refresh() # Set online status tst = "HXpower" if self.power_online: clr = curses.color_pair(self.GREEN_ON_BLACK) else: clr = curses.color_pair(self.RED_ON_BLACK) self.pw_online_win.addstr(0, 0, tst, clr) self.pw_online_win.refresh() tst = "REflex" if self.reflex_online: clr = curses.color_pair(self.GREEN_ON_BLACK) else: clr = curses.color_pair(self.RED_ON_BLACK) self.rf_online_win.addstr(0, 0, tst, clr) self.rf_online_win.refresh() tst = "Joystick" if self.joystick_online: clr = curses.color_pair(self.GREEN_ON_BLACK) else: clr = curses.color_pair(self.BLUE_ON_BLACK) self.js_online_win.addstr(0, 0, tst, clr) self.js_online_win.refresh() tst = "Display" if self.lcd_online: clr = curses.color_pair(self.GREEN_ON_BLACK) else: clr = curses.color_pair(self.BLUE_ON_BLACK) self.lc_online_win.addstr(0, 0, tst, clr) self.lc_online_win.refresh() tst = "Main camera" if self.main_cam_state == HX.CAM_STATE_RUN: clr = curses.color_pair(self.GREEN_ON_BLACK) elif self.main_cam_state == HX.CAM_STATE_STP: clr = curses.color_pair(self.BLUE_ON_BLACK) elif self.main_cam_state == HX.CAM_STATE_WRN: clr = curses.color_pair(self.YELLOW_ON_BLACK) else: clr = curses.color_pair(self.RED_ON_BLACK) self.mc_online_win.addstr(0, 0, tst, clr) self.mc_online_win.refresh() tst = "Rear camera" if self.rear_cam_state == HX.CAM_STATE_RUN: clr = curses.color_pair(self.GREEN_ON_BLACK) elif self.rear_cam_state == HX.CAM_STATE_STP: clr = curses.color_pair(self.BLUE_ON_BLACK) elif self.rear_cam_state == HX.CAM_STATE_WRN: clr = curses.color_pair(self.YELLOW_ON_BLACK) else: clr = curses.color_pair(self.RED_ON_BLACK) self.rc_online_win.addstr(0, 0, tst, clr) self.rc_online_win.refresh() tst = "Main mic" if self.main_mic_state == HX.CAM_STATE_RUN: clr = curses.color_pair(self.GREEN_ON_BLACK) elif self.main_mic_state == HX.CAM_STATE_STP: clr = curses.color_pair(self.BLUE_ON_BLACK) elif self.main_mic_state == HX.CAM_STATE_WRN: clr = curses.color_pair(self.YELLOW_ON_BLACK) else: clr = curses.color_pair(self.RED_ON_BLACK) self.mm_online_win.addstr(0, 0, tst, clr) self.mm_online_win.refresh() # Set EX & BA status tst = "BT block" if self.bt_blocked: clr = curses.color_pair(self.GREEN_ON_BLACK) else: clr = curses.color_pair(self.BLUE_ON_BLACK) self.bt_blocked_win.addstr(0, 0, tst, clr) self.bt_blocked_win.refresh() tst = "BA block" if self.ba_blocked: clr = curses.color_pair(self.GREEN_ON_BLACK) else: clr = curses.color_pair(self.BLUE_ON_BLACK) self.ba_blocked_win.addstr(0, 0, tst, clr) self.ba_blocked_win.refresh() tst = "IN plugg" if self.in_plugged: clr = curses.color_pair(self.GREEN_ON_BLACK) else: clr = curses.color_pair(self.BLUE_ON_BLACK) self.in_status_win.addstr(0, 0, tst, clr) self.in_status_win.refresh() #if self.bt_charge: #tst = "BT chrg" #clr = curses.color_pair(self.YELLOW_ON_BLACK) if self.bt_full: tst = "BT full" clr = curses.color_pair(self.GREEN_ON_BLACK) else: tst = "BT chrg" clr = curses.color_pair(self.BLUE_ON_BLACK) self.bt_status_win.addstr(0, 0, tst, clr) self.bt_status_win.refresh() #if self.ba_charge: #tst = "BA chrg" #clr = curses.color_pair(self.YELLOW_ON_BLACK) if self.ba_full: tst = "BA full" clr = curses.color_pair(self.GREEN_ON_BLACK) else: tst = "BA chrg" clr = curses.color_pair(self.BLUE_ON_BLACK) self.ba_status_win.addstr(0, 0, tst, clr) self.ba_status_win.refresh() def get_data(self): # Get values HOST, PORT = "localhost", HX.SRV_PORT self.s.sendto(struct.pack('B', HX.SRV_CMD_GET_ALL), (HOST, PORT)) try: data = self.s.recv(1024) except socket.timeout: if self.error_count < HX.SRV_MAX_ERR_COUNT: self.error_count += 1 else: self.connected = False return self.error_count = 0 self.connected = True self.vcc, self.vin, self.vdc, self.vbt, self.vba, self.vpf, self.vzu, \ self.abt, self.aba, self.ain, self.ahx, \ self.power_online, \ self.vcc_ok, self.vin_ok, self.vdc_ok, self.vbt_ok, self.vba_ok, \ self.vpf_ok, self.vzu_ok, \ self.abt_ok, self.aba_ok, self.ain_ok, self.ahx_ok, \ self.bt_enabled, self.ba_enabled, self.bt_blocked, self.ba_blocked, \ self.vcc_low, self.vcc_high, self.vin_low, self.vin_high, \ self.vdc_low, self.vdc_high, self.vbt_low, self.vbt_full, \ self.vba_low, self.vba_full, self.vpf_low, self.vpf_high, \ self.vzu_low, self.vzu_high, \ self.abt_low, self.abt_high, self.aba_low, self.aba_high, \ self.ain_low, self.ain_high, self.ahx_low, self.ahx_high, \ self.mv_enabled, self.us_enabled, self.in_plugged, \ self.ba_full, self.bt_full, self.reflex_online, \ self.joystick_online, self.lcd_online, \ self.main_cam_state, self.rear_cam_state, self.main_mic_state = \ struct.unpack( 'fffffffffff??????????????????????????????????????????????BBB', data) def execute(self): self.draw_interface() redrawed = False while True: # Get values self.get_data() self.draw_data() if not self.connected: self.error_pad.refresh(0, 0, 10, 30, 13, 50) redrawed = False else: if not redrawed: self.mainwin.redrawwin() self.mainwin.refresh() redrawed = True self.comline.refresh() if sys.stdin in select.select([sys.stdin], [], [], 0)[0]: key = self.comline.getkey() if key.upper() == 'Q': break time.sleep(0.2) def main(stdscr): HXgui = HXguiClass(stdscr) HXgui.execute() sys.exit() # GENERAL PROGRAM if __name__ == "__main__": # Setup stdscr = curses.initscr() curses.start_color() curses.noecho() curses.cbreak() stdscr.keypad(True) # Start main function wrapper(main) # Cleanup curses.nocbreak() stdscr.keypad(False) curses.echo() curses.endwin()