esphome / feature-requests

ESPHome Feature Request Tracker
https://esphome.io/
404 stars 26 forks source link

ESP32 support ELM (ELM327) OBD2 #935

Open GregoryGost opened 3 years ago

GregoryGost commented 3 years ago

Describe the problem you have/What new integration you would like

ESP32 has bluetooth which can be used for requests to the car CAN bus via OBD2 adapter. Also, such requests can be sent through the UART port.

Please describe your use case for this integration and alternatives you've tried:

The main application case is the collection of vehicle data and transmission over Wi-Fi. For example, through a MikroTik LTAP (mini) access point. There are alternatives not for this application. Example: https://github.com/PowerBroker2/ArduHUD/blob/master/src/ESP32_HUD/ESP32_HUD.ino https://github.com/PowerBroker2/ELMduino

include "ELMduino.h"

Additional context

ELM327 Device: https://www.amazon.com/ELM327/s?k=ELM327 ESP32 OBD-II Emulator: https://github.com/limiter121/esp32-obd2-emulator https://hackaday.com/2018/04/11/emulating-obd-ii-on-the-esp32/

joosthb commented 3 years ago

I am looking for a canbus implementation as well to use in my campervan project! There is already work being done on canbus in this PR but I think they're aiming at interconnecting esphome nodes using canbus, not for pulling car diagnostics.

The ELM327 already supports lot's of car diagnostics protocols which a published on UART over Bluetooth. I recently ordered a ELM327 and have a ESP32 available so I will definitely give it a try in a bit.

GregoryGost commented 3 years ago

I am looking for a canbus implementation as well to use in my campervan project! There is already work being done on canbus in this PR but I think they're aiming at interconnecting esphome nodes using canbus, not for pulling car diagnostics.

The ELM327 already supports lot's of car diagnostics protocols which a published on UART over Bluetooth. I recently ordered a ELM327 and have a ESP32 available so I will definitely give it a try in a bit.

I also ordered a CAN converter. Also I have an ESP32 and many other devices.

Bascht74 commented 2 years ago

Is there any progress? I am looking for a solution, too.

samuelmcconnell commented 2 years ago

I'd also like to see support for ELM327 over Bluetooth. This could be a non-cloud way to monitor charging status and SoC for electric vehicles.

Bascht74 commented 2 years ago

@samuelmcconnell A Bluetooth serial component in esphome is needed (that replaces the direct connection/UART). That is a different feature request in my opinion, isn‘t it…

iamthe1st commented 1 year ago

This would be a great feature! This would be a perferct addon for a electric vehicle.

lwqcz commented 1 year ago

I've just bought vLinker MC+ OBD2 dongle which is BLE capable and I'm wondering how can I transfer data thru esphome to my homeassstant DB + visualisation/graphs. An ESP32 as BLE-OBD2 to IP bridge to push data thru wifi (local or via smartphones hotspot for instance) to MQTT/Influx or Hass in general would be awesome. But I assume I would need to write/manage this as there is virtually no other one interested?

iamthe1st commented 1 year ago

Hi, There is a device on crowdsupply which is a ESP connected directly to CAN / OBD2 called meatPi WICAN . This device publishes CAN Messages over MQTT

I think this is the way to go, if you don't have existing hardware.

linkedupbits commented 1 year ago

I have some sample code that "kind-of" works (but not completely) on an ESP32 using BLE to a LiLink ELM327, using "native" ESPHome.

ble_client:
  - mac_address: B4:99:4C:XX:XX:XX
    id: lelink
    name: LELink Leafspy
    on_connect:
      then:
        - lambda: |-
            ESP_LOGI("ble_client on_connect", "Connected to lelink");
        - logger.log:
            level: INFO
            format: "Sending ATZ"
        - ble_client.ble_write:
              id: lelink
              service_uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
              characteristic_uuid: ffe1
              value: [0x41, 0x54, 0x5A,           0x0D, 0x0A, # ATZ\r\n
                    0x41, 0x54, 0x45, 0x30,     0x0D, 0x0A, # ATE0\r\n 
                    ]           
    on_disconnect:
      then:
        - lambda: |-
            ESP_LOGI("ble_client_lambda", "Disconnected from lelink");
text_sensor:
  - platform: ble_client
    ble_client_id: lelink
    internal: True
    update_interval: never
    notify: True
    name: "lelink response"
    id: lelink_response_text
    service_uuid: "0000ffe0-0000-1000-8000-00805f9b34fb"
    characteristic_uuid: "ffe1"
    on_notify: 
      then:
        - lambda: |-

            //std::string sampleString("A TEST 1\r\n");
            //std::vector<unsigned char> sampleBytes (sampleString.begin(), sampleString.end());
            //ESP_LOGD("lelink_response_text on_notify", "sampleString '%s'",   format_hex_pretty(sampleBytes.c_str(), sampleBytes.size()).c_str());

            ESP_LOGD("lelink_response_text on_notify", "notify text from lelink");
            auto tempvar = format_hex_pretty((uint8_t *) x.c_str(), x.size());
            std::string string2(x.begin(),x.end());

            std::vector<std::string> strings;
            std::string del("\r"); 
            int end = string2.find(del); 
            std::string s(string2);
            while (end != -1) { // Loop until no delimiter is left in the string.
                ESP_LOGD("lelink_response_text on_notify (split)", "x='%s'",    s.substr(0, end).c_str());
                strings.push_back(s.substr(0, end));
                s.erase(s.begin(), s.begin() + end + 1);
                end = s.find(del);
            }

            if (s.length() > 0) {
                ESP_LOGD("lelink_response_text on_notify (split)", "x='%s'",    s.c_str());
                strings.push_back(s);
            }

            std::string toSearch ("\r");
            std::string replaceStr(" cr ");
            size_t pos = string2.find(toSearch);

            // Repeat till end is reached
            while( pos != std::string::npos)
            {
                // Replace this occurrence of Sub String
                string2.replace(pos, toSearch.size(), replaceStr);
                // Get the next occurrence from the current position
                pos = string2.find(toSearch, pos + replaceStr.size());
            }

            ESP_LOGD("lelink_response_text on_notify", "x='%s'",    string2.c_str());
            ESP_LOGD("lelink_response_text on_notify", "b=%s", format_hex_pretty((uint8_t *) x.c_str(), x.size()).c_str());

interval:
  - interval: 30s 
    # https://leaf-obd.readthedocs.io/en/latest/tutorial/elm327.html
    then:
#      - logger.log:
#          level: INFO
#          format: "Sending ATZ"
#      - ble_client.ble_write:
#            id: lelink
#            service_uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
#            characteristic_uuid: ffe1
#            value: [0x41, 0x54, 0x5A,           0x0D, 0x0A, # ATZ\r\n
#                  0x41, 0x54, 0x45, 0x30,     0x0D, 0x0A, # ATE0\r\n
#                     ]
#      - logger.log:
#          level: INFO
#          format: "Sending ATZ (again)"
#      - ble_client.ble_write:
#            id: lelink
#            service_uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
#            characteristic_uuid: ffe1
#            value: [0x41, 0x54, 0x5A,           0x0D, 0x0A, # ATZ\r\n
#                     ]     

#ATWS                
      - logger.log:
          level: INFO
          format: "Sending ATE1 (turn echo on)"
      - ble_client.ble_write:
            id: lelink
            service_uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
            characteristic_uuid: ffe1
            value: [0x41, 0x54, 0x45, 0x31,     0x0D, 0x0A, # ATE1\r\n ATE0 to turn echo off
                     ]
      - logger.log:
          level: INFO
          format: "Sending ATI"
      - ble_client.ble_write:
            id: lelink
            service_uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
            characteristic_uuid: ffe1
            value: [0x41, 0x54, 0x49,           0x0D, 0x0A, # ATI\r\n
                     ]
      - logger.log:
                level: INFO
                format: "Sending ATL1 (line feed on)"                     
      - ble_client.ble_write:
            id: lelink
            service_uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
            characteristic_uuid: ffe1
            # List of bytes to write.
            value: [0x41, 0x54, 0x4C, 0x30,     0x0D, 0x0A, # ATL1
                     ]  
      - logger.log:
                level: INFO
                format: "Sending ATH1 (header control on)"                     
      - ble_client.ble_write:
            id: lelink
            service_uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
            characteristic_uuid: ffe1
            # List of bytes to write.
            value: [0x41, 0x54, 0x48, 0x31,     0x0D, 0x0A, # ATH1
                     ] 
      - logger.log:
                level: INFO
                format: "Sending ATS1 (print spaces on)"                     
      - ble_client.ble_write:
            id: lelink
            service_uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
            characteristic_uuid: ffe1
            # List of bytes to write.
            value: [0x41, 0x54, 0x53, 0x31,     0x0D, 0x0A, # ATS1
                     ]
      - logger.log:
                level: INFO
                format: "Sending ATAL (allow long messages)"                     
      - ble_client.ble_write:
            id: lelink
            service_uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
            characteristic_uuid: ffe1
            # List of bytes to write.
            value: [0x41, 0x54, 0x41, 0x4C,     0x0D, 0x0A, # ATAL
                     ]                                        
      - logger.log:
                level: INFO
                format: "Sending ATDP"                              
      - ble_client.ble_write:
            id: lelink
            service_uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
            characteristic_uuid: ffe1
            # List of bytes to write.
            value: [0x41, 0x54, 0x44, 0x50, 0x0D, 0x0A,#ATDP to return the protocol (its always ISO 15765-4 (CAN 11/500) but this is just a good sanity check)
                     ]   
      - logger.log:
                level: INFO
                format: "Sending ATCRA 5B3"                              
      - ble_client.ble_write:
            id: lelink
            service_uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
            characteristic_uuid: ffe1
            # List of bytes to write.
            value: [0x41, 0x54, 0x43, 0x52, 0x41, 0x20, 0x35, 0x42, 0x33,     0x0D, 0x0A,#ATCRA 5B3 https://leaf-obd.readthedocs.io/en/latest/pid/5b3.html
                     ]   

But I think to have a more synchronous communication I will need a native c++ component ?

sanchosk commented 10 months ago

@linkedupbits This code looks interesting. I have already a sequence of request/response AT codes for my Zoe. I've implemented it into direct arduino code and it sort of works, but is a bit unstable - if the car is away from garage, I often get reboots of the ESP32 or in some cases it just gets stuck on start boot loop. It would be great to have this implemented in basic ESPhome, where I can send request/response/error code from ESP BT proxy back to HA, or at least publish MQTT message. Any chance you had some progress with the code?

myo900 commented 2 months ago

Hi, has anyone managed to make this code work? My idea is to connect my Twizy car to HA and control the charging. Any updates?