Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERROR: ELM_TIMEOUT . Value received for a while and then error happens. #254

Open
jimwhitelaw opened this issue Jun 19, 2024 · 4 comments
Open

Comments

@jimwhitelaw
Copy link
Collaborator

Hi @PowerBroker2 ! Thanks a lot for the library !
I have the same ERROR: ELM_TIMEOUT .
Value received for a while and then error happens.
Code below

 // ga9a01 esp32 2424s012
#include <WiFi.h>
#include "ELMduino.h"
#include <TFT_eSPI.h>
#include <SPI.h>
#include <SoftwareSerial.h>
#include "SerpentineBoldItalic.h"
#include "pin_config.h"

#include "CST816D.h"
#define I2C_SDA 4
#define I2C_SCL 5
#define TP_RST 1
#define TP_INT 0

CST816D touch(I2C_SDA, I2C_SCL, TP_RST, TP_INT);
uint8_t gesture;
uint16_t touchX, touchY;

TFT_eSPI tft = TFT_eSPI();
TFT_eSprite testSprite = TFT_eSprite(&tft);

const char* ssid = "V-LINK";
const char* host = "192.168.0.10";
const int port = 35000;

// IP Address of your ELM327 Dongle
IPAddress server(192, 168, 0, 10);
WiFiClient client;
ELM327 myELM327;

const int ledPin = TFT_BL;  // 3 corresponds to GPIO3

const int freq = 2000;
const int ledChannel = 0;
const int resolution = 8;
const int dutyCycle = 255;  // LED brightness

float rpm = 0;
float volts = 0;

void setup() {
  Serial.begin(115200);

  touch.begin();  // Display init and touch

  tft.init();
  tft.setRotation(4);
  testSprite.setColorDepth(8);
  testSprite.createSprite(240, 240);

  ledcSetup(ledChannel, freq, resolution);  // migration from 2.x to 3.x
  ledcAttachPin(ledPin, ledChannel);        // Attach the LED pin to the channel
  ledcWrite(ledChannel, dutyCycle);         // Set the LED brightness

  // Clear the screen
  tft.fillScreen(TFT_BLACK);

  // Connecting to ELM327 WiFi
  Serial.print("Connecting to ");
  Serial.println(ssid);
  tft.setTextColor(TFT_WHITE);
  tft.drawCentreString("Connecting...", 120, 80, 2);

  WiFi.mode(WIFI_AP);
  WiFi.begin(ssid);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("Connected to Wifi ");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  IPAddress ip = WiFi.localIP();
  char ipChar[16];
  sprintf(ipChar, "%u.%u.%u.%u", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
  String ipStr(ipChar);  // convert char array to string here.
  tft.setTextColor(TFT_CYAN);
  tft.drawCentreString("Connected to Wifi " + ipStr, 120, 120, 2);

  if (client.connect(server, 35000)) {
    Serial.println("Connected!");
    tft.drawCentreString("Connected", 120, 160, 2);
  } else {
    Serial.println(">>>> Connection failed!!! <<<<");
    tft.fillScreen(TFT_BLACK);
    tft.setTextColor(TFT_CYAN);
    tft.drawCentreString("Connection failed!", 120, 80, 2);
    delay(1000);
    resetDraw();
    delay(500);
    ESP.restart();
  }

  myELM327.begin(client, true, 5000, ISO_15765_29_BIT_500_KBAUD);
}

void draw(float value) {
  testSprite.fillSprite(TFT_BLACK);
  
  testSprite.setTextColor(TFT_CYAN);
  testSprite.loadFont(SerpentineBoldItalic68pt);
  testSprite.setTextDatum(CC_DATUM);
  testSprite.drawFloat(value, 2, 120, 130);
  
  testSprite.setTextColor(TFT_GOLD);
  testSprite.loadFont(SerpentineBoldItalic18pt);
  //testSprite.drawString("RPM", 120, 180);
  testSprite.drawString("Volts", 120, 180);

  testSprite.pushSprite(0, 0);
}

void resetDraw() {
  testSprite.fillSprite(TFT_RED);
  testSprite.pushSprite(0, 0);
  Serial.println("Resetting ESP32...");
  delay(500);  // Small delay to allow serial message to be sent
  ESP.restart();
}

void loop() {
  //float tempRPM = myELM327.rpm();
float tempVolts = myELM327.batteryVoltage();
  if (myELM327.nb_rx_state == ELM_SUCCESS) {
    //rpm = tempRPM;
    volts=tempVolts;
  } else {
    Serial.println("Failed to receive data from ELM327.");
    myELM327.printError();
  }

  //draw(rpm);
  draw(volts);

  if (myELM327.nb_rx_state == ELM_TIMEOUT) {
    Serial.print("Reset by: ELM_TIMEOUT");
    resetDraw();
  }
}

void printError() {
  Serial.print("Received: ");
  for (byte i = 0; i < myELM327.recBytes; i++)
    Serial.write(myELM327.payload[i]);
  Serial.println();

  if (myELM327.nb_rx_state == ELM_SUCCESS)
    Serial.println(F("\tELM_SUCCESS"));
  else if (myELM327.nb_rx_state == ELM_NO_RESPONSE)
    Serial.println(F("\tERROR: ELM_NO_RESPONSE"));
  else if (myELM327.nb_rx_state == ELM_BUFFER_OVERFLOW)
    Serial.println(F("\tERROR: ELM_BUFFER_OVERFLOW"));
  else if (myELM327.nb_rx_state == ELM_UNABLE_TO_CONNECT)
    Serial.println(F("\tERROR: ELM_UNABLE_TO_CONNECT"));
  else if (myELM327.nb_rx_state == ELM_NO_DATA)
    Serial.println(F("\tERROR: ELM_NO_DATA"));
  else if (myELM327.nb_rx_state == ELM_STOPPED)
    Serial.println(F("\tERROR: ELM_STOPPED"));
  else if (myELM327.nb_rx_state == ELM_TIMEOUT)
    Serial.println(F("\tERROR: ELM_TIMEOUT"));
  else if (myELM327.nb_rx_state == ELM_GENERAL_ERROR)
    Serial.println(F("\tERROR: ELM_GENERAL_ERROR"));

  delay(100);
}

Log below
ELM_timeout_LOG.txt

Thanks in advance!

Update: No tft (plain) wifi example also shows timeout issue (library 3.3.0, esp32C3, ELM327 v2.3 VGATE iCar Pro)

Originally posted by @molotovec in #210 (comment)

@jimwhitelaw
Copy link
Collaborator Author

@molotovec, here's what I can see happening in your log file.

  1. You're getting a valid connection via WiFi to the adapter.
  2. You're able to send some AT commands to set up your interface parameters.
  3. You start getting errors after sending the "AT TP A7" command.
  4. You do eventually get valid responses to the AT RV (get voltage) command, though the response is interspersed with errors.

Are you certain that protocol 7 (ISO 15765-4 CAN 29bit ID, 500 kbaud) is correct for your vehicle? The way the "AT TP A7" works is that if it doesn't establish a connection with protocol 7, the ELM327 starts an automatic protocol search, which takes some time to complete that needs to be accounted for. Try leaving the protocol off when calling myELM327.begin(). That will do an auto protocol search with the appropriate wait for the search.

void loop() {
  //float tempRPM = myELM327.rpm();
float tempVolts = myELM327.batteryVoltage();
  if (myELM327.nb_rx_state == ELM_SUCCESS) {
    //rpm = tempRPM;
    volts=tempVolts;
  } else {
    Serial.println("Failed to receive data from ELM327.");
    myELM327.printError();
  }

  //draw(rpm);
  draw(volts);

  if (myELM327.nb_rx_state == ELM_TIMEOUT) {
    Serial.print("Reset by: ELM_TIMEOUT");
    resetDraw();
  }
}

This is not the correct way to query in a loop. You need to account for the ELM_GETTING_MESSAGE state. See this code from the Bluetooth serial example:

void loop()
{
  float tempRPM = myELM327.rpm();

  if (myELM327.nb_rx_state == ELM_SUCCESS)
  {
    rpm = (uint32_t)tempRPM;
    Serial.print("RPM: "); Serial.println(rpm);
  }
  else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
    myELM327.printError();
}

Lastly, batteryVoltage() is not a good query to use for testing your ELM327 connection. Unlike all the other queries, when responding to that query, the EML327 does not communicate with the vehicle ECU, it simply reads the voltage on its own power input and returns that. So it's possible to get a good response to batteryVoltage() and still not have a valid connection from your ELM device to the vehicle ECU. A better option is to use supportedPIDs_1_20() as that is guaranteed to communicate with and work on all ECUs (per the OBDII spec).

@molotovec
Copy link

molotovec commented Jun 19, 2024

@jimwhitelaw Thanks a lot for the reply!!! Unfortunately setting protocol is not a case. I tried auto before and it fails with timeouts so i've dig issues and found that protocol setting might fix, but is not. Timeout increase in the myELM327.begin(client, true, 2000); doesn't help.
So point 3 is not a case.
I've tried to use supportedPIDs_1_20() but result was same. Data received for a while and then stopped with timeout error even with no tft library use.
Tests were don in the car and at home.

I've thinking of try to trigger ELM adapter with AT command to wake it up if it does so, but not sure of this workaround and what command is good to send (AT @1 not helped). What do u think of that? Maybe I need to send some extra AT command on adapter initialization?

Please do see code below and log output:

#include <WiFi.h>
#include "ELMduino.h"

int nb_query_state = SEND_COMMAND;  // Set the inital query state ready to send a command

const char* ssid = "V-LINK";
const char* host = "192.168.0.10";
const int port = 35000;


//IP Adress of your ELM327 Dongle
IPAddress server(192, 168, 0, 10);
WiFiClient client;
ELM327 myELM327;


uint32_t rpm = 0;
uint32_t volts = 0;


void setup() {
  Serial.begin(38400);

  // Connecting to ELM327 WiFi
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_AP);
  WiFi.begin(ssid);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("Connected to Wifi");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  if (client.connect(server, 35000))
    Serial.println("connected");
  else {
    Serial.println("connection failed");
    ESP.restart();
    while (1)
      ;
  }
  Serial.println("Start ELM init ");
  myELM327.begin(client, true, 2000);

  // modify sleep time? AT PP 0E SV EA OK      5 min
}

void resetDraw() {
  if (nb_query_state == SEND_COMMAND)  // We are ready to send a new command
  {
    myELM327.sendCommand("AT");               // Send the custom PID commnad
    nb_query_state = WAITING_RESP;            // Set the query state so we are waiting for response
  } else if (nb_query_state == WAITING_RESP)  // Our query has been sent, check for a response
  {
    myELM327.get_response();  // Each time through the loop we will check again
  }
}

void loop() {
   float tempRPM = myELM327.rpm();

  if (myELM327.nb_rx_state == ELM_SUCCESS) {
    rpm = (uint32_t)tempRPM;
    Serial.print("RPM: ");
    Serial.println(rpm);
  } else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
    myELM327.printError();
}

ELMLogNotftNoProtocol.txt

ms-teams_JygZ0R2rk8

@jimwhitelaw
Copy link
Collaborator Author

The log shows that it’s searching for the protocol, but not connecting. I was going to suggest trying a different adapter, but from your screenshot, it appears to be working with Car Scanner. I don’t really know how to help at this point; the only suggestion I have is to go back to specifying the protocol in begin() with a much longer timeout.

@molotovec
Copy link

molotovec commented Jun 25, 2024

Hi @jimwhitelaw
myELM327.begin(client, true, 25000, ISO_15765_29_BIT_500_KBAUD);

void loop() {
float tempRPM = myELM327.rpm();

if (myELM327.nb_rx_state == ELM_SUCCESS) {
rpm = (uint32_t)tempRPM;
Serial.print("RPM: ");
Serial.println(rpm);
draw(rpm);
delay(500);
myELM327.sendCommand("AT");
} else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
myELM327.printError();
if (myELM327.nb_rx_state == ELM_TIMEOUT) {
resetDraw();
}
}

No timeout now as delay raised to 25sec
But value measured now each ~21 sec

UPDATE: in the car value is stuck with the first received. With the less delay and auto protocol it was showing up to 5 sec of updating value and then had timeout issue

13:40:31.177 -> Sending the following command/query: 010C1
13:40:52.336 -> Received char: ?
13:40:52.336 -> Received char: \r
13:40:52.336 -> Received char: \r
13:40:52.336 -> Received char: >
13:40:52.336 -> Delimiter found.
13:40:52.336 -> All chars received:
13:40:52.336 -> Expected response header: 410C
13:40:52.336 -> Response not detected
13:40:52.336 -> WARNING: Number of payload chars is less than the number of expected response chars returned by ELM327 - returning 0
13:40:52.336 -> RPM: 0.00
13:40:52.844 -> Clearing input serial buffer
13:40:52.844 -> Sending the following command/query: AT
13:40:52.882 -> Service: 1
13:40:52.882 -> PID: 12
13:40:52.882 -> Normal length query detected
13:40:52.882 -> Query string: 010C1
13:40:52.882 -> Clearing input serial buffer
13:40:52.882 -> Sending the following command/query: 010C1
13:41:13.946 -> Received char: ?
13:41:13.946 -> Received char: \r
13:41:13.946 -> Received char: \r
13:41:13.946 -> Received char: >
13:41:13.946 -> Delimiter found.
13:41:13.946 -> All chars received:
13:41:13.946 -> Expected response header: 410C
13:41:13.946 -> Response not detected
13:41:13.946 -> WARNING: Number of payload chars is less than the number of expected response chars returned by ELM327 - returning 0
13:41:13.946 -> RPM: 0.00
13:41:14.449 -> Clearing input serial buffer
13:41:14.449 -> Sending the following command/query: AT
13:41:14.488 -> Service: 1
13:41:14.488 -> PID: 12
13:41:14.488 -> Normal length query detected
13:41:14.488 -> Query string: 010C1
13:41:14.488 -> Clearing input serial buffer
13:41:14.488 -> Sending the following command/query: 010C1

How can this delay be reduced to at least 500msec between results ? Thnx in advance!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants