Eigentlich wollte ich über den Karosserie CAN Bus des Fiat Ducato die Zentralverriegelung steuern. Leider musste ich feststellen, dass das über den CAN Bus nicht möglich ist. Trotzdem findet man auf dem CAN einige spannende Signale, die man für mein Smart-Camper-Projekt gebrauchen kann. In diesem Beispiel integriere ich den Status der Fahrzeugtüren in mein Smart Camper System.

Komfort CAN Bus Grundlagen

Der Komfort CAN Bus des Fiat Ducato ist ein Low-Speed-CAN mit 50kBit/s . Das ist auch schon die erste Schwierigkeit. Während es online unterschiedliche CAN Module (mit CAN Controller und Transceiver) für High-Speed-CAN gibt, findet man keine fertigen Module für Low-Speed-CAN. Der Unterschied liegt in den Pegeln der CAN-H und CAN-L Leitung. Für das reine Testen kann man einen High-Speed-CAN Modul verwenden und nur die CAN-H Leitung verbinden. Die Pegel der CAN-H Leitung von High- und Low-Speed-CAN sind sich ähnlich und so sollte es möglich sein auch mit einem High-Speed-CAN Modul den Low-Speed-CAN des Ducato auszulesen. Folgende Grafik zeigt die Pegel von CAN-H und CAN-L von Low- und High-Speed-CAN.

Low-Speed-CAN mit dem ESP32

Der ESP32 hat einen CAN-Controller integriert. Was jetzt noch fehlt ist ein Low-Speed-CAN Transceiver. Hierfür habe ich einen TJA1055t/3 (da der ESP32 3,3V bevorzugt) bestellt. Außerdem benötigt man noch ein paar Widerstände und optional eine LED, die anzeigt, ob auf dem CAN gerade etwas passiert.

Beschreibung Bezeichnung Anzahl
Microcontroller ESP32 1
CAN-Tansceiver TJA1055T/3 1
Widerstand 4,7kOhm 3
Widerstand 3,3kOhm 2
Widerstand 2,2kOhm 1
LED LED 1
Jumper Jumper x
Steckbrett Steckbrett 1

Die Schaltung ist gemäß dem Datenblatt des TJA1055T/3 aufgebaut. Die beiden Widerstände an CAN-H und CAN-L habe ich maximal gewählt, damit sie im Ducato CAN Bus nicht ins Gewicht fallen. Zusätzlich habe ich den Pin 1 (INH = Wake-Up-Signal) über einen Spannungsteiler mit einem Wakeup-Pin des ESP32 verbunden. Sobald eine Kommunikation auf dem CAN Bus startet, geht der Pin auf „High“ und weckt so den ESP32 auf. D.h. solange auf dem CAN Bus keine Kommunikation stattfindet, braucht das System nur einen ganz kleinen Ruhestrom. Die LED zeigt an, ob gerade über den CAN Bus kommuniziert wird (ON) oder sich das System im Ruhezustand befindet (OFF).

Signale auf dem Fiat Ducato Karosserie CAN

Sobald man eine Tür öffnet, das Fahrzeug verriegelt bzw. entriegelt oder den Motor startet, werden diverse Daten mit unterschiedlichen IDs über den CAN-Bus gesendet. Da ich von Fiat leider keine Information zu diesen Daten bekommen habe, habe ich einfach alle Daten aufgezeichnet und unterschiedliche Aktionen ausgeführt. Anschließend habe ich daraus eine Pivot Tabelle gemacht um zu sehen, welche Signale durch welche Aktionen ausgelöst werden. Damit konnte ich herausfinden, dass es kein Signal zum Verriegeln oder Entriegeln der Zentralverriegelung gibt. Außerdem sind die Türen im ersten Byte der ID 0x06214000 zu finden. Wer sich für die unterschiedlichen Signale interessiert, dem habe ich hier die Pivot Tabelle angehängt. Das Event „Zündung“ habe ich ausgeklammert, da damit viele neue Signale auf dem CAN liegen, die mir die Übersichtlichkeit stark verschlechtern.

Einbindung in mein Smart-Camper-System

Der Code ist so geschrieben, dass sich das System eigentlich immer im Deep-Sleep-Modus befindet und nur ganz wenig Strom benötigt. Sobald etwas auf dem CAN Bus passiert, wacht das System auf und liest fleißig mit. Änderungen an den Türen (öffnen schließen) führen zu entsprechenden Signalen auf dem CAN Bus.  Der Microcontroller wertet diese aus und gibt den Status der Türen über den Pegelzustand von 4 GPIOs aus. Ist eine Tür offen, ist der entsprechende Pin „High“ und umgekehrt. Dieser Pegelzustand wird über eine HomeMatic IP 8 Kanal Modulplatine (HmIP MOD-RC8) an das Homematic System weitergegeben und kann zum Auslösen von Ereignissen verwendet werden.

Folgende Abbildung zeigt das fertige System. Da es auch noch verwendet wird um die Alarmanlage und die Daten des Batteriecomputers ins System zu übertragen ist in diesem Gehäuse auch noch die Hardware aus den beiden letzten Artikeln zusammengefasst.

Anzeige in der Cloudmatic App

Den Status der 4 Tür Kanäle zeige ich auch in meiner App an. So weiß ich von überall in der Welt ob eine Tür von meinem Camper gerade offen bzw. nicht richtig verschlossen ist. Gerade ist zum Beispiel die Schiebetür offen.

#include <Arduino.h>
#include <ESP32CAN.h>
#include <CAN_config.h>
#include <driver/rtc_io.h>


//CAN Low Speed Variablen
CAN_device_t CAN_cfg;
RTC_DATA_ATTR CAN_frame_t rx_frame;
gpio_num_t GPIO_ESP_CANWake = GPIO_NUM_35; //CAN Modul Weckt den ESP
#define BUTTON_PIN_BITMASK 0x800000000 // 2^35 in hex
gpio_num_t GPIO_CAN_Wake = GPIO_NUM_21; //ESP aktiviert CAN Modul
gpio_num_t GPIO_CAN_TX = GPIO_NUM_23; //GPIO_NUM_5
gpio_num_t GPIO_CAN_RX = GPIO_NUM_22; //GPIO_NUM_4
RTC_DATA_ATTR byte ZV_Byte_1, Status_FT, Status_BFT, Status_HT, Status_ST;
#define IS_SET(byte,bit) (((byte) & (1UL << (bit))) >> (bit))

//Setup
RTC_DATA_ATTR unsigned long currentMillis, previousMillis;


///////////////////////////////////////////////////////////////////////////////////
/////////////////////////            SETUP          ///////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

//GPIOs konfigurieren
void Setup_GPIO(){
 
      // Pins sind mit dem Homematic 8-Kanal-Empfangsmodul verbunden
      pinMode(GPIO_NUM_33, INPUT_PULLUP);
      pinMode(GPIO_NUM_25, INPUT_PULLUP);
      pinMode(GPIO_NUM_26, INPUT_PULLUP);
      pinMode(GPIO_NUM_27, INPUT_PULLUP);
      pinMode(GPIO_NUM_14, INPUT_PULLUP);
      pinMode(GPIO_NUM_12, INPUT_PULLUP);
      pinMode(GPIO_NUM_13, INPUT_PULLUP);
      //STB_N vom TJA1055T (GPIO_NUM_21)
      pinMode(GPIO_CAN_Wake, OUTPUT);
    
      // Pins sind mit dem Homematic IP 8-Kanal-Sendemodul verbunden
      pinMode(GPIO_NUM_15, OUTPUT);
      pinMode(GPIO_NUM_2, OUTPUT);
      pinMode(GPIO_NUM_0, OUTPUT);
      pinMode(GPIO_NUM_4, OUTPUT);
      pinMode(GPIO_NUM_16, OUTPUT);
      pinMode(GPIO_NUM_17, OUTPUT);
      pinMode(GPIO_NUM_5, OUTPUT);
      pinMode(GPIO_NUM_18, OUTPUT);
          
      //WakeupPin TJA1055T
      pinMode(GPIO_ESP_CANWake, INPUT_PULLDOWN);
      digitalWrite(GPIO_CAN_Wake, HIGH);
      //esp_sleep_enable_ext0_wakeup(GPIO_ESP_CANWake, HIGH);
      esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);
    
      //WakeupPin Homematic
      pinMode(GPIO_NUM_32, INPUT_PULLUP);
      esp_sleep_enable_ext0_wakeup(GPIO_NUM_32, LOW);
      rtc_gpio_pullup_en(GPIO_NUM_32);    
}


void Setup_CAN_LS(){
    Serial.println("Setup_CAN_LS");
    CAN_cfg.speed=CAN_SPEED_50KBPS;
    CAN_cfg.tx_pin_id = GPIO_CAN_TX;
    CAN_cfg.rx_pin_id = GPIO_CAN_RX;
    CAN_cfg.rx_queue = xQueueCreate(100,sizeof(CAN_frame_t));
    ESP32Can.CANInit();
    delay(100);
}

void setup() {
  Serial.begin(115200);
  Setup_GPIO();
  Setup_CAN_LS();
  previousMillis = millis();
}

void loop()
{
  if(digitalRead(GPIO_NUM_32)==0){
        Serial.println("HomeMatic Weckruf");
       //Votronic auslesen
        if(digitalRead(GPIO_NUM_33)==0){
        }
        //Unlock Zentralverriegelung
        if(digitalRead(GPIO_NUM_25)==0){
        }
        //Lock Zentralverriegelung
        if(digitalRead(GPIO_NUM_26)==0){
        }
        //Status der Thitronik auf PIN darstellen
        if(digitalRead(GPIO_NUM_27)==0){
        }
        //Aktuell Unbenutzt
        if(digitalRead(GPIO_NUM_14)==0){Serial.println("GPIO_NUM_14");}
        if(digitalRead(GPIO_NUM_12)==0){Serial.println("GPIO_NUM_12");}
        if(digitalRead(GPIO_NUM_13)==0){Serial.println("GPIO_NUM_13");}
  }
  //Solange der CAN-Transceiver nicht schläft, werden Nachrichten gelesen
  CAN_Nachricht_empfangen();
  if (digitalRead(GPIO_ESP_CANWake)!= HIGH){
          //Schlafenszeit bis GPIO32 == LOW (Homematic) oder GPIO_35 == HIGH (CAN transceiver)
          Serial.println("ich gehen schlafen!!");
          ESP32Can.CANStop();
          gpio_deep_sleep_hold_en(); //Hold GPIO Status
          esp_deep_sleep_start();
  }
}


///////////////////////////////////////////////////////////////////////////////////
/////////////////////////             CAN           ///////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

void CAN_Nachricht_empfangen() {
    //receive next CAN frame from queue
    if(xQueueReceive(CAN_cfg.rx_queue,&rx_frame, 3*portTICK_PERIOD_MS)==pdTRUE){
      digitalWrite(GPIO_CAN_Wake, HIGH);
      if(rx_frame.MsgID==0x06214000){
          if( ZV_Byte_1 != rx_frame.data.u8[1]){
              ZV_Byte_1 = rx_frame.data.u8[1];
              Status_FT = IS_SET(ZV_Byte_1,2);
              Status_BFT = IS_SET(ZV_Byte_1,3);
              Status_ST = IS_SET(ZV_Byte_1,4)|IS_SET(ZV_Byte_1,5);
              Status_HT = IS_SET(ZV_Byte_1,6);   
              printf("FT: %d, BFT: %d, HT: %d, ST: %d, \n",Status_FT, Status_BFT , Status_HT, Status_ST);   
              Set_And_Hold_GPIO(GPIO_NUM_15, Status_FT);//MH-IP_1
              Set_And_Hold_GPIO(GPIO_NUM_2, Status_BFT);//MH-IP_2
              Set_And_Hold_GPIO(GPIO_NUM_0, Status_ST);//MH-IP_3
              Set_And_Hold_GPIO(GPIO_NUM_4, Status_HT);//MH-IP_4
              //Noch nicht belegt
              //Set_And_Hold_GPIO(GPIO_NUM_16, 1);//MH-IP_5 (Nur Taster/ immer Low im Schlaf)
              //Set_And_Hold_GPIO(GPIO_NUM_17, 1);//MH-IP_6 (Nur Taster/ immer Low im Schlaf)
              //Set_And_Hold_GPIO(GPIO_NUM_18, 0);//MH-IP_8
          }
      }
      previousMillis = millis();
    }
    else{
      currentMillis = millis();
      //erst nach 1s Funkstille den Transceiver deaktivieren
      if((currentMillis - previousMillis) > 1000) {
        digitalWrite(GPIO_CAN_Wake, LOW);
      }
    }
}

void Set_And_Hold_GPIO(gpio_num_t gpio_num,byte GPIO_status){
    gpio_hold_dis(gpio_num);
    digitalWrite(gpio_num, GPIO_status);
    gpio_hold_en(gpio_num);
    printf("GPIO: %d set to %d \n", gpio_num , GPIO_status);
}

Leave a Reply