App 2.3.0: Server tab, live telemetry to the car server
- New Server tab: server URL, ingest token and installation id, with
Save, Test connection (health, then a read-only token check) and the
config-file import that upstream removed (app folder / USB stick first,
document picker as fallback). Settings are kept encrypted and read on
every use, so the service picks up a change without a restart. Each
installation generates its own id; the inherited upstream UUID and
the baked-in CONSUMPTION_API_* build fields are gone.
- Live telemetry restored from before ea8032a (TelemetryPayload,
UploadCadence, UploadSettings, GPS) and sent in batches to
POST /v1/telemetry instead of ABRP; the server forwards to ABRP. Adds
ext_temp, voltage and current. Unsent samples queue in memory (about
8 h) while offline.
- Upload tab: the live-telemetry switch and cadence controls work again;
the dead service and autostart switches are removed.
- Manifest: location permissions and foreground service types.
- Unit tests compile again: 114 (stable) / 136 (unstable) pass. Tests
for the deleted AbrpApi and HeadUnitWeather removed; new tests for
ServerConfig and TelemetryQueue. Lint passes.
Not yet tried on the car.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,11 +24,13 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Foreground service that polls vehicle telemetry every 15 s, integrates consumption locally,
|
||||
* and syncs it to the cloud (MongoDB) in 30-minute delta chunks. Never sends anything to ABRP.
|
||||
* syncs it to the car server in 2-minute delta chunks, and sends live telemetry samples that
|
||||
* the server stores and forwards to ABRP ({@link TelemetryUploader}). The car itself never
|
||||
* talks to ABRP and holds no ABRP credentials.
|
||||
*
|
||||
* Always-on by design: started at boot (BootReceiver) and on app open, never gated on
|
||||
* credentials or a toggle. The only thing it needs is a network for the cloud sync, and a
|
||||
* missing one is handled by caching chunks locally until the connection returns.
|
||||
* credentials or a toggle. The only thing it needs is a network, and a missing one is
|
||||
* handled by queueing locally until the connection returns.
|
||||
*/
|
||||
public class AbrpUploadService extends Service {
|
||||
|
||||
@@ -64,6 +66,7 @@ public class AbrpUploadService extends Service {
|
||||
private ConsumptionTracker consumptionTracker;
|
||||
private ConsumptionCloudClient consumptionCloudClient;
|
||||
private ChargeSessionTracker chargeSessionTracker;
|
||||
private TelemetryUploader telemetryUploader;
|
||||
private WifiAutoConnect wifi;
|
||||
private ScheduledExecutorService scheduler;
|
||||
private SharedPreferences prefs;
|
||||
@@ -94,6 +97,7 @@ public class AbrpUploadService extends Service {
|
||||
consumptionCloudClient = new ConsumptionCloudClient(getApplicationContext());
|
||||
chargeSessionTracker = ChargeSessionTracker.get(getApplicationContext());
|
||||
wifi = new WifiAutoConnect(getApplicationContext());
|
||||
telemetryUploader = new TelemetryUploader(getApplicationContext());
|
||||
|
||||
scheduler.scheduleWithFixedDelay(
|
||||
this::safeUploadCycle,
|
||||
@@ -111,15 +115,16 @@ public class AbrpUploadService extends Service {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters the foreground. No location type — this service no longer reads GPS. Foreground
|
||||
* service types do not exist before API 29, so on this API-28 head unit a plain
|
||||
* startForeground is the only correct call.
|
||||
* Enters the foreground. Foreground service types do not exist before API 29, so on this
|
||||
* API-28 head unit a plain startForeground is the only correct call; from API 29 the
|
||||
* location type is what lets the GPS subscription run in the background.
|
||||
*/
|
||||
private void startInForeground() {
|
||||
Notification notification = buildNotification(lastStatus);
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
|
||||
ServiceCompat.startForeground(
|
||||
this, NOTIF_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
|
||||
this, NOTIF_ID, notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC | ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
|
||||
} else {
|
||||
startForeground(NOTIF_ID, notification);
|
||||
}
|
||||
@@ -133,6 +138,7 @@ public class AbrpUploadService extends Service {
|
||||
running = false;
|
||||
prefs.edit().putBoolean("service_running", false).apply();
|
||||
if (scheduler != null) scheduler.shutdownNow();
|
||||
if (telemetryUploader != null) telemetryUploader.stop();
|
||||
Log.i(TAG, "Service stopped");
|
||||
}
|
||||
|
||||
@@ -159,7 +165,16 @@ public class AbrpUploadService extends Service {
|
||||
wifi.ensureConnected(false);
|
||||
}
|
||||
|
||||
updateNotification("Consumption tracking active");
|
||||
UploadSettings settings = UploadSettings.from(prefs);
|
||||
if (!ServerConfig.get(this).isConfigured()) {
|
||||
updateNotification(getString(R.string.server_not_configured));
|
||||
} else if (!settings.abrpUploadEnabled) {
|
||||
updateNotification(getString(R.string.notif_tracking_locally));
|
||||
} else {
|
||||
telemetryUploader.tick(vehicle, chargeSessionTracker.snapshot(), settings);
|
||||
int queued = telemetryUploader.queued();
|
||||
updateNotification(queued > 0 ? "Sending telemetry — " + queued + " queued" : "Sending telemetry");
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Notification ----------
|
||||
|
||||
Reference in New Issue
Block a user