Hackerare una Vending Machine [Parte 1]

In questo ultimo periodo mi è stato assegnato l’incarico di “hackerare” una vending machine (una macchina del caffè in questo caso). Come al solito quando uso il termine hackerare intendo dire “migliorare” qualcosa, e non di certo avere una merendina gratis 🙂

La volontà è quella di inserirsi nel protocollo di comunicazione della macchina, per poter cosi “sniffare” i dati della stessa, e recuperare i dati di diagnostica ed utilizzo, ma anche pilotare gli acquisti delle consumazioni attraverso il classico smartphone, creare un account utente con wallet evitando cosi la seccatura di dover svuotare ogni volta il secchiello della moneta ed il relativo costo per convertire le monete in contanti.

Molti potrebbero dire: “ma le nuove vending machine già lo fanno!”.

È vero, ma è anche vero che c’è un enormità di vecchie macchine del caffè di gran lunga più numerose di quelle di ultima generazione, e modernizzarle in questo modo porterebbe un beneficio non indifferente sia a livello economico in quanto non si andrebbe a sostituirle ex novo, sia a livello ecologico perché non si creerebbero cosi rifiuti. In più gli esperti del settore sostengono che le vecchie macchine proprio per il loro funzionamento “meccanico” siano in grado di fare un caffè più buono, e per noi italiani non c’è niente di più serio del caffè, per cui…

Il mio compito in particolare è quello di far comunicare un raspberry pi con una scheda che gestisce i componenti di ricarica (validatore di monete, lettore di banconote o chiavetta rfid) comunicando i dati alla scheda madre della vending machine tramite un protocollo MDB (Multi Drop Bus), e comunicando i dati anche all’Agenzia delle Entrate.

Il protocollo MDB è tutt’altro che recente, nato verso la fine del 1980, è stato adottato dalle vending machine della Coke (CocaCola per i diversamente giovani come me) per accettare le monete, successivamente la Coke ha spinto per far diventare open source il protocollo e aumentare cosi la competitività. Il bello di questo protocollo è che quasi tutti i componenti di una vending machine comunicano tra loro grazie a lui.

Il brutto di questo protocollo è che comunica a 9 bit (basato su protocollo Motorola 9-bit UART) e lavora con tensioni sia continue che alternate che si aggirano intorno ai 30 V.

A queste tensioni il raspberry pi si guasterebbe rovinosamente. Per fortuna la mia scarsa vita sociale mi ha permesso di scovare su internet un dispositivo che si interfaccia con il raspy, un cosidetto pi hat (cappello).

Tra le varie aziende che si occupano di interfacciarsi alle vending machine, mi sono rivolto ad una in particolare, la Qibixx AG, la quale mi è sembrata specializzata in quello di cui necessito, e rispetto ad altre ditte, per niente improvvisata. Ho constatato con piacere che nientepopodimeno che il CEO mi ha dato la sua personale assistenza, di sabato notte, constatando il fatto che non sono il solo a non avere una vita sociale :-).

Sul sito della Qibixx troviamo già dei codici di esempio in Python per provare subito ad utilizzare la scheda. Piccolo accorgimento che mi è stato consigliato è quello di NON collegare il cavo MDB o il pi hat con l’alimentazione inserita. Lo script in python lo potete trovare qui sotto, o scaricare direttamente dal sito della Qibixx al seguente link: http://firmware.qibixx.com/examples/commands.py

#!/usr/bin/python
import serial
import sys
import tty
import termios
import select


fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
tty.setraw(sys.stdin.fileno())

if len(sys.argv) <= 1:
	termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
	print("provide interface as arguments (e.g. /dev/ttyACM0)")
        
	sys.exit()

ser = serial.Serial(sys.argv[1], 115200, timeout = 0.5)


def readSerial():
    try:
        readOut = ser.readline().rstrip()
        if readOut:
            print('\r'+readOut)
    except:
        pass
    


    
def printmenu():
    print ("\r\n1-Version 2-subscribe 3-start 4-vend0.5 5-vend0 6-stop 0 to stop\r")              

printmenu()
while True:
    rlist, wlist, elist = select.select([sys.stdin,ser], [], [],0.55555)
    if sys.stdin in rlist:
        
        c = sys.stdin.read(1)
        if c=="1":
            print("--> version")
            ser.write(b'V\n')                                                                                                                                                                          
                                                                                                                                                             
                                                                                                                                                                         
        elif c=="2":                                                                                                                                                                       
            print("\r\n--> start emulation")
            ser.write(b'C,SETCONF,mdb-addr=0x10\n')
            ser.write(b'C,SETCONF,mdb-currency-code=0x1756\n')                                                                                                                                                               
            ser.write(b'C,1\n')                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                 
        elif c=="3":                                                                                                                                                                      
            print("\r\n--> start with 10")                                                                                                                                                          
            ser.write(b'C,START,10.0\n')                                                                                                                                                         
        elif c=="4":                                                                                                                                                                      
            print("\r\n--> vend 0.5")                                                                                                                                                               
            ser.write(b'C,VEND,0.5\n')                                                                                                                                                            
        elif c=="5":                                                                                                                                                                       
            print("\r\n--> vend 0")                                                                                                                                                                 
            ser.write(b'C,VEND,0\n')                                                                                                                                                              
        elif c=="6": 
            print("\r\n--> stop")                                                                                                                                                                   
            ser.write(b'C,0\n')
        elif c=="0":
            break                                                                                                                                                               
        else:                                                                                                                                                                                    
            printmenu()
    elif ser in rlist:
        readSerial()                                                                    

termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)

TO BE CONTINUED…

LONG LIVE AND PROSPERITY

2 commenti su “Hackerare una Vending Machine [Parte 1]

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Top