def __configure(attributes, SocketServerObj): # [CONFIG] Get value if len(attributes) == 1: if attributes[0] == 'dump': # DUMP DATA for key, value in read_cfg_file().items(): spcr = (10 - len(key)) SocketServerObj.reply_message(" {}{}:{} {}".format(key, " " * spcr, " " * 7, value)) return True # GET SINGLE PARAMETER VALUE SocketServerObj.reply_message(cfgget(attributes[0])) return True # [CONFIG] Set value if len(attributes) >= 2: # Deserialize params key = attributes[0] value = " ".join(attributes[1:]) # Check irq required memory if 'irq' in key and attributes[1].lower() == 'true': isOK, avmem = __irq_mem_requirement_check(key) if not isOK: SocketServerObj.reply_message("Skip ... feature requires more memory then {} byte".format(avmem)) return True # Set new parameter(s) try: output = cfgput(key, value, type_check=True) except Exception as e: SocketServerObj.reply_message("node_config write error: {}".format(e)) output = False # Evaluation and reply issue_msg = 'Invalid key' if cfgget(key) is None else 'Failed to save' SocketServerObj.reply_message('Saved' if output else issue_msg) return True
def start_micropython_webrepl(cls, update=False): cls.reply_message( " Start micropython WEBREPL for interpreter web access and file transferring." ) cls.reply_message( " [!] micrOS socket shell will be available again after reboot.") cls.reply_message(" \trestart machine shortcut: import reset") cls.reply_message( " Connect over http://micropython.org/webrepl/#{}:8266/".format( cfgget("devip"))) cls.reply_message(" \t[!] webrepl password: {}".format( cfgget('appwd'))) if update: cls.reply_message(' Restart node then start webrepl...') cls.reply_message(" Bye!") if update: from machine import reset with open('.if_mode', 'w') as f: f.write('webrepl') reset() try: import webrepl cls.reply_message(webrepl.start(password=cfgget('appwd'))) # Deinit socket obj to make webrepl available cls.__del__() except Exception as e: cls.reply_message("Error while starting webrepl: {}".format(e)) errlog_add('Start Webrepl error: {}'.format(e))
def setNTP_RTC(): if WLAN(STA_IF).isconnected(): for _ in range(4): try: # Sync with NTP server settime() # Get localtime + GMT (year, month, mday, hour, minute, second, weekday, yearday) = localtime(time() + int(cfgget('gmttime')) * 3600) # Create RealTimeClock + Set RTC with time (+timezone) RTC().datetime((year, month, mday, 0, hour, minute, second, 0)) # Print time console_write("NTP setup DONE: {}".format(localtime())) return True except Exception as e: console_write("NTP setup errer.:{}".format(e)) sleep(0.5) else: console_write("NTP setup errer: STA not connected!") # Recursion to get actual time for cron execution if cfgget('cron'): console_write("[!] NTP setup retry due to cron is {}".format( cfgget('cron'))) return setNTP_RTC() return False
def __new__(cls, host=''): """ Singleton design pattern __new__ - Customize the instance creation cls - class """ if SocketServer.__instance is None: # SocketServer singleton properties SocketServer.__instance = super().__new__(cls) # Socket server initial parameters SocketServer.__instance.__host = host SocketServer.__instance.__s = None SocketServer.__instance.__conn = None SocketServer.__instance.__addr = None SocketServer.__instance.__server_console_indent = 0 SocketServer.__instance.__auth = False SocketServer.__instance.__isconn = False SocketServer.__instance.configure_mode = False # ---- Config --- SocketServer.__instance.pre_prompt = "" SocketServer.__instance.__auth_mode = cfgget('auth') SocketServer.__instance.__prompt = "{} $ ".format(cfgget('devfid')) SocketServer.__instance.__port = cfgget("socport") SocketServer.__instance.__timeout_user = int(cfgget("soctout")) SocketServer.__instance.__hwuid = cfgget("hwuid") # --- ---- SocketServer.__instance.server_console( "[ socket server ] <<constructor>>") return SocketServer.__instance
def bootup_hook(): """ Executes when system boots up. """ # Execute LMs from boothook config parameter console_write("[BOOTHOOK] EXECUTION ...") bootasks = cfgget('boothook') if bootasks is not None and bootasks.lower() != 'n/a': console_write("|-[BOOTHOOK] TASKS: {}".format(bootasks)) if exec_lm_pipe(bootasks): console_write("|-[BOOTHOOK] DONE") else: console_write("|-[BOOTHOOK] ERROR") # Set boostmd (boost mode) if cfgget('boostmd') is True: console_write( "[BOOT HOOKS] Set up CPU 16MHz/24MHz - boostmd: {}".format( cfgget('boostmd'))) if platform == 'esp8266': freq(160000000) if platform == 'esp32': freq(240000000) else: console_write("[BOOT HOOKS] Set up CPU 8MHz - boostmd: {}".format( cfgget('boostmd'))) freq(80000000)
def __irq_mem_requirement_check(key): collect() memavail = mem_free() if 'timirq' == key and memavail < cfgget('irqmreq'): return False, memavail if 'extirq' == key and memavail < int(cfgget('irqmreq') * 0.7): return False, memavail return True, memavail
def emergency_mbuff(): emergency_buff_kb = 1000 if cfgget('extirq') or cfgget("timirq"): from micropython import alloc_emergency_exception_buf console_write("[IRQ] Interrupts was enabled, alloc_emergency_exception_buf={}".format(emergency_buff_kb)) alloc_emergency_exception_buf(emergency_buff_kb) else: console_write("[IRQ] Interrupts disabled, skip alloc_emergency_exception_buf configuration.")
def sys_page(): oled.text(cfgget("devfid"), 0, 15) oled.text(" {}".format(cfgget("devip")), 0, 25) fm = mem_free() kb, byte = int(fm / 1000), int(fm % 1000) oled.text(" {}kb {}b".format(kb, byte), 0, 35) oled.text(" V: {}".format(cfgget("version")), 0, 45) return True
def ha_sta(): """ Check and repair STA network mode """ from ConfigHandler import cfgget from network import STA_IF, WLAN # Set STA and Connect if cfgget('nwmd') == 'AP' or not WLAN(STA_IF).isconnected(): # Soft reset micropython VM - fast recovery from machine import soft_reset soft_reset() return '{} mode, OK'.format(cfgget('nwmd'))
def __enableInterruptScheduler(): """ SMART TIMER INTERRUPT CONFIGURATION # MUST BE CHECK BEFORE CALL: cfgget("timirq") and cfgget('cron') and cfgget('crontasks') """ # CACHE TASKS FOR CBF CFG_TIMER_IRQ[0] = cfgget('crontasks') CFG_TIMER_IRQ[1] = int(cfgget("timirqseq") / 1000) from machine import Timer # INIT TIMER IRQ with callback function wrapper timer = Timer(0) timer.init(period=int(cfgget("timirqseq")), mode=Timer.PERIODIC, callback=secureInterruptHandlerScheduler)
def set_ntp_rtc(): err = '' for _ in range(4 if cfgget('cron') else 2): try: ntptime(utc_shift=int(cfgget('gmttime'))) return True except Exception as e: console_write("set_ntp_rtc errer.:{}".format(e)) err = e sleep_ms(100) errlog_add("set_ntp_rtc error: {}".format(err)) return False
def set_emergency_buffer(): from micropython import alloc_emergency_exception_buf irqmembuf = cfgget('irqmembuf') emergency_buff_kb = irqmembuf if irqmembuf is not None and isinstance( irqmembuf, int) else 1000 if cfgget('extirq') or cfgget("timirq"): console_write( "[IRQ] Interrupts was enabled, alloc_emergency_exception_buf={}". format(emergency_buff_kb)) alloc_emergency_exception_buf(emergency_buff_kb) else: console_write( "[IRQ] Interrupts disabled, skip alloc_emergency_exception_buf configuration." )
def profiling_info(label=""): """ Runtime memory measurements """ if cfgget('dbg'): console_write("{} [PROFILING INFO] - {} {}".format( '~' * 5, label, '~' * 5)) try: mem_info() except Exception as e: console_write("MEM INFO QUERY ERROR: {}".format(e)) console_write("~" * 30) else: console_write("[PROFILING INFO] SKIP dbg:{}".format(cfgget('dbg')))
def __enableInterruptSimple(): """ SIMPLE TIMER INTERRUPT CONFIGURATION """ # LOAD DATA FOR TIMER IRQ: cfgget("timirq") # CACHE TASK FOR CBF CFG_TIMER_IRQ[0] = cfgget('timirqcbf') if CFG_TIMER_IRQ[0].lower() != 'n/a': from machine import Timer # INIT TIMER IRQ with callback function wrapper timer = Timer(0) timer.init(period=int(cfgget("timirqseq")), mode=Timer.PERIODIC, callback=secureInterruptHandlerSimple) else: console_write("[IRQ] TIMIRQ: isenable: {} callback: {}".format(cfgget("timirq"), cfgget('timirqcbf')))
def init_eventPIN(): """ EVENT INTERRUPT CONFIGURATION """ global CFG_EVIRQCBF if cfgget('extirq') and cfgget('extirqcbf').lower() != 'n/a': CFG_EVIRQCBF = cfgget('extirqcbf') pin = get_pin_on_platform_by_key('pwm_4') console_write("[IRQ] EVENTIRQ ENABLED PIN: {} CBF: {}".format(pin, CFG_EVIRQCBF)) # Init event irq with callback function wrapper from machine import Pin pin_obj = Pin(pin, Pin.IN, Pin.PULL_UP) pin_obj.irq(trigger=Pin.IRQ_RISING, handler=secureEventInterruptHandler) else: console_write("[IRQ] EVENTIRQ: isenable: {} callback: {}".format(cfgget('extirq'), CFG_EVIRQCBF))
def bootup_hook(): """ Executes when system boots up. """ console_write("[BOOT HOOKS] EXECUTION...") if cfgget('boothook') is not None and cfgget('boothook').lower() != 'n/a': for shell_cmd in (cmd.strip() for cmd in tuple(cfgget('boothook').split(';')) if len(cmd.split()) > 1): console_write("|-[BOOT HOOKS] SHELL EXEC: {}".format(shell_cmd)) try: state = execute_LM_function_Core(shell_cmd.split()) console_write("|-[BOOT HOOKS] state: {}".format(state)) except Exception as e: console_write("|--[BOOT HOOKS] error: {}".format(e))
def __server_level_cmds(self, data_str): # globally available micrOS functions if data_str == 'exit': # For low level exit handling self.reply_message("Bye!") self.__reconnect() return "" if data_str == 'hello': # For low level device identification - hello msg self.reply_message("hello:{}:{}".format(cfgget('devfid'), self.__hwuid)) return "" if data_str == 'version': # For micrOS system version info self.reply_message("{}".format(self.__socket_interpreter_version)) return "" # Authentication handling data_str = self.__connection_authentication( data_str) if self.__auth_mode else data_str # Authenticated user functions ... shell, etc if data_str == 'reboot': self.reply_message("Reboot micrOS system.") self.__safe_reboot_system() return "" if data_str == 'webrepl': self.start_micropython_webrepl() return "" return data_str
def __set_wifi_dev_static_ip(sta_if): console_write("[NW: STA] Set device static IP.") stored_ip = cfgget('devip') if 'n/a' not in stored_ip.lower() and '.' in stored_ip: conn_ips = list(sta_if.ifconfig()) # Check ip type before change, conn_ip structure: 10.0.1.X if conn_ips[0] != stored_ip and conn_ips[-1].split( '.')[0:3] == stored_ip.split('.')[0:3]: console_write( "\t| [NW: STA] micrOS dev. StaticIP request: {}".format( stored_ip)) conn_ips[0] = stored_ip try: # IP address, subnet mask, gateway and DNS server sta_if.ifconfig(tuple(conn_ips)) return True # was reconfigured except Exception as e: console_write( "\t\t| [NW: STA] StaticIP conf. failed: {}".format(e)) errlog_add("__set_wifi_dev_static_ip error: {}".format(e)) else: console_write("[NW: STA][SKIP] StaticIP conf.: {} ? {}".format( stored_ip, conn_ips[0])) else: console_write("[NW: STA] IP was not stored: {}".format(stored_ip)) return False # was not reconfigured
def run(self): self.server_console( "[ socket server ] SERVER ADDR: telnet {} {}".format( cfgget("devip"), self.__port)) try: cfgput('version', self.__socket_interpreter_version) except Exception as e: console_write( "Export system version to config failed: {}".format(e)) self.__init_socket() self.__bind_and_accept() while True: try: # Evaluate incoming msg via InterpreterShell -> InterpreterCore "Console prompt" is_healthy = InterpreterShell_shell(self.__wait_for_message(), SocketServerObj=self) if not is_healthy: console_write( "[EXEC-WARNING] InterpreterShell internal error.") self.__recovery(is_critic=False) except OSError: # BrokenPipeError self.__reconnect() except Exception as e: console_write( "[EXEC-ERROR] InterpreterShell error: {}".format(e)) self.__recovery(is_critic=True) # Memory dimensioning dump self.server_console( '[X] AFTER INTERPRETER EXECUTION FREE MEM [byte]: {}'.format( mem_free()))
def run(cls): """ Main method, runs socket server with interpreter shell """ cls.server_console( "[ socket server ] SERVER ADDR: telnet {} {}".format( cfgget("devip"), cls.__port)) try: cfgput('version', cls.__socket_interpreter_version) except Exception as e: console_write( "Export system version to config failed: {}".format(e)) errlog_add('socket run system version export error: {}'.format(e)) cls.__init_socket() while True and cls.__isconn: try: # Evaluate incoming msg via InterpreterShell -> InterpreterCore "Console prompt" is_healthy = shell(cls.__wait_for_msg(), sso=cls) if not is_healthy: console_write( "[EXEC-WARNING] InterpreterShell internal error.") cls.__recovery(is_critic=False) except OSError: # Broken pipe error handling cls.__reconnect() except Exception as e: console_write( "[EXEC-ERROR] InterpreterShell error: {}".format(e)) errlog_add("Socket-InterpreterShell error: {}".format(e)) cls.__recovery(is_critic=True) # Memory dimensioning dump cls.server_console( '[X] AFTER INTERPRETER EXECUTION FREE MEM [byte]: {}'.format( mem_free()))
def __server_level_cmds(cls, data_str): # globally available micrOS functions if data_str == 'exit': # For low level exit handling cls.reply_message("Bye!") cls.__reconnect() return "" if data_str == 'hello': # For low level device identification - hello msg cls.reply_message("hello:{}:{}".format(cfgget('devfid'), cls.__hwuid)) return "" if data_str == 'version': # For micrOS system version info cls.reply_message("{}".format(cls.__socket_interpreter_version)) return "" # Authentication handling data_str = cls.__authentication( data_str) if cls.__auth_mode else data_str # Authenticated user functions ... shell, etc if data_str == 'reboot': cls.reply_message("Reboot micrOS system.") cls.__safe_reboot() return "" if data_str.startswith('webrepl'): if '--u' in data_str: cls.start_micropython_webrepl(update=True) cls.start_micropython_webrepl() return "" return data_str
def set_transition(r, g, b, sec): """ Set transition color change for long dimming periods < 30sec - creates the color dimming generators :param r: red value 0-255 :param g: green value 0-255 :param b: blue value 0-255 :param sec: transition length in sec :return: info msg string """ Data.DCACHE[3] = 1 timirqseq = cfgget('timirqseq') from_red = Data.DCACHE[0] from_green = Data.DCACHE[1] from_blue = Data.DCACHE[2] # Generate RGB color transition object (generator) Data.FADE_OBJ = (transition(from_val=from_red, to_val=r, step_ms=timirqseq, interval_sec=sec), transition(from_val=from_green, to_val=g, step_ms=timirqseq, interval_sec=sec), transition(from_val=from_blue, to_val=b, step_ms=timirqseq, interval_sec=sec)) return 'Settings was applied... wait for: run_transition'
def profiling_info(label=""): """ Runtime memory measurements """ if cfgget('dbg'): console_write("{} [PROFILING INFO] - {} {}".format('~'*5, label, '~'*5)) mem_info() console_write("~"*30)
def __init__(self, host='', port=None, uid=None, user_timeout_sec=None): # Socket server initial parameters self.server_console_indent = 0 self.CONFIGURE_MODE = False self.pre_prompt = "" self.host = host self.s = None self.conn = None self.addr = None # ---- Config --- self.prompt = "{} $ ".format(cfgget('devfid')) self.port = port if port is not None else cfgget("socport") self.timeout_user = user_timeout_sec if user_timeout_sec is not None else int( cfgget("soctout")) self.uid = uid if uid is not None else str(cfgget("hwuid")) # --- ---- self.server_console("[ socket server ] <<constructor>>")
def __irq_mem_req_check(key): """ :param key: config param key to check Checks the selected config function hw resource need before setup :return: Enable(True)/Disable(False), available memory """ if key not in ('timirq', 'irq1', 'irq2', 'irq3', 'irq14', 'cron'): return True, None collect() # gc collect memavail = mem_free() # get free memory if key == 'timirq' and memavail < cfgget('irqmreq'): return False, memavail if key == 'cron' and memavail < cfgget('irqmreq') * 2: return False, memavail if key in ('irq1', 'irq2', 'irq3', 'irq4') and memavail < int(cfgget('irqmreq') * 0.7): return False, memavail return True, memavail
def auto_network_configuration(retry=3): for _ in range(0, retry): # SET WIFI (STA) MODE state = set_wifi(cfgget("staessid"), cfgget("stapwd")) if state: # Save STA NW mode cfgput("nwmd", "STA") # Set NTP - RTC setNTP_RTC() # BREAK - STA mode successfully configures break # SET AP MODE state = set_access_point(cfgget("devfid"), cfgget("appwd")) if state: # Save AP NW mode cfgput("nwmd", "AP") # BREAK - AP mode successfully configures break
def show_debug_page(): try: # Clean screen __init().fill(0) __OLED.show() # Print info ltime = localtime() __OLED.text( "{} {}:{}:{}".format(cfgget("nwmd"), ltime[-5], ltime[-4], ltime[-3]), 0, 0) __OLED.text("FUID: {}".format(cfgget("devfid")), 0, 15) __OLED.text("IP: {}".format(cfgget("devip")), 0, 25) __OLED.text("FreeMem: {}".format(mem_free()), 0, 35) __OLED.text("V: {}".format(cfgget("version")), 0, 45) # Show page buffer - send to display __OLED.show() except Exception as e: return str(e) return True
def start_micropython_webrepl(self): self.reply_message( " Start micropython WEBREPL for interpreter web access and file transferring." ) self.reply_message( " [!] micrOS socket shell will be available again after reboot.") self.reply_message(" \trestart machine shortcut: import reset") self.reply_message( " Connect over http://micropython.org/webrepl/#{}:8266/".format( cfgget("devip"))) self.reply_message(" \t[!] webrepl password: {}".format( cfgget('appwd'))) self.reply_message(" Bye!") try: import webrepl self.reply_message(webrepl.start(password=cfgget('appwd'))) self.__del__() except Exception as e: self.reply_message("Error while starting webrepl: {}".format(e))
def ntp(): """ Set NTP manually """ from ConfigHandler import cfgget try: # Automatic setup - over wifi - ntp state = ntptime(utc_shift=int(cfgget('gmttime'))) return state, localtime() except Exception as e: return False, "ntp error:{}".format(e)
def __configure(attributes, sso): """ :param attributes: socket input param list :param sso: socket server object :return: execution status """ # [CONFIG] Get value if len(attributes) == 1: if attributes[0] == 'dump': # DUMP DATA for key, value in cfgget().items(): spcr = (10 - len(key)) sso.reply_message(" {}{}:{} {}".format( key, " " * spcr, " " * 7, value)) return True # GET SINGLE PARAMETER VALUE sso.reply_message(cfgget(attributes[0])) return True # [CONFIG] Set value if len(attributes) >= 2: # Deserialize params key = attributes[0] value = " ".join(attributes[1:]) # Check irq required memory if attributes[1].lower() == 'true': isOK, avmem = __irq_mem_req_check(key) if not isOK: sso.reply_message( "Skip ... feature requires more memory then {} byte". format(avmem)) return True # Set the parameter value in config try: output = cfgput(key, value, type_check=True) except Exception as e: sso.reply_message("node_config write error: {}".format(e)) output = False # Evaluation and reply issue_msg = 'Invalid key' if cfgget(key) is None else 'Failed to save' sso.reply_message('Saved' if output else issue_msg) return True