def end_installation(config): while True: print(f""" {Bcolors.GREEN} c - Configure RH server now - recommended {Bcolors.ENDC} r - Reboot - recommended after configuring s - Start RH server now{Bcolors.YELLOW} e - Exit now{Bcolors.ENDC}""") selection = input() if selection == 'r': os.system("sudo reboot") elif selection == 'e': return elif selection == 'c': conf_rh() break elif selection == 's': clear_the_screen() os.chdir(f"/home/{config.user}/RH-ota") os.system("./scripts/server_start.sh")
def first_page(): while True: clear_the_screen() print("""\n Right now you have your Access Point configured. However, there is still an option to maintain internet connection. You will be able to connect the Pi via ethernet to the router or PC - with internet sharing option enabled. It requires changes in configuration file. Those will be performed automatically, after entering 'netcfg' or 'apcfg' in command line. Remember to reboot the timer after every change. Instruction can be also found in 'apconf.txt' file in net_ap folder. Remember that regardless how you have your Raspberry configured in a given moment, you can always connect to it using WiFi. It can be helpful if you don't remember how your timer was configured when you left it or when some troubleshooting is required. Open second page, for detailed explanation. {green}s - Second page{endc} {yellow}e - Exit to menu{endc} """.format(yellow=Bcolors.YELLOW_S, green=Bcolors.GREEN_S, endc=Bcolors.ENDC)) selection = input() if selection == 's': second_page() elif selection == 'e': break
def end_installation(): print(f"""\n\n{Bcolors.GREEN} 'c' - configure the server now - recommended\n 'r' - reboot - recommended after configuring{Bcolors.ENDC}\n 's' - start the server now\n{Bcolors.YELLOW} 'e' - exit now\n{Bcolors.ENDC}""") def end_menu(): selection = input() if selection == 'r': os.system("sudo reboot") if selection == 'e': json.dump(soft) # todo change to soft config sys.exit() if selection == 'c': conf_ota() end_update() if selection == 's': clear_the_screen() os.chdir(f"/home/{user}/RH-ota") os.system(". ./open_scripts.sh; server_start") else: end_menu() end_menu() clear_the_screen()
def welcome_screen(config): welcome_message = """{bold} Welcome to OTA! With our software you can easily install, update and manage your RotorHazard installation. You can also flash the firmware onto nodes, without the need to open the timer ever again. You have to use official PCB or have 'hardware mod" done for that functionality. You may also check features like smart-hotspot or adding aliases to your system, etc. This program has ability to perform 'self-updates' - see "Features Menu". If you found any bug - please report it via GitHub or Facebook. {endc}{bold} Wish you good experience. Enjoy! Pawel F. {endc}""".format(bold=Bcolors.BOLD, red=Bcolors.RED, green=Bcolors.GREEN, endc=Bcolors.ENDC) first_time_flag = os.path.exists("./.first_time_here") while first_time_flag and not updated_check(config): clear_the_screen() logo_top(config.debug_mode) print(welcome_message) selection = input(f"\n\t\t\t{Bcolors.GREEN}Open next page by typing 'n'{Bcolors.ENDC}\n\n").lower() if selection == 'n': os.system("rm ./.first_time_here") first_time_flag = False # done that way so after configuration user won't be redirected back here show_about(config) if selection == 'f': # helpful when troubleshooting, going further without changing the folder contents first_time_flag = False show_about(config)
def conf_wizard_net(config): while True: clear_the_screen() logo_top(config.debug_mode) features_menu_content = """ {rmh}NETWORKING MENU{endc}{bold} 1 - Setup hotspot - always on 2 - Setup automatic hotspot/wifi {yellow}e - Exit to main menu {endc} """.format(rmh=Bcolors.RED_MENU_HEADER, yellow=Bcolors.YELLOW_S, bold=Bcolors.BOLD, endc=Bcolors.ENDC) print(features_menu_content) selection = input() if selection == '1': net_and_ap_conf(config) elif selection == '2': confirm_auto_hotspot(config) elif selection == 'e': break pass
def ota_update_available_check(config): # no config.user usage due to order of operations if os.path.exists("./.new_ota_version_diff_file") and os.path.exists("./updater-config.json"): if os.path.getsize("./.new_ota_version_diff_file"): ota_update_available_flag = True else: ota_update_available_flag = False # done this way due to development purposes and weird edge cases else: ota_update_available_flag = False if ota_update_available_flag and config.beta_tester is False: # don't show update prompt to beta-testers clear_the_screen() logo_top(config.debug_mode) print("""\n\n {bold} New OTA software release is available. Consider updating now (takes ~20 secs). {endc} {green} u - Update now {endc}{yellow} s - Skip{endc} """.format(bold=Bcolors.BOLD_S, endc=Bcolors.ENDC, red=Bcolors.RED, green=Bcolors.GREEN, yellow=Bcolors.YELLOW)) while True: selection = input() if selection == 'u': self_updater(config) break elif selection == 's': break
def node_menu(): while True: clear_the_screen() logo_top(config.debug_mode) sleep(0.05) flash_node_menu = """ {red}{bold}NODES MENU{endc} {bold} 1 - Flash node 1 5 - Flash node 5 2 - Flash node 2 6 - Flash node 6 3 - Flash node 3 7 - Flash node 7 4 - Flash node 4 8 - Flash node 8 {yellow} 'e'- Exit to main menu{endc} """.format(bold=Bcolors.BOLD_S, red=Bcolors.RED_S, yellow=Bcolors.YELLOW, endc=Bcolors.ENDC) print(flash_node_menu) selection = input(""" {bold}Which node do you want to program:{endc} """.format(bold=Bcolors.BOLD, endc=Bcolors.ENDC)) if selection.isnumeric() and 1 <= int(selection) <= 8: specific_node_menu(int(selection)) elif selection == 'e': break
def node_selection_menu(): clear_the_screen() logo_top(linux_testing) sleep(0.05) flash_node_menu = """ {red}{bold}NODES MENU{endc} {bold} 1 - Flash node 1 5 - Flash node 5 2 - Flash node 2 6 - Flash node 6 3 - Flash node 3 7 - Flash node 7 4 - Flash node 4 8 - Flash node 8 {yellow} 'e'- Exit to main menu{endc} """.format(bold=Bcolors.BOLD, red=Bcolors.RED, yellow=Bcolors.YELLOW, endc=Bcolors.ENDC) print(flash_node_menu) selection = input(""" {bold}Which node do you want to program:{endc} """.format(bold=Bcolors.BOLD, endc=Bcolors.ENDC)) if int(selection) in range(8): selected_node_number = selection return selected_node_number if selection == 'e': main() else: node_selection_menu()
def end_update(conf_flag, serv_installed_flag): print("\n\n") if not conf_flag and serv_installed_flag: print( f"{Bcolors.GREEN}\t\t'c' - configure the server now{Bcolors.ENDC}") else: print("""\t\t'c' - Reconfigure RotorHazard server""") print(f""" 'r' - reboot - recommended when configured\n 's' - start the server now\n{Bcolors.YELLOW} 'e' - exit now\n{Bcolors.ENDC}""") def end_menu(): selection = input() if selection == 'r': os.system("sudo reboot") if selection == 'e': json_dump() # todo only to soft sys.exit() if selection == 'c': conf_ota() end_update() if selection == 's': clear_the_screen() os.chdir(f"/home/{user}/RH-ota") os.system(". ./open_scripts.sh; server_start") else: end_menu() end_menu() clear_the_screen()
def first_page(): clear_the_screen() logo_top() sleep(0.05) print("""\n Right now you have your Access Point configured. However, there is still an option to maintain internet connection. You will be able to connect the Pi via ethernet to the router or PC - with internet sharing option enbled. It requires chages in configuration file. Those will be performed automatically, after entering 'netcfg' or 'apcfg' in command line. Remember to reboot the timer after every change. Instruction can be also found in 'apconf.txt' file in net_ap folder.\n Remember that regardless how you have your Raspberry configured in a given moment, you can always connect to it using WiFi. It can be helpful if you don't remember how your timer was configured when you left it or when some troubleshooting is required.\n Open second page, for detailed explanation.\n\n""") selection = input("\t\t" + Bcolors.GREEN + "'s' - second page'" + Bcolors.ENDC + "\t\t" + Bcolors.YELLOW + "'b' - go back" + Bcolors.ENDC + "\n") if selection == 's': second_page() if selection == 'b': main() else: first_page()
def nodes_update(): clear_the_screen() logo_top() sleep(0.05) print("\n\n\t\t\t " + Bcolors.BOLD + Bcolors.UNDERLINE + "CHOOSE FLASHING TYPE:\n" + Bcolors.ENDC) print("\t\t " + Bcolors.GREEN + Bcolors.BOLD + "1 - Every Node gets own dedicated firmware - recommended\n" + Bcolors.ENDC) print("\t\t " + Bcolors.BOLD + "2 - Nodes will use ground-auto selection firmware\n" + Bcolors.ENDC) print("\t\t " + Bcolors.BOLD + "3 - Flash 'Blink' on every node\n" + Bcolors.ENDC) print("\t\t " + Bcolors.BOLD + "4 - Flash each node individually\n" + Bcolors.ENDC) print("\t\t " + Bcolors.BOLD + "5 - Fix GPIO pins state - obsolete\n" + Bcolors.ENDC) print("\t\t " + Bcolors.YELLOW + Bcolors.BOLD + "e - Exit to main menu\n" + Bcolors.ENDC) sleep(0.3) selection = input() if selection == '1': # todo dedicated node - redundant? logo_update() sleep(3) if selection == '2': flash_firmware_onto_all_gnd_nodes() logo_update() sleep(3) if selection == '3': flash_blink_onto_all_gnd_nodes() logo_update() sleep(3) if selection == '4': flash_each_node() if selection == '5': reset_gpio_state() if selection == 'e': sys.exit() else: nodes_update()
def updated_check(config): user = config.user while True: if os.path.exists(f"/home/{user}/.ota_markers/.was_updated"): clear_the_screen() logo_top(config.debug_mode) print(""" {bold} Software was updated recently to the new version. You can read update notes now or check them later. {endc} {green} 'r' - read update notes {endc} 's' - skip and don't show again """.format(bold=Bcolors.BOLD_S, endc=Bcolors.ENDC, green=Bcolors.GREEN)) selection = input() if selection == 'r': os.system("less ./docs/update-notes.txt") break if selection == 's': break else: break os.system(f"rm /home/{user}/.ota_markers/.was_updated >/dev/null 2>&1")
def flash_firmware_onto_all_nodes(config): # nodes have to be 'auto-numbered' clear_the_screen() print( f"\n\t\t\t{Bcolors.BOLD}Flashing procedure started{Bcolors.BOLD}\n\n") nodes_num = config.nodes_number odd_number = odd_number_of_nodes_check(config) addresses = nodes_addresses() if nodes_num == 1: flash_firmware_onto_a_gpio_node(config) if odd_number else None else: for i in range(0, nodes_num): addr = addresses[i] print( f"\n\t\t{Bcolors.BOLD}Flashing node {i + 1} {Bcolors.ENDC}(reset with I2C address: {addr})\n" ) prepare_mate_node(addr) if not config.debug_mode else print( "simulation mode - flashing disabled") print( f"avrdude -v -p atmega328p -c arduino -P /dev/{config.port_name} -b 57600 -U " f"flash:w:/home/{config.user}/RH-ota/firmware/{firmware_version_selection(config)}/node_0.hex:i" ) flash_firmware_onto_a_node( config) if not config.debug_mode else None print( f"\n\t\t\t{Bcolors.BOLD}Node {i + 1} - flashed{Bcolors.ENDC}\n\n" ) sleep(2) if odd_number and ((nodes_num - i) == 2): break # breaks the "flashing loop" after last even node flash_firmware_onto_a_gpio_node(config) if odd_number else None logo_update(config) input("\nDone. Press ENTER to continue ") sleep(1)
def reset_gpio_state(): clear_the_screen() logo_top() print("\n\n\n") os.system("echo {gpio_reset_pin} > /sys/class/GPIO/unexport") print("\n\n DONE\n\n") sleep(0.3)
def second_page(): clear_the_screen() print("""\n When Raspberry configuration has been changed so it performs as Access Point or as a DHCP client (normal mode), configuration file is being copied with a proper name. Next you have to reboot, so changes can be applied. When you setup Pi as a client, you can just connect it to the router. If you are using PC as a internet sharing device, you have to enable that option in OS settings. Instructions for Windows can be found in net_ap folder.\n If you want to connect to Raspberry via SSH or VNC, when it's in client mode you have to know its IP address. Check it in router settings page or using special program 'Advanced IP Scanner' on a PC. If you are using Pi as a AP, its IP is always 172.20.20.20 (ethernet). Remember to disable internet sharing functionality on your PC's OS, when Raspberry is in Access Point mode. \n Remember that you can always connect to the timer (eg. from yet another device) via WiFi. It's wireless IP is 10.10.10.10.\n You can also read/print those instructions. File 'detailed.txt', in net_ap folder. \n""") selection = input("\t\t" + Bcolors.GREEN + "'k' - OK '" + Bcolors.ENDC + "\t\t" + Bcolors.YELLOW + "'b' - go back" + Bcolors.ENDC + "\n") if selection == 'k': sys.exit() if selection == 'b': first_page() else: second_page()
def specific_node_menu(config, selected_node_number): while True: clear_the_screen() logo_top(config.debug_mode) node_selected_menu = f""" {Bcolors.BOLD}\n\t\t\tNode {str(selected_node_number)} selected{Bcolors.ENDC}\n Choose flashing type:\n{Bcolors.ENDC} 1 - {Bcolors.GREEN}Node ground-auto selection firmware - recommended{Bcolors.ENDC}{Bcolors.BOLD} 2 - Flash custom firmware on the node 3 - Flash 'blink' on the node - only for test purposes 4 - Check UART connection with a node e - Exit{Bcolors.ENDC}""" print(node_selected_menu) selection = input() if selection == '1': flash_firmware_on_a_specific_node(config, selected_node_number) elif selection == '2': flash_custom_firmware_on_a_specific_node(config, selected_node_number) elif selection == '3': flash_blink_on_a_specific_node(config, selected_node_number) elif selection == '4': check_uart_con_with_a_node(config, selected_node_number) elif selection == 'e': break else: continue break
def end_update(): print("\n\n") if not config_flag and serv_installed_flag: print(Bcolors.GREEN + """\t\t'c' - configure the server now""" + Bcolors.ENDC) else: print("""\t\t'c' - Reconfigure RotorHazard server""") print(""" 'r' - reboot - recommended when configured\n 's' - start the server now\n""" + Bcolors.YELLOW + """ 'e' - exit now\n""" + Bcolors.ENDC) def end_menu(): selection = input() if selection == 'r': os.system("sudo reboot") if selection == 'e': parser_write() sys.exit() if selection == 'c': os.system(f". /home/{user}/RH-ota/open_scripts.sh; rh_configuration_start") end_update() if selection == 's': clear_the_screen() os.chdir(f"/home/{user}/RH-ota") os.system(". ./open_scripts.sh; server_start") else: end_menu() end_menu() clear_the_screen()
def end_installation(): print("""\n\n""" + Bcolors.GREEN + """ 'c' - configure the server now - recommended\n 'r' - reboot - recommended after configuring""" + Bcolors.ENDC + """\n 's' - start the server now\n""" + Bcolors.YELLOW + """ 'e' - exit now\n""" + Bcolors.ENDC) def end_menu(): selection = input() if selection == 'r': os.system("sudo reboot") if selection == 'e': parser_write() sys.exit() if selection == 'c': os.system(f". ./open_scripts.sh; rh_configuration_start") end_update() if selection == 's': clear_the_screen() os.chdir(f"/home/{user}/RH-ota") os.system(". ./open_scripts.sh; server_start") else: end_menu() end_menu() clear_the_screen()
def updated_check(config): user = config.user if os.path.exists("/home/" + user + "/.ota_markers/.was_updated"): clear_the_screen() logo_top(config.debug_mode) print(""" {bold} Software was updated recently to the new version. You can read update notes now or check them later. {endc} {green} 'r' - read update notes {endc} 's' - skip and don't show again """.format(bold=Bcolors.BOLD_S, underline=Bcolors.UNDERLINE, endc=Bcolors.ENDC, green=Bcolors.GREEN, blue=Bcolors.BLUE, yellow=Bcolors.YELLOW_S, red=Bcolors.RED_S, orange=Bcolors.ORANGE_S)) selection = input() if selection == 'r': os.system("less ./docs/update-notes.txt") if selection == 's': pass else: updated_check(config) os.system("rm /home/" + user + "/.ota_markers/.was_updated >/dev/null 2>&1")
def node_menu(): clear_the_screen() logo_top() sleep(0.05) flash_node_menu = """ {red}{bold}NODES MENU{endc} {bold} 1 - Flash node 1 5 - Flash node 5 2 - Flash node 2 6 - Flash node 6 3 - Flash node 3 7 - Flash node 7 4 - Flash node 4 8 - Flash node 8 {yellow} 'e'- Exit to main menu{endc} """.format(bold=Bcolors.BOLD, red=Bcolors.RED, yellow=Bcolors.YELLOW, endc=Bcolors.ENDC) print(flash_node_menu) selection = input("\n\n\t\t" + Bcolors.BOLD + "Which node do you want to program:" + Bcolors.ENDC + " ") print("\n\n") if selection.isdigit() and int(selection) <= 8: x = selection sleep(0.5) node_x_menu() if selection == 'e': nodes_update() else: node_menu()
def step_zero(): clear_the_screen() sleep(0.05) print("""\n\n After performing this process your Raspberry Pi can be used as standalone\n Access Point. You won't need additional router for connecting with it. \n You will loose ability of connecting Raspberry wirelessly to any router or hotspot.\n You will still have ability to connect it to the Internet sharing device, \n like router or PC via ethernet cable. You will also be able to connect with the timer\n via Wifi from PC or mobile phone etc. - if you had range. \n If during this process you would want to check detailed instructions,\n you can enter 'net_ap' folder from this repo, on your mobile phone etc.\n This process will require few reboots. Do you want to continue?\n""") print(("""\n \t""" + Bcolors.GREEN + """'y' - Yes, let's do it """ + Bcolors.ENDC + """\n \t'3' - enters "Step 3." - check it after first two steps\n \t'x' - enters Access Point extra menu - check it after operation\n \t""" + Bcolors.YELLOW + """'e' - exit to main menu""" + Bcolors.ENDC + """\n""")) selection = input() if selection == 'y': step_one() if selection == '3': step_three() if selection == 'x': ap_menu() if selection == 'e': sys.exit() else: main()
def avr_dude(config): while True: clear_the_screen() logo_top(config.debug_mode) avrdude_menu = """ {red}{bold} AVRDUDE MENU {blue} 'i' - Install avrdude {endc}{yellow} {bold} 'e' - Go back {endc} """.format(bold=Bcolors.BOLD, endc=Bcolors.ENDC, blue=Bcolors.BLUE, yellow=Bcolors.YELLOW_S, red=Bcolors.RED_S) print(avrdude_menu) selection = input() if selection == 'i': os.system("sudo apt-get update") os.system("sudo apt-get install avrdude -y") print("\nDone\n") sleep(2) if selection == 'e': break
def end(): clear_the_screen() print("\n\n") ota_image() print(f"\t\t\t\t\t{Bcolors.BOLD}Happy flyin'!{Bcolors.ENDC}\n") sleep(1.3) clear_the_screen() sys.exit()
def end(parser, config): parser_write(parser, config) clear_the_screen() print("\n\n") ota_image() print("\t\t\t\t " + Bcolors.BOLD + "Happy flyin'!" + Bcolors.ENDC + "\n") sleep(1.3) clear_the_screen() sys.exit()
def first(config, updater_version): clear_the_screen() print("\n\n") image_show() print( f"\t\t\t{Bcolors.BOLD} Updater version: {str(updater_version)}{Bcolors.ENDC}" ) sleep(1) updated_check(config)
def first(parser, config, updater_version): parser.read(f'/home/{config.user}/.ota_markers/ota_config.txt') clear_the_screen() print("\n\n") image_show() print("\t\t\t " + Bcolors.BOLD + "Updater version: " + str(updater_version) + Bcolors.ENDC) sleep(1) updated_check(config)
def serial_menu(config): ota_status = load_ota_config(config.user) def serial_content(): # TODO Make this repeatable without adding multiple copies at the end of config.txt. os.system("echo 'enable_uart=1'| sudo tee -a /boot/config.txt") os.system( "sudo sed -i 's/console=serial0,115200//g' /boot/cmdline.txt") ota_status.serial_added = True write_ota_config(ota_status, config.user) print(""" Serial port enabled successfully You have to reboot Raspberry now. Ok? r - Reboot now{yellow} b - Go back{endc} """.format(endc=Bcolors.ENDC, yellow=Bcolors.YELLOW_S)) selection_2 = input() if selection_2 == 'r': os.system("sudo reboot") if selection_2 == 'b': return while True: clear_the_screen() logo_top(config.debug_mode) menu = """ Serial port has to be enabled. Without it Arduinos cannot be programmed. Do you want to enable it now? {yellow} y - for yes a - for abort{endc} """.format(endc=Bcolors.ENDC, yellow=Bcolors.YELLOW) selection = input(menu) if selection == 'y': if ota_status.serial_added: print( "\n\n\t\tLooks like you already enabled Serial port. \n\t\tDo you want to continue anyway?\n" ) selection = input( f"\t\t\t{Bcolors.YELLOW}Press 'y' for yes or 'a' for abort{Bcolors.ENDC}\n" ) if selection == 'y': serial_content() break if selection == 'a': break else: serial_content() break if selection == 'a': break
def serial_menu(config): ota_status = load_ota_sys_markers(config.user) def uart_enabling(): # UART enabling prompt is also being shown when entering nodes flash menu for the first time # TODO Make this repeatable without adding multiple copies at the end of config.txt. os.system("./scripts/sys_conf.sh uart") ota_status.uart_support_added = True write_ota_sys_markers(ota_status, config.user) print(""" Serial port enabled successfully. You have to reboot Raspberry now, so changes would be implemented. Ok? r - Reboot now{yellow} e - Exit{endc} """.format(endc=Bcolors.ENDC, yellow=Bcolors.YELLOW_S)) selection = input() if selection == 'r': os.system("sudo reboot") elif selection == 'e': return while True: clear_the_screen() logo_top(config.debug_mode) serial_adding_menu = """ Serial port (UART) has to be enabled. Without it Arduino-nodes cannot be programmed. Do you want to enable it now? {green}y - for yes {endc} {yellow}a - for abort{endc} """.format(yellow=Bcolors.YELLOW_S, green=Bcolors.GREEN_S, endc=Bcolors.ENDC) selection = input(serial_adding_menu) if selection == 'y': if ota_status.uart_support_added: print("\n\n\t\tLooks like you already enabled Serial port. \n\t\tDo you want to continue anyway?\n") selection = input(f"\t\t\t{Bcolors.YELLOW}Press 'y' for yes or 'a' for abort{Bcolors.ENDC}\n") if selection == 'y': uart_enabling() break elif selection == 'a': break else: uart_enabling() break elif selection == 'a': break
def main_menu(config): while True: clear_the_screen() logo_top(config.debug_mode) config_check() main_menu_content = """ {red}{bold}{underline}MAIN MENU{endc}{blue}{bold} 1 - RotorHazard Manager 2 - Nodes flash and update {endc}{bold} 3 - Start the server now 4 - Additional features 5 - Info + first time here 6 - Configuration wizard {endc}{yellow} e - Exit {endc} """.format(bold=Bcolors.BOLD_S, underline=Bcolors.UNDERLINE, endc=Bcolors.ENDC, blue=Bcolors.BLUE, yellow=Bcolors.YELLOW_S, red=Bcolors.RED_S) print(main_menu_content) selection = input() if selection == '1': print("todo: call rpi_update") # rpi_update(config) #TODO modulalize rpi-update # os.system("python3 ./rpi_update.py") # opens raspberry updating file if selection == '2': print("todo: call node_update") # nodes_update(config) #TODO modulalize node-update (i2c_ !) # os.system("python3 ./nodes_update.py") # opens nodes updating file if selection == '3': clear_the_screen() os.system(". ./scripts/server_start.sh") if selection == '4': features_menu(config) if selection == '5': first_time() if selection == '6': config = conf_ota(config) if selection == 'logme': log_to_dev(config) if selection == 'e': end()
def node_selection_menu(config): while True: clear_the_screen() logo_top(config.debug_mode) flash_node_menu = """\n {red}{bold}NODES MENU{endc}{bold} 1 - Flash node 1 5 - Flash node 5 2 - Flash node 2 6 - Flash node 6 3 - Flash node 3 7 - Flash node 7 4 - Flash node 4 8 - Flash node 8 {yellow}e - Exit to main menu{endc} """.format(bold=Bcolors.BOLD_S, red=Bcolors.RED_S, yellow=Bcolors.YELLOW_S, endc=Bcolors.ENDC) print(flash_node_menu) selection = input( f"\t\t{Bcolors.BOLD}Which node do you want to program: {Bcolors.ENDC}" ) if selection.isdigit(): if odd_number_of_nodes_check(config): if int(selection) in range(config.nodes_number + 1) and int( selection) != config.nodes_number: selected_node_number = selection specific_node_menu(config, int(selected_node_number)) elif int(selection) in range(config.nodes_number + 1) and int( selection) == config.nodes_number: odd_node_menu(config) elif int(selection) in range(8) and int( selection) not in range(config.nodes_number): print( "\n\n\tNode number higher than configured amount of nodes." ) sleep(1.5) elif not odd_number_of_nodes_check(config): if int(selection) in range(config.nodes_number + 1): selected_node_number = selection specific_node_menu(config, int(selected_node_number)) elif int(selection) in range(8) and int( selection) not in range(config.nodes_number): print( "\n\n\tNode number higher than configured amount of nodes." ) sleep(1.5) elif selection == 'e': break