micrOSDevToolKit 2.10.6__py3-none-any.whl → 2.13.0__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.
- env/driver_cp210x/macOS_VCP_Driver/SiLabsUSBDriverDisk.dmg +0 -0
- env/driver_cp210x/macOS_VCP_Driver/macOS_VCP_Driver_Release_Notes.txt +17 -1
- micrOS/micropython/esp32c6-GENERIC-20250415-v1.25.0.bin +0 -0
- micrOS/micropython/esp32s3-4MBflash-20241129-v1.24.1.bin +0 -0
- micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +57 -61
- micrOS/source/Common.py +286 -91
- micrOS/source/Config.py +7 -7
- micrOS/source/Debug.py +50 -94
- micrOS/source/Espnow.py +7 -7
- micrOS/source/Files.py +23 -2
- micrOS/source/Hooks.py +62 -19
- micrOS/source/IO_esp32c6.py +16 -0
- micrOS/source/IO_esp32s3.py +37 -1
- micrOS/source/IO_m5stamp.py +35 -1
- micrOS/source/IO_qtpy.py +22 -17
- micrOS/source/IO_s3matrix.py +21 -0
- micrOS/source/IO_tinypico.py +38 -0
- micrOS/source/InterConnect.py +5 -5
- micrOS/source/Interrupts.py +2 -2
- micrOS/source/LM_VL53L0X.py +1 -1
- micrOS/source/LM_buzzer.py +6 -7
- micrOS/source/LM_cct.py +6 -5
- micrOS/source/LM_dashboard_be.py +2 -2
- micrOS/source/LM_dimmer.py +6 -5
- micrOS/source/LM_espnow.py +15 -10
- micrOS/source/LM_i2c.py +3 -2
- micrOS/source/LM_neoeffects.py +173 -230
- micrOS/source/LM_neomatrix.py +335 -0
- micrOS/source/LM_neopixel.py +10 -10
- micrOS/source/LM_pacman.py +40 -23
- micrOS/source/LM_qmi8658.py +204 -0
- micrOS/source/LM_rgb.py +6 -6
- micrOS/source/LM_roboarm.py +5 -4
- micrOS/source/LM_switch.py +6 -4
- micrOS/source/LM_tcs3472.py +75 -0
- micrOS/source/LM_telegram.py +5 -4
- micrOS/source/Logger.py +47 -33
- micrOS/source/Network.py +6 -6
- micrOS/source/Notify.py +2 -2
- micrOS/source/Scheduler.py +5 -5
- micrOS/source/Server.py +6 -6
- micrOS/source/Shell.py +4 -4
- micrOS/source/Tasks.py +20 -17
- micrOS/source/Time.py +12 -10
- micrOS/source/Types.py +2 -2
- micrOS/source/Web.py +20 -13
- micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
- micrOS/source/__pycache__/Debug.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/micrOS.py +10 -7
- micrOS/source/micrOSloader.py +6 -6
- micrOS/source/microIO.py +8 -6
- micrOS/source/urequests.py +4 -4
- {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/METADATA +24 -22
- {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/RECORD +142 -132
- toolkit/DevEnvCompile.py +20 -15
- toolkit/DevEnvOTA.py +29 -8
- toolkit/DevEnvUSB.py +52 -10
- toolkit/LM_to_compile.dat +1 -0
- toolkit/MicrOSDevEnv.py +10 -2
- toolkit/MicrosFiles.py +26 -0
- toolkit/dashboard_apps/NeoEffectsDemo.py +8 -15
- toolkit/dashboard_apps/QMI8685_GYRO.py +68 -0
- toolkit/dashboard_apps/_app_base.py +2 -2
- toolkit/dashboard_apps/_gyro_visualizer.py +78 -0
- toolkit/lib/LocalMachine.py +6 -1
- toolkit/lib/file_extensions.py +9 -3
- toolkit/micrOSlint.py +3 -1
- toolkit/simulator_lib/__pycache__/IO_darwin.cpython-312.pyc +0 -0
- toolkit/simulator_lib/__pycache__/machine.cpython-312.pyc +0 -0
- toolkit/simulator_lib/__pycache__/neopixel.cpython-312.pyc +0 -0
- toolkit/simulator_lib/machine.py +0 -1
- toolkit/simulator_lib/neopixel.py +3 -2
- toolkit/socketClient.py +3 -2
- toolkit/workspace/precompiled/Common.cpython-312.pyc +0 -0
- toolkit/workspace/precompiled/Common.mpy +0 -0
- toolkit/workspace/precompiled/Config.mpy +0 -0
- toolkit/workspace/precompiled/Debug.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/IO_esp32c6.mpy +0 -0
- toolkit/workspace/precompiled/IO_esp32s3.mpy +0 -0
- toolkit/workspace/precompiled/IO_m5stamp.mpy +0 -0
- toolkit/workspace/precompiled/IO_qtpy.mpy +0 -0
- toolkit/workspace/precompiled/IO_s3matrix.mpy +0 -0
- toolkit/workspace/precompiled/IO_tinypico.mpy +0 -0
- toolkit/workspace/precompiled/InterConnect.mpy +0 -0
- toolkit/workspace/precompiled/Interrupts.mpy +0 -0
- toolkit/workspace/precompiled/LM_VL53L0X.py +1 -1
- toolkit/workspace/precompiled/LM_buzzer.mpy +0 -0
- toolkit/workspace/precompiled/LM_cct.mpy +0 -0
- toolkit/workspace/precompiled/LM_dashboard_be.py +2 -2
- toolkit/workspace/precompiled/LM_dimmer.mpy +0 -0
- toolkit/workspace/precompiled/LM_espnow.py +15 -10
- toolkit/workspace/precompiled/LM_i2c.py +3 -2
- toolkit/workspace/precompiled/LM_neoeffects.mpy +0 -0
- toolkit/workspace/precompiled/LM_neomatrix.mpy +0 -0
- toolkit/workspace/precompiled/LM_neopixel.mpy +0 -0
- toolkit/workspace/precompiled/LM_pacman.mpy +0 -0
- toolkit/workspace/precompiled/LM_qmi8658.py +204 -0
- toolkit/workspace/precompiled/LM_rgb.mpy +0 -0
- toolkit/workspace/precompiled/LM_roboarm.mpy +0 -0
- toolkit/workspace/precompiled/LM_switch.mpy +0 -0
- toolkit/workspace/precompiled/LM_tcs3472.py +75 -0
- toolkit/workspace/precompiled/LM_telegram.mpy +0 -0
- toolkit/workspace/precompiled/Logger.cpython-312.pyc +0 -0
- toolkit/workspace/precompiled/Logger.mpy +0 -0
- toolkit/workspace/precompiled/Network.mpy +0 -0
- toolkit/workspace/precompiled/Notify.mpy +0 -0
- toolkit/workspace/precompiled/Scheduler.mpy +0 -0
- toolkit/workspace/precompiled/Server.cpython-312.pyc +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/Time.mpy +0 -0
- toolkit/workspace/precompiled/Types.mpy +0 -0
- toolkit/workspace/precompiled/Web.mpy +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/urequests.mpy +0 -0
- micrOS/micropython/esp32s3-20240105-v1.22.1.bin +0 -0
- micrOS/source/LM_catgame.py +0 -75
- micrOS/source/LM_demo.py +0 -97
- micrOS/source/LM_intercon.py +0 -60
- micrOS/source/LM_ph_sensor.py +0 -51
- toolkit/workspace/precompiled/LM_catgame.py +0 -75
- toolkit/workspace/precompiled/LM_demo.py +0 -97
- toolkit/workspace/precompiled/LM_intercon.mpy +0 -0
- toolkit/workspace/precompiled/LM_ph_sensor.py +0 -51
- /micrOS/micropython/{esp32s3-20241129-v1.24.1.bin → esp32s3-8MBflash-20241129-v1.24.1.bin} +0 -0
- /micrOS/source/{dashboard.html → web/dashboard.html} +0 -0
- /micrOS/source/{index.html → web/index.html} +0 -0
- /micrOS/source/{uapi.js → web/uapi.js} +0 -0
- /micrOS/source/{udashboard.js → web/udashboard.js} +0 -0
- /micrOS/source/{ustyle.css → web/ustyle.css} +0 -0
- /micrOS/source/{uwidgets.js → web/uwidgets.js} +0 -0
- /micrOS/source/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
- {microsdevtoolkit-2.10.6.data → microsdevtoolkit-2.13.0.data}/scripts/devToolKit.py +0 -0
- {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/WHEEL +0 -0
- {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/licenses/LICENSE +0 -0
- {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/top_level.txt +0 -0
- /toolkit/workspace/precompiled/{dashboard.html → web/dashboard.html} +0 -0
- /toolkit/workspace/precompiled/{index.html → web/index.html} +0 -0
- /toolkit/workspace/precompiled/{uapi.js → web/uapi.js} +0 -0
- /toolkit/workspace/precompiled/{udashboard.js → web/udashboard.js} +0 -0
- /toolkit/workspace/precompiled/{ustyle.css → web/ustyle.css} +0 -0
- /toolkit/workspace/precompiled/{uwidgets.js → web/uwidgets.js} +0 -0
- /toolkit/workspace/precompiled/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
micrOS/source/Common.py
CHANGED
|
@@ -3,94 +3,25 @@ micrOS Load Module programming Official API-s
|
|
|
3
3
|
Designed by Marcell Ban aka BxNxM
|
|
4
4
|
"""
|
|
5
5
|
from Server import Server, WebCli
|
|
6
|
-
from Debug import
|
|
6
|
+
from Debug import syslog as debug_syslog, console_write
|
|
7
7
|
from Logger import logger, log_get
|
|
8
|
+
from Files import OSPath, path_join
|
|
8
9
|
from microIO import resolve_pin
|
|
9
10
|
from Tasks import TaskBase, Manager, lm_exec
|
|
10
11
|
from machine import Pin, ADC
|
|
11
12
|
from Notify import Notify
|
|
12
13
|
|
|
13
|
-
################## Common LM features ##################
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
:param from_val: from value - start from
|
|
19
|
-
:param to_val: to value - target value
|
|
20
|
-
:param step_ms: step to reach to_val - timirq_seq
|
|
21
|
-
:param interval_sec: time of full interval
|
|
22
|
-
"""
|
|
23
|
-
if interval_sec > 0:
|
|
24
|
-
step_cnt = round((interval_sec*1000)/step_ms)
|
|
25
|
-
delta = abs((from_val-to_val)/step_cnt)
|
|
26
|
-
direc = -1 if from_val > to_val else 1
|
|
27
|
-
for cnt in range(0, step_cnt+1):
|
|
28
|
-
yield round(from_val + (cnt * delta) * direc)
|
|
29
|
-
else:
|
|
30
|
-
yield round(to_val)
|
|
15
|
+
#####################################################################################
|
|
16
|
+
# SYSTEM #
|
|
17
|
+
#####################################################################################
|
|
31
18
|
|
|
32
|
-
|
|
33
|
-
def transition_gen(*args, interval_sec=1.0):
|
|
34
|
-
"""
|
|
35
|
-
[LM] Multiple Generator for color/value transitions:
|
|
36
|
-
- calculate minimum step count -> step_ms
|
|
37
|
-
- autofill and use transition(from_val, to_val, step_ms, interval_sec)
|
|
38
|
-
:param args: ch1_from, ch1_to, ch2_from, ch2_to, etc...
|
|
39
|
-
:param interval_sec: interval in sec to calculate optimal fade/transition effect
|
|
40
|
-
return: gen, step_ms OR gen list, step_ms
|
|
19
|
+
def micro_task(tag:str, task=None):
|
|
41
20
|
"""
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
transitions = list((transition(args[ch_from_i], args[ch_from_i+1], step_ms, interval_sec) for ch_from_i in range(0, len(args)-1, 2)))
|
|
47
|
-
if len(transitions) == 1:
|
|
48
|
-
return transitions[0], step_ms
|
|
49
|
-
return list(transitions), step_ms
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class SmartADC:
|
|
53
|
-
"""
|
|
54
|
-
[LM] General ADC implementation for auto scaled output: raw, percent, volt
|
|
55
|
-
https://docs.micropython.org/en/latest/esp32/quickref.html#adc-analog-to-digital-conversion
|
|
56
|
-
ADC.ATTN_0DB: 0 dB attenuation, resulting in a full-scale voltage range of 0-1.1V
|
|
57
|
-
ADC.ATTN_2_5DB: 2.5 dB ... of 0-1.5V
|
|
58
|
-
ADC.ATTN_6DB: 6 dB ... of 0-2.2V
|
|
59
|
-
ADC.ATTN_11DB: 11 dB ... of 0-2450mV/
|
|
60
|
-
Note that the absolute maximum voltage rating for input pins is 3.6V. Going near to this boundary risks damage to the IC!
|
|
61
|
-
"""
|
|
62
|
-
OBJS = {}
|
|
63
|
-
|
|
64
|
-
def __init__(self, pin):
|
|
65
|
-
self.adp_prop = (65535, 2450) # raw value, 2450mV (so 2,45V)
|
|
66
|
-
self.adc = None
|
|
67
|
-
if not isinstance(pin, int):
|
|
68
|
-
pin = resolve_pin(pin)
|
|
69
|
-
self.adc = ADC(Pin(pin))
|
|
70
|
-
self.adc.atten(ADC.ATTN_11DB) # 2450mV measure range
|
|
71
|
-
|
|
72
|
-
def get(self):
|
|
73
|
-
raw = int((self.adc.read_u16() + self.adc.read_u16())/2) # 16-bit ADC value (0-65535)
|
|
74
|
-
percent = raw / self.adp_prop[0]
|
|
75
|
-
volt = round(percent * self.adp_prop[1] / 1000, 2) # devide with 1000 to get V from mV
|
|
76
|
-
return {'raw': raw, 'percent': round(percent*100, 1), 'volt': volt}
|
|
77
|
-
|
|
78
|
-
@staticmethod
|
|
79
|
-
def get_instance(pin):
|
|
80
|
-
if pin in SmartADC.OBJS.keys():
|
|
81
|
-
return SmartADC.OBJS[pin]
|
|
82
|
-
SmartADC.OBJS[pin] = SmartADC(pin)
|
|
83
|
-
return SmartADC.OBJS[pin]
|
|
84
|
-
|
|
85
|
-
################# micrOS feature interfaces #################
|
|
86
|
-
|
|
87
|
-
def micro_task(tag, task=None):
|
|
88
|
-
"""
|
|
89
|
-
[LM] Async task creation
|
|
90
|
-
:param tag:
|
|
91
|
-
[1] tag=None: return task generator object
|
|
92
|
-
[2] tag=taskID: return existing task object by tag
|
|
93
|
-
:param task: coroutine to execute (with built-in overload protection and lcm)
|
|
21
|
+
[LM] Async task manager.
|
|
22
|
+
:param tag: task tag string
|
|
23
|
+
:param task: coroutine (or list of command arguments) to contract a task with the given async task callback
|
|
24
|
+
return bool|callable
|
|
94
25
|
"""
|
|
95
26
|
if task is None:
|
|
96
27
|
# [1] Task is None -> Get task mode by tag
|
|
@@ -103,11 +34,11 @@ def micro_task(tag, task=None):
|
|
|
103
34
|
return None
|
|
104
35
|
# [3] Create task (not running) + task coroutine was provided
|
|
105
36
|
# RETURN task creation state - success (True) / fail (False)
|
|
106
|
-
state = Manager().create_task(callback=task, tag=tag)
|
|
37
|
+
state:bool = Manager().create_task(callback=task, tag=tag)
|
|
107
38
|
return state
|
|
108
39
|
|
|
109
40
|
|
|
110
|
-
def manage_task(tag, operation):
|
|
41
|
+
def manage_task(tag:str, operation:str):
|
|
111
42
|
"""
|
|
112
43
|
[LM] Async task management
|
|
113
44
|
:param tag: task tag
|
|
@@ -125,19 +56,15 @@ def manage_task(tag, operation):
|
|
|
125
56
|
raise Exception(f"Invalid operation: {operation}")
|
|
126
57
|
|
|
127
58
|
|
|
128
|
-
def exec_cmd(cmd:list, jsonify:bool=None, skip_check=
|
|
59
|
+
def exec_cmd(cmd:list, jsonify:bool=None, skip_check=None):
|
|
129
60
|
"""
|
|
130
61
|
[LM] Single (sync) LM execution
|
|
131
62
|
:param cmd: command string list, ex.: ['system', 'clock']
|
|
132
63
|
:param jsonify: request json output
|
|
133
|
-
:param skip_check:
|
|
64
|
+
:param skip_check: legacy (check was removed) - remove parameter
|
|
134
65
|
return state, output
|
|
135
66
|
"""
|
|
136
|
-
|
|
137
|
-
# Invalid type, must be list: <class list>" ...
|
|
138
|
-
if skip_check:
|
|
139
|
-
return lm_exec(cmd, jsonify=jsonify)
|
|
140
|
-
return lm_exec(cmd, jsonify=jsonify) if isinstance(cmd, list) else False, f"CMD {type(cmd)}, must be list!"
|
|
67
|
+
return lm_exec(cmd, jsonify=jsonify)
|
|
141
68
|
|
|
142
69
|
|
|
143
70
|
def notify(text=None) -> bool:
|
|
@@ -153,7 +80,7 @@ def notify(text=None) -> bool:
|
|
|
153
80
|
try:
|
|
154
81
|
out = Notify.notify(text)
|
|
155
82
|
except Exception as e:
|
|
156
|
-
|
|
83
|
+
debug_syslog(f"[ERR] Notify: {e}")
|
|
157
84
|
out = str(e)
|
|
158
85
|
if out is not None and (out.startswith('Sent') or out.endswith('disabled')):
|
|
159
86
|
return True
|
|
@@ -209,10 +136,278 @@ def data_logger(f_name, data=None, limit=12, msgobj=None):
|
|
|
209
136
|
|
|
210
137
|
|
|
211
138
|
def syslog(msg):
|
|
212
|
-
""" Wrapper of
|
|
213
|
-
return
|
|
139
|
+
""" Wrapper of debug_syslog """
|
|
140
|
+
return debug_syslog(f"{msg}")
|
|
214
141
|
|
|
215
142
|
|
|
216
143
|
def console(msg):
|
|
217
144
|
""" Wrapper of console_write """
|
|
218
145
|
return console_write(msg)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def data_dir(f_name=None):
|
|
149
|
+
"""
|
|
150
|
+
Access for data dir path
|
|
151
|
+
:param f_name: if given, returns full path, otherwise returns data dir root path
|
|
152
|
+
"""
|
|
153
|
+
root_path = OSPath.DATA
|
|
154
|
+
if f_name is None:
|
|
155
|
+
return root_path
|
|
156
|
+
return path_join(root_path, f_name)
|
|
157
|
+
|
|
158
|
+
def web_dir(f_name=None):
|
|
159
|
+
"""
|
|
160
|
+
Access for web dir path
|
|
161
|
+
:param f_name: if given, returns full path, otherwise returns web dir root path
|
|
162
|
+
"""
|
|
163
|
+
root_path = OSPath.WEB
|
|
164
|
+
if f_name is None:
|
|
165
|
+
return root_path
|
|
166
|
+
return path_join(root_path, f_name)
|
|
167
|
+
|
|
168
|
+
#####################################################################################
|
|
169
|
+
# CHANNEL: SIGNAL GENERATORS #
|
|
170
|
+
#####################################################################################
|
|
171
|
+
|
|
172
|
+
def transition(from_val, to_val, step_ms, interval_sec):
|
|
173
|
+
"""
|
|
174
|
+
[LM] Single Generator for color/value transition:
|
|
175
|
+
:param from_val: from value - start from
|
|
176
|
+
:param to_val: to value - target value
|
|
177
|
+
:param step_ms: step to reach to_val - timirq_seq
|
|
178
|
+
:param interval_sec: time of full interval
|
|
179
|
+
"""
|
|
180
|
+
if interval_sec > 0:
|
|
181
|
+
step_cnt = round((interval_sec*1000)/step_ms)
|
|
182
|
+
delta = abs((from_val-to_val)/step_cnt)
|
|
183
|
+
direc = -1 if from_val > to_val else 1
|
|
184
|
+
for cnt in range(0, step_cnt+1):
|
|
185
|
+
yield round(from_val + (cnt * delta) * direc)
|
|
186
|
+
else:
|
|
187
|
+
yield round(to_val)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def transition_gen(*args, interval_sec=1.0):
|
|
191
|
+
"""
|
|
192
|
+
[LM] Multiple Generator for color/value transitions:
|
|
193
|
+
- calculate minimum step count -> step_ms
|
|
194
|
+
- autofill and use transition(from_val, to_val, step_ms, interval_sec)
|
|
195
|
+
:param args: ch1_from, ch1_to, ch2_from, ch2_to, etc...
|
|
196
|
+
:param interval_sec: interval in sec to calculate optimal fade/transition effect
|
|
197
|
+
return: gen, step_ms OR gen list, step_ms
|
|
198
|
+
"""
|
|
199
|
+
step_ms_min = 5 # min calculated step is 5 ms - good enough
|
|
200
|
+
delta = max((abs(args[ch_from_i] - args[ch_from_i+1]) for ch_from_i in range(0, len(args)-1, 2)))
|
|
201
|
+
step_ms = 0 if delta == 0 else int(interval_sec*1000 / delta)
|
|
202
|
+
step_ms = step_ms_min if step_ms < step_ms_min else step_ms
|
|
203
|
+
transitions = list((transition(args[ch_from_i], args[ch_from_i+1], step_ms, interval_sec) for ch_from_i in range(0, len(args)-1, 2)))
|
|
204
|
+
if len(transitions) == 1:
|
|
205
|
+
return transitions[0], step_ms
|
|
206
|
+
return list(transitions), step_ms
|
|
207
|
+
|
|
208
|
+
#####################################################################################
|
|
209
|
+
# EXTRAS #
|
|
210
|
+
#####################################################################################
|
|
211
|
+
|
|
212
|
+
class SmartADC:
|
|
213
|
+
"""
|
|
214
|
+
[LM] General ADC implementation for auto scaled output: raw, percent, volt
|
|
215
|
+
https://docs.micropython.org/en/latest/esp32/quickref.html#adc-analog-to-digital-conversion
|
|
216
|
+
ADC.ATTN_0DB: 0 dB attenuation, resulting in a full-scale voltage range of 0-1.1V
|
|
217
|
+
ADC.ATTN_2_5DB: 2.5 dB ... of 0-1.5V
|
|
218
|
+
ADC.ATTN_6DB: 6 dB ... of 0-2.2V
|
|
219
|
+
ADC.ATTN_11DB: 11 dB ... of 0-2450mV/
|
|
220
|
+
Note that the absolute maximum voltage rating for input pins is 3.6V. Going near to this boundary risks damage to the IC!
|
|
221
|
+
"""
|
|
222
|
+
OBJS = {}
|
|
223
|
+
|
|
224
|
+
def __init__(self, pin):
|
|
225
|
+
self.adp_prop = (65535, 2450) # raw value, 2450mV (so 2,45V)
|
|
226
|
+
self.adc = None
|
|
227
|
+
if not isinstance(pin, int):
|
|
228
|
+
pin = resolve_pin(pin)
|
|
229
|
+
self.adc = ADC(Pin(pin))
|
|
230
|
+
self.adc.atten(ADC.ATTN_11DB) # 2450mV measure range
|
|
231
|
+
|
|
232
|
+
def get(self):
|
|
233
|
+
raw = int((self.adc.read_u16() + self.adc.read_u16())/2) # 16-bit ADC value (0-65535)
|
|
234
|
+
percent = raw / self.adp_prop[0]
|
|
235
|
+
volt = round(percent * self.adp_prop[1] / 1000, 2) # devide with 1000 to get V from mV
|
|
236
|
+
return {'raw': raw, 'percent': round(percent*100, 1), 'volt': volt}
|
|
237
|
+
|
|
238
|
+
@staticmethod
|
|
239
|
+
def get_instance(pin):
|
|
240
|
+
if pin in SmartADC.OBJS.keys():
|
|
241
|
+
return SmartADC.OBJS[pin]
|
|
242
|
+
SmartADC.OBJS[pin] = SmartADC(pin)
|
|
243
|
+
return SmartADC.OBJS[pin]
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class AnimationPlayer:
|
|
247
|
+
"""
|
|
248
|
+
Generic async animation (generator) player.
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
def __init__(self, animation:callable=None, tag:str=None, batch_draw:bool=False, batch_size:int=None, loop:bool=True):
|
|
252
|
+
"""
|
|
253
|
+
Initialize the AnimationPlayer with an optional animation.
|
|
254
|
+
:param animation: Function to GENERATE animation data
|
|
255
|
+
:param tag: Optional task tag for micro_task management.
|
|
256
|
+
:param batch_draw: If True - draw in batches
|
|
257
|
+
:param batch_size: Number of pixels per batch when drawing
|
|
258
|
+
:param loop: If True - loop the animation (default)
|
|
259
|
+
"""
|
|
260
|
+
self.animation:callable = None
|
|
261
|
+
self.batch_draw:bool = batch_draw
|
|
262
|
+
self.__max_batch_size:int = 256 # MAX BATCH SIZE - ASYNC PROTECTION
|
|
263
|
+
self.__batch_size:int = 8 # Default batch size: 8
|
|
264
|
+
self.__loop:bool = loop # Loop the animation (generator)
|
|
265
|
+
self._set_batch_size(batch_size) # Set batch size from parameter
|
|
266
|
+
self._player_speed_ms:int = 10 # Default speed in ms between frames
|
|
267
|
+
main_tag:str = tag if tag else "animation"
|
|
268
|
+
self._task_tag:str = f"{main_tag}.player"
|
|
269
|
+
if animation is not None and not self._set_animation(animation):
|
|
270
|
+
raise Exception("Invalid animation function provided.")
|
|
271
|
+
self.__running:bool = True
|
|
272
|
+
|
|
273
|
+
def _set_animation(self, animation:callable) -> bool:
|
|
274
|
+
"""
|
|
275
|
+
Setter to change/set current animation.
|
|
276
|
+
"""
|
|
277
|
+
if callable(animation):
|
|
278
|
+
self.animation = animation
|
|
279
|
+
return True
|
|
280
|
+
return False
|
|
281
|
+
|
|
282
|
+
def _set_batch_size(self, batch_size:int) -> None:
|
|
283
|
+
"""
|
|
284
|
+
Setter to change/set batch size.
|
|
285
|
+
- with max batch size check (due to async event loop feeding)
|
|
286
|
+
"""
|
|
287
|
+
if batch_size is None:
|
|
288
|
+
return
|
|
289
|
+
self.__batch_size = max(0, min(batch_size, self.__max_batch_size))
|
|
290
|
+
|
|
291
|
+
async def _render(self, my_task):
|
|
292
|
+
# Cache methods for speed
|
|
293
|
+
clear = self.clear
|
|
294
|
+
update = self.update
|
|
295
|
+
draw = self.draw
|
|
296
|
+
# Cache the current animation for comparison
|
|
297
|
+
current_animation = self.animation
|
|
298
|
+
frame_counter = 0
|
|
299
|
+
# Clear the display before each frame
|
|
300
|
+
if not self.batch_draw:
|
|
301
|
+
clear()
|
|
302
|
+
for data in self.animation():
|
|
303
|
+
# Check if animation has changed under the loop
|
|
304
|
+
if not self.__running or self.animation != current_animation:
|
|
305
|
+
# Animation changed — break — clean and restart animation loop.
|
|
306
|
+
clear()
|
|
307
|
+
break
|
|
308
|
+
# Update data cache
|
|
309
|
+
update(*data)
|
|
310
|
+
if self.batch_draw:
|
|
311
|
+
# Batched draw mode
|
|
312
|
+
frame_counter += 1
|
|
313
|
+
if frame_counter >= self.__batch_size:
|
|
314
|
+
draw()
|
|
315
|
+
frame_counter = 0
|
|
316
|
+
await my_task.feed(sleep_ms=self._player_speed_ms)
|
|
317
|
+
else:
|
|
318
|
+
# Real-time draw mode
|
|
319
|
+
draw()
|
|
320
|
+
await my_task.feed(sleep_ms=self._player_speed_ms)
|
|
321
|
+
|
|
322
|
+
async def _player(self):
|
|
323
|
+
"""
|
|
324
|
+
Async task to play the current animation.
|
|
325
|
+
"""
|
|
326
|
+
with micro_task(tag=self._task_tag) as my_task:
|
|
327
|
+
while self.__running:
|
|
328
|
+
my_task.out = f"Play {self.animation.__name__} ({self._player_speed_ms}ms/frame)"
|
|
329
|
+
try:
|
|
330
|
+
await self._render(my_task)
|
|
331
|
+
except IndexError:
|
|
332
|
+
# Draw after generator exhausted and Restart animation if IndexError occurs
|
|
333
|
+
self.draw()
|
|
334
|
+
if not self.__loop:
|
|
335
|
+
break
|
|
336
|
+
await my_task.feed(sleep_ms=self._player_speed_ms)
|
|
337
|
+
my_task.out = "Restart animation"
|
|
338
|
+
except Exception as e:
|
|
339
|
+
my_task.out = f"Error: {e}"
|
|
340
|
+
break
|
|
341
|
+
my_task.out = f"Animation stopped...{my_task.out}"
|
|
342
|
+
|
|
343
|
+
def control(self, play_speed_ms:int, bt_draw:bool=None, bt_size:int=None, loop:bool=None):
|
|
344
|
+
"""
|
|
345
|
+
Set/Get current play speed of the animation.
|
|
346
|
+
:param play_speed_ms: player loop speed in milliseconds.
|
|
347
|
+
:param bt_draw: batch drawing flag.
|
|
348
|
+
:param bt_size: batch drawing size.
|
|
349
|
+
:param loop: loop flag.
|
|
350
|
+
"""
|
|
351
|
+
if isinstance(play_speed_ms, int):
|
|
352
|
+
self._player_speed_ms = max(0, min(10000, int(play_speed_ms)))
|
|
353
|
+
if isinstance(bt_draw, bool):
|
|
354
|
+
self.batch_draw = bt_draw
|
|
355
|
+
if isinstance(bt_size, int):
|
|
356
|
+
self._set_batch_size(bt_size)
|
|
357
|
+
if isinstance(loop, bool):
|
|
358
|
+
self.__loop = loop
|
|
359
|
+
return {"realtime": not self.batch_draw, "batched": self.batch_draw,
|
|
360
|
+
"size": self.__batch_size, "speed_ms": self._player_speed_ms,
|
|
361
|
+
"loop": self.__loop}
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def play(self, animation=None, speed_ms=None, bt_draw=False, bt_size=None, loop=True):
|
|
365
|
+
"""
|
|
366
|
+
Play animation via generator function.
|
|
367
|
+
:param animation: Animation generator function.
|
|
368
|
+
:param speed_ms: Speed of the animation in milliseconds. (min.: 3ms)
|
|
369
|
+
:param bt_draw: batch drawing flag.
|
|
370
|
+
:param bt_size: batch drawing size.
|
|
371
|
+
:param loop: Loop the animation.
|
|
372
|
+
:return: Player settings.
|
|
373
|
+
"""
|
|
374
|
+
|
|
375
|
+
if animation is not None:
|
|
376
|
+
if not self._set_animation(animation):
|
|
377
|
+
return "Invalid animation"
|
|
378
|
+
if self.animation is None:
|
|
379
|
+
return "No animation to play"
|
|
380
|
+
# Handle player settings
|
|
381
|
+
settings = self.control(play_speed_ms=speed_ms, bt_draw=bt_draw, bt_size=bt_size, loop=loop)
|
|
382
|
+
# Ensure async loop set up correctly. (After stop operation, it is needed)
|
|
383
|
+
self.__running = True
|
|
384
|
+
# [!] ASYNC TASK CREATION
|
|
385
|
+
raw_state:bool = micro_task(tag=self._task_tag, task=self._player())
|
|
386
|
+
state = "starting" if raw_state else "running"
|
|
387
|
+
settings["state"] = state
|
|
388
|
+
return settings
|
|
389
|
+
|
|
390
|
+
def stop(self):
|
|
391
|
+
"""
|
|
392
|
+
Stop the animation.
|
|
393
|
+
"""
|
|
394
|
+
self.__running = False
|
|
395
|
+
return "Stop animation player"
|
|
396
|
+
|
|
397
|
+
def update(self, *arg, **kwargs):
|
|
398
|
+
"""
|
|
399
|
+
Child class must implement this method to handle drawing logic.
|
|
400
|
+
"""
|
|
401
|
+
raise NotImplementedError("Child class must implement update method.")
|
|
402
|
+
|
|
403
|
+
def draw(self):
|
|
404
|
+
"""
|
|
405
|
+
Draw the current frame.
|
|
406
|
+
"""
|
|
407
|
+
raise NotImplementedError("Child class must implement draw method.")
|
|
408
|
+
|
|
409
|
+
def clear(self):
|
|
410
|
+
"""
|
|
411
|
+
Clear the display.
|
|
412
|
+
"""
|
|
413
|
+
raise NotImplementedError("Child class must implement clear method.")
|
micrOS/source/Config.py
CHANGED
|
@@ -16,11 +16,11 @@ from re import search
|
|
|
16
16
|
from json import load, dump
|
|
17
17
|
from uos import remove
|
|
18
18
|
from utime import sleep
|
|
19
|
-
from Debug import DebugCfg, console_write,
|
|
19
|
+
from Debug import DebugCfg, console_write, syslog
|
|
20
20
|
try:
|
|
21
21
|
from microIO import set_pinmap
|
|
22
22
|
except:
|
|
23
|
-
|
|
23
|
+
syslog("[ERR] LogicalPins import: set_pinmap")
|
|
24
24
|
set_pinmap = None
|
|
25
25
|
|
|
26
26
|
|
|
@@ -109,7 +109,7 @@ class Data:
|
|
|
109
109
|
Data.write_cfg_file()
|
|
110
110
|
console_write("[CONF] Save conf successful")
|
|
111
111
|
except Exception as e:
|
|
112
|
-
|
|
112
|
+
syslog(f"[ERR] Save (__inject) conf failed: {e}")
|
|
113
113
|
finally:
|
|
114
114
|
del liveconf
|
|
115
115
|
|
|
@@ -127,7 +127,7 @@ class Data:
|
|
|
127
127
|
if nosafe:
|
|
128
128
|
break
|
|
129
129
|
sleep(0.2)
|
|
130
|
-
|
|
130
|
+
syslog(f'[ERR] read_cfg_file error: {e}')
|
|
131
131
|
# Return config cache
|
|
132
132
|
return conf
|
|
133
133
|
|
|
@@ -140,7 +140,7 @@ class Data:
|
|
|
140
140
|
dump(Data.CONFIG_CACHE, f)
|
|
141
141
|
break
|
|
142
142
|
except Exception as e:
|
|
143
|
-
|
|
143
|
+
syslog(f'[ERR] write_cfg_file {Data.CONFIG_PATH} (json): {e}')
|
|
144
144
|
sleep(0.2)
|
|
145
145
|
return True
|
|
146
146
|
|
|
@@ -217,7 +217,7 @@ def cfgget(key=None):
|
|
|
217
217
|
return Data.disk_keys(key)
|
|
218
218
|
return val
|
|
219
219
|
except Exception as e:
|
|
220
|
-
|
|
220
|
+
syslog(f'[ERR] cfgget {key} error: {e}')
|
|
221
221
|
return None
|
|
222
222
|
|
|
223
223
|
def cfgput(key, value, type_check=False):
|
|
@@ -242,7 +242,7 @@ def cfgput(key, value, type_check=False):
|
|
|
242
242
|
del value
|
|
243
243
|
return True
|
|
244
244
|
except Exception as e:
|
|
245
|
-
|
|
245
|
+
syslog(f'[ERR] cfgput {key} error: {e}')
|
|
246
246
|
return False
|
|
247
247
|
|
|
248
248
|
#################################################################
|
micrOS/source/Debug.py
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
micrOS Console and Log write interface implementations.
|
|
3
|
+
- with progress led feature, simple and custom
|
|
4
|
+
Designed by Marcell Ban aka BxNxM
|
|
5
|
+
"""
|
|
6
|
+
|
|
1
7
|
from machine import Pin
|
|
2
8
|
try:
|
|
3
|
-
from Logger import syslog
|
|
9
|
+
from Logger import syslog as logger_syslog
|
|
4
10
|
except:
|
|
5
|
-
|
|
11
|
+
logger_syslog = None
|
|
6
12
|
try:
|
|
7
|
-
from microIO import resolve_pin, pinmap_search,
|
|
13
|
+
from microIO import resolve_pin, pinmap_search, register_pin
|
|
8
14
|
except:
|
|
9
|
-
|
|
15
|
+
pinmap_search = None
|
|
10
16
|
|
|
11
17
|
|
|
12
18
|
#############################################
|
|
@@ -17,110 +23,60 @@ except:
|
|
|
17
23
|
class DebugCfg:
|
|
18
24
|
DEBUG = True # DEBUG PRINT ON/OFF - SET FROM ConfigHandler
|
|
19
25
|
PLED_STEP = None # PROGRESS LED OBJECT - init in init_pled
|
|
20
|
-
NEO_WHEEL = None # NEOPIXEL (ws2812/esp32s3) color wheel object
|
|
21
|
-
COLOR_INDEX = 0 # APA102 TinyPico color wheel counter
|
|
22
26
|
|
|
23
27
|
@staticmethod
|
|
24
28
|
def init_pled():
|
|
25
29
|
# CALL FROM ConfigHandler
|
|
26
|
-
if
|
|
30
|
+
if pinmap_search is None:
|
|
27
31
|
# Check LogicalPins module loadable (robustness...)
|
|
28
32
|
return
|
|
29
|
-
micro_platform = detect_platform()
|
|
30
|
-
if micro_platform == "tinypico":
|
|
31
|
-
# Progress led for TinyPico
|
|
32
|
-
DebugCfg._init_apa102()
|
|
33
|
-
return
|
|
34
33
|
pled = pinmap_search('builtin')['builtin']
|
|
35
|
-
if pled is
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
34
|
+
if pled is None:
|
|
35
|
+
# No available builtin pin, skip pled init...
|
|
36
|
+
return
|
|
37
|
+
# CONFIGURE PROGRESS LED
|
|
38
|
+
if isinstance(pled, int):
|
|
39
|
+
# [MODE] Simple flashing progress LED
|
|
40
|
+
try:
|
|
41
|
+
# Progress led for esp32/etc
|
|
42
|
+
led_obj = Pin(abs(resolve_pin('builtin')), Pin.OUT)
|
|
43
|
+
if resolve_pin('builtin') < 0:
|
|
44
|
+
# Pin number start with (-), like -8 (means inverted output)
|
|
45
|
+
led_obj.value(1) # Turn OFF built-in LED state invert (1:OFF)
|
|
46
|
+
# Set function callback for step function (simple led - blink)
|
|
47
|
+
DebugCfg.PLED_STEP = lambda: led_obj.value(not led_obj.value()) # # double-blink: return None
|
|
48
|
+
except Exception as e:
|
|
49
|
+
syslog(f"[PLED] led error: {e}")
|
|
50
|
+
elif callable(pled):
|
|
51
|
+
# [MODE] OVERRIDE PROGRESS LED WITH CUSTOM step FUNCTION
|
|
52
|
+
DebugCfg.PLED_STEP = pled
|
|
53
|
+
DebugCfg._auto_register_pin()
|
|
54
|
+
else:
|
|
55
|
+
syslog(f"[WARN] pled type not supported: {pled}")
|
|
47
56
|
|
|
48
|
-
@staticmethod
|
|
49
|
-
def step():
|
|
50
|
-
"""
|
|
51
|
-
DEBUG LED FEEDBACK
|
|
52
|
-
- handle 3 types of builtin LEDs: analog, neopixel(ws2812), apa102
|
|
53
|
-
- automatic selection based on board type + builtin logical pin number
|
|
54
|
-
"""
|
|
55
|
-
try:
|
|
56
|
-
if callable(DebugCfg.PLED_STEP):
|
|
57
|
-
return DebugCfg.PLED_STEP() # Run step function (return None: double-blink OR True: no d-b)
|
|
58
|
-
except Exception as e:
|
|
59
|
-
errlog_add(f"[PLED] step error: {e}")
|
|
60
|
-
return True
|
|
61
57
|
|
|
62
58
|
@staticmethod
|
|
63
|
-
def
|
|
59
|
+
def _auto_register_pin():
|
|
64
60
|
try:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
led_obj.value(1) # Turn OFF built-in LED state invert (1:OFF)
|
|
69
|
-
# Set function callback for step function (simple led - blink)
|
|
70
|
-
DebugCfg.PLED_STEP = lambda: led_obj.value(not led_obj.value()) # # double-blink: return None
|
|
61
|
+
pin = DebugCfg.PLED_STEP(pin=True)
|
|
62
|
+
if isinstance(pin, int):
|
|
63
|
+
register_pin('builtin', pin)
|
|
71
64
|
except Exception as e:
|
|
72
|
-
|
|
65
|
+
syslog(f"[ERR] pled pin registration: {e}", console=False)
|
|
73
66
|
|
|
74
|
-
@staticmethod
|
|
75
|
-
def _init_apa102():
|
|
76
|
-
try:
|
|
77
|
-
from machine import SoftSPI
|
|
78
|
-
from dotstar import DotStar
|
|
79
|
-
from tinypico import DOTSTAR_CLK, DOTSTAR_DATA, SPI_MISO, set_dotstar_power, dotstar_color_wheel
|
|
80
|
-
spi = SoftSPI(sck=Pin(DOTSTAR_CLK), mosi=Pin(DOTSTAR_DATA), miso=Pin(SPI_MISO))
|
|
81
|
-
# Create a DotStar instance
|
|
82
|
-
dotstar = DotStar(spi, 1, brightness=0.4) # Just one DotStar, half brightness
|
|
83
|
-
# Turn on the power to the DotStar
|
|
84
|
-
set_dotstar_power(True)
|
|
85
|
-
DebugCfg.PLED_STEP = lambda: DebugCfg._step_apa102(led_obj=dotstar, color_wheel=dotstar_color_wheel)
|
|
86
|
-
except Exception as e:
|
|
87
|
-
errlog_add(f"[PLED] apa102 error: {e}")
|
|
88
|
-
|
|
89
|
-
@staticmethod
|
|
90
|
-
def _step_apa102(led_obj, color_wheel):
|
|
91
|
-
# Get the R,G,B values of the next colour
|
|
92
|
-
r, g, b = color_wheel(DebugCfg.COLOR_INDEX*2)
|
|
93
|
-
# Set the colour on the DOTSTAR
|
|
94
|
-
led_obj[0] = (int(r * 0.6), g, b, 0.4)
|
|
95
|
-
# Increase the wheel index
|
|
96
|
-
DebugCfg.COLOR_INDEX = 0 if DebugCfg.COLOR_INDEX > 1000 else DebugCfg.COLOR_INDEX + 2
|
|
97
|
-
return True # No double-blink
|
|
98
67
|
|
|
99
68
|
@staticmethod
|
|
100
|
-
def
|
|
69
|
+
def step():
|
|
70
|
+
"""
|
|
71
|
+
DEBUG LED FLASHING FEEDBACK
|
|
72
|
+
- handle step callback function execution
|
|
73
|
+
"""
|
|
101
74
|
try:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
led_obj = NeoPixel(neo_pin, 1)
|
|
105
|
-
DebugCfg.PLED_STEP = lambda: DebugCfg._step_ws2812(led_obj)
|
|
75
|
+
if callable(DebugCfg.PLED_STEP):
|
|
76
|
+
return DebugCfg.PLED_STEP() # Run step function (return None: double-blink OR True: no d-b)
|
|
106
77
|
except Exception as e:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
@staticmethod
|
|
110
|
-
def _step_ws2812(led_obj):
|
|
111
|
-
def _color_wheel():
|
|
112
|
-
while True:
|
|
113
|
-
yield 10, 0, 0
|
|
114
|
-
yield 5, 5, 0
|
|
115
|
-
yield 0, 10, 0
|
|
116
|
-
yield 0, 5, 5
|
|
117
|
-
yield 0, 0, 10
|
|
118
|
-
yield 5, 0, 5
|
|
119
|
-
if DebugCfg.NEO_WHEEL is None:
|
|
120
|
-
DebugCfg.NEO_WHEEL = _color_wheel()
|
|
121
|
-
led_obj[0] = next(DebugCfg.NEO_WHEEL)
|
|
122
|
-
led_obj.write()
|
|
123
|
-
return True # No double-blink
|
|
78
|
+
syslog(f"[PLED] step error: {e}")
|
|
79
|
+
return True
|
|
124
80
|
|
|
125
81
|
|
|
126
82
|
def console_write(msg):
|
|
@@ -131,10 +87,10 @@ def console_write(msg):
|
|
|
131
87
|
if analog is None:
|
|
132
88
|
DebugCfg.step() # Double-blink
|
|
133
89
|
except Exception as e:
|
|
134
|
-
|
|
90
|
+
syslog(f"[ERR] console_write: {e}", console=False)
|
|
135
91
|
|
|
136
92
|
|
|
137
|
-
def
|
|
93
|
+
def syslog(data, console=True):
|
|
138
94
|
"""
|
|
139
95
|
:param data: msg string / data
|
|
140
96
|
:param console: activate console_write (default: True)
|
|
@@ -142,4 +98,4 @@ def errlog_add(data, console=True):
|
|
|
142
98
|
"""
|
|
143
99
|
if console:
|
|
144
100
|
console_write(data)
|
|
145
|
-
return False if
|
|
101
|
+
return False if logger_syslog is None else logger_syslog(data)
|