micrOSDevToolKit 2.13.1__py3-none-any.whl → 2.17.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of micrOSDevToolKit might be problematic. Click here for more details.
- micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +125 -121
- micrOS/source/Common.py +48 -26
- micrOS/source/Config.py +13 -5
- micrOS/source/Espnow.py +100 -58
- micrOS/source/Files.py +77 -41
- micrOS/source/Hooks.py +18 -34
- micrOS/source/Logger.py +2 -7
- micrOS/source/Network.py +36 -16
- micrOS/source/Server.py +22 -8
- micrOS/source/Shell.py +9 -6
- micrOS/source/Tasks.py +34 -13
- micrOS/source/Web.py +69 -31
- micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
- micrOS/source/__pycache__/Files.cpython-312.pyc +0 -0
- micrOS/source/__pycache__/Logger.cpython-312.pyc +0 -0
- micrOS/source/__pycache__/Server.cpython-312.pyc +0 -0
- micrOS/source/config/_git.keep +0 -0
- micrOS/source/micrOS.py +7 -0
- micrOS/source/micrOSloader.py +4 -10
- micrOS/source/microIO.py +2 -2
- micrOS/source/modules/IO_esp32c6.py +38 -0
- micrOS/source/modules/LM_L298N.py +161 -0
- micrOS/source/modules/LM_cluster.py +255 -0
- {toolkit/workspace/precompiled → micrOS/source/modules}/LM_esp32.py +5 -0
- micrOS/source/modules/LM_espnow.py +36 -0
- micrOS/source/{LM_i2c.py → modules/LM_i2c.py} +1 -1
- micrOS/source/{LM_light_sensor.py → modules/LM_light_sensor.py} +2 -2
- micrOS/source/modules/LM_mqtt_client.py +246 -0
- micrOS/source/{LM_neoeffects.py → modules/LM_neoeffects.py} +14 -4
- micrOS/source/{LM_neomatrix.py → modules/LM_neomatrix.py} +140 -38
- micrOS/source/{LM_oled_ui.py → modules/LM_oled_ui.py} +2 -2
- micrOS/source/{LM_oledui.py → modules/LM_oledui.py} +2 -2
- micrOS/source/{LM_pacman.py → modules/LM_pacman.py} +74 -29
- micrOS/source/{LM_presence.py → modules/LM_presence.py} +2 -2
- micrOS/source/{LM_robustness.py → modules/LM_robustness.py} +49 -2
- micrOS/source/{LM_tcs3472.py → modules/LM_tcs3472.py} +4 -6
- micrOS/source/web/dashboard.html +2 -0
- micrOS/source/web/matrix_draw.html +390 -0
- micrOS/source/web/uapi.js +9 -6
- {microsdevtoolkit-2.13.1.dist-info → microsdevtoolkit-2.17.1.dist-info}/METADATA +30 -37
- {microsdevtoolkit-2.13.1.dist-info → microsdevtoolkit-2.17.1.dist-info}/RECORD +200 -190
- toolkit/DevEnvCompile.py +21 -12
- toolkit/DevEnvOTA.py +27 -16
- toolkit/DevEnvUSB.py +35 -21
- toolkit/LM_to_compile.dat +3 -1
- toolkit/MicrOSDevEnv.py +37 -21
- toolkit/dashboard_apps/QMI8685_GYRO.py +1 -1
- toolkit/dashboard_apps/SystemTest.py +8 -5
- toolkit/{MicrosFiles.py → lib/MicrosFiles.py} +24 -4
- toolkit/micrOSdashboard.py +2 -2
- toolkit/micrOSlint.py +17 -7
- toolkit/simulator_lib/__pycache__/simulator.cpython-312.pyc +0 -0
- toolkit/simulator_lib/__pycache__/uos.cpython-312.pyc +0 -0
- toolkit/simulator_lib/mqtt_as/Note.md +15 -0
- toolkit/simulator_lib/mqtt_as/__init__.py +950 -0
- toolkit/simulator_lib/mqtt_as/__pycache__/__init__.cpython-312.pyc +0 -0
- toolkit/simulator_lib/mqtt_as/clean.py +69 -0
- toolkit/simulator_lib/mqtt_as/mqtt_v5_properties.py +239 -0
- toolkit/simulator_lib/mqtt_as/range.py +90 -0
- toolkit/simulator_lib/mqtt_as/range_ex.py +119 -0
- toolkit/simulator_lib/simulator.py +14 -1
- toolkit/simulator_lib/uos.py +2 -0
- toolkit/workspace/precompiled/Common.mpy +0 -0
- toolkit/workspace/precompiled/Config.mpy +0 -0
- toolkit/workspace/precompiled/Espnow.mpy +0 -0
- toolkit/workspace/precompiled/Files.mpy +0 -0
- toolkit/workspace/precompiled/Hooks.mpy +0 -0
- toolkit/workspace/precompiled/Logger.mpy +0 -0
- toolkit/workspace/precompiled/Network.mpy +0 -0
- toolkit/workspace/precompiled/Server.mpy +0 -0
- toolkit/workspace/precompiled/Shell.mpy +0 -0
- toolkit/workspace/precompiled/Tasks.mpy +0 -0
- toolkit/workspace/precompiled/Web.mpy +0 -0
- toolkit/workspace/precompiled/config/_git.keep +0 -0
- toolkit/workspace/precompiled/micrOS.mpy +0 -0
- toolkit/workspace/precompiled/micrOSloader.mpy +0 -0
- toolkit/workspace/precompiled/microIO.mpy +0 -0
- toolkit/workspace/precompiled/{IO_esp32.mpy → modules/IO_esp32.mpy} +0 -0
- toolkit/workspace/precompiled/{IO_esp32c3.mpy → modules/IO_esp32c3.mpy} +0 -0
- toolkit/workspace/precompiled/modules/IO_esp32c6.mpy +0 -0
- toolkit/workspace/precompiled/{IO_esp32s2.mpy → modules/IO_esp32s2.mpy} +0 -0
- toolkit/workspace/precompiled/{IO_esp32s3.mpy → modules/IO_esp32s3.mpy} +0 -0
- toolkit/workspace/precompiled/{IO_m5stamp.mpy → modules/IO_m5stamp.mpy} +0 -0
- toolkit/workspace/precompiled/{IO_qtpy.mpy → modules/IO_qtpy.mpy} +0 -0
- toolkit/workspace/precompiled/modules/IO_rp2.mpy +0 -0
- toolkit/workspace/precompiled/modules/IO_s3matrix.mpy +0 -0
- toolkit/workspace/precompiled/{IO_tinypico.mpy → modules/IO_tinypico.mpy} +0 -0
- toolkit/workspace/precompiled/modules/LM_L298N.mpy +0 -0
- toolkit/workspace/precompiled/{LM_OV2640.mpy → modules/LM_OV2640.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_aht10.mpy → modules/LM_aht10.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_bme280.mpy → modules/LM_bme280.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_buzzer.mpy → modules/LM_buzzer.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_cct.mpy → modules/LM_cct.mpy} +0 -0
- toolkit/workspace/precompiled/modules/LM_cluster.mpy +0 -0
- toolkit/workspace/precompiled/{LM_co2.mpy → modules/LM_co2.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_dht11.mpy → modules/LM_dht11.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_dht22.mpy → modules/LM_dht22.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_dimmer.mpy → modules/LM_dimmer.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_distance.mpy → modules/LM_distance.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_ds18.mpy → modules/LM_ds18.mpy} +0 -0
- {micrOS/source → toolkit/workspace/precompiled/modules}/LM_esp32.py +5 -0
- toolkit/workspace/precompiled/modules/LM_espnow.py +36 -0
- toolkit/workspace/precompiled/{LM_gameOfLife.mpy → modules/LM_gameOfLife.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_genIO.mpy → modules/LM_genIO.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_haptic.mpy → modules/LM_haptic.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_i2c.py → modules/LM_i2c.py} +1 -1
- toolkit/workspace/precompiled/{LM_i2s_mic.mpy → modules/LM_i2s_mic.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_keychain.mpy → modules/LM_keychain.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_ld2410.mpy → modules/LM_ld2410.mpy} +0 -0
- toolkit/workspace/precompiled/modules/LM_light_sensor.mpy +0 -0
- toolkit/workspace/precompiled/modules/LM_mqtt_client.mpy +0 -0
- toolkit/workspace/precompiled/{LM_neoeffects.mpy → modules/LM_neoeffects.mpy} +0 -0
- toolkit/workspace/precompiled/modules/LM_neomatrix.mpy +0 -0
- toolkit/workspace/precompiled/{LM_neopixel.mpy → modules/LM_neopixel.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_oled.mpy → modules/LM_oled.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_oled_sh1106.mpy → modules/LM_oled_sh1106.mpy} +0 -0
- toolkit/workspace/precompiled/modules/LM_oled_ui.mpy +0 -0
- toolkit/workspace/precompiled/modules/LM_oledui.mpy +0 -0
- toolkit/workspace/precompiled/modules/LM_pacman.mpy +0 -0
- toolkit/workspace/precompiled/modules/LM_presence.mpy +0 -0
- toolkit/workspace/precompiled/{LM_rest.mpy → modules/LM_rest.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_rgb.mpy → modules/LM_rgb.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_rgbcct.mpy → modules/LM_rgbcct.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_roboarm.mpy → modules/LM_roboarm.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_robustness.py → modules/LM_robustness.py} +49 -2
- toolkit/workspace/precompiled/{LM_servo.mpy → modules/LM_servo.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_sound_event.mpy → modules/LM_sound_event.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_stepper.mpy → modules/LM_stepper.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_switch.mpy → modules/LM_switch.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_system.mpy → modules/LM_system.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_tcs3472.py → modules/LM_tcs3472.py} +4 -6
- toolkit/workspace/precompiled/{LM_telegram.mpy → modules/LM_telegram.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_tinyrgb.mpy → modules/LM_tinyrgb.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_trackball.mpy → modules/LM_trackball.mpy} +0 -0
- toolkit/workspace/precompiled/{LM_veml7700.mpy → modules/LM_veml7700.mpy} +0 -0
- toolkit/workspace/precompiled/web/dashboard.html +2 -0
- toolkit/workspace/precompiled/web/matrix_draw.html +390 -0
- toolkit/workspace/precompiled/web/uapi.js +9 -6
- micrOS/source/IO_esp32c6.py +0 -16
- micrOS/source/LM_L298N_DCmotor.py +0 -86
- micrOS/source/LM_espnow.py +0 -57
- micrOS/source/LM_mqtt_pro.py +0 -211
- toolkit/lib/file_extensions.py +0 -22
- toolkit/workspace/precompiled/Common.cpython-312.pyc +0 -0
- toolkit/workspace/precompiled/IO_esp32c6.mpy +0 -0
- toolkit/workspace/precompiled/IO_rp2.mpy +0 -0
- toolkit/workspace/precompiled/IO_s3matrix.mpy +0 -0
- toolkit/workspace/precompiled/LM_L298N_DCmotor.mpy +0 -0
- toolkit/workspace/precompiled/LM_espnow.py +0 -57
- toolkit/workspace/precompiled/LM_light_sensor.mpy +0 -0
- toolkit/workspace/precompiled/LM_mqtt_pro.py +0 -211
- toolkit/workspace/precompiled/LM_neomatrix.mpy +0 -0
- toolkit/workspace/precompiled/LM_oled_ui.mpy +0 -0
- toolkit/workspace/precompiled/LM_oledui.mpy +0 -0
- toolkit/workspace/precompiled/LM_pacman.mpy +0 -0
- toolkit/workspace/precompiled/LM_presence.mpy +0 -0
- toolkit/workspace/precompiled/Logger.cpython-312.pyc +0 -0
- toolkit/workspace/precompiled/Server.cpython-312.pyc +0 -0
- /micrOS/source/{IO_esp32.py → modules/IO_esp32.py} +0 -0
- /micrOS/source/{IO_esp32c3.py → modules/IO_esp32c3.py} +0 -0
- /micrOS/source/{IO_esp32s2.py → modules/IO_esp32s2.py} +0 -0
- /micrOS/source/{IO_esp32s3.py → modules/IO_esp32s3.py} +0 -0
- /micrOS/source/{IO_m5stamp.py → modules/IO_m5stamp.py} +0 -0
- /micrOS/source/{IO_qtpy.py → modules/IO_qtpy.py} +0 -0
- /micrOS/source/{IO_rp2.py → modules/IO_rp2.py} +0 -0
- /micrOS/source/{IO_s3matrix.py → modules/IO_s3matrix.py} +0 -0
- /micrOS/source/{IO_tinypico.py → modules/IO_tinypico.py} +0 -0
- /micrOS/source/{LM_L9110_DCmotor.py → modules/LM_L9110_DCmotor.py} +0 -0
- /micrOS/source/{LM_OV2640.py → modules/LM_OV2640.py} +0 -0
- /micrOS/source/{LM_VL53L0X.py → modules/LM_VL53L0X.py} +0 -0
- /micrOS/source/{LM_aht10.py → modules/LM_aht10.py} +0 -0
- /micrOS/source/{LM_bme280.py → modules/LM_bme280.py} +0 -0
- /micrOS/source/{LM_buzzer.py → modules/LM_buzzer.py} +0 -0
- /micrOS/source/{LM_cct.py → modules/LM_cct.py} +0 -0
- /micrOS/source/{LM_co2.py → modules/LM_co2.py} +0 -0
- /micrOS/source/{LM_dashboard_be.py → modules/LM_dashboard_be.py} +0 -0
- /micrOS/source/{LM_dht11.py → modules/LM_dht11.py} +0 -0
- /micrOS/source/{LM_dht22.py → modules/LM_dht22.py} +0 -0
- /micrOS/source/{LM_dimmer.py → modules/LM_dimmer.py} +0 -0
- /micrOS/source/{LM_distance.py → modules/LM_distance.py} +0 -0
- /micrOS/source/{LM_ds18.py → modules/LM_ds18.py} +0 -0
- /micrOS/source/{LM_gameOfLife.py → modules/LM_gameOfLife.py} +0 -0
- /micrOS/source/{LM_genIO.py → modules/LM_genIO.py} +0 -0
- /micrOS/source/{LM_haptic.py → modules/LM_haptic.py} +0 -0
- /micrOS/source/{LM_i2s_mic.py → modules/LM_i2s_mic.py} +0 -0
- /micrOS/source/{LM_keychain.py → modules/LM_keychain.py} +0 -0
- /micrOS/source/{LM_ld2410.py → modules/LM_ld2410.py} +0 -0
- /micrOS/source/{LM_neopixel.py → modules/LM_neopixel.py} +0 -0
- /micrOS/source/{LM_oled.py → modules/LM_oled.py} +0 -0
- /micrOS/source/{LM_oled_sh1106.py → modules/LM_oled_sh1106.py} +0 -0
- /micrOS/source/{LM_pet_feeder.py → modules/LM_pet_feeder.py} +0 -0
- /micrOS/source/{LM_qmi8658.py → modules/LM_qmi8658.py} +0 -0
- /micrOS/source/{LM_rencoder.py → modules/LM_rencoder.py} +0 -0
- /micrOS/source/{LM_rest.py → modules/LM_rest.py} +0 -0
- /micrOS/source/{LM_rgb.py → modules/LM_rgb.py} +0 -0
- /micrOS/source/{LM_rgbcct.py → modules/LM_rgbcct.py} +0 -0
- /micrOS/source/{LM_roboarm.py → modules/LM_roboarm.py} +0 -0
- /micrOS/source/{LM_rp2w.py → modules/LM_rp2w.py} +0 -0
- /micrOS/source/{LM_sdcard.py → modules/LM_sdcard.py} +0 -0
- /micrOS/source/{LM_servo.py → modules/LM_servo.py} +0 -0
- /micrOS/source/{LM_sound_event.py → modules/LM_sound_event.py} +0 -0
- /micrOS/source/{LM_stepper.py → modules/LM_stepper.py} +0 -0
- /micrOS/source/{LM_switch.py → modules/LM_switch.py} +0 -0
- /micrOS/source/{LM_system.py → modules/LM_system.py} +0 -0
- /micrOS/source/{LM_telegram.py → modules/LM_telegram.py} +0 -0
- /micrOS/source/{LM_tinyrgb.py → modules/LM_tinyrgb.py} +0 -0
- /micrOS/source/{LM_trackball.py → modules/LM_trackball.py} +0 -0
- /micrOS/source/{LM_veml7700.py → modules/LM_veml7700.py} +0 -0
- {microsdevtoolkit-2.13.1.data → microsdevtoolkit-2.17.1.data}/scripts/devToolKit.py +0 -0
- {microsdevtoolkit-2.13.1.dist-info → microsdevtoolkit-2.17.1.dist-info}/WHEEL +0 -0
- {microsdevtoolkit-2.13.1.dist-info → microsdevtoolkit-2.17.1.dist-info}/licenses/LICENSE +0 -0
- {microsdevtoolkit-2.13.1.dist-info → microsdevtoolkit-2.17.1.dist-info}/top_level.txt +0 -0
- /toolkit/workspace/precompiled/{LM_L9110_DCmotor.py → modules/LM_L9110_DCmotor.py} +0 -0
- /toolkit/workspace/precompiled/{LM_VL53L0X.py → modules/LM_VL53L0X.py} +0 -0
- /toolkit/workspace/precompiled/{LM_dashboard_be.py → modules/LM_dashboard_be.py} +0 -0
- /toolkit/workspace/precompiled/{LM_pet_feeder.py → modules/LM_pet_feeder.py} +0 -0
- /toolkit/workspace/precompiled/{LM_qmi8658.py → modules/LM_qmi8658.py} +0 -0
- /toolkit/workspace/precompiled/{LM_rencoder.py → modules/LM_rencoder.py} +0 -0
- /toolkit/workspace/precompiled/{LM_rp2w.py → modules/LM_rp2w.py} +0 -0
- /toolkit/workspace/precompiled/{LM_sdcard.py → modules/LM_sdcard.py} +0 -0
micrOS/source/Network.py
CHANGED
|
@@ -20,6 +20,7 @@ from network import AP_IF, STA_IF, WLAN
|
|
|
20
20
|
from machine import unique_id
|
|
21
21
|
from Config import cfgget, cfgput
|
|
22
22
|
from Debug import console_write, syslog
|
|
23
|
+
from microIO import detect_platform
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class NW:
|
|
@@ -48,23 +49,36 @@ def ifconfig():
|
|
|
48
49
|
|
|
49
50
|
|
|
50
51
|
def set_dev_uid():
|
|
52
|
+
if detect_platform() == "esp32c6":
|
|
53
|
+
# ESP32-C6: unique_id() not unique (can return same ID on different boards)
|
|
54
|
+
try:
|
|
55
|
+
sta = WLAN(STA_IF)
|
|
56
|
+
was = sta.active()
|
|
57
|
+
if not was: sta.active(True)
|
|
58
|
+
uid = hexlify(sta.config('mac')).decode()
|
|
59
|
+
if not was: sta.active(False)
|
|
60
|
+
cfgput('hwuid', f"micr{uid}OS")
|
|
61
|
+
return
|
|
62
|
+
except Exception as e:
|
|
63
|
+
syslog(f"[ERR] set_dev_uid (esp32c6): {e}")
|
|
64
|
+
# Legacy micrOS device UID generation (+fallback)
|
|
51
65
|
try:
|
|
52
66
|
cfgput('hwuid', f'micr{hexlify(unique_id()).decode("utf-8")}OS')
|
|
53
67
|
except Exception as e:
|
|
54
|
-
syslog(f"[ERR] set_dev_uid
|
|
68
|
+
syslog(f"[ERR] set_dev_uid: {e}")
|
|
55
69
|
|
|
56
70
|
|
|
57
71
|
def get_mac():
|
|
58
|
-
|
|
72
|
+
""" Get AP/STA mac address as raw binary data"""
|
|
73
|
+
return NW.NIF.config('mac')
|
|
59
74
|
|
|
60
75
|
#################################################################
|
|
61
76
|
# SET WIFI STA MODE #
|
|
62
77
|
#################################################################
|
|
63
78
|
|
|
64
79
|
|
|
65
|
-
def
|
|
80
|
+
def _select_available_wifi_nw(raw_essid:str, raw_pwd:str):
|
|
66
81
|
"""
|
|
67
|
-
raw_essid: essid parameter, in case of multiple values separator is ;
|
|
68
82
|
raw_pwd: essid pwd parameter, in case of multiple values separator is ;
|
|
69
83
|
return detected essid with corresponding password
|
|
70
84
|
"""
|
|
@@ -72,7 +86,7 @@ def __select_available_wifi_nw(sta_if, raw_essid, raw_pwd):
|
|
|
72
86
|
essid = essid.strip()
|
|
73
87
|
# Scan wifi network - retry workaround
|
|
74
88
|
for _ in range(0, 2):
|
|
75
|
-
if essid in (wifispot[0].decode('utf-8') for wifispot in
|
|
89
|
+
if essid in (wifispot[0].decode('utf-8') for wifispot in NW.NIF.scan()):
|
|
76
90
|
console_write(f'\t| - [NW: STA] ESSID WAS FOUND: {essid}')
|
|
77
91
|
try:
|
|
78
92
|
return essid, str(raw_pwd.split(';')[idx]).strip()
|
|
@@ -82,8 +96,8 @@ def __select_available_wifi_nw(sta_if, raw_essid, raw_pwd):
|
|
|
82
96
|
return None, ''
|
|
83
97
|
|
|
84
98
|
|
|
85
|
-
def set_wifi(essid, pwd, timeout=60):
|
|
86
|
-
console_write(
|
|
99
|
+
def set_wifi(essid:str, pwd:str, timeout=60):
|
|
100
|
+
console_write('[NW: STA] Enable')
|
|
87
101
|
|
|
88
102
|
# Disable AP mode
|
|
89
103
|
ap_if = WLAN(AP_IF)
|
|
@@ -94,18 +108,25 @@ def set_wifi(essid, pwd, timeout=60):
|
|
|
94
108
|
# Set STA and Connect
|
|
95
109
|
sta_if = WLAN(STA_IF)
|
|
96
110
|
sta_if.active(True)
|
|
111
|
+
NW.NIF = sta_if
|
|
97
112
|
# Handle rsp2-w limitation (try)
|
|
98
113
|
try:
|
|
99
114
|
# Set custom DHCP hostname for dhcp name resolve
|
|
100
115
|
sta_if.config(dhcp_hostname=cfgget('devfid'))
|
|
101
116
|
except Exception as e:
|
|
102
|
-
|
|
117
|
+
syslog(f"[ERR] STA dhcp_hostname: {e}")
|
|
118
|
+
if cfgget("espnow"):
|
|
119
|
+
try:
|
|
120
|
+
# prevents Wi-Fi PS from dropping ESP-NOW frames while STA is connected.
|
|
121
|
+
sta_if.config(pm=sta_if.PM_NONE)
|
|
122
|
+
except Exception as e:
|
|
123
|
+
syslog(f"[ERR] ESPNow STA PM_NONE: {e}")
|
|
103
124
|
# Check are we already connected
|
|
104
125
|
if sta_if.isconnected():
|
|
105
126
|
console_write(f"\t| [NW: STA] ALREADY CONNECTED TO {essid}")
|
|
106
127
|
else:
|
|
107
128
|
# Multiple essid and pwd handling with retry mechanism
|
|
108
|
-
essid, pwd =
|
|
129
|
+
essid, pwd = _select_available_wifi_nw(essid, pwd)
|
|
109
130
|
|
|
110
131
|
# Connect to the located wifi network
|
|
111
132
|
if essid is not None:
|
|
@@ -118,7 +139,7 @@ def set_wifi(essid, pwd, timeout=60):
|
|
|
118
139
|
timeout -= 1
|
|
119
140
|
sleep_ms(500)
|
|
120
141
|
# Set static IP - here because some data comes from connection. (subnet, etc.)
|
|
121
|
-
if sta_if.isconnected() and
|
|
142
|
+
if sta_if.isconnected() and _set_wifi_dev_static_ip(sta_if):
|
|
122
143
|
sta_if.disconnect()
|
|
123
144
|
del sta_if
|
|
124
145
|
return set_wifi(essid, pwd)
|
|
@@ -131,11 +152,10 @@ def set_wifi(essid, pwd, timeout=60):
|
|
|
131
152
|
# Store STA IP (make it static ip)
|
|
132
153
|
cfgput("devip", str(sta_if.ifconfig()[0]))
|
|
133
154
|
set_dev_uid()
|
|
134
|
-
NW.NIF = sta_if
|
|
135
155
|
return sta_if.isconnected()
|
|
136
156
|
|
|
137
157
|
|
|
138
|
-
def
|
|
158
|
+
def _set_wifi_dev_static_ip(sta_if:STA_IF):
|
|
139
159
|
console_write("[NW: STA] Set device static IP.")
|
|
140
160
|
stored_ip = cfgget('devip')
|
|
141
161
|
if 'n/a' not in stored_ip.lower() and '.' in stored_ip:
|
|
@@ -162,7 +182,7 @@ def __set_wifi_dev_static_ip(sta_if):
|
|
|
162
182
|
#################################################################
|
|
163
183
|
|
|
164
184
|
|
|
165
|
-
def set_access_point(_essid, _pwd, _authmode=3):
|
|
185
|
+
def set_access_point(_essid:str, _pwd:str, _authmode:int=3):
|
|
166
186
|
console_write(f"[NW: AP] SET AP MODE: {_essid} - {_pwd} - auth mode: {_authmode} (if possible)")
|
|
167
187
|
|
|
168
188
|
sta_if = WLAN(STA_IF)
|
|
@@ -171,6 +191,7 @@ def set_access_point(_essid, _pwd, _authmode=3):
|
|
|
171
191
|
|
|
172
192
|
ap_if = WLAN(AP_IF)
|
|
173
193
|
ap_if.active(True)
|
|
194
|
+
NW.NIF = ap_if
|
|
174
195
|
# Set WiFi access point name (formally known as ESSID) and WiFi authmode (3): WPA2-PSK
|
|
175
196
|
try:
|
|
176
197
|
# Config #1 (esp)
|
|
@@ -189,7 +210,6 @@ def set_access_point(_essid, _pwd, _authmode=3):
|
|
|
189
210
|
syslog("[ERR][AP] error")
|
|
190
211
|
console_write(f"\t|\t| [NW: AP] network config: {str(ap_if.ifconfig())}")
|
|
191
212
|
set_dev_uid()
|
|
192
|
-
NW.NIF = ap_if
|
|
193
213
|
return ap_if.active()
|
|
194
214
|
|
|
195
215
|
#################################################################
|
|
@@ -228,7 +248,7 @@ def sta_high_avail():
|
|
|
228
248
|
raw_essid = cfgget("staessid")
|
|
229
249
|
wifi_avail = False
|
|
230
250
|
# [CHECK 2] check known network is available
|
|
231
|
-
for
|
|
251
|
+
for essid in raw_essid.split(';'):
|
|
232
252
|
essid = essid.strip()
|
|
233
253
|
# Scan wifi network - retry workaround
|
|
234
254
|
for _ in range(0, 2):
|
|
@@ -241,7 +261,7 @@ def sta_high_avail():
|
|
|
241
261
|
if wifi_avail or not ap_if.active():
|
|
242
262
|
# ACTION: Restart micrOS node (boot phase automatically detects nw mode)
|
|
243
263
|
from machine import reset
|
|
244
|
-
|
|
264
|
+
syslog("[WARN] Restart, network repair")
|
|
245
265
|
reset()
|
|
246
266
|
return f'{cfgget("nwmd")} mode NOK, wifi avail: {wifi_avail}'
|
|
247
267
|
return f'{cfgget("nwmd")} mode OK'
|
micrOS/source/Server.py
CHANGED
|
@@ -27,7 +27,7 @@ except:
|
|
|
27
27
|
if cfgget('webui'):
|
|
28
28
|
from Web import WebEngine
|
|
29
29
|
else:
|
|
30
|
-
# Create dummy web engine -
|
|
30
|
+
# Create dummy web engine - Lazy loading
|
|
31
31
|
class WebEngine:
|
|
32
32
|
__slots__ = []
|
|
33
33
|
def __init__(self, *args, **kwargs):
|
|
@@ -142,7 +142,7 @@ class Client:
|
|
|
142
142
|
if Client.ACTIVE_CLIS.get(client_id, None) is not None:
|
|
143
143
|
Client.ACTIVE_CLIS.pop(client_id)
|
|
144
144
|
# Update server task output (? test ?)
|
|
145
|
-
Manager().
|
|
145
|
+
Manager().task_msg('server', ','.join(list(Client.ACTIVE_CLIS)))
|
|
146
146
|
|
|
147
147
|
def __del__(self):
|
|
148
148
|
"""Client GC collect"""
|
|
@@ -158,7 +158,7 @@ class WebCli(Client, WebEngine):
|
|
|
158
158
|
|
|
159
159
|
async def run_web(self):
|
|
160
160
|
# Update server task output
|
|
161
|
-
Manager().
|
|
161
|
+
Manager().task_msg('server', ','.join(list(Client.ACTIVE_CLIS)))
|
|
162
162
|
|
|
163
163
|
# Run async connection handling
|
|
164
164
|
while self.connected:
|
|
@@ -167,7 +167,8 @@ class WebCli(Client, WebEngine):
|
|
|
167
167
|
state, request = await self.read()
|
|
168
168
|
if state:
|
|
169
169
|
break
|
|
170
|
-
await self.response(request)
|
|
170
|
+
if not await self.response(request):
|
|
171
|
+
break
|
|
171
172
|
except Exception as e:
|
|
172
173
|
syslog(f"[ERR] Client.run_web: {e}")
|
|
173
174
|
break
|
|
@@ -175,14 +176,27 @@ class WebCli(Client, WebEngine):
|
|
|
175
176
|
await self.close()
|
|
176
177
|
|
|
177
178
|
@staticmethod
|
|
178
|
-
def register(endpoint, callback):
|
|
179
|
+
def register(endpoint:str, callback:callable, method:str='GET', auto_enable:bool=True):
|
|
180
|
+
"""
|
|
181
|
+
:param endpoint: name of the endpoint
|
|
182
|
+
:param callback: callback function (WebEngine compatible: return: html_type, content)
|
|
183
|
+
:param method: HTTP method name
|
|
184
|
+
:param auto_enable: enable webui when register (endpoint)
|
|
185
|
+
"""
|
|
186
|
+
if method not in WebEngine.METHODS:
|
|
187
|
+
raise ValueError(f"method must be one of {WebEngine.METHODS}")
|
|
188
|
+
|
|
189
|
+
if cfgget('webui'):
|
|
190
|
+
if not endpoint in WebEngine.ENDPOINTS:
|
|
191
|
+
WebEngine.ENDPOINTS[endpoint] = {}
|
|
192
|
+
WebEngine.ENDPOINTS[endpoint][method] = callback
|
|
193
|
+
return
|
|
179
194
|
# AUTO ENABLE webui when register (endpoint) called and webui is False
|
|
180
|
-
if
|
|
195
|
+
if auto_enable:
|
|
181
196
|
from Config import cfgput
|
|
182
197
|
if cfgput('webui', True): # SET webui to True
|
|
183
198
|
from machine import reset
|
|
184
199
|
reset() # HARD RESET (REBOOT)
|
|
185
|
-
WebEngine.ENDPOINTS[endpoint] = callback
|
|
186
200
|
|
|
187
201
|
|
|
188
202
|
class ShellCli(Client, Shell):
|
|
@@ -245,7 +259,7 @@ class ShellCli(Client, Shell):
|
|
|
245
259
|
|
|
246
260
|
async def run_shell(self):
|
|
247
261
|
# Update server task output
|
|
248
|
-
Manager().
|
|
262
|
+
Manager().task_msg('server', ','.join(list(Client.ACTIVE_CLIS)))
|
|
249
263
|
# Init prompt
|
|
250
264
|
await self.a_send(self.prompt())
|
|
251
265
|
# Run async connection handling
|
micrOS/source/Shell.py
CHANGED
|
@@ -14,7 +14,7 @@ Designed by Marcell Ban aka BxNxM
|
|
|
14
14
|
from sys import modules
|
|
15
15
|
from machine import reset as hard_reset, soft_reset
|
|
16
16
|
from Config import cfgget, cfgput
|
|
17
|
-
from Files import ilist_fs
|
|
17
|
+
from Files import OSPath, ilist_fs, path_join
|
|
18
18
|
from Tasks import lm_exec
|
|
19
19
|
from Debug import syslog
|
|
20
20
|
|
|
@@ -25,7 +25,7 @@ from Debug import syslog
|
|
|
25
25
|
|
|
26
26
|
class Shell:
|
|
27
27
|
__slots__ = ['__devfid', '__auth_mode', '__hwuid', '__auth_ok', '__conf_mode']
|
|
28
|
-
MICROS_VERSION = '2.
|
|
28
|
+
MICROS_VERSION = '2.17.1-0'
|
|
29
29
|
|
|
30
30
|
def __init__(self):
|
|
31
31
|
"""
|
|
@@ -177,8 +177,8 @@ class Shell:
|
|
|
177
177
|
await self.a_send(" Postfix hints:")
|
|
178
178
|
await self.a_send(" ... &<x> - start one-shot task")
|
|
179
179
|
await self.a_send(" ... &&<x> - start periodic task, where <x>: delay ms [x min: 20ms]")
|
|
180
|
-
await self.a_send(" ... >>hostname - remote command execution (intercon)")
|
|
181
180
|
await self.a_send(" ... >json - request json formatted output")
|
|
181
|
+
await self.a_send(" ... >>hostname - remote command execution (intercon)")
|
|
182
182
|
await self.a_send(" help lm - list ALL available LoadModules")
|
|
183
183
|
if "lm" in str(msg_list):
|
|
184
184
|
return await Shell._show_lm_funcs(msg_obj=self.a_send)
|
|
@@ -257,6 +257,7 @@ class Shell:
|
|
|
257
257
|
Dump LM module with help function call - in case of [mpy] files
|
|
258
258
|
"""
|
|
259
259
|
async def _help(mods):
|
|
260
|
+
nonlocal mpath
|
|
260
261
|
for lm_path in mods:
|
|
261
262
|
lm_name = lm_path.replace('LM_', '').split('.')[0]
|
|
262
263
|
try:
|
|
@@ -264,7 +265,7 @@ class Shell:
|
|
|
264
265
|
if lm_path.endswith('.mpy'):
|
|
265
266
|
await msg_obj(f" {' ' * len(lm_path.replace('LM_', '').split('.')[0])}help")
|
|
266
267
|
continue
|
|
267
|
-
with open(lm_path, 'r') as f:
|
|
268
|
+
with open(path_join(mpath, lm_path), 'r') as f:
|
|
268
269
|
line = "micrOSisTheBest"
|
|
269
270
|
while line:
|
|
270
271
|
line = f.readline()
|
|
@@ -278,12 +279,14 @@ class Shell:
|
|
|
278
279
|
|
|
279
280
|
await msg_obj("")
|
|
280
281
|
# [1] list active modules (default in shell)
|
|
282
|
+
mpath = OSPath.MODULES
|
|
281
283
|
if active_only:
|
|
282
284
|
mod_keys = modules.keys()
|
|
283
|
-
active_modules = (dir_mod for dir_mod in ilist_fs(type_filter='f', select="LM")
|
|
285
|
+
active_modules = (dir_mod for dir_mod in ilist_fs(path=mpath, type_filter='f', select="LM")
|
|
286
|
+
if dir_mod.split('.')[0] in mod_keys)
|
|
284
287
|
return await _help(active_modules)
|
|
285
288
|
# [2] list all LMs on file system (ALL - help lm) - manual
|
|
286
|
-
return await _help(ilist_fs(type_filter='f', select="LM"))
|
|
289
|
+
return await _help(ilist_fs(path=mpath, type_filter='f', select="LM"))
|
|
287
290
|
|
|
288
291
|
@staticmethod
|
|
289
292
|
async def webrepl(msg_obj, update=False):
|
micrOS/source/Tasks.py
CHANGED
|
@@ -65,6 +65,17 @@ class TaskBase:
|
|
|
65
65
|
del TaskBase.TASKS[passive[i]]
|
|
66
66
|
collect() # GC collect
|
|
67
67
|
|
|
68
|
+
@staticmethod
|
|
69
|
+
async def feed(sleep_ms=1):
|
|
70
|
+
"""
|
|
71
|
+
Feed event loop
|
|
72
|
+
:param sleep_ms: in millisecond
|
|
73
|
+
"""
|
|
74
|
+
# TODO: feed WDT - preemptive cooperative multitasking aka reboot if no feed until X time period
|
|
75
|
+
if sleep_ms <= 0:
|
|
76
|
+
return await asyncio.sleep(0.000_000_1) # 0 means: 100ns (Absolute minimum)
|
|
77
|
+
return await asyncio.sleep_ms(sleep_ms)
|
|
78
|
+
|
|
68
79
|
def cancel(self) -> bool:
|
|
69
80
|
"""
|
|
70
81
|
Cancel task (+cleanup)
|
|
@@ -94,16 +105,16 @@ class TaskBase:
|
|
|
94
105
|
del TaskBase.TASKS[self.tag]
|
|
95
106
|
collect() # GC collect
|
|
96
107
|
|
|
97
|
-
|
|
98
|
-
async def feed(sleep_ms=1):
|
|
108
|
+
async def await_result(self, timeout:int=5):
|
|
99
109
|
"""
|
|
100
|
-
|
|
101
|
-
:param
|
|
110
|
+
Wait for task completion with timeout
|
|
111
|
+
:param timeout: in seconds
|
|
102
112
|
"""
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
113
|
+
try:
|
|
114
|
+
await asyncio.wait_for(self.done.wait(), timeout)
|
|
115
|
+
except asyncio.TimeoutError:
|
|
116
|
+
return "Timeout has beed exceeded"
|
|
117
|
+
return self.out
|
|
107
118
|
|
|
108
119
|
def __del__(self):
|
|
109
120
|
try:
|
|
@@ -404,11 +415,19 @@ class Manager:
|
|
|
404
415
|
asyncio.get_event_loop().close()
|
|
405
416
|
|
|
406
417
|
@staticmethod
|
|
407
|
-
def
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
418
|
+
def task_msg(tag:str, msg:str=None) -> bool|str:
|
|
419
|
+
"""
|
|
420
|
+
Set/Get task message (for server virtual task, etc.)
|
|
421
|
+
"""
|
|
422
|
+
_task = TaskBase.TASKS.get(tag, None)
|
|
423
|
+
if _task is None:
|
|
424
|
+
return False
|
|
425
|
+
# Get task output
|
|
426
|
+
if tag is None:
|
|
427
|
+
return _task.out
|
|
428
|
+
# Set task output
|
|
429
|
+
_task.out = msg
|
|
430
|
+
return True
|
|
412
431
|
|
|
413
432
|
|
|
414
433
|
#################################################################
|
|
@@ -467,6 +486,8 @@ def exec_builtins(func):
|
|
|
467
486
|
|
|
468
487
|
# Call the decorated function with the additional flag
|
|
469
488
|
return func(arg_list, json_flag)
|
|
489
|
+
return False, None
|
|
490
|
+
|
|
470
491
|
return wrapper
|
|
471
492
|
|
|
472
493
|
|
micrOS/source/Web.py
CHANGED
|
@@ -9,7 +9,7 @@ Built-in-function:
|
|
|
9
9
|
- "virtual" endpoints - to reply from script on a defined endpoint
|
|
10
10
|
- stream - stream data (jpeg) function
|
|
11
11
|
|
|
12
|
-
Designed by Marcell Ban aka BxNxM
|
|
12
|
+
Designed by Marcell Ban aka BxNxM and szeka9 (GitHub)
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
from json import dumps, loads
|
|
@@ -18,6 +18,10 @@ from Tasks import lm_exec, NativeTask, lm_is_loaded
|
|
|
18
18
|
from Debug import syslog, console_write
|
|
19
19
|
from Config import cfgget
|
|
20
20
|
from Files import OSPath, path_join
|
|
21
|
+
try:
|
|
22
|
+
from gc import mem_free, collect
|
|
23
|
+
except:
|
|
24
|
+
from simgc import mem_free, collect # simulator mode
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
class WebEngine:
|
|
@@ -36,13 +40,18 @@ class WebEngine:
|
|
|
36
40
|
"jpeg": "image/jpeg",
|
|
37
41
|
"png": "image/png",
|
|
38
42
|
"gif": "image/gif"}
|
|
43
|
+
METHODS = ("GET", "POST")
|
|
44
|
+
MEM_LIMITED = (None, 0)
|
|
39
45
|
|
|
40
46
|
def __init__(self, client, version):
|
|
41
47
|
self.client = client
|
|
42
48
|
WebEngine.VERSION = version
|
|
43
49
|
|
|
50
|
+
async def a_send(self, response:str, encode:str='utf8'):
|
|
51
|
+
raise NotImplementedError("Child class must implement a_send coroutine.")
|
|
52
|
+
|
|
44
53
|
@staticmethod
|
|
45
|
-
def file_type(path):
|
|
54
|
+
def file_type(path:str):
|
|
46
55
|
"""File dynamic Content-Type handling"""
|
|
47
56
|
default_type = "text/plain"
|
|
48
57
|
# Extract the file extension
|
|
@@ -50,58 +59,78 @@ class WebEngine:
|
|
|
50
59
|
# Return the content type based on the file extension
|
|
51
60
|
return WebEngine.CONTENT_TYPES.get(ext, default_type)
|
|
52
61
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
@staticmethod
|
|
63
|
+
def is_mem_limited() -> (bool, int):
|
|
64
|
+
"""Check if memory is limited for the FE"""
|
|
65
|
+
if WebEngine.MEM_LIMITED[0] is None:
|
|
66
|
+
collect()
|
|
67
|
+
mfree = int(mem_free() * 0.001)
|
|
68
|
+
WebEngine.MEM_LIMITED = (mfree < 50, mfree) # 50 kb memory requirement
|
|
69
|
+
return WebEngine.MEM_LIMITED
|
|
70
|
+
|
|
71
|
+
async def response(self, request:str) -> bool:
|
|
72
|
+
"""HTTP GET/POST REQUEST - WEB INTERFACE"""
|
|
73
|
+
# [0] PROTOCOL VALIDATION AND PARSING
|
|
74
|
+
lines = request.splitlines()
|
|
75
|
+
if not lines:
|
|
76
|
+
_err = "Empty request"
|
|
77
|
+
await self.a_send(self.REQ400.format(len=len(_err), data=_err))
|
|
78
|
+
return True
|
|
79
|
+
request_parts = lines[0].split()
|
|
80
|
+
if len(request_parts) != 3:
|
|
81
|
+
if request_parts[0] not in self.METHODS:
|
|
82
|
+
# INVALID REQUEST - REQUEST OVERFLOW - NO RESPONSE
|
|
83
|
+
syslog(f"[WARN] WebCli REQ Overflow: {len(lines[0])}")
|
|
84
|
+
return False # Close connection...
|
|
85
|
+
_err = "Malformed request line"
|
|
86
|
+
await self.a_send(self.REQ400.format(len=len(_err), data=_err))
|
|
87
|
+
return True
|
|
88
|
+
_method, url, _version = request_parts
|
|
89
|
+
if _method not in self.METHODS or not _version.startswith('HTTP/'):
|
|
90
|
+
_err = f"Unsupported method: {_method} {_version}"
|
|
91
|
+
await self.a_send(self.REQ400.format(len=len(_err), data=_err))
|
|
92
|
+
return True
|
|
62
93
|
|
|
63
94
|
# [1] REST API GET ENDPOINT [/rest]
|
|
64
|
-
if url.startswith('/rest'):
|
|
95
|
+
if url.startswith('/rest') and _method == "GET":
|
|
65
96
|
self.client.console("[WebCli] --- /rest ACCEPT")
|
|
66
97
|
try:
|
|
67
98
|
await self.client.a_send(WebEngine.rest(url))
|
|
68
99
|
except Exception as e:
|
|
69
100
|
await self.client.a_send(self.REQ404.format(len=len(str(e)), data=e))
|
|
70
|
-
return
|
|
101
|
+
return True
|
|
71
102
|
# [2] DYNAMIC/USER ENDPOINTS (from Load Modules)
|
|
72
|
-
if
|
|
73
|
-
|
|
103
|
+
payload = lines if _method == "POST" else []
|
|
104
|
+
if await self.endpoints(url, _method, payload):
|
|
105
|
+
return True
|
|
106
|
+
mem_limited, free = self.is_mem_limited()
|
|
107
|
+
if mem_limited:
|
|
108
|
+
_err = f"Low memory ({free} kb): serving API only."
|
|
109
|
+
await self.a_send(self.REQ400.format(len=len(_err), data=_err))
|
|
110
|
+
return True
|
|
74
111
|
# [3] HOME/PAGE ENDPOINT(s) [default: / -> /index.html]
|
|
75
|
-
if url.startswith('/'):
|
|
112
|
+
if url.startswith('/') and _method == "GET":
|
|
76
113
|
resource = 'index.html' if url == '/' else url.replace('/', '')
|
|
77
114
|
web_resource = path_join(OSPath.WEB, resource) # Redirect path to web folder
|
|
78
115
|
self.client.console(f"[WebCli] --- {url} ACCEPT -> {web_resource}")
|
|
79
116
|
if resource.split('.')[-1] not in tuple(self.CONTENT_TYPES.keys()):
|
|
80
117
|
await self.client.a_send(self.REQ404.format(len=27, data='404 Not supported file type'))
|
|
81
|
-
return
|
|
118
|
+
return True
|
|
82
119
|
try:
|
|
83
120
|
# SEND RESOURCE CONTENT: HTML, JS, CSS (WebEngine.CONTENT_TYPES)
|
|
84
121
|
with open(web_resource, 'r') as file:
|
|
85
122
|
data = file.read()
|
|
86
123
|
response = self.REQ200.format(dtype=WebEngine.file_type(resource), len=len(data), data=data)
|
|
87
|
-
# Send entire response data
|
|
124
|
+
# Send entire response data (implement chunking if necessary)
|
|
88
125
|
await self.client.a_send(response)
|
|
89
|
-
|
|
90
|
-
# Send chunks of response data (experimental)
|
|
91
|
-
#response_len, chunk_size, position = len(response), 300, 0
|
|
92
|
-
#while position < response_len:
|
|
93
|
-
# # Calculate the size of the next chunk
|
|
94
|
-
# next_chunk_size = min(chunk_size, response_len - position)
|
|
95
|
-
# chunk = response[position:position + next_chunk_size]
|
|
96
|
-
# await self.client.a_send(chunk)
|
|
97
|
-
# position += next_chunk_size
|
|
98
126
|
except Exception as e:
|
|
99
127
|
if 'memory allocation failed' in str(e):
|
|
100
128
|
syslog(f"[ERR] WebCli {resource}: {e}")
|
|
101
129
|
await self.client.a_send(self.REQ404.format(len=13, data='404 Not Found'))
|
|
102
|
-
return
|
|
130
|
+
return True
|
|
103
131
|
# INVALID/BAD REQUEST
|
|
104
132
|
await self.client.a_send(self.REQ400.format(len=15, data='400 Bad Request'))
|
|
133
|
+
return True
|
|
105
134
|
|
|
106
135
|
@staticmethod
|
|
107
136
|
def rest(url):
|
|
@@ -130,9 +159,9 @@ class WebEngine:
|
|
|
130
159
|
response = dumps(resp_schema)
|
|
131
160
|
return WebEngine.REQ200.format(dtype='text/html', len=len(response), data=response)
|
|
132
161
|
|
|
133
|
-
async def endpoints(self, url):
|
|
162
|
+
async def endpoints(self, url:str, method:str, payload:list):
|
|
134
163
|
url = url[1:] # Cut first / char
|
|
135
|
-
if url in WebEngine.ENDPOINTS:
|
|
164
|
+
if url in WebEngine.ENDPOINTS and method in WebEngine.ENDPOINTS[url]:
|
|
136
165
|
console_write(f"[WebCli] endpoint: {url}")
|
|
137
166
|
# Registered endpoint was found - exec callback
|
|
138
167
|
try:
|
|
@@ -141,7 +170,16 @@ class WebEngine:
|
|
|
141
170
|
# one-shot (simple MIME types): image/jpeg | text/html | text/plain - data: raw
|
|
142
171
|
# task (streaming MIME types): multipart/x-mixed-replace | multipart/form-data - data: dict{callback,content-type}
|
|
143
172
|
# content-type: image/jpeg | audio/l16;*
|
|
144
|
-
|
|
173
|
+
if method == "POST":
|
|
174
|
+
try:
|
|
175
|
+
blank_index = payload.index("")
|
|
176
|
+
body_lines = payload[blank_index + 1:]
|
|
177
|
+
except ValueError:
|
|
178
|
+
body_lines = []
|
|
179
|
+
dtype, data = WebEngine.ENDPOINTS[url][method]("\n".join(body_lines))
|
|
180
|
+
else:
|
|
181
|
+
dtype, data = WebEngine.ENDPOINTS[url][method]()
|
|
182
|
+
|
|
145
183
|
if dtype == 'image/jpeg':
|
|
146
184
|
resp = f"HTTP/1.1 200 OK\r\nContent-Type: {dtype}\r\nContent-Length:{len(data)}\r\n\r\n".encode('utf8') + data
|
|
147
185
|
await self.client.a_send(resp, encode=None)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
micrOS/source/micrOS.py
CHANGED
|
@@ -4,6 +4,13 @@ dedicated to micrOS framework.
|
|
|
4
4
|
|
|
5
5
|
Designed by Marcell Ban aka BxNxM
|
|
6
6
|
"""
|
|
7
|
+
|
|
8
|
+
#################################################################
|
|
9
|
+
# INIT FS #
|
|
10
|
+
#################################################################
|
|
11
|
+
from Files import init_micros_dirs
|
|
12
|
+
init_micros_dirs()
|
|
13
|
+
|
|
7
14
|
#################################################################
|
|
8
15
|
# IMPORTS #
|
|
9
16
|
#################################################################
|
micrOS/source/micrOSloader.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Module is responsible for invoke micrOS or recovery webrepl mode
|
|
3
|
+
[IMPORTANT] This module must never use any micrOS specific functions in main scope.
|
|
3
4
|
|
|
4
5
|
Designed by Marcell Ban aka BxNxM
|
|
5
6
|
"""
|
|
@@ -11,11 +12,6 @@ try:
|
|
|
11
12
|
import traceback
|
|
12
13
|
except:
|
|
13
14
|
traceback = None
|
|
14
|
-
try:
|
|
15
|
-
from Debug import syslog
|
|
16
|
-
except Exception as e:
|
|
17
|
-
print(f"[loader] Import error: {e}")
|
|
18
|
-
syslog = None
|
|
19
15
|
from machine import reset
|
|
20
16
|
|
|
21
17
|
|
|
@@ -59,6 +55,8 @@ def _is_micrOS():
|
|
|
59
55
|
|
|
60
56
|
def __recovery_mode():
|
|
61
57
|
# Recovery/Update mode (webrepl) - dependencies: Network, ConfigHandler
|
|
58
|
+
from sys import path
|
|
59
|
+
path.insert(0, "/modules")
|
|
62
60
|
from Network import auto_nw_config
|
|
63
61
|
from Config import cfgget
|
|
64
62
|
pwd = cfgget('appwd') # Get pwd from config
|
|
@@ -70,9 +68,7 @@ def __recovery_mode():
|
|
|
70
68
|
import webrepl
|
|
71
69
|
webrepl.start(password=pwd)
|
|
72
70
|
except Exception as e:
|
|
73
|
-
|
|
74
|
-
syslog(f"[ERR][micrOSloader] webrepl failed: {e}")
|
|
75
|
-
print("[loader] Reset .if_mode to micros and reboot")
|
|
71
|
+
print(f"[loader] webrepl failed: {e} - Reset .if_mode to micros and reboot")
|
|
76
72
|
with open('.if_mode', 'w') as f:
|
|
77
73
|
f.write("micros")
|
|
78
74
|
# Reboot machine
|
|
@@ -126,8 +122,6 @@ def main():
|
|
|
126
122
|
# Handle micrOS system crash (never happened...but) -> webrepl mode default pwd: ADmin123
|
|
127
123
|
print(f"[loader][main mode] micrOS start failed: {e}")
|
|
128
124
|
print("[loader][main mode] -> [recovery mode]")
|
|
129
|
-
if callable(syslog):
|
|
130
|
-
syslog(f"[ERR][micrOSloader] start failed: {e}")
|
|
131
125
|
# Recovery aka webrepl mode
|
|
132
126
|
__recovery_mode()
|
|
133
127
|
__auto_restart_event()
|
micrOS/source/microIO.py
CHANGED
|
@@ -11,7 +11,7 @@ Designed by Marcell Ban aka BxNxM
|
|
|
11
11
|
#################################################################
|
|
12
12
|
from sys import platform
|
|
13
13
|
from uos import uname
|
|
14
|
-
from Files import ilist_fs
|
|
14
|
+
from Files import ilist_fs, OSPath
|
|
15
15
|
from Logger import syslog
|
|
16
16
|
|
|
17
17
|
#################################################################
|
|
@@ -68,7 +68,7 @@ def set_pinmap(map_data=None):
|
|
|
68
68
|
|
|
69
69
|
# SELECT LOOKUP TABLE BASED ON PLATFORM / User input
|
|
70
70
|
if isinstance(io_file, str) and io_file != 'n/a':
|
|
71
|
-
if f"IO_{io_file}" in [io.split('.')[0] for io in ilist_fs(type_filter='f', select="IO")]:
|
|
71
|
+
if f"IO_{io_file}" in [io.split('.')[0] for io in ilist_fs(OSPath.MODULES, type_filter='f', select="IO")]:
|
|
72
72
|
PinMap.MAPPING_LUT = io_file
|
|
73
73
|
return PinMap.MAPPING_LUT
|
|
74
74
|
PinMap.MAPPING_LUT = detect_platform()
|