Pular para o conteúdo

Testar IoT sem placa

O simulador que fala o mesmo protocolo — e como um projeto de hardware passa no CI.

Código de hardware costuma ser código sem teste, e a razão é sempre a mesma: o teste precisaria da placa, e o CI não tem placa. IoT.conectar_simulada resolve isso de um jeito específico — não é um dublê da API, é um dispositivo do outro lado do cabo.

dataforge
adopt Arcane.IoT as IoT

placa := IoT.conectar_simulada("uno")
assert placa.info()["firmware"]["nome"] is "StandardFirmata.ino"
assert placa.info()["protocolo"] is "2.5"
placa.fechar()

A diferença importa: o simulador recebe os bytes do Firmata e responde com os bytes que a placa responderia. O parser, a máquina de estados, a partição em sete bits, o sysex — tudo isso é exercitado. Um dublê que só implementasse escrever(pino, valor) não provaria nada sobre o protocolo, que é justamente onde estão os erros.

O simulador deixa PERGUNTAR e deixa MENTIR#

ParaMétodo
perguntar o estado de um pinoplaca.simulador.pino(13)
perguntar o modo declaradoplaca.simulador.modo_do_pino(9)
perguntar a posição de um servoplaca.simulador.servo(3)
fingir um sensorplaca.simulador.definir_analogico(0, 733)
fingir um botãoplaca.simulador.definir_digital(2, 1)
fingir um dispositivo I²Cplaca.simulador.definir_i2c(0x68, 0x3B, […])
fingir um Firmata.sendStringplaca.simulador.mandar_texto("…")

Um teste de verdade, com `crucible`#

dataforge
adopt Arcane.IoT as IoT
adopt Arcane.Crucible as Crucible

crucible "o termostato":

    trial "liga o aquecedor quando esfria":
        placa := IoT.conectar_simulada("uno")
        placa.modo(7, "saida")
        placa.modo(14, "analogico")
        placa.relatar_analogico(0)

        aquecedor := IoT.histerese(18, 21)
        placa.simulador.definir_analogico(0, 300)       // frio
        sleep(120)
        placa.escrever(7, aquecedor(IoT.tmp36(placa.analogico(0))))

        expect placa.simulador.pino(7) is 1
        placa.fechar()

    trial "e nao bate o rele na soleira":
        termostato := IoT.histerese(30, 28)
        expect termostato(31) is yes
        expect termostato(29) is yes
        expect termostato(27) is no

Crucible.run()

O que o simulador NÃO prova#

  • Tempo de subida de um sinal, ruído de sensor, corrente, queda de tensão.
  • O cabo caindo no meio de um sysex — o defeito mais chato do mundo real.
  • O bootloader, o driver USB, o avrdude.
  • Que o seu sensor está ligado nos pinos certos.

Por isso tests/test_iot.py tem duas provas que o simulador não dá: a camada serial é testada contra um PTY de verdade (um dispositivo tty do sistema), e os sketches gerados são compilados pelo `arduino-cli` de verdade. E há um teste de hardware que só roda quando alguém aponta uma placa:

bash
$ DATAFORGE_ARDUINO=/dev/cu.usbmodem1101 python3 -m pytest tests/test_iot.py -k verdade