· ·
Raspberry Pi · Python

API Python

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.

CAN v2.3 (recomanada) I2C Simulador en línia Raspberry Pi
CAN bus — /boot/firmware/config.txt
# 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
I2C — /boot/firmware/config.txt
# Activar I2C
dtparam=i2c_arm=on
# Instal·lar smbus
sudo apt install -y python3-smbus
Nota: Cada crida I2C obre i tanca el bus. No cal can_on() / can_off().
Bus CAN — can_iotv_v2_3.py

API recomanada per a Head02 (ESP32-S3). Comunicació via bus CAN a 100 kbps. Suporta callbacks asíncrons de canvis d'entrada digital.

Ús ràpid:
import can_iotv_v2_3 as iotv

iotv.can_on()
print(iotv.dversion('0000'))   # '1.5'
print(iotv.aversion('0000'))   # '1.4'
iotv.can_off()
⬇ can_iotv_v2_3.py ⬇ can_iotv_v2_2.py ⬇ can_iotv_v2_1.py ⬇ can_iotv_v2_0.py ⬇ Head02TestRPi02.py
Instal·lació via pip (recomanada):

En comptes de descarregar el fitxer manualment, instal·la'l com a paquet des del servidor. Cada Raspberry Pi el descarrega directament — no cal copiar cap fitxer .py a mà, i actualitzar-lo a la classe sencera és una sola comanda. El nom d'importació (import can_iotv_v2_3 as iotv) no canvia.

# Instal·lar
pip install --extra-index-url https://doc.iotvertebrae.com/simple/ iotv-pi-libs --break-system-packages

# Actualitzar a una versió nova
pip install --extra-index-url https://doc.iotvertebrae.com/simple/ --upgrade iotv-pi-libs --break-system-packages

# Desinstal·lar
pip uninstall iotv-pi-libs --break-system-packages

(--break-system-packages és necessari a Raspberry Pi OS Bookworm i posteriors, que per defecte bloquegen pip install/uninstall fora d'un entorn virtual — vegeu PEP 668.)

Exemple complet — HelloWorld.py:

Script complet que fa parpellejar la sortida digital DO7 del costat B (compatible amb Raspberry Pi i amb el simulador).

import can_iotv_v2_3 as iotv
import asyncio
from time import sleep

# Vertebra address (4-bit binary string) and side to control — edit these two lines for your setup
DIG_VERT_ADDR = "0100"
SIDE = "B"
led_DO7_on = True

# 'aturat' only exists when this script runs inside the simulator;
# it lets the IDE's Stop button end the loop below cleanly.
# On a real Raspberry Pi this variable is undefined, so it's created here as False,
# and the loop only ends via Ctrl+C (KeyboardInterrupt), handled further down.
if 'aturat' not in globals():
    aturat = False

# Async function required by asyncio; the same code runs unchanged on Raspberry Pi and in the simulator
async def main():
    global led_DO7_on

    print(f"DO7 blinking on {SIDE} rib at {DIG_VERT_ADDR} address vertebra")
    while not aturat:   # keeps blinking until stopped
        if led_DO7_on:
            iotv.doutbit(DIG_VERT_ADDR, "b", 7, 1)   # DO7 on
        else:
            iotv.doutbit(DIG_VERT_ADDR, "b", 7, 0)   # DO7 off
        led_DO7_on = not led_DO7_on
        await asyncio.sleep(0.5)   # non-blocking wait, required inside an async function

if __name__ == "__main__":   # entry point: runs only when the script is executed directly, not on import
    try:
        iotv.can_on()

        # Blocking call that runs main() until it returns or is interrupted
        asyncio.run(main())

    except KeyboardInterrupt:   # Ctrl+C on Raspberry Pi
        iotv.dout(DIG_VERT_ADDR, 'B', 0x00)   # turn off all outputs on side B before exiting
        print("\nProgram stopped by user.")
        sleep(0.1)
        iotv.can_off()
⬇ helloWorld.py
Control del bus
None can_on() RPi

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.

None can_off() RPi

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).

Vèrtebra digital
str din(str addr, str side) CAN

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àmetreTipusDescripció
addrstrAdreça binària de 4 bits (ex: '0000')
sidestr'A' o 'B'
strString binari de 8 caràcters (ex: '10110100'), o 'Error' en timeout
exemple
val = iotv.din('0000', 'B')  # ex: '00100100'
di1 = bool(int(val[6]))        # bit DI1 (posició 6 des de l'esquerra)
None dout(str addr, str side, int value) CAN

Escriu el byte complet (0–255) a un costat de sortida digital. Els 8 LEDs/relès s'actualitzen en un sol missatge CAN.

exemple
iotv.dout('0000', 'A', 0xFF)  # tots encesos
iotv.dout('0000', 'A', 0x00)  # tots apagats
None doutbit(str addr, str side, int posbyte, int value) CAN

Escriu un bit individual de sortida sense afectar els altres. posbyte és 0 (DO0) a 7 (DO7). value és 0 o 1.

exemple
for bit in range(8):
    iotv.doutbit('0000', 'A', bit, 1)
    time.sleep(0.1)
    iotv.doutbit('0000', 'A', bit, 0)
None dsetup(str addr, str modeA, str modeB) CAN

Configura els modes de treball dels dos costats d'una vèrtebra digital. El costat A pot ser 'din', 'dout', 'pwm' o 'dfast'. El costat B afegeix 'touch'. Restriccions: PWM només pot estar a un costat; 'touch' només al costat B; 'dfast' (costella de motor pas a pas, nou a v2.3) només pot estar a un costat — vegeu la categoria Costella dfast més avall.

exemple
iotv.dsetup('0000', 'dout', 'din')
iotv.dsetup('0001', 'pwm', 'din')
iotv.dsetup('0001', 'dout', 'dfast')  # B = costella dfast (motor pas a pas)
str getdsetup(str addr) CAN

Llegeix la configuració actual de la vèrtebra digital i retorna un string llegible. Des de v2.3, distingeix correctament 'dfast' de 'dout'/'din'/'pwm'/'touch' (fa una consulta CAN addicional a get_dfast_side() internament).

exemple
iotv.getdsetup('0000')  # 'A:dout, B:din'
iotv.getdsetup('0001')  # 'A:dout, B:dfast'
str dversion(str addr) CAN

Retorna la versió del firmware de la vèrtebra digital (ex: '1.5'), o '0.0' en timeout.

Costella dfast — motor pas a pas DM556 (nou a v2.3)
Només a la Raspberry Pi: Aquestes funcions (dfast_*, stepper_*) encara no estan disponibles al simulador en línia — funcionen només amb bus CAN físic. Requereixen firmware de la vèrtebra dvert_v3_asyncInputChanges_05.ino o superior, amb la costella dfast connectada a un dels dos costats (mai els dos alhora).
Com funciona: Un cop declarat quin costat porta la costella dfast (amb dsetup(..., 'dfast') o dfast_setup()), aquell costat queda dedicat al motor: ja no es pot fer servir per E/S digital normal. Consulteu-ho en qualsevol moment amb get_dfast_side(). El sentit de gir es pot indicar amb el signe de steps (finit) o amb el paràmetre clockwise (obligatori de facto en mode infinit, ja que steps=0 no té signe real en Python).
None dfast_setup(str addr, str side) CAN

Declara quin costat porta la costella dfast. Equivalent a cridar dsetup() amb 'dfast' en un dels dos costats, però sense tocar l'altre costat. Es desa a l'EEPROM de la vèrtebra (persisteix entre reinicis).

ParàmetreTipusDescripció
addrstrAdreça binària de 4 bits (ex: '0000')
sidestr'A' o 'B'
exemple
iotv.dfast_setup('0001', 'B')
None dfast_clear(str addr) CAN

Desactiva la costella dfast en aquesta vèrtebra: el costat que la portava queda alliberat i disponible per configurar de nou amb dsetup(); l'altre costat no es veu afectat en cap moment.

exemple
iotv.dfast_clear('0001')
str get_dfast_side(str addr) CAN

Consulta quin costat porta la costella dfast ara mateix.

ParàmetreTipusDescripció
addrstrAdreça binària de 4 bits (ex: '0000')
str'none', 'A' o 'B', o '?' en timeout
exemple
iotv.get_dfast_side('0001')  # 'B'
None stepper_start(str addr, str side, int steps, int delay_us, bool infinit=False, bool clockwise=None) CAN

Engega el motor pas a pas: finit (nombre de passos concret) o infinit (gira fins stepper_stop()). El firmware aplica un mínim de 250 µs entre flancs.

ParàmetreTipusDescripció
addrstrAdreça binària de 4 bits (ex: '0000')
sidestr'A' o 'B'
stepsintNombre de passos amb signe (+ horari, − antihorari). Ignorat si infinit=True
delay_usintTemps entre flancs en microsegons (0–65535)
infinitboolSi True, gira sense parar fins stepper_stop()
clockwiseboolSi s'indica, substitueix el sentit deduït de steps. Necessari amb infinit=True per indicar sentit antihorari (steps=0 no té signe real)
exemple
iotv.stepper_start('0001', 'B', 4000, 300)  # 4000 passos horaris, 300us
iotv.stepper_start('0001', 'B', 0, 500, infinit=True, clockwise=False)  # infinit, antihorari
None stepper_stop(str addr, str side, bool disable_ena=False) CAN

Atura el motor (finit o infinit). Per defecte manté el parell de manteniment habilitat (ENA); amb disable_ena=True el deshabilita també, deixant l'eix lliure de girar a mà.

exemple
iotv.stepper_stop('0001', 'B')              # atura, mantenint parell
iotv.stepper_stop('0001', 'B', True)        # atura i deshabilita ENA
None stepper_set_speed(str addr, str side, int delay_us) CAN

Canvia el temps entre flancs en calent (amb el motor girant o aturat), sense interrompre el moviment. Pensada per tancar un llaç de control (PID) des de la Raspberry Pi.

exemple
iotv.stepper_set_speed('0001', 'B', 300)
None stepper_set_direction(str addr, str side, bool clockwise) CAN

Canvia el sentit de gir en calent, sense aturar el motor. El canvi s'aplica sempre entre polsos, mai a mig pols.

exemple
iotv.stepper_set_direction('0001', 'B', False)  # antihorari
Canvis d'entrada digital asíncrons (nou a v2.1)
Com funciona: La vèrtebra digital publica missatges espontanis quan detecta un canvi a qualsevol entrada. 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.
None on_din_change(str addr, callable callback) async

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).

Thread-safety: No crideu funcions de bloqueig (sleep, can_on/off) dins del callback. Useu una variable compartida per coordinar amb el bucle principal.
exemple complet (Head02TestRPi02)
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)
None off_din_change(str addr) async

Cancel·la el listener de canvis digitals per a l'adreça indicada. Atura el thread de fons de manera neta.

None off_all_din_change() async

Cancel·la tots els listeners actius. Es crida automàticament a can_off().

Vèrtebra analògica
int ain(str addr, str side, int ndac) CAN

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.

exemple
raw = iotv.ain('0000', 'B', 1)
volts = iotv.ain2v(raw)   # ex: 4.98
list ainBatch(str addr, str side) CAN

Llegeix els 4 canals analògics d'un costat EN UNA SOLA petició CAN i retorna una llista de 4 valors crus (0–26624), índex 0 = canal 1. ain() ja fa aquesta mateixa petició internament i en descarta 3 — cridar-lo un cop per canal fa un round-trip CAN sencer per cadascun. Useu ainBatch() sempre que calgui més d'un canal del mateix costat.

exemple
valors = iotv.ainBatch('0000', 'B')   # [v1, v2, v3, v4], cru
volts = [iotv.ain2v(v) for v in valors]
Important: ain() i ainBatch() no fan mai una conversió ADC en viu — retornen el que la vèrtebra ja tenia en una memòria cau, actualitzada pel seu propi escaneig de fons, independent de quan les crideu. Escriure amb aout() i llegir tot seguit amb ain()/ainBatch() sovint retorna el valor ANTERIOR, no el que acabeu de fixar — no hi ha un temps fix a esperar. El simulador no reprodueix aquest retard (llegeix l'estat instantani), així que el mateix codi pot semblar correcte al simulador i sortir desfasat a la Pi real. Preferiu llegir al començament d'una iteració (no just després d'escriure), o useu el push asíncron (set_async_adc + on_ain_change) si cal reaccionar ràpid a un canvi.
None aout(str addr, str side, int ndac, int value) CAN

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.

exemple
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))
str aversion(str addr) CAN

Retorna la versió del firmware de la vèrtebra analògica (ex: '1.4'), o '0.0' en timeout.

str getasetup(str addr) CAN

Llegeix la configuració de la vèrtebra analògica. Retorna string com 'A:ain, B:aout'.

Conversió de tensió
float ain2v(int ain_value) utilitat

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
int v2aout(float voltage_0_10) utilitat

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
Lectura ADC asíncrona (nou a v2.2)
Com funciona: La vèrtebra analògica pot publicar sola els 4 valors ADC d'un costat cada period_ms, en lloc de fer polling manual amb ain(). Cal activar-ho amb set_async_adc() abans de registrar el callback amb on_ain_change(), o no arribarà mai res.
None set_async_adc(str addr, str side, bool enable, int period_ms=50) async

Activa o desactiva l'enviament periòdic dels valors ADC d'un costat. side pot ser 'A', 'B' o 'AB' (ambdós alhora). period_ms es limita internament a 10–5000 ms. No bloqueja esperant resposta (fire-and-forget, igual que aout()/dout()).

exemple
iotv.set_async_adc('0000', 'A', True, 200)   # costat A cada 200ms
iotv.set_async_adc('0000', 'AB', False)      # desactiva els dos costats
None on_ain_change(str addr, str side, callable callback) async

Registra un listener passiu per als valors ADC d'un costat concret. A diferència de on_din_change() (una vèrtebra sencera), aquí cal un listener per costat — 'A' o 'B', mai els dos alhora. Requereix haver activat abans set_async_adc(addr, side, True, ...). El callback rep (addr, side, values), on values és una llista de 4 valors crus (0–26624), un per canal — useu ain2v() per convertir-los a volts. Si es torna a cridar amb la mateixa addr/side, el listener anterior es cancel·la automàticament.

exemple
def rebre_valors(addr, side, values):
    volts = [iotv.ain2v(v) for v in values]
    print(f"addr={addr} side={side} -> {volts} V")

iotv.set_async_adc('0000', 'A', True, 200)
iotv.on_ain_change('0000', 'A', rebre_valors)
None off_ain_change(str addr, str side) async

Cancel·la el listener d'un costat concret. Nota: això només atura l'escolta al costat del Raspberry Pi — si voleu que la vèrtebra deixi de trametre, cal cridar també set_async_adc(addr, side, False).

None off_all_ain_change() async

Cancel·la tots els listeners ADC asíncrons actius. Es crida automàticament a can_off().

Bus I2C — i2c_iotv.py

Compatible amb qualsevol versió de cap (Head01 i Head02). Cada crida obre i tanca el bus I2C; no cal inicialitzar un bus global.

Ús ràpid:
import i2c_iotv as iotv

print(iotv.dversion('0000'))  # 'Digital rib version: 1.2' → '0000000100000010'
print(iotv.din('0000', 'B'))    # '00100100'
⬇ i2c_iotv.py
Diferència respecte CAN: A I2C, 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.
Vèrtebra digital
str din(str addr, str side) I2C

Llegeix les 8 entrades digitals d'un costat via I2C. Retorna un string de 8 bits (ex: '00100100').

exemple
val = iotv.din('0000', 'B')  # '00100100'
None dout(str addr, str side, int value) I2C

Escriu el byte complet (0–255) a un costat de sortida digital.

None doutbit(str addr, str side, int posbyte, int value) I2C

Escriu un bit individual de sortida (0–7) sense afectar els altres.

None doutpwm(str addr, str side, int value) I2C

Escriu un valor PWM (0–255) a tots els canals del costat configurat en mode PWM.

None doutbitpwm(str addr, str side, int posbyte, int value) I2C

Escriu un valor PWM (0–255) a un bit individual del costat configurat en mode PWM.

bool dsetup(str addr, str modeA, str modeB) I2C

Configura els dos costats. Modes A: 'ain', 'aout', 'aoutpwm'. Modes B: 'bin', 'bout', 'boutpwm', 'bintouch'. Retorna False si la combinació no és vàlida.

exemple
iotv.dsetup('0000', 'aout', 'bin')
iotv.dsetup('0000', 'ain', 'bout')
str dversion(str addr) I2C

Imprimeix 'Digital rib version: X.Y' i retorna un string binari de 16 bits que codifica la versió.

str getdsetup(str addr) I2C

Imprimeix la configuració actual i retorna un string binari de 8 bits que codifica el mode de cada costat.

exemple
iotv.getdsetup('0000')
# → imprimeix "A digital output, B digital input"
# → retorna '00010010'
Vèrtebra analògica
int ain(str addr, str side, int ndac) I2C

Llegeix una entrada analògica. ndac és 1–4. Retorna valor cru de 16 bits (0–26624).

exemple
v = iotv.ain2v(iotv.ain('0000', 'A', 4))  # 4.98
None aout(str addr, str side, int ndac, int value) I2C

Escriu un valor cru (0–4095) a un canal DAC. Per enregistrar a l'EEPROM, suma 4096 al valor (màxim 20.000 escriptures).

exemple
iotv.aout('0000', 'B', 4, iotv.v2aout(9.3))
str aversion(str addr) I2C

Imprimeix 'Analog rib version: X.Y' i retorna un string binari de 16 bits.

Conversió de tensió
int v2aout(float voltage_0_10) utilitat

Converteix 0–10 V a valor cru DAC (0–4095). Limita a [0, 4095].

iotv.v2aout(10.0)  # → 4095
iotv.v2aout(5.0)   # → 2048
float ain2v(int ainValue) utilitat

Converteix el valor cru ADC (0–26624) a volts (−10.0 a +10.0 V).

Simulador en línia — iotvSim

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.

Diferències respecte CAN/I2C
Funció / CaracterísticaRPi (CAN/I2C)Simulador
Importacióimport can_iotv_v2_3 as iotvobjecte iotv disponible directament (no cal import)
Inici del busiotv.can_on() / can_off()iotv.init() / iotv.reset()
dindin(addr, side) → string binaridin(addr, side) → string binari (igual)
doutdout(addr, side, value)dout(addr, side, value) (igual)
doutbitdoutbit(addr, side, pos, val)doutbit(addr, side, pos, val) (igual)
dinbitNo existeixdinbit(addr, side, bit) → int (0 o 1)
ain canalain(addr, side, ndac) ndac=1–4ain(addr, side, ch) ch=1–4 (igual)
set_async_adcset_async_adc(addr, side, enable, ms) (v2.2)set_async_adc(...) (igual, no-op real)
on_ain_changeon_ain_change(addr, side, cb) (v2.2)on_ain_change(addr, side, cb) (igual)
off_ain_changeoff_ain_change(addr, side)off_ain_change(addr, side) (igual)
off_all_ain_changeoff_all_ain_change()off_all_ain_change() (igual)
ainBatchainBatch(addr, side) → llista[4] (cru)ainBatch(addr, side) → array[4]
aoutBatchNo existeixaoutBatch(addr, side, voltages)
v2ainNo existeixv2ain(voltage) → int (rang ADC entrada)
aout2vNo existeixaout2v(raw) → float (0–10 V)
v2aoutv2aout(voltage)v2aout(voltage) (igual)
ain2vain2v(raw)ain2v(raw) (igual)
on_din_changeon_din_change(addr, cb) (v2.1)on_din_change(addr, cb) (igual)
off_din_changeoff_din_change(addr)off_din_change(addr) (igual)
off_all_din_changeoff_all_din_change()off_all_din_change() (igual)
PLCMemoryNo existeixPLCMemory.set(key, val) / .get(key)
dfast_setup / dfast_cleardfast_setup(addr, side) / dfast_clear(addr) (v2.3)No existeix
get_dfast_sideget_dfast_side(addr) (v2.3)No existeix
stepper_start / stepper_stopstepper_start(...) / stepper_stop(...) (v2.3)No existeix
stepper_set_speed / stepper_set_directionstepper_set_speed(...) / stepper_set_direction(...) (v2.3)No existeix
time.sleeptime.sleep(s)time.sleep(s) (igual, suporta floats)
Limitacions del transpilador (Python → JavaScript)
El codi Python es transpila a JS. Eviteu:
Sí que funciona:
Vèrtebra digital (simulador)
str din(str addr, str side) sim

Llegeix les 8 entrades digitals. Retorna string binari de 8 caràcters. Igual que a CAN/I2C.

int dinbit(str addr, str side, int bit) sim

Llegeix un bit individual d'entrada (0–7). Exclusiva del simulador.

exemple
estat = iotv.dinbit('0000', 'B', 1)  # 0 o 1
None dout / doutbit / doutpwm / doutbitpwm sim

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.

Vèrtebra analògica (simulador)
int ain(str addr, str side, int ch) sim

Llegeix una entrada analògica. ch és 1–4, igual que a CAN/I2C. Retorna valor cru 0–26624 (mateixa escala que la Pi real).

exemple
raw = iotv.ain('0000', 'B', 1)
v = iotv.ain2v(raw)
list ainBatch(str addr, str side) sim

Llegeix els 4 canals analògics d'un costat en una sola crida. Retorna una llista de 4 valors crus (0–26624). Exclusiva del simulador.

exemple
vals = iotv.ainBatch('0000', 'B')  # [6656, 13312, 0, 26624]
v0 = iotv.ain2v(vals[0])
None aoutBatch(str addr, str side, list voltages) sim

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.

exemple
iotv.aoutBatch('0000', 'A', [0.0, 5.0, 10.0, 2.5])
Exemple complet per al simulador
Codi generat per a la petició: "Fes un blink de DO5 del costat A de la vèrtebra 0000"
# 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()
Equivalent per a RPi (CAN v2.3):
import can_iotv_v2_3 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)