Barmaja-PyArduino 2.0.0__tar.gz
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.
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/BARMAJA_PyArduino.ico +0 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/__init__.py +528 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/__init__.pyi +331 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/__main__.py +2 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/adapters/__init__.py +35 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/api_registry.py +459 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/backend/__init__.py +3 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/backend/uno_cpp.py +1680 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/board.py +80 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/cli.py +223 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/compiler.py +1721 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/console.py +217 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs.py +367 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/Button/arduino/Barmaja_Button/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/Button/arduino/Barmaja_Button/src/Barmaja_Button.h +18 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/Button/example.py +10 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/Button/pack.json +40 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ClockDS3231/arduino/Barmaja_ClockDS3231/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ClockDS3231/arduino/Barmaja_ClockDS3231/src/Barmaja_ClockDS3231.h +20 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ClockDS3231/example.py +8 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ClockDS3231/pack.json +136 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/DistanceVL53L0X/arduino/Barmaja_DistanceVL53L0X/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/DistanceVL53L0X/arduino/Barmaja_DistanceVL53L0X/src/Barmaja_DistanceVL53L0X.h +12 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/DistanceVL53L0X/example.py +8 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/DistanceVL53L0X/pack.json +48 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/LCDParallel/arduino/Barmaja_LCDParallel/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/LCDParallel/arduino/Barmaja_LCDParallel/src/Barmaja_LCDParallel.h +17 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/LCDParallel/example.py +10 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/LCDParallel/pack.json +137 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/LoadCellHX711/arduino/Barmaja_LoadCellHX711/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/LoadCellHX711/arduino/Barmaja_LoadCellHX711/src/Barmaja_LoadCellHX711.h +16 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/LoadCellHX711/example.py +11 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/LoadCellHX711/pack.json +74 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/NeoPixelStrip/arduino/Barmaja_NeoPixelStrip/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/NeoPixelStrip/arduino/Barmaja_NeoPixelStrip/src/Barmaja_NeoPixelStrip.h +15 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/NeoPixelStrip/example.py +13 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/NeoPixelStrip/pack.json +114 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/OLEDText/arduino/Barmaja_OLEDText/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/OLEDText/arduino/Barmaja_OLEDText/src/Barmaja_OLEDText.h +21 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/OLEDText/example.py +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/OLEDText/pack.json +103 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/PressureBMP280/arduino/Barmaja_PressureBMP280/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/PressureBMP280/arduino/Barmaja_PressureBMP280/src/Barmaja_PressureBMP280.h +16 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/PressureBMP280/example.py +8 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/PressureBMP280/pack.json +92 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/RotaryEncoder/arduino/Barmaja_RotaryEncoder/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/RotaryEncoder/arduino/Barmaja_RotaryEncoder/src/Barmaja_RotaryEncoder.h +18 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/RotaryEncoder/example.py +10 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/RotaryEncoder/pack.json +44 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ServoDriverPCA9685/arduino/Barmaja_ServoDriverPCA9685/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ServoDriverPCA9685/arduino/Barmaja_ServoDriverPCA9685/src/Barmaja_ServoDriverPCA9685.h +15 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ServoDriverPCA9685/example.py +10 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ServoDriverPCA9685/pack.json +117 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ShiftRegister595/arduino/Barmaja_ShiftRegister595/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ShiftRegister595/arduino/Barmaja_ShiftRegister595/src/Barmaja_ShiftRegister595.h +14 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ShiftRegister595/example.py +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/ShiftRegister595/pack.json +83 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/TemperatureDS18B20/arduino/Barmaja_TemperatureDS18B20/library.properties +9 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/TemperatureDS18B20/arduino/Barmaja_TemperatureDS18B20/src/Barmaja_TemperatureDS18B20.h +16 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/TemperatureDS18B20/example.py +8 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/device_packs_builtin/TemperatureDS18B20/pack.json +63 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/doctor.py +406 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/environment.py +595 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/errors.py +166 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/flow.py +754 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/frontend.py +611 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/installer.py +151 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/ir.py +660 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/library_adder.py +440 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/live.py +859 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/lowering.py +596 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/numeric.py +748 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/pack_builder.py +544 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/py.typed +0 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/serial_monitor.py +172 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/source.py +184 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/stubgen.py +148 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/symbols.py +646 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/target.py +1631 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/toolchain.py +506 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/typesys.py +917 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino/workflow.py +213 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino.egg-info/PKG-INFO +39 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino.egg-info/SOURCES.txt +90 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino.egg-info/dependency_links.txt +1 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino.egg-info/requires.txt +1 -0
- barmaja_pyarduino-2.0.0/Barmaja_PyArduino.egg-info/top_level.txt +1 -0
- barmaja_pyarduino-2.0.0/LICENSE.txt +7 -0
- barmaja_pyarduino-2.0.0/PKG-INFO +39 -0
- barmaja_pyarduino-2.0.0/README.md +16 -0
- barmaja_pyarduino-2.0.0/pyproject.toml +36 -0
- barmaja_pyarduino-2.0.0/setup.cfg +4 -0
|
Binary file
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
"""Student-facing Barmaja PyArduino API.
|
|
2
|
+
|
|
3
|
+
Two execution modes use the same Arduino-style student API:
|
|
4
|
+
|
|
5
|
+
Standalone mode
|
|
6
|
+
``upload()`` compiles the Python program to Arduino C++ and uploads it. The
|
|
7
|
+
Uno then runs independently from the PC.
|
|
8
|
+
|
|
9
|
+
LiveRun mode
|
|
10
|
+
``LiveRun()`` keeps Python running on the PC/PictoBlox and controls the Uno
|
|
11
|
+
live through the pinned Telemetrix firmware.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
__version__ = "2.0.0"
|
|
15
|
+
# Internal same-version build marker used by the small DEV1 updater. Earlier
|
|
16
|
+
# DEV1 wheels share the public version but do not contain the final runtime
|
|
17
|
+
# layout fix, so version metadata alone cannot identify the corrected build.
|
|
18
|
+
__liverun_update__ = "1.1.0.dev8-library-adder-2026-10-31"
|
|
19
|
+
|
|
20
|
+
HIGH = 1
|
|
21
|
+
LOW = 0
|
|
22
|
+
INPUT = 0
|
|
23
|
+
OUTPUT = 1
|
|
24
|
+
INPUT_PULLUP = 2
|
|
25
|
+
A0, A1, A2, A3, A4, A5 = 14, 15, 16, 17, 18, 19
|
|
26
|
+
DHT11 = 11
|
|
27
|
+
DHT22 = 22
|
|
28
|
+
CM = 28
|
|
29
|
+
INC = 71
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ArduinoOnlyError(RuntimeError):
|
|
33
|
+
"""Raised when Arduino-only code is run on the PC without LiveRun."""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _not_desktop(*_args, **_kwargs):
|
|
37
|
+
raise ArduinoOnlyError(
|
|
38
|
+
"This is a Barmaja PyArduino program. Choose one mode near the top: "
|
|
39
|
+
"upload() for standalone Arduino execution, or LiveRun() for live PC/PictoBlox control."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _live_backend_or_none():
|
|
44
|
+
try:
|
|
45
|
+
from .live import is_live, backend
|
|
46
|
+
return backend() if is_live() else None
|
|
47
|
+
except Exception:
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _dispatch(method, *args):
|
|
52
|
+
live = _live_backend_or_none()
|
|
53
|
+
if live is None:
|
|
54
|
+
return _not_desktop(*args)
|
|
55
|
+
return getattr(live, method)(*args)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def pinMode(pin, mode):
|
|
59
|
+
return _dispatch("pin_mode", pin, mode)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def digitalWrite(pin, value):
|
|
63
|
+
return _dispatch("digital_write", pin, value)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def digitalRead(pin):
|
|
67
|
+
return _dispatch("digital_read", pin)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def analogRead(pin):
|
|
71
|
+
return _dispatch("analog_read", pin)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def analogWrite(pin, value):
|
|
75
|
+
return _dispatch("analog_write", pin, value)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def delay(milliseconds):
|
|
79
|
+
return _dispatch("delay", milliseconds)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def millis():
|
|
83
|
+
return _dispatch("millis")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def tone(pin, frequency, duration=None):
|
|
87
|
+
"""Arduino square-wave output. Standalone only until tested LiveRun firmware exists."""
|
|
88
|
+
if _live_backend_or_none() is not None:
|
|
89
|
+
raise RuntimeError("tone() is available with upload(), but not with LiveRun() yet (Telemetrix firmware has no tone command).")
|
|
90
|
+
return _not_desktop(pin, frequency, duration)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def noTone(pin):
|
|
94
|
+
if _live_backend_or_none() is not None:
|
|
95
|
+
raise RuntimeError("noTone() is available with upload(), but not with LiveRun() yet (Telemetrix firmware has no tone command).")
|
|
96
|
+
return _not_desktop(pin)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def micros():
|
|
100
|
+
if _live_backend_or_none() is not None:
|
|
101
|
+
raise RuntimeError("micros() currently requires upload() mode; LiveRun timing is host-side, not Arduino microseconds.")
|
|
102
|
+
return _not_desktop()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def delayMicroseconds(microseconds):
|
|
106
|
+
if _live_backend_or_none() is not None:
|
|
107
|
+
raise RuntimeError("delayMicroseconds() currently requires upload() mode; USB LiveRun timing cannot guarantee microseconds.")
|
|
108
|
+
return _not_desktop(microseconds)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def map(value, in_min, in_max, out_min, out_max):
|
|
112
|
+
"""Integer Arduino-style linear mapping (truncates division toward zero)."""
|
|
113
|
+
if in_min == in_max:
|
|
114
|
+
raise ValueError("map() input range cannot have equal minimum and maximum.")
|
|
115
|
+
# Small host-only convenience for LiveRun; always compiled to C++ for upload().
|
|
116
|
+
numerator = (value - in_min) * (out_max - out_min)
|
|
117
|
+
denominator = in_max - in_min
|
|
118
|
+
result = (abs(numerator) // abs(denominator)) * (1 if numerator * denominator >= 0 else -1) + out_min
|
|
119
|
+
return result
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def constrain(value, lower, upper):
|
|
123
|
+
if lower > upper:
|
|
124
|
+
raise ValueError("constrain() requires lower <= upper.")
|
|
125
|
+
return max(lower, min(value, upper))
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# Stage 2 hardware is compiled into the Uno sketch for upload() only.
|
|
129
|
+
# Explicitly reject desktop/LiveRun usage rather than pretending it works.
|
|
130
|
+
class _UploadOnlyModule:
|
|
131
|
+
_label = "Stage 2 device"
|
|
132
|
+
def _only_upload(self, *args):
|
|
133
|
+
if _live_backend_or_none() is not None:
|
|
134
|
+
raise RuntimeError(f"{self._label} is supported by upload() only, not LiveRun() yet.")
|
|
135
|
+
return _not_desktop(*args)
|
|
136
|
+
|
|
137
|
+
# Stage 4: separate module-dependent standalone transports and motion sensors.
|
|
138
|
+
class BluetoothSerial(_UploadOnlyModule):
|
|
139
|
+
_label = "BluetoothSerial (HC-05/HC-06 UART)"
|
|
140
|
+
def __init__(self, rx_pin, tx_pin): self.pins = (rx_pin, tx_pin)
|
|
141
|
+
def begin(self, baud): return self._only_upload(baud)
|
|
142
|
+
def listen(self): return self._only_upload()
|
|
143
|
+
def available(self): return self._only_upload()
|
|
144
|
+
def read(self): return self._only_upload()
|
|
145
|
+
def write(self, value): return self._only_upload(value)
|
|
146
|
+
|
|
147
|
+
class MPU6050Sensor(_UploadOnlyModule):
|
|
148
|
+
_label = "MPU6050Sensor (GY-521 only)"
|
|
149
|
+
def begin(self): return self._only_upload()
|
|
150
|
+
def update(self): return self._only_upload()
|
|
151
|
+
def angleX(self): return self._only_upload()
|
|
152
|
+
def angleY(self): return self._only_upload()
|
|
153
|
+
def angleZ(self): return self._only_upload()
|
|
154
|
+
def accelX(self): return self._only_upload()
|
|
155
|
+
def accelY(self): return self._only_upload()
|
|
156
|
+
def accelZ(self): return self._only_upload()
|
|
157
|
+
def gyroX(self): return self._only_upload()
|
|
158
|
+
def gyroY(self): return self._only_upload()
|
|
159
|
+
def gyroZ(self): return self._only_upload()
|
|
160
|
+
|
|
161
|
+
class GPSModule(_UploadOnlyModule):
|
|
162
|
+
_label = "GPSModule (NMEA UART)"
|
|
163
|
+
def __init__(self, rx_pin, tx_pin): self.pins = (rx_pin, tx_pin)
|
|
164
|
+
def begin(self, baud): return self._only_upload(baud)
|
|
165
|
+
def update(self): return self._only_upload()
|
|
166
|
+
def hasFix(self): return self._only_upload()
|
|
167
|
+
def latitude(self): return self._only_upload()
|
|
168
|
+
def longitude(self): return self._only_upload()
|
|
169
|
+
def satellites(self): return self._only_upload()
|
|
170
|
+
|
|
171
|
+
class EthernetW5500(_UploadOnlyModule):
|
|
172
|
+
_label = "EthernetW5500 (W5500 shield/module)"
|
|
173
|
+
def __init__(self, cs_pin, mac0, mac1, mac2, mac3, mac4, mac5):
|
|
174
|
+
self.mac = (mac0,mac1,mac2,mac3,mac4,mac5); self.cs_pin = cs_pin
|
|
175
|
+
def beginIP(self, a,b,c,d): return self._only_upload(a,b,c,d)
|
|
176
|
+
def connect(self, a,b,c,d,port): return self._only_upload(a,b,c,d,port)
|
|
177
|
+
def connected(self): return self._only_upload()
|
|
178
|
+
def write(self, value): return self._only_upload(value)
|
|
179
|
+
def available(self): return self._only_upload()
|
|
180
|
+
def read(self): return self._only_upload()
|
|
181
|
+
def stop(self): return self._only_upload()
|
|
182
|
+
|
|
183
|
+
class WiFiESPAT(_UploadOnlyModule):
|
|
184
|
+
_label = "WiFiESPAT (ESP8266/ESP32 with AT firmware)"
|
|
185
|
+
def __init__(self, rx_pin, tx_pin): self.pins = (rx_pin, tx_pin)
|
|
186
|
+
def begin(self, baud): return self._only_upload(baud)
|
|
187
|
+
def connect(self, ssid, password): return self._only_upload(ssid,password)
|
|
188
|
+
def connected(self): return self._only_upload()
|
|
189
|
+
def tcpConnect(self, a,b,c,d,port): return self._only_upload(a,b,c,d,port)
|
|
190
|
+
def write(self, value): return self._only_upload(value)
|
|
191
|
+
def available(self): return self._only_upload()
|
|
192
|
+
def read(self): return self._only_upload()
|
|
193
|
+
def stop(self): return self._only_upload()
|
|
194
|
+
|
|
195
|
+
class RFID(_UploadOnlyModule):
|
|
196
|
+
_label = "RFID"
|
|
197
|
+
def __init__(self, ss_pin, reset_pin):
|
|
198
|
+
self.ss_pin = ss_pin
|
|
199
|
+
self.reset_pin = reset_pin
|
|
200
|
+
def begin(self): return self._only_upload()
|
|
201
|
+
def readUID(self): return self._only_upload()
|
|
202
|
+
|
|
203
|
+
class IRRemote(_UploadOnlyModule):
|
|
204
|
+
_label = "IRRemote"
|
|
205
|
+
def __init__(self, receive_pin): self.receive_pin = receive_pin
|
|
206
|
+
def begin(self): return self._only_upload()
|
|
207
|
+
def readCommand(self): return self._only_upload()
|
|
208
|
+
|
|
209
|
+
class Keypad4x4(_UploadOnlyModule):
|
|
210
|
+
_label = "Keypad4x4"
|
|
211
|
+
def __init__(self, r1, r2, r3, r4, c1, c2, c3, c4):
|
|
212
|
+
self.pins = (r1,r2,r3,r4,c1,c2,c3,c4)
|
|
213
|
+
def getKey(self): return self._only_upload()
|
|
214
|
+
|
|
215
|
+
class StepperMotor(_UploadOnlyModule):
|
|
216
|
+
_label = "StepperMotor"
|
|
217
|
+
def __init__(self, p1,p2,p3,p4): self.pins = (p1,p2,p3,p4)
|
|
218
|
+
def setMaxSpeed(self, speed): return self._only_upload(speed)
|
|
219
|
+
def setAcceleration(self, value): return self._only_upload(value)
|
|
220
|
+
def moveTo(self, position): return self._only_upload(position)
|
|
221
|
+
def move(self, distance): return self._only_upload(distance)
|
|
222
|
+
def run(self): return self._only_upload()
|
|
223
|
+
def distanceToGo(self): return self._only_upload()
|
|
224
|
+
def currentPosition(self): return self._only_upload()
|
|
225
|
+
def setCurrentPosition(self, position): return self._only_upload(position)
|
|
226
|
+
|
|
227
|
+
class OneWireBus(_UploadOnlyModule):
|
|
228
|
+
_label = "OneWireBus"
|
|
229
|
+
def __init__(self, pin): self.pin = pin
|
|
230
|
+
def reset(self): return self._only_upload()
|
|
231
|
+
def write(self, value): return self._only_upload(value)
|
|
232
|
+
def read(self): return self._only_upload()
|
|
233
|
+
|
|
234
|
+
class LEDMatrixMAX7219(_UploadOnlyModule):
|
|
235
|
+
_label = "LEDMatrixMAX7219 (MAX7219/MAX7221 only)"
|
|
236
|
+
def __init__(self, data_pin, clk_pin, cs_pin): self.pins = (data_pin, clk_pin, cs_pin)
|
|
237
|
+
def begin(self): return self._only_upload()
|
|
238
|
+
def clear(self): return self._only_upload()
|
|
239
|
+
def setPixel(self, row, col, on): return self._only_upload(row,col,on)
|
|
240
|
+
def setRow(self, row, value): return self._only_upload(row,value)
|
|
241
|
+
def setBrightness(self, brightness): return self._only_upload(brightness)
|
|
242
|
+
|
|
243
|
+
class FourDigitTM1637(_UploadOnlyModule):
|
|
244
|
+
_label = "FourDigitTM1637 (TM1637 only)"
|
|
245
|
+
def __init__(self, clk_pin, dio_pin): self.pins = (clk_pin,dio_pin)
|
|
246
|
+
def setBrightness(self, brightness): return self._only_upload(brightness)
|
|
247
|
+
def showNumber(self, number): return self._only_upload(number)
|
|
248
|
+
def clear(self): return self._only_upload()
|
|
249
|
+
|
|
250
|
+
class _EEPROMAPI(_UploadOnlyModule):
|
|
251
|
+
_label = "EEPROM"
|
|
252
|
+
def read(self, address): return self._only_upload(address)
|
|
253
|
+
def write(self, address, value): return self._only_upload(address,value)
|
|
254
|
+
def update(self, address, value): return self._only_upload(address,value)
|
|
255
|
+
def length(self): return self._only_upload()
|
|
256
|
+
EEPROM = _EEPROMAPI()
|
|
257
|
+
|
|
258
|
+
class _SPIAPI(_UploadOnlyModule):
|
|
259
|
+
_label = "SPI"
|
|
260
|
+
def begin(self): return self._only_upload()
|
|
261
|
+
def transfer(self, value): return self._only_upload(value)
|
|
262
|
+
def end(self): return self._only_upload()
|
|
263
|
+
SPI = _SPIAPI()
|
|
264
|
+
|
|
265
|
+
class Servo:
|
|
266
|
+
def __init__(self):
|
|
267
|
+
self._pin = None
|
|
268
|
+
self._last_angle = None
|
|
269
|
+
|
|
270
|
+
def attach(self, pin, min_us=None, max_us=None):
|
|
271
|
+
if (min_us is None) != (max_us is None):
|
|
272
|
+
raise TypeError("Servo.attach() accepts attach(pin) or attach(pin, min, max).")
|
|
273
|
+
live = _live_backend_or_none()
|
|
274
|
+
if live is None:
|
|
275
|
+
return _not_desktop(pin, min_us, max_us)
|
|
276
|
+
live.servo_attach(pin, min_us, max_us)
|
|
277
|
+
self._pin = int(pin)
|
|
278
|
+
|
|
279
|
+
def _attached_pin(self):
|
|
280
|
+
if self._pin is None:
|
|
281
|
+
raise RuntimeError("Call Servo.attach(pin) before using this Servo.")
|
|
282
|
+
return self._pin
|
|
283
|
+
|
|
284
|
+
def write(self, angle):
|
|
285
|
+
live = _live_backend_or_none()
|
|
286
|
+
if live is None:
|
|
287
|
+
return _not_desktop(angle)
|
|
288
|
+
result = live.servo_write(self._attached_pin(), angle)
|
|
289
|
+
self._last_angle = int(angle)
|
|
290
|
+
return result
|
|
291
|
+
|
|
292
|
+
def writeMicroseconds(self, microseconds):
|
|
293
|
+
live = _live_backend_or_none()
|
|
294
|
+
if live is None:
|
|
295
|
+
return _not_desktop(microseconds)
|
|
296
|
+
return live.servo_write_microseconds(self._attached_pin(), microseconds)
|
|
297
|
+
|
|
298
|
+
def read(self):
|
|
299
|
+
live = _live_backend_or_none()
|
|
300
|
+
if live is None:
|
|
301
|
+
return _not_desktop()
|
|
302
|
+
if self._last_angle is None:
|
|
303
|
+
raise RuntimeError("Servo.read() has no value yet; call Servo.write(angle) first in LiveRun.")
|
|
304
|
+
return self._last_angle
|
|
305
|
+
|
|
306
|
+
def detach(self):
|
|
307
|
+
live = _live_backend_or_none()
|
|
308
|
+
if live is None:
|
|
309
|
+
return _not_desktop()
|
|
310
|
+
pin = self._attached_pin()
|
|
311
|
+
result = live.servo_detach(pin)
|
|
312
|
+
self._pin = None
|
|
313
|
+
return result
|
|
314
|
+
|
|
315
|
+
def attached(self):
|
|
316
|
+
live = _live_backend_or_none()
|
|
317
|
+
if live is None:
|
|
318
|
+
return _not_desktop()
|
|
319
|
+
return False if self._pin is None else bool(live.servo_attached(self._pin))
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
class Ultrasonic:
|
|
323
|
+
def __init__(self, trigger_pin, echo_pin):
|
|
324
|
+
self._pins = (int(trigger_pin), int(echo_pin))
|
|
325
|
+
|
|
326
|
+
def read(self, unit=None):
|
|
327
|
+
if unit not in (None, CM):
|
|
328
|
+
raise ValueError("LiveRun ultrasonic currently supports centimetres (CM).")
|
|
329
|
+
live = _live_backend_or_none()
|
|
330
|
+
if live is None:
|
|
331
|
+
return _not_desktop(unit)
|
|
332
|
+
return live.ultrasonic_read(*self._pins)
|
|
333
|
+
|
|
334
|
+
def setTimeout(self, timeout):
|
|
335
|
+
# Existing Telemetrix wrapper manages its own bounded read timeout.
|
|
336
|
+
# Keep the call accepted in standalone compilation, but make unsupported
|
|
337
|
+
# live behavior explicit rather than silently ignoring it.
|
|
338
|
+
if _live_backend_or_none() is not None:
|
|
339
|
+
raise RuntimeError("Ultrasonic.setTimeout() is not configurable in LiveRun DEV1.")
|
|
340
|
+
return _not_desktop(timeout)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
class DHT:
|
|
344
|
+
def __init__(self, pin, sensor_type):
|
|
345
|
+
self._config = (int(pin), int(sensor_type))
|
|
346
|
+
self._begun = False
|
|
347
|
+
|
|
348
|
+
def begin(self):
|
|
349
|
+
live = _live_backend_or_none()
|
|
350
|
+
if live is None:
|
|
351
|
+
return _not_desktop()
|
|
352
|
+
live.dht_begin(*self._config)
|
|
353
|
+
self._begun = True
|
|
354
|
+
|
|
355
|
+
def _last(self):
|
|
356
|
+
live = _live_backend_or_none()
|
|
357
|
+
if live is None:
|
|
358
|
+
return _not_desktop()
|
|
359
|
+
if not self._begun:
|
|
360
|
+
live.dht_begin(*self._config)
|
|
361
|
+
self._begun = True
|
|
362
|
+
return live.dht_last(*self._config)
|
|
363
|
+
|
|
364
|
+
def readTemperature(self):
|
|
365
|
+
temperature, _humidity = self._last()
|
|
366
|
+
return temperature
|
|
367
|
+
|
|
368
|
+
def readHumidity(self):
|
|
369
|
+
_temperature, humidity = self._last()
|
|
370
|
+
return humidity
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
class LiquidCrystal_I2C:
|
|
374
|
+
def __init__(self, address, columns, rows):
|
|
375
|
+
self._config = (int(address), int(columns), int(rows))
|
|
376
|
+
self._lcd = None
|
|
377
|
+
|
|
378
|
+
def _ensure_lcd(self):
|
|
379
|
+
live = _live_backend_or_none()
|
|
380
|
+
if live is None:
|
|
381
|
+
return _not_desktop()
|
|
382
|
+
if self._lcd is None:
|
|
383
|
+
self._lcd = live.lcd_create(*self._config)
|
|
384
|
+
return self._lcd
|
|
385
|
+
|
|
386
|
+
def init(self):
|
|
387
|
+
return self._ensure_lcd().begin()
|
|
388
|
+
|
|
389
|
+
def begin(self, columns, rows, charsize=None):
|
|
390
|
+
# Constructor dimensions remain authoritative in the Arduino-compatible
|
|
391
|
+
# API. Accept matching begin() dimensions used by many classroom examples.
|
|
392
|
+
if int(columns) != self._config[1] or int(rows) != self._config[2]:
|
|
393
|
+
self._config = (self._config[0], int(columns), int(rows))
|
|
394
|
+
self._lcd = None
|
|
395
|
+
return self._ensure_lcd().begin()
|
|
396
|
+
|
|
397
|
+
def clear(self): return self._ensure_lcd().clear()
|
|
398
|
+
def home(self): return self._ensure_lcd().home()
|
|
399
|
+
def setCursor(self, column, row): return self._ensure_lcd().set_cursor(column, row)
|
|
400
|
+
def print(self, value): return self._ensure_lcd().print(value)
|
|
401
|
+
def backlight(self): return self._ensure_lcd().backlight(True)
|
|
402
|
+
def noBacklight(self): return self._ensure_lcd().backlight(False)
|
|
403
|
+
def display(self): return self._ensure_lcd().display(True)
|
|
404
|
+
def noDisplay(self): return self._ensure_lcd().display(False)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def _arduino_text(value, fmt=None) -> str:
|
|
408
|
+
"""Format a value like Arduino's ``Serial.print`` (used by LiveRun only).
|
|
409
|
+
|
|
410
|
+
* int + base 2/8/10/16 -> that base (HEX uppercase, like Arduino);
|
|
411
|
+
* float -> 2 decimals by default, or ``fmt`` decimals;
|
|
412
|
+
* bool -> 1 / 0 (Arduino prints bool as an integer);
|
|
413
|
+
* str -> unchanged.
|
|
414
|
+
"""
|
|
415
|
+
if isinstance(value, bool):
|
|
416
|
+
return "1" if value else "0"
|
|
417
|
+
if isinstance(value, int):
|
|
418
|
+
if fmt in (None, 10):
|
|
419
|
+
return str(value)
|
|
420
|
+
digits = {2: "01", 8: "01234567", 16: "0123456789ABCDEF"}
|
|
421
|
+
if fmt not in digits:
|
|
422
|
+
return str(value)
|
|
423
|
+
base = int(fmt)
|
|
424
|
+
number = value if value >= 0 else value & 0xFFFFFFFF # Arduino prints negatives as unsigned
|
|
425
|
+
if number == 0:
|
|
426
|
+
return "0"
|
|
427
|
+
out = ""
|
|
428
|
+
while number:
|
|
429
|
+
number, rem = divmod(number, base)
|
|
430
|
+
out = digits[base][rem] + out
|
|
431
|
+
return out
|
|
432
|
+
if isinstance(value, float):
|
|
433
|
+
places = 2 if fmt is None else int(fmt)
|
|
434
|
+
return f"{value:.{places}f}"
|
|
435
|
+
return str(value)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
class _SerialAPI:
|
|
439
|
+
"""``Serial`` for both modes.
|
|
440
|
+
|
|
441
|
+
``upload()`` programs are compiled to real Arduino Serial calls; this object
|
|
442
|
+
is only used on the PC. In LiveRun mode it is a *stdout compatibility layer*:
|
|
443
|
+
Telemetrix owns the USB port, so text goes to the host Python console and
|
|
444
|
+
nothing is ever written into the Telemetrix binary channel.
|
|
445
|
+
``Serial.begin(baud)`` is a documented no-op in LiveRun (the Telemetrix
|
|
446
|
+
firmware baud is fixed).
|
|
447
|
+
"""
|
|
448
|
+
|
|
449
|
+
def _live(self) -> bool:
|
|
450
|
+
return _live_backend_or_none() is not None
|
|
451
|
+
|
|
452
|
+
@staticmethod
|
|
453
|
+
def _emit(text: str) -> None:
|
|
454
|
+
import sys
|
|
455
|
+
try:
|
|
456
|
+
sys.stdout.write(text)
|
|
457
|
+
except UnicodeEncodeError:
|
|
458
|
+
enc = getattr(sys.stdout, "encoding", None) or "ascii"
|
|
459
|
+
sys.stdout.write(text.encode(enc, errors="replace").decode(enc, errors="replace"))
|
|
460
|
+
try:
|
|
461
|
+
sys.stdout.flush()
|
|
462
|
+
except Exception:
|
|
463
|
+
pass
|
|
464
|
+
|
|
465
|
+
def begin(self, baud=9600):
|
|
466
|
+
if self._live():
|
|
467
|
+
return None
|
|
468
|
+
return _not_desktop(baud)
|
|
469
|
+
|
|
470
|
+
def print(self, value="", fmt=None):
|
|
471
|
+
if self._live():
|
|
472
|
+
self._emit(_arduino_text(value, fmt))
|
|
473
|
+
return None
|
|
474
|
+
return _not_desktop(value, fmt)
|
|
475
|
+
|
|
476
|
+
def println(self, value=None, fmt=None):
|
|
477
|
+
if self._live():
|
|
478
|
+
self._emit(("" if value is None else _arduino_text(value, fmt)) + "\n")
|
|
479
|
+
return None
|
|
480
|
+
return _not_desktop(value, fmt)
|
|
481
|
+
|
|
482
|
+
def available(self):
|
|
483
|
+
if self._live():
|
|
484
|
+
raise RuntimeError("Serial.available() is unavailable in LiveRun because Telemetrix owns USB Serial.")
|
|
485
|
+
return _not_desktop()
|
|
486
|
+
|
|
487
|
+
def read(self):
|
|
488
|
+
if self._live():
|
|
489
|
+
raise RuntimeError("Serial.read() is unavailable in LiveRun because Telemetrix owns USB Serial.")
|
|
490
|
+
return _not_desktop()
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
class _WireAPI:
|
|
494
|
+
def begin(self): return _dispatch("wire_begin")
|
|
495
|
+
def beginTransmission(self, address): return _dispatch("wire_begin_transmission", address)
|
|
496
|
+
def write(self, value): return _dispatch("wire_write", value)
|
|
497
|
+
def endTransmission(self): return _dispatch("wire_end_transmission")
|
|
498
|
+
def requestFrom(self, address, count): return _dispatch("wire_request_from", address, count)
|
|
499
|
+
def available(self): return _dispatch("wire_available")
|
|
500
|
+
def read(self): return _dispatch("wire_read")
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
Serial = _SerialAPI()
|
|
504
|
+
Wire = _WireAPI()
|
|
505
|
+
|
|
506
|
+
# Device packs: one upload-only Python class per pack.json (same names the compiler uses).
|
|
507
|
+
from . import device_packs as _device_packs
|
|
508
|
+
from . import api_registry as _api_registry # noqa: F401 (loads packs)
|
|
509
|
+
def _install_device_pack_classes() -> None:
|
|
510
|
+
for name, pack in _device_packs.LOADED.items():
|
|
511
|
+
globals()[name] = _device_packs.make_python_class(pack, _UploadOnlyModule)
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
_install_device_pack_classes()
|
|
515
|
+
|
|
516
|
+
# PC-side workflows callable from PictoBlox and normal Python editors.
|
|
517
|
+
from .workflow import show_code, upload, verify
|
|
518
|
+
from .live import LiveRun, LiveStop
|
|
519
|
+
|
|
520
|
+
# Diagnostic helper for PictoBlox/embedded Python hosts.
|
|
521
|
+
from .doctor import doctor_pictoblox
|
|
522
|
+
|
|
523
|
+
__all__ = [
|
|
524
|
+
"HIGH", "LOW", "INPUT", "OUTPUT", "INPUT_PULLUP", "A0", "A1", "A2", "A3", "A4", "A5",
|
|
525
|
+
"DHT11", "DHT22", "CM", "INC", "pinMode", "digitalWrite", "digitalRead", "analogRead", "analogWrite",
|
|
526
|
+
"delay", "millis", "tone", "noTone", "micros", "delayMicroseconds", "map", "constrain", "Servo", "Ultrasonic", "DHT", "LiquidCrystal_I2C", "RFID", "IRRemote", "Keypad4x4", "StepperMotor", "OneWireBus", "LEDMatrixMAX7219", "FourDigitTM1637", "BluetoothSerial", "MPU6050Sensor", "GPSModule", "EthernetW5500", "WiFiESPAT", "EEPROM", "SPI", "Serial", "Wire",
|
|
527
|
+
"upload", "verify", "show_code", "LiveRun", "LiveStop",
|
|
528
|
+
] + list(_device_packs.LOADED)
|