12-OBD-Speed: battery voltage arc and idle/screen-off mode
- ATRV every 2 s; voltage arc in the bottom gap (11-15 V) + number, colored by state (low / weak / resting / charging / overcharge) - idle after Off/2/5/10 min without speed data (settings page, NVS): screen off, GIF paused, OBD polling stopped, ATRV every 30 s; wakes on touch (swallowed by a top-layer overlay) or > 13.2 V - status pill moved up to make room for the voltage Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0777db3498
commit
be69bda4f1
5 files changed
+258
-16
No files matched your search
@@ -4,12 +4,20 @@
|
||||
#include <Preferences.h>
|
||||
|
||||
#define RETRY_DELAY_MS 3000
|
||||
#define IDLE_RETRY_DELAY_MS 30000
|
||||
#define POLL_FAIL_LIMIT 3
|
||||
#define VOLTAGE_INTERVAL_MS 2000 // ATRV while driving
|
||||
#define IDLE_VOLTAGE_INTERVAL_MS 30000 // ATRV while idle (adapter-internal, doesn't wake the car's bus)
|
||||
#define WAKE_VOLTAGE 13.2f // above this the alternator is charging: engine running
|
||||
|
||||
// ---------- shared state (protected by `mtx`) ----------
|
||||
static SemaphoreHandle_t mtx;
|
||||
static volatile ObdState state = ObdState::NoDevice;
|
||||
static volatile int speed_kmh = -1;
|
||||
static volatile float voltage = -1;
|
||||
static volatile bool idle = false;
|
||||
static volatile uint32_t idle_timeout_ms = 2 * 60 * 1000;
|
||||
static volatile uint32_t last_data_ms = 0; // last valid speed (or wake-up)
|
||||
static String status_text = "starting";
|
||||
static String saved_addr, saved_name;
|
||||
static uint8_t saved_type = 0;
|
||||
@@ -18,7 +26,7 @@ static uint32_t devices_version = 1;
|
||||
static String elm_rx; // bytes received from the ELM (notifications)
|
||||
|
||||
// ---------- requests from the UI ----------
|
||||
static volatile bool req_select = false, req_forget = false;
|
||||
static volatile bool req_select = false, req_forget = false, req_wake = false;
|
||||
static volatile bool scan_wanted = false;
|
||||
static ObdDevInfo req_dev;
|
||||
|
||||
@@ -155,6 +163,23 @@ static int parse_speed(String reply)
|
||||
return (int)strtol(reply.substring(i + 4, i + 6).c_str(), nullptr, 16);
|
||||
}
|
||||
|
||||
// "12.6V" -> 12.6, -1 if not a voltage
|
||||
static float parse_voltage(const String &reply)
|
||||
{
|
||||
int v = reply.indexOf('V');
|
||||
if (v <= 0)
|
||||
return -1;
|
||||
float f = reply.substring(0, v).toFloat();
|
||||
return f > 0 ? f : -1;
|
||||
}
|
||||
|
||||
static void read_voltage()
|
||||
{
|
||||
float v = parse_voltage(elm_command("ATRV", 1500));
|
||||
if (v > 0)
|
||||
voltage = v;
|
||||
}
|
||||
|
||||
// ---------- connection ----------
|
||||
static void disconnect()
|
||||
{
|
||||
@@ -259,9 +284,28 @@ static void load_saved()
|
||||
static void worker_task(void *)
|
||||
{
|
||||
uint32_t next_attempt = 0;
|
||||
uint32_t next_voltage = 0;
|
||||
int fails = 0;
|
||||
last_data_ms = millis();
|
||||
for (;;)
|
||||
{
|
||||
if (req_wake)
|
||||
{
|
||||
req_wake = false;
|
||||
if (idle)
|
||||
Serial.println("[obd] wake (touch)");
|
||||
idle = false;
|
||||
last_data_ms = millis();
|
||||
next_attempt = 0;
|
||||
}
|
||||
// no speed data for a while (ignition off / adapter gone): go idle
|
||||
if (!idle && idle_timeout_ms && millis() - last_data_ms > idle_timeout_ms)
|
||||
{
|
||||
idle = true;
|
||||
speed_kmh = -1;
|
||||
Serial.println("[obd] idle");
|
||||
}
|
||||
|
||||
// requests from the UI
|
||||
if (req_forget)
|
||||
{
|
||||
@@ -296,6 +340,8 @@ static void worker_task(void *)
|
||||
if (saved_addr.length() == 0)
|
||||
{
|
||||
state = ObdState::NoDevice;
|
||||
idle = false;
|
||||
last_data_ms = millis(); // no idle while no adapter is chosen (user is setting up)
|
||||
set_status("No adapter - swipe left");
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
continue;
|
||||
@@ -317,11 +363,36 @@ static void worker_task(void *)
|
||||
{
|
||||
disconnect();
|
||||
state = ObdState::Waiting;
|
||||
next_attempt = millis() + RETRY_DELAY_MS;
|
||||
next_attempt = millis() + (idle ? IDLE_RETRY_DELAY_MS : RETRY_DELAY_MS);
|
||||
}
|
||||
next_voltage = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (idle)
|
||||
{
|
||||
// only the battery voltage now and then; an engine start (charging voltage) wakes us up
|
||||
if ((int32_t)(millis() - next_voltage) >= 0)
|
||||
{
|
||||
next_voltage = millis() + IDLE_VOLTAGE_INTERVAL_MS;
|
||||
read_voltage();
|
||||
if (voltage > WAKE_VOLTAGE)
|
||||
{
|
||||
idle = false;
|
||||
last_data_ms = millis();
|
||||
Serial.printf("[obd] wake (%.1f V)\n", voltage);
|
||||
}
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((int32_t)(millis() - next_voltage) >= 0)
|
||||
{
|
||||
next_voltage = millis() + VOLTAGE_INTERVAL_MS;
|
||||
read_voltage();
|
||||
}
|
||||
|
||||
// connected: poll the vehicle speed
|
||||
String reply = elm_command("010D", 1500);
|
||||
int v = parse_speed(reply);
|
||||
@@ -329,6 +400,7 @@ static void worker_task(void *)
|
||||
if (v >= 0)
|
||||
{
|
||||
fails = 0;
|
||||
last_data_ms = millis();
|
||||
set_status(saved_name.length() ? saved_name : saved_addr);
|
||||
}
|
||||
else if (reply.length() == 0)
|
||||
@@ -365,6 +437,10 @@ void obd_begin()
|
||||
|
||||
ObdState obd_state() { return state; }
|
||||
int obd_speed() { return speed_kmh; }
|
||||
float obd_voltage() { return voltage; }
|
||||
bool obd_is_idle() { return idle; }
|
||||
void obd_wake() { req_wake = true; }
|
||||
void obd_set_idle_timeout(uint32_t minutes) { idle_timeout_ms = minutes * 60 * 1000; }
|
||||
|
||||
String obd_status_text()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user