Biblioteques Python per controlar l'IoT-Vertebrae des de Raspberry Pi, amb bus CAN (recomanat) o bus I2C. Inclou referència per al simulador en línia.
# I2C + SPI dtparam=i2c_arm=on dtparam=spi=on # MCP2515 (8 MHz, IRQ GPIO6) dtoverlay=mcp2515-can0,oscillator=8000000,interrupt=6,spimaxfrequency=1000000 dtoverlay=spi-bcm2835-overlay
# Instal·lar python-can
sudo apt install -y python3-can
# Activar I2C
dtparam=i2c_arm=on
# Instal·lar smbus
sudo apt install -y python3-smbus
can_on() / can_off().
API recomanada per a Head02 (ESP32-S3). Comunicació via bus CAN a 100 kbps. Suporta callbacks asíncrons de canvis d'entrada digital.
import can_iotv_v2_1 as iotv iotv.can_on() print(iotv.dversion('0000')) # '1.5' print(iotv.aversion('0000')) # '1.4' iotv.can_off()
Activa la interfície CAN (can0) a 100 kbps. Executa sudo ip link set up can0 type can bitrate 100000. Cal cridar-la al principi de qualsevol programa.
Atura tots els listeners actius, tanca el bus CAN i executa sudo ifconfig can0 down. El tancament també es fa automàticament en sortir del programa (atexit).
Llegeix les 8 entrades digitals d'un costat. Les entrades arriben en actiu baix des de la vèrtebra; la biblioteca les inverteix i retorna el byte en actiu alt com a string de 8 bits.
| Paràmetre | Tipus | Descripció |
|---|---|---|
| addr | str | Adreça binària de 4 bits (ex: '0000') |
| side | str | 'A' o 'B' |
| → | str | String binari de 8 caràcters (ex: '10110100'), o 'Error' en timeout |
val = iotv.din('0000', 'B') # ex: '00100100' di1 = bool(int(val[6])) # bit DI1 (posició 6 des de l'esquerra)
Escriu el byte complet (0–255) a un costat de sortida digital. Els 8 LEDs/relès s'actualitzen en un sol missatge CAN.
iotv.dout('0000', 'A', 0xFF) # tots encesos iotv.dout('0000', 'A', 0x00) # tots apagats
Escriu un bit individual de sortida sense afectar els altres. posbyte és 0 (DO0) a 7 (DO7). value és 0 o 1.
for bit in range(8): iotv.doutbit('0000', 'A', bit, 1) time.sleep(0.1) iotv.doutbit('0000', 'A', bit, 0)
Configura els modes de treball dels dos costats d'una vèrtebra digital. El costat A pot ser 'din', 'dout' o 'pwm'. El costat B afegeix 'touch'. Restriccions: PWM només pot estar a un costat; 'touch' només al costat B.
iotv.dsetup('0000', 'dout', 'din') iotv.dsetup('0001', 'pwm', 'din')
Llegeix la configuració actual de la vèrtebra digital i retorna un string llegible.
iotv.getdsetup('0000') # 'A:dout, B:din'
Retorna la versió del firmware de la vèrtebra digital (ex: '1.5'), o '0.0' en timeout.
on_din_change() registra un callback que s'executa en un thread de fons sense fer polling, de manera que no col·lapsa el bus.
Registra un callback per a canvis d'entrada digital espontanis de la vèrtebra a addr. El callback rep tres arguments: addr (int, adreça i2c), val_a (byte del costat A, actiu alt), val_b (byte del costat B, actiu alt). El callback s'executa en un thread de fons (core separat del while True principal).
seq_running = False last_di1 = None def on_din_change(addr, val_a, val_b): global seq_running, last_di1 di1 = bool(val_b & 0x02) # DI1 = bit 1 del costat B if di1 == last_di1: return last_di1 = di1 if di1: seq_running = True else: seq_running = False iotv.dout('0000', 'A', 0x00) iotv.can_on() iotv.dsetup('0000', 'dout', 'din') iotv.on_din_change('0000', on_din_change) while True: if seq_running: # ... lògica de seqüència ... time.sleep(0.05)
Cancel·la el listener de canvis digitals per a l'adreça indicada. Atura el thread de fons de manera neta.
Cancel·la tots els listeners actius. Es crida automàticament a can_off().
Llegeix una entrada analògica. ndac és 1, 2, 3 o 4. Retorna el valor cru de 16 bits (0–26624) corresponent a −10V..+10V, o 'Error' en timeout.
raw = iotv.ain('0000', 'B', 1) volts = iotv.ain2v(raw) # ex: 4.98
Escriu un valor cru (0–4095) a un canal DAC. ndac és 1–4. Useu v2aout() per convertir des de volts. Per enregistrar un valor a l'EEPROM del DAC (default en reset), sumeu 4096 al valor. Limiteu les escriptures EEPROM a menys de 20.000 vegades.
iotv.aout('0000', 'B', 1, iotv.v2aout(5.0)) # 5V al canal 1 # Enregistrar 9.3V a l'EEPROM del DAC canal 4: iotv.aout('0000', 'B', 4, 4096 + iotv.v2aout(9.3))
Retorna la versió del firmware de la vèrtebra analògica (ex: '1.4'), o '0.0' en timeout.
Llegeix la configuració de la vèrtebra analògica. Retorna string com 'A:ain, B:aout'.
Converteix el valor cru ADC (0–26624) a volts (−10.0 a +10.0 V, 2 decimals).
iotv.ain2v(26624) # → 10.0 iotv.ain2v(13312) # → 0.0 iotv.ain2v(0) # → -10.0
Converteix una tensió entre 0 i 10 V al valor cru de 12 bits (0–4095) per al DAC. Els valors fora del rang es clampegen per evitar escriptures accidentals a l'EEPROM del DAC.
iotv.v2aout(10.0) # → 4095 iotv.v2aout(5.0) # → 2048 iotv.v2aout(0.0) # → 0
Compatible amb qualsevol versió de cap (Head01 i Head02). Cada crida obre i tanca el bus I2C; no cal inicialitzar un bus global.
import i2c_iotv as iotv print(iotv.dversion('0000')) # 'Digital rib version: 1.2' → '0000000100000010' print(iotv.din('0000', 'B')) # '00100100'
din() retorna un string de 8 bits directament. No hi ha suport per a callbacks asíncrons (on_din_change). El canal analògic (ndac) és 1–4 igual que a CAN.
Llegeix les 8 entrades digitals d'un costat via I2C. Retorna un string de 8 bits (ex: '00100100').
val = iotv.din('0000', 'B') # '00100100'
Escriu el byte complet (0–255) a un costat de sortida digital.
Escriu un bit individual de sortida (0–7) sense afectar els altres.
Escriu un valor PWM (0–255) a tots els canals del costat configurat en mode PWM.
Escriu un valor PWM (0–255) a un bit individual del costat configurat en mode PWM.
Configura els dos costats. Modes A: 'ain', 'aout', 'aoutpwm'. Modes B: 'bin', 'bout', 'boutpwm', 'bintouch'. Retorna False si la combinació no és vàlida.
iotv.dsetup('0000', 'aout', 'bin') iotv.dsetup('0000', 'ain', 'bout')
Imprimeix 'Digital rib version: X.Y' i retorna un string binari de 16 bits que codifica la versió.
Imprimeix la configuració actual i retorna un string binari de 8 bits que codifica el mode de cada costat.
iotv.getdsetup('0000') # → imprimeix "A digital output, B digital input" # → retorna '00010010'
Llegeix una entrada analògica. ndac és 1–4. Retorna valor cru de 16 bits (0–26624).
v = iotv.ain2v(iotv.ain('0000', 'A', 4)) # 4.98
Escriu un valor cru (0–4095) a un canal DAC. Per enregistrar a l'EEPROM, suma 4096 al valor (màxim 20.000 escriptures).
iotv.aout('0000', 'B', 4, iotv.v2aout(9.3))
Imprimeix 'Analog rib version: X.Y' i retorna un string binari de 16 bits.
Converteix 0–10 V a valor cru DAC (0–4095). Limita a [0, 4095].
iotv.v2aout(10.0) # → 4095 iotv.v2aout(5.0) # → 2048
Converteix el valor cru ADC (0–26624) a volts (−10.0 a +10.0 V).
El simulador de iotvsim.binefa.cat executa codi Python transpilat a JavaScript. L'API és similar però amb diferències importants respecte a les biblioteques RPi.
| Funció / Característica | RPi (CAN/I2C) | Simulador |
|---|---|---|
| Importació | import can_iotv_v2_1 as iotv | objecte iotv disponible directament (no cal import) |
| Inici del bus | iotv.can_on() / can_off() | iotv.init() / iotv.reset() |
| din | din(addr, side) → string binari | din(addr, side) → string binari (igual) |
| dout | dout(addr, side, value) | dout(addr, side, value) (igual) |
| doutbit | doutbit(addr, side, pos, val) | doutbit(addr, side, pos, val) (igual) |
| dinbit | No existeix | dinbit(addr, side, bit) → int (0 o 1) |
| ain canal | ain(addr, side, ndac) ndac=1–4 | ain(addr, side, ch) ch=0–3 |
| ainBatch | No existeix | ainBatch(addr, side) → array[4] |
| aoutBatch | No existeix | aoutBatch(addr, side, voltages) |
| v2ain | No existeix | v2ain(voltage) → int (rang ADC entrada) |
| aout2v | No existeix | aout2v(raw) → float (0–10 V) |
| v2aout | v2aout(voltage) | v2aout(voltage) (igual) |
| ain2v | ain2v(raw) | ain2v(raw) (igual) |
| on_din_change | on_din_change(addr, cb) (v2.1) | No existeix (polleig manual) |
| PLCMemory | No existeix | PLCMemory.set(key, val) / .get(key) |
| time.sleep | time.sleep(s) | time.sleep(s) (igual, suporta floats) |
try / except / finally — useu if/else per comprovar valorsclass — no suportat[x for x in ...] — useu bucles for explícitsf-strings amb expressions complexes — useu concatenaciólambda, *args, **kwargs, global, nonlocal, yieldimport — tan sols disponibles: iotv, time, math, random, PLCMemorydef de primer nivell (no niuades)for, while, if/elif/elseappend, len)await per a crides iotv que retornen promesesLlegeix les 8 entrades digitals. Retorna string binari de 8 caràcters. Igual que a CAN/I2C.
Llegeix un bit individual d'entrada (0–7). Exclusiva del simulador.
estat = iotv.dinbit('0000', 'B', 1) # 0 o 1
Mateixa signatura que CAN/I2C. doutpwm(addr, side, val) escriu un valor PWM (0–255) a tots els canals. doutbitpwm(addr, side, bit, val) escriu PWM a un bit individual.
Llegeix una entrada analògica. Atenció: al simulador el canal ch va de 0 a 3 (a CAN/I2C va de 1 a 4). Retorna valor cru 0–4095.
# Simulador: ch 0..3 raw = iotv.ain('0000', 'B', 0) v = iotv.ain2v(raw)
Llegeix els 4 canals analògics d'un costat en una sola crida. Retorna una llista de 4 valors crus (0–4095). Exclusiva del simulador.
vals = iotv.ainBatch('0000', 'B') # [1024, 2048, 0, 4095] v0 = iotv.ain2v(vals[0])
Escriu múltiples canals analògics de sortida alhora. voltages és una llista de fins a 4 valors en volts (0–10 V). Exclusiva del simulador.
iotv.aoutBatch('0000', 'A', [0.0, 5.0, 10.0, 2.5])
# Blink de DO5 (costat A, vèrtebra 0000) # Funcions de primer nivell — sense try/except, sense classes def setup(): iotv.dsetup('0000', 'output', 'input') def main(): setup() while True: iotv.doutbit('0000', 'A', 5, 1) # DO5 encès time.sleep(0.5) iotv.doutbit('0000', 'A', 5, 0) # DO5 apagat time.sleep(0.5) main()
import can_iotv_v2_1 as iotv import time iotv.can_on() iotv.dsetup('0000', 'dout', 'din') while True: iotv.doutbit('0000', 'A', 5, 1) time.sleep(0.5) iotv.doutbit('0000', 'A', 5, 0) time.sleep(0.5)