screen_height = self.parent.winfo_screenheight() splash_canvas = tk.Canvas(self.parent, width=screen_width, height=screen_height) splash_canvas.pack() self.tkimage = ImageTk.PhotoImage(self.image1) splash_canvas.create_image(0, 0, image=self.tkimage, anchor="nw") splash_canvas.create_text(200, 34, text="[LOADING]...PLEASE WAIT", font=("small fonts", 20), fill="white") progressbar = ttk.Progressbar(orient=tk.HORIZONTAL, length=900, mode='determinate', style="Horizontal.TProgressbar") progressbar.place(x=450, y=25) progressbar.start() if self.nxt_func != None: self.parent.after(5050, self.proceed) if __name__ == '__main__': root = ThemedTk("black") root["bg"] = "gray21" style = ttk.Style() style.configure("Horizontal.TProgressbar", foreground='gray21') app = SplashScreen(root, None) app.display() root.after(5050, root.destroy) root.mainloop()
class Toplevel1(object): def __init__(self): '''This class configures and populates the toplevel window. top is the toplevel containing window.''' self.root = ThemedTk(theme="arc") self.style = ttk.Style() # self.root = tk.Tk() self.root.geometry("1200x661+284+114") # self.root.minsize(120, 1) # self.root.maxsize(1924, 1061) self.root.resizable(1, 1) self.root.title("New Toplevel") self.img = Image.open(r"G:\MoveOn\Gispot\GUIs\Icons\folder1.png") self.image_1 = ImageTk.PhotoImage(self.img) # top.configure(background="#d9d9d9") # # self.menubar = tk.Menu(top,font="TkMenuFont",bg=_bgcolor,fg=_fgcolor) # top.configure(menu = self.menubar) # self.style.configure('TNotebook.Tab', background=_bgcolor) # self.style.configure('TNotebook.Tab', foreground=_fgcolor) # self.style.map('TNotebook.Tab', background= # [('selected', _compcolor), ('active',_ana2color)]) self.TNotebook1 = ttk.Notebook(self.root) self.TNotebook1.place(relx=0.0, rely=0.0, relheight=1.0, relwidth=1.0) self.TNotebook1.configure(takefocus="") self.TNotebook1_t1 = tk.Frame(self.TNotebook1) self.TNotebook1.add(self.TNotebook1_t1, padding=3) self.TNotebook1.tab(0, text="Page 1", compound="left", image = self.image_1) self.TNotebook1_t2 = tk.Frame(self.TNotebook1) self.TNotebook1.add(self.TNotebook1_t2, padding=3) self.TNotebook1.tab(1, text="Page 2", compound="left", underline="-1", ) self.f = tk.Frame(self.TNotebook1_t1, width=20, height=100 ) self.f.place(x=0, y=0) self.set_button() # self.f2 = tk.Frame(self.TNotebook1_t1, width=20, height=100, bg="blue") # self.f2.place(x=0, y=600,anchor="nw") # self.set_label() def set_button(self): button = ttk.Button(self.TNotebook1_t1,text = "bt",command = self.set_button_command) # lambda 形式也可以 # button = ttk.Button(self.TNotebook1_t1,text = "bt",command = lambda:(self.root.after(2000, self.add_label))) button.pack() def add_label(self): lb = ttk.Button(self.f, text=1) lb.pack() # 加入该行可以循环添加 self.set_button_command() def set_button_command(self): self.root.after(100, self.add_label)
) autostart_box.grid(column=0, row=1) chars = get_characters() if selected_char.get() == "": selected_char.set(chars[0]) set_conf() character_dropdown = OptionMenu(frame, selected_char, selected_char.get(), *chars, command=set_conf) character_dropdown.grid(column=1, row=0) status_message = Message(frame, width=300) status_message.grid(column=0, columnspan=2, row=2) credit_button = Button( frame, text="Github Page", command=lambda: webbrowser.open( "https://github.com/ToasterUwU/EVE-Discord-Presence"), ) credit_button.grid(column=0, columnspan=2, row=3) frame.place(relx=0.5, rely=0.5, anchor="c") tk.after(0, loop) tk.mainloop()
class SSN_Server_UI(): def __init__(self, window_theme="aquativo", window_title="Hello World!", window_geometry="400x400+100+100"): self.root_window = ThemedTk() self.root_window.set_theme(theme_name=window_theme) self.root_window.title(window_title) self.root_window.geometry(window_geometry) self.window_width = self.root_window.winfo_screenwidth() self.window_height = self.root_window.winfo_screenheight() # essential communicators self.udp_comm = None self.mqtt_comm = None self.serial_comm = None self.use_udp = False self.use_mqtt = False self.csv_data_recording = None ############# if we have more than one node self.NodeCountInGUI = 0 self.message_type_text = list() self.node_select_radio_button = SSN_Radio_Button_Common_Option_Widget( self.root_window) self.nodeid_text = list() self.temperature_text = list() self.humidity_text = list() self.nodeuptime_text = list() self.abnormalactivity_text = list() ######## Machine Incoming data to be displayed self.machine_loadcurrents, self.machine_percentageloads, self.machine_status = [ [] for _ in range(4) ], [[] for _ in range(4)], [[] for _ in range(4)] self.machine_timeinstate, self.machine_sincewheninstate = [ [] for _ in range(4) ], [[] for _ in range(4)] self.no_connection = 0 pass def start(self): self.root_window.mainloop() # threading.Thread.__init__(self) # self.start() def setup_input_interface(self, current_sensor_ratings, mac_addresses_filename, default_configs): # enter the SSN new MAC full_mac_list = get_MAC_addresses_from_file(mac_addresses_filename) self.ssn_mac_dropdown = SSN_DropDown_Widget( window=self.root_window, label_text="SSN MAC", label_pos=(0, vertical_spacing * 0 + 2), dropdown_list=full_mac_list, dropdown_pos=(horizontal_spacing - 10, vertical_spacing * 0 + 2), dropdown_block_width=17) ######## Machine Config Inputs self.machine_ratings, self.machine_maxloads, self.machine_thresholds = list( ), list(), list() for i in range(4): # generate machine label rating_label_text = "M{} Sensor Rating (A)".format(i + 1) maxload_label_text = "M{} Max Load (A)".format(i + 1) thres_label_text = "M{} Threshold (A)".format(i + 1) # enter machine sensor rating rating_dropdown = SSN_DropDown_Widget( window=self.root_window, label_text=rating_label_text, label_pos=(horizontal_spacing * 2 * i, vertical_spacing * 1 + 5), dropdown_list=current_sensor_ratings, dropdown_pos=(horizontal_spacing * (2 * i + 1), vertical_spacing * 1 + 5), dropdown_block_width=12, default_selected_item=default_configs[0 + 3 * i]) # enter machine max load maxload_text_entry = SSN_Text_Entry_Widget( window=self.root_window, label_text=maxload_label_text, label_pos=(horizontal_spacing * 2 * i, vertical_spacing * 2 + 5), text_entry_width=15, text_pos=(horizontal_spacing * (2 * i + 1), vertical_spacing * 2 + 5), default_value=default_configs[1 + 3 * i]) # enter machine threshold current thresh_text_entry = SSN_Text_Entry_Widget( window=self.root_window, label_text=thres_label_text, label_pos=(horizontal_spacing * 2 * i, vertical_spacing * 3 + 5), text_entry_width=15, text_pos=(horizontal_spacing * (2 * i + 1), vertical_spacing * 3 + 5), default_value=default_configs[2 + 3 * i]) self.machine_ratings.append(rating_dropdown) self.machine_maxloads.append(maxload_text_entry) self.machine_thresholds.append(thresh_text_entry) pass # reporting interval text input self.reportinterval_text_entry = SSN_Text_Entry_Widget( window=self.root_window, label_text="Report Interval (sec)", label_pos=(horizontal_spacing * 2, vertical_spacing * 4 + 5), text_entry_width=15, text_pos=(horizontal_spacing * (2 + 1), vertical_spacing * 4 + 5), default_value=default_configs[12]) pass def clear_status_panel(self): # clear node status for this_node in range(self.NodeCountInGUI): self.message_type_text[this_node].clear() self.nodeid_text[this_node].clear() # clear existing texts for node specific information self.temperature_text[this_node].clear() self.humidity_text[this_node].clear() self.nodeuptime_text[this_node].clear() self.abnormalactivity_text[this_node].clear() # clear existing texts for machine specific information for i in range(4): self.machine_loadcurrents[this_node][i].clear() self.machine_percentageloads[this_node][i].clear() self.machine_status[this_node][i].clear() self.machine_timeinstate[this_node][i].clear() self.machine_sincewheninstate[this_node][i].clear() pass pass pass def send_mac_btn_clicked(self): # clear node status panel self.clear_status_panel() if self.use_udp: # construct and send set_mac message try: self.udp_comm.send_set_mac_message( node_index=self.node_select_radio_button.getSelectedNode() - 1, mac_address=self.ssn_mac_dropdown.get()) print('\033[34m' + "Sent MAC to SSN-{}".format( self.node_select_radio_button.getSelectedNode())) except IndexError: print( '\033[31m' + "SSN Network Node Count: {}. Can't Send to SSN Indexed: {}" .format( self.udp_comm.getNodeCountinNetwork(), self.node_select_radio_button.getSelectedNode() - 1)) pass elif self.use_mqtt: # construct and send set_mac message try: self.mqtt_comm.send_set_mac_message( mac_address=self.ssn_mac_dropdown.get()) print('\033[34m' + "Sent MAC to SSN-{}".format( self.node_select_radio_button.getSelectedNode())) except error: print('\033[31m' + f"{error}") pass pass pass def send_config_btn_clicked(self): # clear node status panel self.clear_status_panel() # get the configs from the GUI self.configs = list() for i in range(4): this_sensor_rating = self.machine_ratings[i].get() this_sensor_rating = int( this_sensor_rating) if this_sensor_rating != 'NONE' else 0 self.configs.append(this_sensor_rating) self.configs.append( int(10 * float(self.machine_thresholds[i].get()))) self.configs.append(int(self.machine_maxloads[i].get())) pass self.configs.append(int(self.reportinterval_text_entry.get())) if self.use_udp: try: self.udp_comm.send_set_config_message( node_index=self.node_select_radio_button.getSelectedNode() - 1, config=self.configs) print('\033[34m' + "Sent CONFIG to SSN-{}".format( self.node_select_radio_button.getSelectedNode())) except IndexError: print( '\033[31m' + "SSN Network Node Count: {}. Can't Send to SSN Indexed: {}" .format( self.udp_comm.getNodeCountinNetwork(), self.node_select_radio_button.getSelectedNode() - 1)) # change button color # self.config_button.config(bg='white') elif self.use_mqtt: # construct and send set_mac message try: self.mqtt_comm.send_set_config_message(config=self.configs) print('\033[34m' + "Sent CONFIG to SSN-{}".format( self.node_select_radio_button.getSelectedNode())) except error: print('\033[31m' + f"{error}") pass pass pass def send_timeofday_btn_clicked(self): if self.use_udp: try: # self.udp_comm.send_set_timeofday_message(node_index=self.node_select_radio_button.getSelectedNode() - 1, current_time=self.server_time_now) self.udp_comm.send_set_timeofday_Tick_message( node_index=self.node_select_radio_button.getSelectedNode() - 1, current_tick=utils.get_bytes_from_int( self.servertimeofday_Tick)) print('\033[34m' + "Sent Time of Day to SSN-{}".format( self.node_select_radio_button.getSelectedNode())) except IndexError: print( '\033[31m' + "SSN Network Node Count: {}. Can't Send to SSN Indexed: {}" .format( self.udp_comm.getNodeCountinNetwork(), self.node_select_radio_button.getSelectedNode() - 1)) elif self.use_mqtt: # construct and send set_mac message try: self.mqtt_comm.send_set_timeofday_Tick_message( current_tick=utils.get_bytes_from_int( self.servertimeofday_Tick)) print('\033[34m' + "Sent Time of Day to SSN-{}".format( self.node_select_radio_button.getSelectedNode())) except error: print('\033[31m' + f"{error}") pass pass pass def debug_reset_eeprom_btn_clicked(self): # clear node status panel self.clear_status_panel() if self.use_udp: # send message and clear the status texts try: self.udp_comm.send_debug_reset_eeprom_message( node_index=self.node_select_radio_button.getSelectedNode() - 1) print('\033[34m' + "Sent CLEAR EEPROM to SSN-{}".format( self.node_select_radio_button.getSelectedNode())) except IndexError: print( '\033[31m' + "SSN Network Node Count: {}. Can't Send to SSN Indexed: {}" .format( self.udp_comm.getNodeCountinNetwork(), self.node_select_radio_button.getSelectedNode() - 1)) elif self.use_mqtt: # construct and send set_mac message try: self.mqtt_comm.send_debug_reset_eeprom_message() print('\033[34m' + "Sent CLEAR EEPROM to SSN-{}".format( self.node_select_radio_button.getSelectedNode())) except error: print('\033[31m' + f"{error}") pass pass pass def debug_reset_ssn_btn_clicked(self): # clear node status panel self.clear_status_panel() if self.use_udp: # send message and clear statuss try: self.udp_comm.send_debug_reset_ssn_message( node_index=self.node_select_radio_button.getSelectedNode() - 1) print('\033[34m' + "Sent RESET to SSN-{}".format( self.node_select_radio_button.getSelectedNode())) except IndexError: print( '\033[31m' + "SSN Network Node Count: {}. Can't Send to SSN Indexed: {}" .format( self.udp_comm.getNodeCountinNetwork(), self.node_select_radio_button.getSelectedNode() - 1)) elif self.use_mqtt: # construct and send set_mac message try: self.mqtt_comm.send_debug_reset_ssn_message() print('\033[34m' + "Sent RESET to SSN-{}".format( self.node_select_radio_button.getSelectedNode())) except error: print('\033[31m' + f"{error}") pass pass pass def setup_buttons(self): # update mac button self.mac_button = SSN_Button_Widget( window=self.root_window, button_text="Send MAC Address", button_command=self.send_mac_btn_clicked, button_pos=(2 * horizontal_spacing, vertical_spacing * 0 + 0)) # send sensor configuration button self.config_button = SSN_Button_Widget( window=self.root_window, button_text="Send Configuration", button_command=self.send_config_btn_clicked, button_pos=(horizontal_spacing * 4, vertical_spacing * 4 + 5)) # send time of day button; we will also give a display of current time of day with this self.servertimeofday_text = SSN_Text_Display_Widget( window=self.root_window, label_text="Server Time of Day", label_pos=(3 * horizontal_spacing + 52, vertical_spacing * 7), text_size=(150, vertical_spacing), text_pos=(3 * horizontal_spacing + 30, vertical_spacing * 8)) self.servertimeofday_button = SSN_Button_Widget( window=self.root_window, button_text="Send Time of Day", button_command=self.send_timeofday_btn_clicked, button_pos=(3 * horizontal_spacing + 54, vertical_spacing * 9 + 5)) self.debug_reset_eeprom_button = SSN_Button_Widget( window=self.root_window, button_text="(DEBUG) CLEAR EEPROM", button_command=self.debug_reset_eeprom_btn_clicked, button_pos=(5 * horizontal_spacing + 50, vertical_spacing * 8 - 10)) self.debug_reset_ssn_button = SSN_Button_Widget( window=self.root_window, button_text="(DEBUG) RESET SSN", button_command=self.debug_reset_ssn_btn_clicked, button_pos=(5 * horizontal_spacing + 64, vertical_spacing * 9 + 5)) self.clear_status_panel_button = SSN_Button_Widget( window=self.root_window, button_text="Clear Status Panel", button_command=self.clear_status_panel, button_pos=(5 * horizontal_spacing + 69, vertical_spacing * 10 + 22)) pass def GUI_Block(self): return (self.NodeCountInGUI - 1) * vertical_spacing * 14 + 40 def setup_incoming_data_interface(self, NumOfNodes): for k in range(NumOfNodes): self.NodeCountInGUI += 1 # received message/status to be displayed self.message_type_text.append( SSN_Text_Display_Widget( window=self.root_window, label_text="Incoming Message Type", label_pos=(0, self.GUI_Block() + vertical_spacing * 6), text_size=(110, vertical_spacing), text_pos=(horizontal_spacing + 20, self.GUI_Block() + vertical_spacing * 6))) # add a radio-button to chose this one when we have to send the message self.node_select_radio_button.add_radio( radio_text="SSN-{}".format(self.NodeCountInGUI), radio_value=self.NodeCountInGUI, radio_pos=(2 * horizontal_spacing + 20, self.GUI_Block() + vertical_spacing * 6)) # SSN Node ID to be displayed self.nodeid_text.append( SSN_Text_Display_Widget( window=self.root_window, label_text="Node ID", label_pos=(0, self.GUI_Block() + vertical_spacing * 7), text_size=(110, vertical_spacing), text_pos=(horizontal_spacing + 20, self.GUI_Block() + vertical_spacing * 7))) # temperature to be displayed self.temperature_text.append( SSN_Text_Display_Widget( window=self.root_window, label_text="Temperature ({}C)".format(chr(176)), label_pos=(0, self.GUI_Block() + vertical_spacing * 8), text_size=(110, vertical_spacing), text_pos=(horizontal_spacing + 20, self.GUI_Block() + vertical_spacing * 8))) # humidity to be displayed self.humidity_text.append( SSN_Text_Display_Widget( window=self.root_window, label_text="Relative Humidity (%)", label_pos=(0, self.GUI_Block() + vertical_spacing * 9), text_size=(110, vertical_spacing), text_pos=(horizontal_spacing + 20, self.GUI_Block() + vertical_spacing * 9))) # node uptime to be displayed self.nodeuptime_text.append( SSN_Text_Display_Widget( window=self.root_window, label_text="Node Up Time in (sec)", label_pos=(0, self.GUI_Block() + vertical_spacing * 10), text_size=(110, vertical_spacing), text_pos=(horizontal_spacing + 20, self.GUI_Block() + vertical_spacing * 10))) # abnormal activity to be displayed self.abnormalactivity_text.append( SSN_Text_Display_Widget( window=self.root_window, label_text="Abnormal Activity", label_pos=(0, self.GUI_Block() + vertical_spacing * 11), text_size=(110, vertical_spacing), text_pos=(horizontal_spacing + 20, self.GUI_Block() + vertical_spacing * 11), color='green')) for i in range(4): # generate machine labels loadcurrent_label_text = "M{} Load Current (A)".format(i + 1) percentload_label_text = "M{} Percentage Load (%)".format(i + 1) state_label_text = "M{} State (OFF/IDLE/ON)".format(i + 1) duration_label_text = "M{} Time In State (sec)".format(i + 1) timestamp_label_text = "M{} State Time Stamp".format(i + 1) # machine load current loadcurrent_text = SSN_Text_Display_Widget( window=self.root_window, label_text=loadcurrent_label_text, label_pos=(horizontal_spacing * 2 * i, self.GUI_Block() + vertical_spacing * 12 + 20), text_size=(80, vertical_spacing), text_pos=((2 * i + 1) * horizontal_spacing + 20, self.GUI_Block() + vertical_spacing * 12 + 20)) percentload_text_entry = SSN_Text_Display_Widget( window=self.root_window, label_text=percentload_label_text, label_pos=(horizontal_spacing * 2 * i, self.GUI_Block() + vertical_spacing * 13 + 20), text_size=(80, vertical_spacing), text_pos=(horizontal_spacing * (2 * i + 1) + 20, self.GUI_Block() + vertical_spacing * 13 + 20)) # machine state state_text_entry = SSN_Text_Display_Widget( window=self.root_window, label_text=state_label_text, label_pos=(horizontal_spacing * 2 * i, self.GUI_Block() + vertical_spacing * 14 + 20), text_size=(80, vertical_spacing), text_pos=(horizontal_spacing * (2 * i + 1) + 20, self.GUI_Block() + vertical_spacing * 14 + 20)) # machine state duration duration_text_entry = SSN_Text_Display_Widget( window=self.root_window, label_text=duration_label_text, label_pos=(horizontal_spacing * 2 * i, self.GUI_Block() + vertical_spacing * 15 + 20), text_size=(80, vertical_spacing), text_pos=(horizontal_spacing * (2 * i + 1) + 20, self.GUI_Block() + vertical_spacing * 15 + 20)) # machine state timestamp timestamp_dual_text_entry = SSN_Dual_Text_Display_Widget( window=self.root_window, label_text=timestamp_label_text, label_pos=(horizontal_spacing * 2 * i, self.GUI_Block() + vertical_spacing * 16 + 20), text_size=(80, vertical_spacing), text_pos1=(horizontal_spacing * (2 * i + 1) + 20, self.GUI_Block() + vertical_spacing * 16 + 20), text_pos2=(horizontal_spacing * (2 * i + 1) + 20, self.GUI_Block() + vertical_spacing * 17 + 20)) self.machine_loadcurrents[self.NodeCountInGUI - 1].append(loadcurrent_text) self.machine_percentageloads[self.NodeCountInGUI - 1].append(percentload_text_entry) self.machine_status[self.NodeCountInGUI - 1].append(state_text_entry) self.machine_timeinstate[self.NodeCountInGUI - 1].append(duration_text_entry) self.machine_sincewheninstate[self.NodeCountInGUI - 1].append( timestamp_dual_text_entry) pass pass # set default node for sending messages self.node_select_radio_button.radio_buttons[0].invoke() pass def setup_serial_communication(self, serial_port='COM5', baudrate=19200, log_file='../serial_log-110920-130920.txt'): self.serial_comm = SERIAL_COMM(serial_port, baudrate, log_file) pass def setup_udp_communication(self, server_end): # essential UDP communicator self.udp_comm = UDP_COMM() connection_status = self.udp_comm.udp_setup_connection( server_address=server_end[0], server_port=server_end[1]) if connection_status is None: print("Cannot Connect to Network!!!") return self.use_udp = True # invoke it just once self.read_messages_and_update_UI() pass def setup_mqtt_communication(self, client_id, host="192.168.0.120"): self.mqtt_comm = MQTT(client_id=client_id, host=host) self.mqtt_comm.client.loop_start() self.use_mqtt = True # invoke it just once self.read_messages_and_update_UI() pass def setup_csv_data_recording(self, csv_file): this_date = datetime.datetime.fromtimestamp(int(round(time.time()))) file_name, extension = os.path.splitext(csv_file) self.csv_data_file = file_name self.csv_data_recording = True pass def read_messages_and_update_UI(self): # check serial comm for messages if self.serial_comm: self.serial_comm.log() self.servertimeofday_Tick = int(round(time.time())) self.servertimeofday_text.update( new_text_string=self.servertimeofday_Tick) # receive the incoming message if self.use_udp: node_index, message_id, params = self.udp_comm.read_udp_message() # check if a valid message was received or not if node_index == -1 and message_id == -1: self.no_connection += 1 if self.no_connection > 10: self.no_connection = 0 print('\033[30m' + "XXX Nothing Received XXX") # recall this method after another second self.root_window.after(200, self.read_messages_and_update_UI) return elif self.use_mqtt: if not self.mqtt_comm.message_queue.qsize(): self.no_connection += 1 if self.no_connection > 10: self.no_connection = 0 print('\033[30m' + "XXX Nothing Received XXX") # recall this method after another second self.root_window.after(200, self.read_messages_and_update_UI) return node_index, message_id, params = self.mqtt_comm.message_queue.get() # proceed only if a genuine message is found self.no_connection = 0 # message type and node id will always be displayed self.message_type_text[node_index].update( new_text_string=SSN_MessageID_to_Type[message_id], justification='left') self.nodeid_text[node_index].update(new_text_string=params[0]) # basic get messages received? if message_id == SSN_MessageType_to_ID['GET_MAC']: print('\033[34m' + "Received GET_MAC from SSN-{}".format(node_index + 1)) elif message_id == SSN_MessageType_to_ID['GET_TIMEOFDAY']: print('\033[34m' + "Received GET_TIMEOFDAY from SSN-{}".format(node_index + 1)) # automate set time of day print('\033[34m' + "Sending SET_TIMEOFDAY to SSN-{}".format(node_index + 1)) if self.use_udp: self.udp_comm.send_set_timeofday_Tick_message( node_index=self.node_select_radio_button.getSelectedNode() - 1, current_tick=utils.get_bytes_from_int( self.servertimeofday_Tick)) print('\033[34m' + "Sent Time of Day to SSN-{}".format( self.node_select_radio_button.getSelectedNode())) elif self.use_mqtt: self.mqtt_comm.send_set_timeofday_Tick_message( current_tick=utils.get_bytes_from_int( self.servertimeofday_Tick)) elif message_id == SSN_MessageType_to_ID['GET_CONFIG']: print('\033[34m' + "Received GET_CONFIG from SSN-{}".format(node_index + 1)) # configs have been acknowledged? elif message_id == SSN_MessageType_to_ID['ACK_CONFIG']: configs_acknowledged = params[1] # it is a list if configs_acknowledged == self.configs: print('\033[34m' + "Received CONFIG ACK from SSN-{}".format(node_index + 1)) # self.config_button.config(bg='light green') pass pass # status update message brings the ssn heartbeat status elif message_id == SSN_MessageType_to_ID['STATUS_UPDATE']: print('\033[34m' + "Received Status Update from SSN-{}".format(node_index + 1)) self.temperature_text[node_index].update(new_text_string=params[1]) self.humidity_text[node_index].update(new_text_string=params[2]) self.nodeuptime_text[node_index].update( new_text_string=self.servertimeofday_Tick - params[3] ) # get the difference of static tick and current tick activity_level = SSN_ActivityLevelID_to_Type[params[4]] # get activity level of the SSN and display properly self.abnormalactivity_text[node_index].update( new_text_string=activity_level) if activity_level == 'NORMAL': self.abnormalactivity_text[node_index].change_text_color( new_color='green') else: self.abnormalactivity_text[node_index].change_text_color( new_color='red') fault_count = params[-1] if fault_count is not None: print('\033[34m' + "Fault Count from SSN-{}: {}".format( node_index + 1, fault_count)) machine_state_timestamps = [] for i in range(4): self.machine_loadcurrents[node_index][i].update( new_text_string=params[5 + i]) self.machine_percentageloads[node_index][i].update( new_text_string=params[9 + i]) self.machine_status[node_index][i].update( new_text_string=Machine_State_ID_to_State[params[13 + i]]) state_timestamp_tick = params[17 + i] if state_timestamp_tick != 0: # elapsed_time_in_state = self.servertimeofday_Tick - state_timestamp_tick good_time = datetime.datetime.fromtimestamp( state_timestamp_tick) exact_time_strings = [ "{}:{}:{}".format(good_time.hour, good_time.minute, good_time.second), "{}/{}/{}".format(good_time.day, good_time.month, good_time.year) ] else: # elapsed_time_in_state = state_timestamp_tick exact_time_strings = ["0:0:0", "0/0/0"] machine_state_timestamps.append(exact_time_strings) self.machine_timeinstate[node_index][i].update( new_text_string=params[21 + i]) self.machine_sincewheninstate[node_index][i].update( new_text_strings=machine_state_timestamps[i]) pass # append this data to our CSV file if self.csv_data_recording: # insertiontimestamp, node_id, node_uptime, activitylevel, # temperature, humidity, # M1_load, M1_load%, M1_state, M1_statetimestamp, M1_stateduration, # M2_*... server_time_of_the_day = datetime.datetime.fromtimestamp( self.servertimeofday_Tick) data_packet = [ server_time_of_the_day, params[0], datetime.datetime.fromtimestamp(params[3]), activity_level, params[1], params[2], params[5], params[9], params[13], datetime.datetime.fromtimestamp(params[17]), params[21], params[6], params[10], params[14], datetime.datetime.fromtimestamp(params[18]), params[22], fault_count ] with open(self.csv_data_file + "-{}-{}-{}".format(server_time_of_the_day.day, server_time_of_the_day.month, server_time_of_the_day.year) + ".csv", 'a', newline="") as f: writer = csv.writer(f) writer.writerow(data_packet) pass pass pass # recall this method after another second self.root_window.after(200, self.read_messages_and_update_UI) pass pass
class StereoVisionCalculator(object): def __init__(self): """ Class constructor of StereoVisionCalculator. This method initalizes the tkinter GUI and the object variables to store the user input and calculation results. """ # Focal length calculator parameters self.sensor_size = None self.img_width = None self.img_height = None self.focal_fov = None # Design limits self.perf_depth = None self.perf_depth_error = None self.perf_disp_max = None self.perf_disp = None self.perf_disp_calibration_error = None # Baseline calculator results self._min_depth = None self._baseline = None self._focal_length = None # Initialize the complete GUI self._initializeGUI() Row = namedtuple('Row', ['var_name', 'name', 'io', 'activate', 'units']) class RowElement(object): def __init__(self): self.name = None self.io = None self.activate = None self.units = None def setrow(self, row): if self.name: self.name.grid(row=row) if self.io: self.io.grid(row=row) if self.activate: self.activate.grid(row=row) if self.units: self.units.grid(row=row) def _rowPropertiesToGUI(self, master, row_prop): """ Method to convert row_prop of type Row() into a GUI element :param: master (The master of tk element) :param: row_prop (An instance of Row()) :return: An instance of RowElement """ row = StereoVisionCalculator.RowElement() # Create the name label row.name = ttk.Label(master, text=row_prop.name) row.name.grid(column=0, sticky="W", pady=5) # Create io Entry var if row_prop.io: row.io = ttk.Entry(master) else: row.io = ttk.Label(master, text="0.0") row.io.grid(column=1, sticky="W") if row_prop.activate: row.activate = ttk.Checkbutton(master) row.activate.grid(column=1, sticky="E") # Create units Label/OptionMenu var if row_prop.units: if isinstance(row_prop.units, list): row.units = ttk.OptionMenu( master, tk.StringVar(master, row_prop.units[1]), *row_prop.units) else: row.units = tk.Label(master, text=row_prop.units) row.units.grid(column=2, sticky="W") return row def _initializeGUI(self): """ Method to setup the StereoVision Calculator GUI using tkinter """ self.root = ThemedTk(theme="arc") self.root.tk_setPalette(background='#f5f6f7') self.root.title("StereoVision Calculator") self.root.resizable(0, 0) # Don't allow resize sensor_size_units = ['', 'mm', 'in'] fov_type = ['', 'Horizontal', 'Vertical', 'Diagonal'] depth_units = ['', 'mm', 'cm', 'm', 'in', 'ft'] row_properties = [ StereoVisionCalculator.Row('ui_sensor_size', 'Sensor size', True, False, sensor_size_units), StereoVisionCalculator.Row('ui_img_width', 'Image width', True, False, 'px'), StereoVisionCalculator.Row('ui_img_height', 'Image height', True, False, 'px'), StereoVisionCalculator.Row('ui_focal_fov', 'Focal FoV', True, False, fov_type), StereoVisionCalculator.Row('ui_perf_depth', 'Performance depth', True, False, depth_units), StereoVisionCalculator.Row('ui_perf_depth_error', 'Performance depth error', True, False, depth_units), StereoVisionCalculator.Row('ui_perf_disp', 'Performance disparity', True, True, 'px'), StereoVisionCalculator.Row('ui_disp_max', 'Max disparity', True, False, 'px'), StereoVisionCalculator.Row('ui_disp_cal_error', 'Calibration disparity error', True, False, 'px'), StereoVisionCalculator.Row('ui_focal_length', 'Focal length', False, False, 'mm'), StereoVisionCalculator.Row('ui_baseline', 'Baseline', False, False, 'mm'), StereoVisionCalculator.Row('ui_depth_min', 'Min depth', False, False, 'mm'), # StereoVisionCalculator.Row('ui_depth_max', 'Max depth', False, False, 'm'), StereoVisionCalculator.Row('ui_depth_res', 'Depth resolution', False, False, 'px'), StereoVisionCalculator.Row('ui_depth_fov', 'Depth FoV', False, False, 'deg') ] for row_num, rp in enumerate(row_properties, start=1): row_element = self._rowPropertiesToGUI(self.root, rp) row_element.setrow(row_num) self.__setattr__(rp.var_name, row_element) self.ui_perf_disp.io["state"] = tk.DISABLED self.ui_perf_disp.io["width"] = 14 self.ui_perf_disp.activate["command"] = self._disp self.ui_depth_res.io["text"] = "0 x 0" self.ui_depth_fov.io["text"] = "0° x 0°" # Buttons self.ui_auto_calculate = ttk.Checkbutton(self.root, text="Auto calculate", command=self._callback) self.ui_auto_calculate.grid(row=0, sticky="W", pady=5) self.ui_capture = ttk.Button(self.root, text="Capture", width=12, command=self._capture) self.ui_capture.grid(row=0, column=2, sticky="W") self.ui_calculate = ttk.Button(self.root, text="Calculate", width=12, command=self._callback) self.ui_calculate.grid(row=16, sticky="W") self.ui_plot = ttk.Button(self.root, text="Plot", width=12, command=self._plot) self.ui_plot.grid(row=16, column=2, sticky="W") col_count, row_count = self.root.grid_size() for col in range(col_count): self.root.grid_columnconfigure(col, pad=2) def mainloop(self): self.root.mainloop() def calculateToMeter(self, variable, conversion_from): result = 0 if conversion_from is "mm": result = variable / 1000 elif conversion_from is "cm": result = variable / 100 elif conversion_from is "m": result = variable elif conversion_from is "in": result = variable * 0.0254 elif conversion_from is "ft": result = variable * 0.3048 return result def _focalLengthCalculator(self, size, fov_type): """ Function to calculate the focal length of the imaging sensor given: :param: sensor_size: The diagonal sensor size :param: size: The measurement system of the sensor (metric/imperial) :param: img_width: The amount of pixels in width :param: img_height: The amount of pixels in height :param: focal_fov: The field of view of the lens :param: fov_type: Horizontal, vertical or diagonal FoV """ if size == 'inch': self.sensor_size = self.sensor_size * 25.4 else: self.sensor_size = self.sensor_size ratio = self.img_height / self.img_width sensor_width_mm = math.sqrt(self.sensor_size**2 / (1.0 + ratio**2)) sensor_height_mm = math.sqrt(self.sensor_size**2 / (1.0 + 1.0 / (ratio**2))) roi_width_mm = sensor_width_mm # * roi_width / img_width roi_height_mm = sensor_height_mm # * roi_height / img_height roi_diagonal_mm = math.sqrt(roi_height_mm * roi_height_mm + roi_width_mm * roi_width_mm) fov = self.focal_fov / 180 * math.pi atanInner = math.tan(fov * 0.5) try: if fov_type == 'Horizontal': f_mm = roi_width_mm / (2 * atanInner) elif fov_type == 'Vertical': f_mm = roi_height_mm / (2 * atanInner) elif fov_type == 'Diagonal': f_mm = roi_diagonal_mm / (2 * atanInner) pixel_size_mm = roi_width_mm / self.img_width self._focal_length = f_mm / pixel_size_mm except ZeroDivisionError: f_mm = 0 self._focal_length = 0 return f_mm, roi_width_mm, roi_height_mm def _baselineCalculator(self): """ Function to calculate the baseline and min depth of the stereo camera given: 1. Focal length of the lens 2. Performace depth 3. Performance depth error 4. Disparity at performance depth 5. Calibration disparity error """ disparity = self.perf_disp + self.perf_disp_calibration_error depth = self.perf_depth - self.perf_depth_error self._baseline = baselineCalculator(self._focal_length, disparity, depth) self._min_depth = disparityToDepth(self._baseline, self._focal_length, self.perf_disp_max) def _depthErrorCalculator(self, depth): """ Method to calculate the max_depth_error for a given depth for pre-determined baseline and focal length :param: depth :return: max_depth_error """ disparity_real = depthToDisparity(self._baseline, self._focal_length, depth) disparity_measured = disparity_real + self.perf_disp_calibration_error depth_measured = disparityToDepth(self._baseline, self._focal_length, disparity_measured) return abs(depth_measured - depth) def _depthCalculator(self, roi_width, roi_height, roi_width_mm, roi_height_mm, img_width, d_max, f_mm): roi_full_pixel = str(roi_width - d_max) + ' x ' + str(roi_height) h_full_angle = 2 * math.atan( (1 * roi_width_mm * (img_width - d_max) / img_width) / (2 * f_mm)) v_angle = 2 * math.atan(roi_height_mm / (2 * f_mm)) FoV_h = round(h_full_angle / math.pi * 180, 1) FoV_v = round(v_angle / math.pi * 180, 1) FoV = str(FoV_h) + '° x ' + str(FoV_v) + '°' return FoV, roi_full_pixel def _callback(self): if (self.ui_sensor_size.io.get() and self.ui_img_width.io.get() and self.ui_img_height.io.get() and self.ui_focal_fov.io.get()): self.sensor_size = float(self.ui_sensor_size.io.get()) size = self.ui_sensor_size.units["text"] self.img_width = int(self.ui_img_width.io.get()) self.img_height = int(self.ui_img_height.io.get()) self.focal_fov = float(self.ui_focal_fov.io.get()) fov_type = self.ui_focal_fov.units["text"] f_mm, roi_width_mm, roi_height_mm = self._focalLengthCalculator( size, fov_type) self.ui_focal_length.io["text"] = round(f_mm, 2) if (self.ui_perf_depth.io.get() and self.ui_perf_depth_error.io.get() and self.ui_disp_max.io.get() and self.ui_disp_cal_error.io.get()): self.perf_depth = self.calculateToMeter( float(self.ui_perf_depth.io.get()), self.ui_perf_depth.units["text"]) self.perf_depth_error = self.calculateToMeter( float(self.ui_perf_depth_error.io.get()), self.ui_perf_depth_error.units["text"]) self.perf_disp = 1 if not self.ui_perf_disp.io.get() else int( self.ui_perf_disp.io.get()) self.perf_disp_max = int(self.ui_disp_max.io.get()) self.perf_disp_calibration_error = float( self.ui_disp_cal_error.io.get()) self._baselineCalculator() d_max = self.perf_disp_max - 1 depth_fov, depth_res = self._depthCalculator( self.img_width, self.img_height, roi_width_mm, roi_height_mm, self.img_width, d_max, f_mm) self.ui_baseline.io["text"] = round(self._baseline * 1000, 2) self.ui_depth_min.io["text"] = round(self._min_depth * 1000, 2) self.ui_depth_res.io["text"] = depth_res self.ui_depth_fov.io["text"] = depth_fov if self.ui_auto_calculate.instate(["selected"]): self.root.after(100, self._callback) def _disp(self): if self.ui_perf_disp.activate.instate(["selected"]): self.ui_perf_disp.io["state"] = tk.NORMAL else: self.ui_perf_disp.io["state"] = tk.DISABLED def _capture(self): x1 = self.root.winfo_rootx() x2 = x1 + self.root.winfo_reqwidth() y1 = self.root.winfo_rooty() y2 = y1 + self.root.winfo_reqheight() im = grab(bbox=(x1, y1, x2, y2)) im.show() def _plot(self): # Parameters if not (self._focal_length and self._baseline and self._min_depth): self.error = ThemedTk(theme="arc") self.error.tk_setPalette(background='#f5f6f7') self.error.title("Error!") label = ttk.Label(self.error, text="Missing input variables!").grid(padx=15, pady=25) self.error.mainloop() else: style.use('seaborn-whitegrid') fig1, ax = plt.subplots() fig1.canvas.set_window_title('Plot') plt.title("Depth Error Chart") plt.xlabel("Depth (m)") plt.ylabel("Depth error (m)") x1 = [] y1 = [] # Light theme fig1.patch.set_facecolor('#f5f6f7') # 212121 Dark ax.patch.set_facecolor('#f5f6f7') ax.spines['bottom'].set_color('#5c616c') # FAFAFA Dark ax.spines['top'].set_color('#5c616c') ax.spines['right'].set_color('#5c616c') ax.spines['left'].set_color('#5c616c') ax.tick_params(axis='x', colors='#5c616c', which='both') ax.tick_params(axis='y', colors='#5c616c', which='both') ax.yaxis.label.set_color('#5c616c') ax.xaxis.label.set_color('#5c616c') ax.title.set_color('#5c616c') # Plot # Min range to max range max_depth = self._baseline * self._focal_length * 10 for x in range(int(self._min_depth * 10), int(max_depth)): y = self._depthErrorCalculator(float(x / 10)) x1.append(float(x / 10)) y1.append(y) plt.plot(x1, y1, color="#039BE5") # Show plt.show()
temperatureLabel.grid(row=1, column=0) pressureLabel = Label( main, textvariable=pressureVar) # On crée un label qui affiche la pression pressureLabel.grid(row=1, column=1) humidityLabel = Label( main, textvariable=humidityVar) # On crée un label qui affiche l'humidité humidityLabel.grid(row=1, column=2) reloadButton = Button(main, text="Recharger les données", command=reloadData) # On crée un boutton qui permet de recharger les données reloadButton.grid(row=2, column=0, columnspan=3) directionLabel = Label( main, textvariable=directionVar ) # On crée un label qui affiche la direction de la carte directionLabel.grid(row=3, column=0, columnspan=3) compass = Canvas(main, width=450, height=450, bd=0, highlightthickness=0, background="#464646") canvasImg = compass.create_image(0, 0, anchor="nw", image=images[0]) compass.grid(row=4, column=0, columnspan=3) main.after(1000, sense) main.mainloop()