Home » Pompa di calore » Daikin HPSU Compact » Hack » Hack Daikin HPSU Compact con Raspberry Pi, Python e PiCAN2 – II

Hack Daikin HPSU Compact con Raspberry Pi, Python e PiCAN2 – II

Rotex HPSU Compact hack con Raspberry Pi e PiCAN2: seconda parte

Probabilmente avete letto il primo articolo che spiegava come hackerare a basso livello la vostra pompa di calore Daikin HPSU Compact grazie alla squadra formata da Raspberry Pi, PiCAN2, Python e python-CAN.

E’ venuto ora il momento di capire quali dati transitano sul bus dati CAN-Bus della pompa di calore al fine di poterli comprendere ed utilizzare. Materia ostica e noiosa ma fondamentale per poter procedere.

La doverosa premessa è che tutto quanto descritto in questo articolo è esclusivamente frutto di zanac. Che ha passato ore “sniffando” dati e determinandone empiricamente la semantica (partendo da un semilavorato trovato in un forum tedesco). Inoltre le operazioni di scrittura sul bus non sono ancora state esplorate fino in fondo.

Se pensi di aver trovato un approccio troppo complesso, ti invito a leggere in alternativa fin dove mi sono spinto in termini di ottimizzazione del riscaldamento sulla mia pompa di calore Daikin HPSU Compact con un approccio tradizionale in Pompa di calore Daikin HPSU Compact: curva climatica inversa a 4 scorrimenti.

CAN-Bus, python-CAN, Python e scheda PiCAN2

Il Controller Area Network, noto anche come CAN-Bus, è uno standard seriale per bus di campo (principalmente in ambiente automotive), di tipo multicast, introdotto negli anni ottanta dalla Bosch.

Lo standard CAN-Bus, a differenza del procollo TCP/IP utilizzato su internet,  non prevede per i messaggi che transitano un indirizzo del nodo mittente e uno per il nodo destinatario, ma semplicemente l’identificativo del nodo CAN-Bus sorgente.

Un messaggio CAN-Bus transita infatti su tutto il bus e viene ricevuto da tutti i nodi collegati, è compito del singolo nodo gestire, se di interesse, il messaggio.

Questa architettura facilita di molto il lavoro di intercettazione (sniffing) dei dati che transitano: ogni periferica ha la piena visibilità di tutto quanto transita sul bus.… è per questo motivo che risulta facile sniffare comandi: ogni periferica connessa al CAN-Bus ha piena visibilità di quanto transita nel bus.

diag_canbus2

Non a caso ho riportato uno schema concettuale di un’automobile che utilizza proprio il CAN-Bus reso disponibile a chiunque tramite una presa OBD2 (On Board Diagnostic).

Suggerisco questa lettura: Cosa succede se un hacker prende il controllo di un’auto a distanza.

Sniffing messaggi CAN-Bus Daikin HPSU Compact tramite PiCAN2

La pompa di calore Daikin HPSU Compact implementa il CAN-Bus nella variante 11 bit (base format); lo standard CAN stabilisce che i device debbano tollerare anche la variante a 29 bit (extended) senza andare in errore.

Essendo un protocollo aperto abbiamo almeno un piccolo vantaggio in partenza. Ma come vedremo piccolo.

Tralasciando i campi tecnici, il formato base di un messaggio è essenzialmente composto da:

  • un identificatore di dati (ID)
  • un campo dati (Data) che può essere lungo sino a 8 byte
can-bus-frame_in_base_format_without_stuffbits-svg

La lunghezza del campo dati del messaggio è detta DLC.

Nella pompa di calore Daikin HPSU Compact tutti i campi dati sono da 7 byte (DLC = 7) e quindi occorre tenerne assolutamente conto quando si spediscono i dati alla macchina.

All’interno della libreria python-CAN è disponibile uno script che consente di aggregare i messaggi che transitano sul CAN-Bus in base al loro identificativo ID in modo da avere statistiche sulla loro frequenza:

python3 -m can.viewer -c can0 -i socketcan

Lasciando girare questo script per qualche minuto mentre la nostra pompa di calore aria acqua Daikin HPSU Compact si trova in modalità riscaldamento senza intervenire in alcun modo sul suo pannello di controllo troviamo ad esempio questo output con un elenco di messaggi transitati sul CAN-Bus:

Count   Time           dt          ID          DLC  Data
83      1144.665077    59.979867   0x10A       7    31 00 FA C0 B4 00 00
229     1147.443998    2.7622953   0x180       7    20 0A 0C 00 45 00 00
59      844.042803     0.01214224  0x300       7    20 0A FA 01 1A 00 00
36      842.115780     0.00595495  0x500       7    20 0A 61 01 00 00 00
21      843.939823     0.01195700  0x600       7    20 0A 57 00 00 00 00
21      904.953210     0.00580325  0x780       7    B0 79 FA 01 22 1D 00

Dove:

  • Count è il numero di volte che un messaggio con quell’ID è stato ricevuto
  • Time è il time-stamp dell’ultimo messaggio ricevuto con quell’ID
  • dt è la differenza di tempo tra gli ultimi due messaggi ricevuti con quell’ID
  • ID è l’identificato del messaggio (formato esadecimale)
  • DLC è la lunghezza del messaggio in byte
  • Data sono i dati contenuti nell’ultimo messaggio di quell’ID (formato esadecimale)

Il campo dati contiene una sequenza di byte con una semantica applicativa ben precisa specifica del sistema che utilizza il bus: vediamo il caso specifico della Daikin HPSU Compact limitatamente a quello di cui è stato possibile fare reverse engineering.

Possiamo notare nel primo esempio come ci siano alcuni identificativi con una numerosità decisamente più alta degli altri: è probabile che siano i dati scambiati per aggiornare frequentemente le informazioni visualizzate sul display del pannello di controllo nella schermata correntemente selezionata.

Come primo esperimento ho lasciato il pannello di controllo controllo della macchina fermo su questa schermata per molte decine di minuti:

Il risultato è il seguente:

Count   Time           dt          ID          DLC  Data
3043    2190.429196    0.005633    0x10A       7    31 00 FA C1 01 00 00
3352    2190.462394    0.005885    0x180       7    22 0A FA C1 01 03 6D
127     2178.270777    0.00625344  0x300       7    20 0A FA 01 1A 00 00
78      2176.428710    0.01096660  0x500       7    20 0A 61 01 00 00 00
45      2178.186774    0.01193118  0x600       7    20 0A 57 00 00 00 00
36      1995.233171    0.01105037  0x780       7    B0 79 FA 01 22 1D 00

Esperimento ripetuto con questa seconda schermata:

Col risultato seguente:

Count   Time           dt          ID          DLC  Data
3653    2641.662374    0.005546    0x10A       7    31 00 FA C1 01 00 00
3998    2641.732388    0.014217    0x180       7    22 0A FA C1 01 03 6D
148     2524.143194    0.00625052  0x300       7    20 0A FA 01 1A 00 00
84      2522.309635    0.00598129  0x500       7    20 0A 61 01 00 00 00
51      2524.082409    0.00587598  0x600       7    20 0A 57 00 00 00 00
45      2461.075303    0.00589475  0x780       7    B0 79 FA 01 22 1D 00

Come vedete da entrambi i casi, abbiamo due evidenze:

  • ci sono solamente 6 identificativi distinti, probabilmente corrispondenti ai componenti della pompa di calore che comunicano tra di loro tramite il CAN-Bus
  • la stragrande maggioranza dei messaggi scambiati ha identificativo ID 0x10A e 0x180

Facciamo allora un dump dei messaggi:

python3 can_logger.py -c can0 -v -i socketcan

Fermandoci alla prima “raffica”, che compare proprio con quelle coppie di identificativi, riordinando in base ad identificativo e poi timestamp abbiamo questo:

Timestamp: 1638210695.494380  ID: 010a    S  DLC:  7    31 00 fa c0 fc 00 00  Channel: can0
Timestamp: 1638210695.499678  ID: 010a    S  DLC:  7    31 00 fa c0 fd 00 00  Channel: can0
Timestamp: 1638210695.510810  ID: 010a    S  DLC:  7    31 00 fa c0 fe 00 00  Channel: can0
Timestamp: 1638210695.521915  ID: 010a    S  DLC:  7    31 00 fa c0 ff 00 00  Channel: can0
Timestamp: 1638210695.527504  ID: 010a    S  DLC:  7    31 00 fa c1 00 00 00  Channel: can0
Timestamp: 1638210695.533056  ID: 010a    S  DLC:  7    31 00 fa c1 01 00 00  Channel: can0
Timestamp: 1638210695.505260  ID: 0180    S  DLC:  7    22 0a fa c0 fc 01 23  Channel: can0
Timestamp: 1638210695.516309  ID: 0180    S  DLC:  7    22 0a fa c0 fd 01 ad  Channel: can0
Timestamp: 1638210695.538606  ID: 0180    S  DLC:  7    22 0a fa c0 fe 01 15  Channel: can0
Timestamp: 1638210695.548981  ID: 0180    S  DLC:  7    22 0a fa c0 ff 00 36  Channel: can0
Timestamp: 1638210695.554933  ID: 0180    S  DLC:  7    22 0a fa c1 00 01 05  Channel: can0
Timestamp: 1638210695.560883  ID: 0180    S  DLC:  7    22 0a fa c1 01 03 9a  Channel: can0

Ovvero 6 messaggi con ID 010a ed altrettanti con ID 0180 leggermente sfalsati nel tempo.

Formato messaggi CAN-Bus Daikin HPSU Compact

Direi che abbiamo fatto bingo provando ad intuire la semantica dei messaggi scambiati sul CAN-Bus della pompa di calore Daikin HPSU Compact:

  • i 6 messaggi corrispondono esattamente ai 6 valori visualizzati sul display del pannello di controllo
  • a 6 messaggi di richiesta (con ID 010a) corrispondono 6 messaggi di risposta (con ID 0180)
  • tutti i messaggi di richiesta hanno i primi 3 byte identici (31 00 fa)
  • tutti i messaggi di richiesta hanno i primi 3 byte identici (22 0a fa)
  • il terzo e quarto byte del messaggio sono identici tra richiesta e risposta, probabilmente per indicare il parametro
  • il sesto ed il settimo byte del messaggio di richiesta sono vuoti
  • il sesto ed il settimo byte del messaggio di risposta hanno valori differenziati, probabilmente contengono il valore effettivo del parametro richiesto

E’ quindi presumibile che il funzionamento sia il seguente:

  • il pannello di controllo della pompa di calore richiede via messaggi sul CAN-Bus i valori aggiornati dei parametri da visualizzare
  • la scheda principale della pompa di calore recepisce la richiesta e pubblica i messaggi di risposta con i valori aggiornati sul CAN-Bus
  • il modulo pannello di controllo della pompa di calore visualizza i dati così ricevuti

Questo si chiama reverse engineering che dobbiamo provare a sintetizzare.

Identificativo

Per quanto nello standard CAN-Bus non ci sia un concetto di indirizzo, è probabile che nell’implementazione della pompa di calore Daikin HPSU Compact corrisponda al componente che ha depositato il messaggio.

Una possibile interpretazione è la seguente:

ID Messaggio CAN-BusComponente Daikin HPSU Compact
0x10APannello di controllo
0x180Scheda principale pompa di calore
0x300
0x500
0x600
0x780

Ritengo che questi valori siano definiti in fase di configurazione iniziale della pompa di calore e dipendenti anche dalla presenza di accessori esterni collegati via CAN-Bus, come ad esempio il comando remoto termostato ambiente RoCon U1.

Primo byte

  • Il primo semi-byte contiene il nodo CAN di destinazione (da decodificare moltiplicandolo per 0x80)
  • Il secondo semi-byte indica se il messaggio e’ in lettura (1) oppure risposta / scrittura (2); la differenziazione tra risposta e scrittura viene poi fatta mediante il secondo byte

Vediamolo con un paio di esempi concreti:

  • 0x31 ⇒ comando di lettura spedito al nodo CAN 0x180 (0x3 * 0x80)
  • 0x22 ⇒ risposta o scrittura dal nodo CAN 0x180 (0x2 * 0x80)

Secondo byte

  • Comando di lettura: è valorizzato fisso a 0x00
  • Risposta a comando di lettura: vale 0x10 oppure 0x0a (non ancora chiara la differenza)
  • Comando di scrittura: è valorizzato fisso a 0x00 (non ancora verificato se vale per tutti i casi)

Terzo byte

  • Valorizzato a 0xfa: se il comando o la risposta è di lettura (vedi primo/secondo byte), significa che il parametro applicativo oggetto di lettura è codificato nei due byte successivi (4 e 5)
  • Altro valore: il parametro applicativo è codificato direttamente nel terzo byte stesso

Prendiamo di nuovo un paio di esempi concreti:

Dati (Esadecimale)Significato
31 00 FA 01 D6 00 00Comando lettura dal nodo 0x180 del parametro 01 D6
31 00 0E 00 00 00 00Comando lettura dal nodo 0x180 del parametro 0E

Quarto / quinto byte

  • Lettura “non 0xFA”: 0x00 0x00 (non rilevanti)
  • Risposta “non 0xFA”: contengono il valore applicativo richiesto (con rappresentazione su due byte; sia valori positivi che negativi)
  • Lettura / Risposta / Scrittura “0xFA”: contengono il parametro applicativo oggetto di lettura / risposta (secondo un dizionario predefinito)

Sesto / settimo byte

  • Risposta / Scrittura “0xFA”: contengono il valore applicativo oggetto di risposta o di scrittura

La Stele di Rosetta grazie a PiCAN2

Nonostante tutte le meravigliose premesse ed informazioni precedenti, siamo comunque di fronte ad un flusso di informazioni binarie la cui semantica deve essere compresa.

Penso che zanac all’inizio si sia sentito come di fronte alla Stele di Rosetta (mi piace più questa metafora che parlare di reverse engineering).

697323

La stesura del dizionario di transcodifica tra valori binari/esadecimali ed i parametri applicativi, scolpito da qualche parte nel firmware della nostra pompa di calore Daikin HPSU Compact, non è comunque tutto, occorre pure scoprire:

  • codifica dei valori applicativi negativi (come la temperatura esterna ad esempio)
  • codifica dei valori applicativi multi-valore (come la modalità corrente di funzionamento)
  • assegnazione degli indirizzi dei nodi CAN-Bus che compongono il sistema (Unita’ interna, unita’ esterna, ecc.)

Esempi di messaggi catturati con PiCAN2

Per chiudere con la speranza in una prossima puntata di questa storia, qualche esempio completo di messaggio interpretato grazie a Raspberry Pi, PiCAN2 e tanta pazienza:

DatiComandoParametro
31 00 16 00 00 00 00Lettura temperatura di ritornoN/A
32 10 16 00 DF 00 00Risposta temperatura di ritorno00 DF (223 decimale, ovvero 22,3 ºC)
61 00 FA 0A 0C 00 00Lettura temperature esternaN/A
62 10 FA 0A 0C FF 69Risposta temperature esternaFF 69 (-115 decimale, ovvero -11,5 ºC)

Mi raccomando di continuare la lettura della puntata successiva Daikin HPSU Compact hack: terza parte.

Nel caso vi capiti con frequenza di bruciare la SD Card del vostro Raspberry Pi leggere la mia soluzione in Raspberry Pi | Collegare hard disk esterno.

Leggi tutti i miei articoli su Raspberry Pi:

Ultimo aggiornamento Amazon Affiliate 2021-12-06 at 20:30

2 commenti su “Hack Daikin HPSU Compact con Raspberry Pi, Python e PiCAN2 – II”

Lascia un commento

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

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.