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.

Files changed (151) hide show
  1. env/driver_cp210x/macOS_VCP_Driver/SiLabsUSBDriverDisk.dmg +0 -0
  2. env/driver_cp210x/macOS_VCP_Driver/macOS_VCP_Driver_Release_Notes.txt +17 -1
  3. micrOS/micropython/esp32c6-GENERIC-20250415-v1.25.0.bin +0 -0
  4. micrOS/micropython/esp32s3-4MBflash-20241129-v1.24.1.bin +0 -0
  5. micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +57 -61
  6. micrOS/source/Common.py +286 -91
  7. micrOS/source/Config.py +7 -7
  8. micrOS/source/Debug.py +50 -94
  9. micrOS/source/Espnow.py +7 -7
  10. micrOS/source/Files.py +23 -2
  11. micrOS/source/Hooks.py +62 -19
  12. micrOS/source/IO_esp32c6.py +16 -0
  13. micrOS/source/IO_esp32s3.py +37 -1
  14. micrOS/source/IO_m5stamp.py +35 -1
  15. micrOS/source/IO_qtpy.py +22 -17
  16. micrOS/source/IO_s3matrix.py +21 -0
  17. micrOS/source/IO_tinypico.py +38 -0
  18. micrOS/source/InterConnect.py +5 -5
  19. micrOS/source/Interrupts.py +2 -2
  20. micrOS/source/LM_VL53L0X.py +1 -1
  21. micrOS/source/LM_buzzer.py +6 -7
  22. micrOS/source/LM_cct.py +6 -5
  23. micrOS/source/LM_dashboard_be.py +2 -2
  24. micrOS/source/LM_dimmer.py +6 -5
  25. micrOS/source/LM_espnow.py +15 -10
  26. micrOS/source/LM_i2c.py +3 -2
  27. micrOS/source/LM_neoeffects.py +173 -230
  28. micrOS/source/LM_neomatrix.py +335 -0
  29. micrOS/source/LM_neopixel.py +10 -10
  30. micrOS/source/LM_pacman.py +40 -23
  31. micrOS/source/LM_qmi8658.py +204 -0
  32. micrOS/source/LM_rgb.py +6 -6
  33. micrOS/source/LM_roboarm.py +5 -4
  34. micrOS/source/LM_switch.py +6 -4
  35. micrOS/source/LM_tcs3472.py +75 -0
  36. micrOS/source/LM_telegram.py +5 -4
  37. micrOS/source/Logger.py +47 -33
  38. micrOS/source/Network.py +6 -6
  39. micrOS/source/Notify.py +2 -2
  40. micrOS/source/Scheduler.py +5 -5
  41. micrOS/source/Server.py +6 -6
  42. micrOS/source/Shell.py +4 -4
  43. micrOS/source/Tasks.py +20 -17
  44. micrOS/source/Time.py +12 -10
  45. micrOS/source/Types.py +2 -2
  46. micrOS/source/Web.py +20 -13
  47. micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
  48. micrOS/source/__pycache__/Debug.cpython-312.pyc +0 -0
  49. micrOS/source/__pycache__/Logger.cpython-312.pyc +0 -0
  50. micrOS/source/__pycache__/Server.cpython-312.pyc +0 -0
  51. micrOS/source/micrOS.py +10 -7
  52. micrOS/source/micrOSloader.py +6 -6
  53. micrOS/source/microIO.py +8 -6
  54. micrOS/source/urequests.py +4 -4
  55. {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/METADATA +24 -22
  56. {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/RECORD +142 -132
  57. toolkit/DevEnvCompile.py +20 -15
  58. toolkit/DevEnvOTA.py +29 -8
  59. toolkit/DevEnvUSB.py +52 -10
  60. toolkit/LM_to_compile.dat +1 -0
  61. toolkit/MicrOSDevEnv.py +10 -2
  62. toolkit/MicrosFiles.py +26 -0
  63. toolkit/dashboard_apps/NeoEffectsDemo.py +8 -15
  64. toolkit/dashboard_apps/QMI8685_GYRO.py +68 -0
  65. toolkit/dashboard_apps/_app_base.py +2 -2
  66. toolkit/dashboard_apps/_gyro_visualizer.py +78 -0
  67. toolkit/lib/LocalMachine.py +6 -1
  68. toolkit/lib/file_extensions.py +9 -3
  69. toolkit/micrOSlint.py +3 -1
  70. toolkit/simulator_lib/__pycache__/IO_darwin.cpython-312.pyc +0 -0
  71. toolkit/simulator_lib/__pycache__/machine.cpython-312.pyc +0 -0
  72. toolkit/simulator_lib/__pycache__/neopixel.cpython-312.pyc +0 -0
  73. toolkit/simulator_lib/machine.py +0 -1
  74. toolkit/simulator_lib/neopixel.py +3 -2
  75. toolkit/socketClient.py +3 -2
  76. toolkit/workspace/precompiled/Common.cpython-312.pyc +0 -0
  77. toolkit/workspace/precompiled/Common.mpy +0 -0
  78. toolkit/workspace/precompiled/Config.mpy +0 -0
  79. toolkit/workspace/precompiled/Debug.mpy +0 -0
  80. toolkit/workspace/precompiled/Espnow.mpy +0 -0
  81. toolkit/workspace/precompiled/Files.mpy +0 -0
  82. toolkit/workspace/precompiled/Hooks.mpy +0 -0
  83. toolkit/workspace/precompiled/IO_esp32c6.mpy +0 -0
  84. toolkit/workspace/precompiled/IO_esp32s3.mpy +0 -0
  85. toolkit/workspace/precompiled/IO_m5stamp.mpy +0 -0
  86. toolkit/workspace/precompiled/IO_qtpy.mpy +0 -0
  87. toolkit/workspace/precompiled/IO_s3matrix.mpy +0 -0
  88. toolkit/workspace/precompiled/IO_tinypico.mpy +0 -0
  89. toolkit/workspace/precompiled/InterConnect.mpy +0 -0
  90. toolkit/workspace/precompiled/Interrupts.mpy +0 -0
  91. toolkit/workspace/precompiled/LM_VL53L0X.py +1 -1
  92. toolkit/workspace/precompiled/LM_buzzer.mpy +0 -0
  93. toolkit/workspace/precompiled/LM_cct.mpy +0 -0
  94. toolkit/workspace/precompiled/LM_dashboard_be.py +2 -2
  95. toolkit/workspace/precompiled/LM_dimmer.mpy +0 -0
  96. toolkit/workspace/precompiled/LM_espnow.py +15 -10
  97. toolkit/workspace/precompiled/LM_i2c.py +3 -2
  98. toolkit/workspace/precompiled/LM_neoeffects.mpy +0 -0
  99. toolkit/workspace/precompiled/LM_neomatrix.mpy +0 -0
  100. toolkit/workspace/precompiled/LM_neopixel.mpy +0 -0
  101. toolkit/workspace/precompiled/LM_pacman.mpy +0 -0
  102. toolkit/workspace/precompiled/LM_qmi8658.py +204 -0
  103. toolkit/workspace/precompiled/LM_rgb.mpy +0 -0
  104. toolkit/workspace/precompiled/LM_roboarm.mpy +0 -0
  105. toolkit/workspace/precompiled/LM_switch.mpy +0 -0
  106. toolkit/workspace/precompiled/LM_tcs3472.py +75 -0
  107. toolkit/workspace/precompiled/LM_telegram.mpy +0 -0
  108. toolkit/workspace/precompiled/Logger.cpython-312.pyc +0 -0
  109. toolkit/workspace/precompiled/Logger.mpy +0 -0
  110. toolkit/workspace/precompiled/Network.mpy +0 -0
  111. toolkit/workspace/precompiled/Notify.mpy +0 -0
  112. toolkit/workspace/precompiled/Scheduler.mpy +0 -0
  113. toolkit/workspace/precompiled/Server.cpython-312.pyc +0 -0
  114. toolkit/workspace/precompiled/Server.mpy +0 -0
  115. toolkit/workspace/precompiled/Shell.mpy +0 -0
  116. toolkit/workspace/precompiled/Tasks.mpy +0 -0
  117. toolkit/workspace/precompiled/Time.mpy +0 -0
  118. toolkit/workspace/precompiled/Types.mpy +0 -0
  119. toolkit/workspace/precompiled/Web.mpy +0 -0
  120. toolkit/workspace/precompiled/micrOS.mpy +0 -0
  121. toolkit/workspace/precompiled/micrOSloader.mpy +0 -0
  122. toolkit/workspace/precompiled/microIO.mpy +0 -0
  123. toolkit/workspace/precompiled/urequests.mpy +0 -0
  124. micrOS/micropython/esp32s3-20240105-v1.22.1.bin +0 -0
  125. micrOS/source/LM_catgame.py +0 -75
  126. micrOS/source/LM_demo.py +0 -97
  127. micrOS/source/LM_intercon.py +0 -60
  128. micrOS/source/LM_ph_sensor.py +0 -51
  129. toolkit/workspace/precompiled/LM_catgame.py +0 -75
  130. toolkit/workspace/precompiled/LM_demo.py +0 -97
  131. toolkit/workspace/precompiled/LM_intercon.mpy +0 -0
  132. toolkit/workspace/precompiled/LM_ph_sensor.py +0 -51
  133. /micrOS/micropython/{esp32s3-20241129-v1.24.1.bin → esp32s3-8MBflash-20241129-v1.24.1.bin} +0 -0
  134. /micrOS/source/{dashboard.html → web/dashboard.html} +0 -0
  135. /micrOS/source/{index.html → web/index.html} +0 -0
  136. /micrOS/source/{uapi.js → web/uapi.js} +0 -0
  137. /micrOS/source/{udashboard.js → web/udashboard.js} +0 -0
  138. /micrOS/source/{ustyle.css → web/ustyle.css} +0 -0
  139. /micrOS/source/{uwidgets.js → web/uwidgets.js} +0 -0
  140. /micrOS/source/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
  141. {microsdevtoolkit-2.10.6.data → microsdevtoolkit-2.13.0.data}/scripts/devToolKit.py +0 -0
  142. {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/WHEEL +0 -0
  143. {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/licenses/LICENSE +0 -0
  144. {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/top_level.txt +0 -0
  145. /toolkit/workspace/precompiled/{dashboard.html → web/dashboard.html} +0 -0
  146. /toolkit/workspace/precompiled/{index.html → web/index.html} +0 -0
  147. /toolkit/workspace/precompiled/{uapi.js → web/uapi.js} +0 -0
  148. /toolkit/workspace/precompiled/{udashboard.js → web/udashboard.js} +0 -0
  149. /toolkit/workspace/precompiled/{ustyle.css → web/ustyle.css} +0 -0
  150. /toolkit/workspace/precompiled/{uwidgets.js → web/uwidgets.js} +0 -0
  151. /toolkit/workspace/precompiled/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
@@ -0,0 +1,204 @@
1
+ """
2
+ A simple driver for the QMI8658 IMU.
3
+ https://github.com/echo-lalia/qmi8658-micropython/blob/main/qmi8685.py
4
+ """
5
+
6
+ import struct
7
+ import time
8
+ from machine import Pin, I2C
9
+ from micropython import const
10
+ from microIO import bind_pin, pinmap_search
11
+
12
+
13
+ # Sensor constants
14
+ _QMI8685_PARTID = const(0x05)
15
+ _REG_PARTID = const(0x00)
16
+ _REG_REVISION = const(0x01)
17
+
18
+ _REG_CTRL1 = const(0x02) # Serial interface and sensor enable
19
+ _REG_CTRL2 = const(0x03) # Accelerometer settings
20
+ _REG_CTRL3 = const(0x04) # Gyroscope settings
21
+ _REG_CTRL4 = const(0x05) # Magnetomer settings (support not implemented in this driver yet)
22
+ _REG_CTRL5 = const(0x06) # Sensor data processing settings
23
+ _REG_CTRL6 = const(0x07) # Attitude Engine ODR and Motion on Demand
24
+ _REG_CTRL7 = const(0x08) # Enable Sensors and Configure Data Reads
25
+
26
+ _REG_TEMP = const(0x33) # Temperature sensor.
27
+
28
+ _REG_AX_L = const(0x35) # Read accelerometer
29
+ _REG_AX_H = const(0x36)
30
+ _REG_AY_L = const(0x37)
31
+ _REG_AY_H = const(0x38)
32
+ _REG_AZ_L = const(0x39)
33
+ _REG_AZ_H = const(0x3A)
34
+
35
+ _REG_GX_L = const(0x3B) # read gyro
36
+ _REG_GX_H = const(0x3C)
37
+ _REG_GY_L = const(0x3D)
38
+ _REG_GY_H = const(0x3E)
39
+ _REG_GZ_L = const(0x3F)
40
+ _REG_GZ_H = const(0x40)
41
+
42
+ _QMI8658_I2CADDR_DEFAULT = const(0X6B)
43
+
44
+
45
+ _ACCELSCALE_RANGE_2G = const(0b00)
46
+ _ACCELSCALE_RANGE_4G = const(0b01)
47
+ _ACCELSCALE_RANGE_8G = const(0b10)
48
+ _ACCELSCALE_RANGE_16G = const(0b11)
49
+
50
+ _GYROSCALE_RANGE_16DPS = const(0b000)
51
+ _GYROSCALE_RANGE_32DPS = const(0b001)
52
+ _GYROSCALE_RANGE_64DPS = const(0b010)
53
+ _GYROSCALE_RANGE_128DPS = const(0b011)
54
+ _GYROSCALE_RANGE_256DPS = const(0b100)
55
+ _GYROSCALE_RANGE_512DPS = const(0b101)
56
+ _GYROSCALE_RANGE_1024DPS = const(0b110)
57
+ _GYROSCALE_RANGE_2048DPS = const(0b111)
58
+
59
+ _ODR_8000HZ = const(0b0000)
60
+ _ODR_4000HZ = const(0b0001)
61
+ _ODR_2000HZ = const(0b0010)
62
+ _ODR_1000HZ = const(0b0011)
63
+ _ODR_500HZ = const(0b0100)
64
+ _ODR_250HZ = const(0b0101)
65
+ _ODR_125HZ = const(0b0110)
66
+ _ODR_62_5HZ = const(0b0111)
67
+
68
+
69
+ class QMI8658:
70
+ """QMI8658 inertial measurement unit."""
71
+ INSTANCE = None
72
+
73
+ def __init__(
74
+ self,
75
+ i2c_bus: I2C,
76
+ address: int = _QMI8658_I2CADDR_DEFAULT,
77
+ accel_scale: int = _ACCELSCALE_RANGE_8G,
78
+ gyro_scale: int = _GYROSCALE_RANGE_256DPS):
79
+ """Read from a sensor on the given I2C bus, at the given address."""
80
+ self.i2c = i2c_bus
81
+ self.address = address
82
+ # Cache the sensor instance globally for easy access
83
+ QMI8658.INSTANCE = self
84
+
85
+ # Verify sensor part ID
86
+ if self._read_u8(_REG_PARTID) != _QMI8685_PARTID:
87
+ raise AttributeError("Cannot find a QMI8658")
88
+
89
+ # Setup initial configuration
90
+ self._configure_sensor(accel_scale, gyro_scale)
91
+
92
+ # Configure scales/divisors for the driver
93
+ self.acc_scale_divisor = {
94
+ _ACCELSCALE_RANGE_2G: 1 << 14,
95
+ _ACCELSCALE_RANGE_4G: 1 << 13,
96
+ _ACCELSCALE_RANGE_8G: 1 << 12,
97
+ _ACCELSCALE_RANGE_16G: 1 << 11,
98
+ }[accel_scale]
99
+
100
+ self.gyro_scale_divisor = {
101
+ _GYROSCALE_RANGE_16DPS: 2048,
102
+ _GYROSCALE_RANGE_32DPS: 1024,
103
+ _GYROSCALE_RANGE_64DPS: 512,
104
+ _GYROSCALE_RANGE_128DPS: 256,
105
+ _GYROSCALE_RANGE_256DPS: 128,
106
+ _GYROSCALE_RANGE_512DPS: 64,
107
+ _GYROSCALE_RANGE_1024DPS: 32,
108
+ _GYROSCALE_RANGE_2048DPS: 16,
109
+ }[gyro_scale]
110
+
111
+
112
+ def _configure_sensor(self, accel_scale: int, gyro_scale: int):
113
+ # Initialize accelerometer and gyroscope settings
114
+ self._write_u8(_REG_CTRL1, 0x60) # Set SPI auto increment and big endian (Ctrl 1)
115
+ self._write_u8(_REG_CTRL2, (accel_scale << 4) | _ODR_1000HZ) # Accel Config
116
+ self._write_u8(_REG_CTRL3, (gyro_scale << 4) | _ODR_1000HZ) # Gyro Config
117
+ self._write_u8(_REG_CTRL5, 0x01) # Low-pass filter enable
118
+ self._write_u8(_REG_CTRL7, 0x03) # Enable accel and gyro
119
+ time.sleep_ms(100)
120
+
121
+
122
+ # Helper functions for register operations
123
+ def _read_u8(self, reg:int) -> int:
124
+ return self.i2c.readfrom_mem(self.address, reg, 1)[0]
125
+
126
+ def _read_xyz(self, reg:int) -> tuple[int, int, int]:
127
+ data = self.i2c.readfrom_mem(self.address, reg, 6)
128
+ return struct.unpack('<hhh', data)
129
+
130
+ def _write_u8(self, reg: int, value: int):
131
+ self.i2c.writeto_mem(self.address, reg, bytes([value]))
132
+
133
+
134
+ @property
135
+ def temperature(self) -> float:
136
+ """Get the device temperature."""
137
+ temp_raw = self._read_u8(_REG_TEMP)
138
+ return temp_raw / 256
139
+
140
+ @property
141
+ def acceleration(self) -> tuple[float, float, float]:
142
+ """Get current acceleration reading."""
143
+ raw_accel = self._read_xyz(_REG_AX_L)
144
+ return tuple(val / self.acc_scale_divisor for val in raw_accel)
145
+
146
+ @property
147
+ def gyro(self) -> tuple[float, float, float]:
148
+ """Get current gyroscope reading."""
149
+ raw_gyro = self._read_xyz(_REG_GX_L)
150
+ return tuple(val / self.gyro_scale_divisor for val in raw_gyro)
151
+
152
+ #######################
153
+ # Public functions #
154
+ #######################
155
+
156
+ def load():
157
+ """
158
+ Load the QMI8658 sensor instance.
159
+ The QMI8658 is a motion sensor that measures acceleration, angular velocity (gyroscope), and temperature
160
+ """
161
+ if QMI8658.INSTANCE is None:
162
+ QMI8658(I2C(0, sda=Pin(bind_pin('i2c_sda')), scl=Pin(bind_pin('i2c_scl'))))
163
+ return QMI8658.INSTANCE
164
+
165
+
166
+ def temperature():
167
+ return load().temperature
168
+
169
+
170
+ def acceleration():
171
+ return load().acceleration
172
+
173
+
174
+ def gyro():
175
+ return load().gyro
176
+
177
+
178
+ def measure():
179
+ inst = load()
180
+ return {"temp": inst.temperature, "accel": inst.acceleration, "gyro": inst.gyro}
181
+
182
+
183
+ #######################
184
+ # LM helper functions #
185
+ #######################
186
+
187
+ def pinmap():
188
+ """
189
+ [i] micrOS LM naming convention
190
+ Shows logical pins - pin number(s) used by this Load module
191
+ - info which pins to use for this application
192
+ :return dict: pin name (str) - pin value (int) pairs
193
+ """
194
+ return pinmap_search(['i2c_scl', 'i2c_sda'])
195
+
196
+
197
+ def help(widgets=False):
198
+ """
199
+ [i] micrOS LM naming convention - built-in help message
200
+ :return tuple:
201
+ (widgets=False) list of functions implemented by this application
202
+ (widgets=True) list of widget json for UI generation
203
+ """
204
+ return 'load', 'temperature', 'acceleration', 'gyro', 'measure', 'pinmap'
micrOS/source/LM_rgb.py CHANGED
@@ -2,8 +2,7 @@
2
2
  # ANALOG rgb CONTROLLER PARAMS #
3
3
  #########################################
4
4
  from machine import Pin, PWM
5
- from sys import platform
6
- from Common import transition_gen, micro_task
5
+ from Common import transition_gen, micro_task, data_dir
7
6
  from utime import sleep_ms
8
7
  from microIO import bind_pin, pinmap_search
9
8
  from random import randint
@@ -20,6 +19,7 @@ class Data:
20
19
  CH_MAX = 1000 # maximum value per channel
21
20
  TASK_STATE = False
22
21
  RGB_TASK_TAG = "rgb._tran"
22
+ FILE_CACHE = data_dir('rgb.cache')
23
23
 
24
24
 
25
25
  #########################################
@@ -39,7 +39,7 @@ def __RGB_init(red_pin=None, green_pin=None, blue_pin=None):
39
39
 
40
40
  def __persistent_cache_manager(mode):
41
41
  """
42
- pds - persistent data structure
42
+ File state cache
43
43
  modes:
44
44
  r - recover, s - save
45
45
  """
@@ -47,12 +47,12 @@ def __persistent_cache_manager(mode):
47
47
  return
48
48
  if mode == 's':
49
49
  # SAVE CACHE
50
- with open('rgb.pds', 'w') as f:
50
+ with open(Data.FILE_CACHE, 'w') as f:
51
51
  f.write(','.join([str(k) for k in Data.RGB_CACHE]))
52
52
  return
53
53
  try:
54
54
  # RESTORE CACHE
55
- with open('rgb.pds', 'r') as f:
55
+ with open(Data.FILE_CACHE, 'r') as f:
56
56
  Data.RGB_CACHE = [float(data) for data in f.read().strip().split(',')]
57
57
  except:
58
58
  pass
@@ -74,7 +74,7 @@ def load(red_pin=None, green_pin=None, blue_pin=None, cache=True):
74
74
  :param red_pin: optional red color pin to overwrite built-in
75
75
  :param green_pin: optional green color pin to overwrite built-in
76
76
  :param blue_pin: optional blue color pin to overwrite built-in
77
- :param cache: file state machine cache: True/False (.pds), default=True
77
+ :param cache: file state machine cache: True/False (.cache), default=True
78
78
  :return str: Cache state
79
79
  """
80
80
  Data.PERSISTENT_CACHE = cache
@@ -2,7 +2,7 @@ from utime import sleep_ms
2
2
  from random import randint
3
3
  import LM_servo as servo
4
4
  from LM_switch import set_state, pinmap as switch_pinmap
5
- from Common import transition, micro_task
5
+ from Common import transition, micro_task, data_dir
6
6
  from Types import resolve
7
7
 
8
8
 
@@ -13,23 +13,24 @@ class RoboArm:
13
13
  SPEED_MS = 10 # Set default speed between steps (ms)
14
14
  MOVE_RECORD = [] # Buffer for XY move record/replay
15
15
  PLAY_TAG = 'roboarm._play'
16
+ FILE_CACHE = data_dir('rarm.cache')
16
17
 
17
18
 
18
19
  def __persistent_cache_manager(mode):
19
20
  """
20
- pds - persistent data structure
21
+ File state cache
21
22
  modes:
22
23
  r - recover, s - save
23
24
  """
24
25
 
25
26
  if mode == 's':
26
27
  # SAVE CACHE
27
- with open('rarm.pds', 'w') as f:
28
+ with open(RoboArm.FILE_CACHE, 'w') as f:
28
29
  f.write(','.join([str(k) for k in RoboArm.MOVE_RECORD]))
29
30
  return
30
31
  try:
31
32
  # RESTORE CACHE
32
- with open('rarm.pds', 'r') as f:
33
+ with open(RoboArm.FILE_CACHE, 'r') as f:
33
34
  RoboArm.MOVE_RECORD = [int(data) for data in f.read().strip().split(',')]
34
35
  except:
35
36
  pass
@@ -1,5 +1,6 @@
1
1
  from machine import Pin
2
2
  from microIO import bind_pin, pinmap_search
3
+ from Common import data_dir
3
4
  from Types import resolve
4
5
 
5
6
  #########################################
@@ -8,6 +9,7 @@ from Types import resolve
8
9
  __SWITCH_OBJ = [None, None, None, None]
9
10
  __PERSISTENT_CACHE = False
10
11
  __SWITCH_STATE = [0, 0, 0, 0]
12
+ __FILE_CACHE = data_dir('switch.cache')
11
13
 
12
14
 
13
15
  #########################################
@@ -16,7 +18,7 @@ __SWITCH_STATE = [0, 0, 0, 0]
16
18
 
17
19
  def __persistent_cache_manager(mode):
18
20
  """
19
- pds - persistent data structure
21
+ File cache
20
22
  modes:
21
23
  r - recover, s - save
22
24
  """
@@ -25,12 +27,12 @@ def __persistent_cache_manager(mode):
25
27
  global __SWITCH_STATE
26
28
  if mode == 's':
27
29
  # SAVE CACHE
28
- with open('switch.pds', 'w') as f:
30
+ with open(__FILE_CACHE, 'w') as f:
29
31
  f.write(','.join([str(k) for k in __SWITCH_STATE]))
30
32
  return
31
33
  try:
32
34
  # RESTORE CACHE
33
- with open('switch.pds', 'r') as f:
35
+ with open(__FILE_CACHE, 'r') as f:
34
36
  __SWITCH_STATE = [int(data) for data in f.read().strip().split(',')]
35
37
  except:
36
38
  pass
@@ -54,7 +56,7 @@ def load(cache=None, ch_init=None):
54
56
  """
55
57
  Initiate switch module (4 switch pack)
56
58
  :param cache bool: file state machine cache: True/False/None(default: automatic True)
57
- - Load .pds (state machine cache) for this load module
59
+ - Load .cache (state machine cache) for this load module
58
60
  - Apply loaded states to gpio pins (boot function)
59
61
  :return str: Cache state
60
62
  """
@@ -0,0 +1,75 @@
1
+ """
2
+ A MicroPython library for the TCS3472 light sensing chip
3
+ https://github.com/tti0/tcs3472-micropython
4
+
5
+ Copyright (c) 2021 tti0
6
+ Licensed under the MIT License
7
+ """
8
+
9
+ from machine import I2C, Pin
10
+ from microIO import bind_pin, pinmap_search
11
+ import struct
12
+
13
+
14
+ class TCS3472:
15
+ INSTANCE = None
16
+
17
+ def __init__(self, bus, address=0x29):
18
+ self._bus = bus
19
+ self._i2c_address = address
20
+
21
+ self._bus.start()
22
+
23
+ self._bus.writeto(self._i2c_address, b'\x80\x03')
24
+ self._bus.writeto(self._i2c_address, b'\x81\x2b')
25
+
26
+ TCS3472.INSTANCE = self
27
+
28
+ def scaled(self):
29
+ crgb = self.raw()
30
+ if crgb[0] > 0:
31
+ return tuple(float(x) / crgb[0] for x in crgb[1:])
32
+
33
+ return (0, 0, 0)
34
+
35
+ def rgb(self):
36
+ return tuple(int(x * 255) for x in self.scaled())
37
+
38
+ def light(self):
39
+ return self.raw()[0]
40
+
41
+ def brightness(self, level=65.535):
42
+ return int((self.light() / level))
43
+
44
+ def valid(self):
45
+ self._bus.writeto(self._i2c_address, b'\x93')
46
+ return self._bus.readfrom(self._i2c_address, 1)[0] & 1
47
+
48
+ def raw(self):
49
+ self._bus.writeto(self._i2c_address, b'\xb4')
50
+ return struct.unpack("<HHHH", self._bus.readfrom(self._i2c_address, 8))
51
+
52
+
53
+ ############################ Exposed functions ############################
54
+
55
+ def load():
56
+ """
57
+ Load the TCS3472 Color sensor instance.
58
+ """
59
+ if TCS3472.INSTANCE is None:
60
+ bus = I2C(sda=Pin(bind_pin('i2c_sda')), scl=Pin(bind_pin('i2c_scl')))
61
+ TCS3472.INSTANCE = TCS3472(bus)
62
+ return TCS3472.INSTANCE
63
+
64
+
65
+ def pinmap():
66
+ return pinmap_search(['i2c_scl', 'i2c_sda'])
67
+
68
+
69
+ def measure():
70
+ sensor = load()
71
+ return {"rgb": sensor.rgb(), "light": sensor.light(), "brightness": sensor.brightness()}
72
+
73
+
74
+ def help(widgest=False):
75
+ return 'load', 'measure'
@@ -2,7 +2,7 @@ from sys import modules
2
2
  import urequests
3
3
  from Notify import Notify
4
4
  from Config import cfgget
5
- from Common import micro_task, syslog, console_write
5
+ from Common import micro_task, syslog, console_write, data_dir
6
6
  from LM_system import ifconfig
7
7
  from utime import localtime
8
8
 
@@ -18,6 +18,7 @@ class Telegram(Notify):
18
18
  _CHAT_IDS = set() # Telegram bot chat IDs - multi group support - persistent caching
19
19
  _API_PARAMS = "?offset=-1&limit=1&timeout=2" # Generic API params - optimization
20
20
  _IN_MSG_ID = None
21
+ _FILE_CACHE = data_dir('telegram.cache')
21
22
 
22
23
  def __init__(self):
23
24
  # Subscribe to the notification system - provide send_msg method (over self)
@@ -26,20 +27,20 @@ class Telegram(Notify):
26
27
  @staticmethod
27
28
  def __id_cache(mode):
28
29
  """
29
- pds - persistent data structure
30
+ File cache
30
31
  modes:
31
32
  r - recover, s - save
32
33
  """
33
34
  if mode == 's':
34
35
  # SAVE CACHE
35
36
  console_write("[NTFY] Save chatIDs cache...")
36
- with open('telegram.pds', 'w') as f:
37
+ with open(Telegram._FILE_CACHE, 'w') as f:
37
38
  f.write(','.join([str(k) for k in Telegram._CHAT_IDS]))
38
39
  return
39
40
  try:
40
41
  # RESTORE CACHE
41
42
  console_write("[NTFY] Restore chatIDs cache...")
42
- with open('telegram.pds', 'r') as f:
43
+ with open(Telegram._FILE_CACHE, 'r') as f:
43
44
  # set() comprehension
44
45
  Telegram._CHAT_IDS = {int(k) for k in f.read().strip().split(',')}
45
46
  except:
micrOS/source/Logger.py CHANGED
@@ -6,48 +6,52 @@ Designed by Marcell Ban aka BxNxM
6
6
  """
7
7
  from time import localtime
8
8
  from re import match
9
- from uos import remove, mkdir, getcwd
10
- from Files import ilist_fs, is_dir
9
+ from uos import remove, mkdir
10
+ from Files import OSPath, path_join, ilist_fs, is_dir
11
11
 
12
12
  #############################################
13
13
  # LOGGING WITH DATA ROTATION #
14
14
  #############################################
15
- LOG_FOLDER = None
16
15
 
17
16
  def _init_logger():
18
17
  """ Init /logs folder """
19
- global LOG_FOLDER
20
- if LOG_FOLDER is None:
21
- LOG_FOLDER = f"{getcwd()}logs"
22
- if not is_dir(LOG_FOLDER):
23
- try:
24
- mkdir(LOG_FOLDER)
25
- syslog(f"[BOOT] log dir {LOG_FOLDER} init")
26
- except Exception as e:
27
- LOG_FOLDER = getcwd()
28
- syslog(f"[BOOT] log dir {LOG_FOLDER} fallback: {e}")
29
- return LOG_FOLDER
18
+ if not is_dir(OSPath.LOGS):
19
+ try:
20
+ mkdir(OSPath.LOGS)
21
+ syslog(f"[BOOT] log dir {OSPath.LOGS} init")
22
+ except Exception as e:
23
+ OSPath.LOGS = OSPath.ROOT
24
+ syslog(f"[BOOT] log dir {OSPath.LOGS} fallback: {e}")
25
+ return OSPath.LOGS
26
+
27
+
28
+ def _dir_select(f_name:str) -> str:
29
+ """
30
+ Select log dir based on file extension
31
+ :param f_name: filename with extension to detect target dir
32
+ """
33
+ if f_name.endswith(".log"):
34
+ return OSPath.LOGS
35
+ return OSPath.DATA
30
36
 
31
37
 
32
- def logger(data, f_name, limit):
38
+ def logger(data, f_name:str, limit:int):
33
39
  """
34
- Create generic logger function
35
- - implements log line rotation
36
- - automatic time stump
37
- :param data: input string data to log
40
+ Generic logger function with line rotation and time
41
+ :param data: data to log
38
42
  :param f_name: file name to use
39
43
  :param limit: line limit for log rotation
40
44
  return write verdict - true / false
41
45
  INFO: hardcoded max data number = 30
42
46
  """
43
47
  def _logger(f_mode='r+'):
44
- nonlocal data, f_name, limit
48
+ nonlocal data, f_path, limit
45
49
  limit = min(limit, 30) # Hardcoded max data line = 30
46
50
  # [1] GET TIME STUMP
47
51
  ts_buff = [str(k) for k in localtime()]
48
52
  ts = ".".join(ts_buff[0:3]) + "-" + ":".join(ts_buff[3:6])
49
53
  # [2] OPEN FILE - WRITE DATA WITH TS
50
- with open(f_name, f_mode) as f:
54
+ with open(f_path, f_mode) as f:
51
55
  _data = f"{ts} {data}\n"
52
56
  # read file lines and filter by time stump chunks (hack for replace truncate)
53
57
  lines = [_l for _l in f.readlines() if '-' in _l and '.' in _l]
@@ -61,7 +65,7 @@ def logger(data, f_name, limit):
61
65
  # write file
62
66
  f.write(''.join(lines))
63
67
 
64
- f_name = f"{LOG_FOLDER}/{f_name}"
68
+ f_path = path_join(_dir_select(f_name), f_name)
65
69
  # Run logger
66
70
  try:
67
71
  # There is file - append 'r+'
@@ -75,17 +79,17 @@ def logger(data, f_name, limit):
75
79
  return True
76
80
 
77
81
 
78
- def log_get(f_name, msgobj=None):
82
+ def log_get(f_name:str, msgobj=None):
79
83
  """
80
- Get and stream (ver osocket/stdout) .log file's content and count "critical" errors
81
- - critical error tag in log line: [ERR]
84
+ Generic file getter for .log files
85
+ - log content critical [ERR] counter
82
86
  """
83
- f_name = f"{LOG_FOLDER}/{f_name}"
87
+ f_path = path_join(_dir_select(f_name), f_name)
84
88
  err_cnt = 0
85
89
  try:
86
90
  if msgobj is not None:
87
- msgobj(f_name)
88
- with open(f_name, 'r') as f:
91
+ msgobj(f_path)
92
+ with open(f_path, 'r') as f:
89
93
  eline = f.readline().strip()
90
94
  while eline:
91
95
  # GET error from log line (tag: [ERR])
@@ -100,20 +104,30 @@ def log_get(f_name, msgobj=None):
100
104
 
101
105
 
102
106
  def syslog(data=None, msgobj=None):
107
+ """
108
+ System log setter/getter
109
+ :param data: None - read logs, str - write logs
110
+ :param msgobj: function to stream .log files
111
+ """
103
112
  if data is None:
104
- err_cnt = sum([log_get(f, msgobj) for f in ilist_fs(LOG_FOLDER, type_filter='f') if f.endswith(".sys.log")])
113
+ # READ LOGS
114
+ err_cnt = sum([log_get(f, msgobj) for f in ilist_fs(OSPath.LOGS, type_filter='f') if f.endswith(".sys.log")])
105
115
  return err_cnt
106
-
116
+ # WRITE LOGS - [target].sys.log automatic log level detection
107
117
  _match = match(r"^\[([^\[\]]+)\]", data)
108
118
  log_lvl = _match.group(1).lower() if _match else 'user'
109
- f_name = f"{log_lvl}.sys.log" if log_lvl in ("err", "warn", "boot") else 'user.sys.log'
119
+ f_name = f"{log_lvl}.sys.log" if log_lvl in ("err", "warn", "boot", "info") else 'user.sys.log'
110
120
  return logger(data, f_name, limit=4)
111
121
 
112
122
 
113
123
  def log_clean(msgobj=None):
114
- to_del = [file for file in ilist_fs(LOG_FOLDER, type_filter='f') if file.endswith('.log')]
124
+ """
125
+ Clean logs folder
126
+ """
127
+ logs_dir = OSPath.LOGS
128
+ to_del = [file for file in ilist_fs(logs_dir, type_filter='f') if file.endswith('.log')]
115
129
  for _del in to_del:
116
- _del = f"{LOG_FOLDER}/{_del}"
130
+ _del = path_join(logs_dir, _del)
117
131
  if msgobj is not None:
118
132
  msgobj(f" Delete: {_del}")
119
133
  remove(_del)
micrOS/source/Network.py CHANGED
@@ -19,7 +19,7 @@ from utime import sleep_ms
19
19
  from network import AP_IF, STA_IF, WLAN
20
20
  from machine import unique_id
21
21
  from Config import cfgget, cfgput
22
- from Debug import console_write, errlog_add
22
+ from Debug import console_write, syslog
23
23
 
24
24
 
25
25
  class NW:
@@ -51,7 +51,7 @@ def set_dev_uid():
51
51
  try:
52
52
  cfgput('hwuid', f'micr{hexlify(unique_id()).decode("utf-8")}OS')
53
53
  except Exception as e:
54
- errlog_add(f"[ERR] set_dev_uid error: {e}")
54
+ syslog(f"[ERR] set_dev_uid error: {e}")
55
55
 
56
56
 
57
57
  def get_mac():
@@ -77,7 +77,7 @@ def __select_available_wifi_nw(sta_if, raw_essid, raw_pwd):
77
77
  try:
78
78
  return essid, str(raw_pwd.split(';')[idx]).strip()
79
79
  except Exception as e:
80
- errlog_add(f'[ERR][SET STA] stapwd config error: {e}')
80
+ syslog(f'[ERR][SET STA] stapwd config error: {e}')
81
81
  sleep_ms(400)
82
82
  return None, ''
83
83
 
@@ -149,7 +149,7 @@ def __set_wifi_dev_static_ip(sta_if):
149
149
  sta_if.ifconfig(tuple(conn_ips))
150
150
  return True # was reconfigured
151
151
  except Exception as e:
152
- errlog_add(f"[ERR][STA] StaticIP conf failed: {e}")
152
+ syslog(f"[ERR][STA] StaticIP conf failed: {e}")
153
153
  else:
154
154
  console_write(f"[NW: STA][SKIP] StaticIP conf.: {stored_ip} ? {conn_ips[0]}")
155
155
  else:
@@ -184,9 +184,9 @@ def set_access_point(_essid, _pwd, _authmode=3):
184
184
  # Config #2 (rp2-w)???
185
185
  ap_if.config(essid=_essid, password=_pwd)
186
186
  except Exception as e2:
187
- errlog_add(f"[ERR][AP] config failed: {e2}")
187
+ syslog(f"[ERR][AP] config failed: {e2}")
188
188
  if not (ap_if.active() and str(ap_if.config('essid')) == str(_essid)):
189
- errlog_add("[ERR][AP] error")
189
+ syslog("[ERR][AP] error")
190
190
  console_write(f"\t|\t| [NW: AP] network config: {str(ap_if.ifconfig())}")
191
191
  set_dev_uid()
192
192
  NW.NIF = ap_if
micrOS/source/Notify.py CHANGED
@@ -11,7 +11,7 @@ Designed by Marcell Ban aka BxNxM
11
11
 
12
12
  from Config import cfgget
13
13
  from Tasks import lm_exec, lm_is_loaded
14
- from Debug import errlog_add
14
+ from Debug import syslog
15
15
 
16
16
  #########################################
17
17
  # micrOS Notifications #
@@ -47,7 +47,7 @@ class Notify:
47
47
  # !!! SUBSCRIBER HAS TO DEFINE send_msg(text, reply_to, chat_id) method !!!
48
48
  s.send_msg(text, reply_to, chat_id)
49
49
  except Exception as e:
50
- errlog_add(f"[ERR] Notify: {e}")
50
+ syslog(f"[ERR] Notify: {e}")
51
51
  exit_code+=1
52
52
  return f"Sent for {len(Notify._SUBSCRIBERS)} client(s), errors: ({exit_code})"
53
53