Public Access
Updates: a newer release installs by itself, after a question
With Settings > System > Install updates on By itself (issue #52), a release found by the daily check is offered once no key was pressed for 2 minutes and nothing would be cut by a restart. The question goes over whatever App is open, with Cancel and Accept, and installs after 30 s without an answer. Each update that held, and each one undone, is a dated line in /system/updates.log on the card. Tried on the device: the question, Cancel, and an install of v0.23.0 left unanswered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0162FokPdvY2KsS4NBfwyWPk
This commit is contained in:
+69
-3
@@ -20,6 +20,7 @@
|
||||
#include "services/web_share.h"
|
||||
#include "apps/gemini_app.h"
|
||||
#include "apps/gnss_app.h"
|
||||
#include "auto_update.h"
|
||||
#include "apps/irc_app.h"
|
||||
#include "apps/launcher_app.h"
|
||||
#include "apps/lora_scanner_app.h"
|
||||
@@ -81,6 +82,12 @@ static Screen screen;
|
||||
static BatteryService* battery;
|
||||
static StorageService* storageService;
|
||||
static FileOps* fileOps;
|
||||
static WebShare* webShare;
|
||||
// Installing a release by itself (issue #52): see autoUpdateStep().
|
||||
static release::AutoUpdate autoUpdate;
|
||||
static std::unique_ptr<DialogModel> autoDialog;
|
||||
static uint32_t lastKeyMs = 0;
|
||||
static bool autoRedraw = false;
|
||||
static std::vector<std::string> filesInUse(const std::string& path, bool folder);
|
||||
static PowerService* power;
|
||||
static ClockService* clockService;
|
||||
@@ -238,7 +245,7 @@ void setup() {
|
||||
apps->registerApp({"gnss", "GNSS", false, new GnssApp(*gnssService, settings, *storageService), icons::gnss});
|
||||
apps->registerApp({"gemini", "Gemini", false, new GeminiApp(*geminiService), icons::gemini});
|
||||
apps->registerApp({"lora", "LoRa Scanner", false, new LoraScannerApp(*radioService, *loraCapture, settings, *clockService), icons::lora});
|
||||
apps->registerApp({"storage", "Storage", false, new StorageApp(*fileOps, *storageService, *clockService, *update, *power, bus, *new WebShare(*storageService, *fileOps, *wifi)), icons::storage});
|
||||
apps->registerApp({"storage", "Storage", false, new StorageApp(*fileOps, *storageService, *clockService, *update, *power, bus, *(webShare = new WebShare(*storageService, *fileOps, *wifi))), icons::storage});
|
||||
apps->registerApp({"notes", "Notes", false, new NotesApp(*fileOps, *storageService, *clockService, *power), icons::notes});
|
||||
sshService = new SshService(settings);
|
||||
sshApp = new SshApp(*sshService, settings, *storageService);
|
||||
@@ -569,6 +576,9 @@ static void updateCommand(const String& args) {
|
||||
console.printf("update: running %s, failed here before: %s, daily check %s, heap %u\n", update->runningVersion().c_str(),
|
||||
update->failedVersion().empty() ? "none" : update->failedVersion().c_str(),
|
||||
settings.getBool(Setting::CheckUpdates) ? "on" : "off", (unsigned)ESP.getFreeHeap());
|
||||
console.printf("update: installing by itself %s%s%s\n", settings.getBool(Setting::InstallUpdates) ? "on" : "off",
|
||||
autoUpdate.waiting() ? ", waiting for a quiet moment to offer " : autoUpdate.asking() ? ", asking about " : "",
|
||||
autoUpdate.waiting() || autoUpdate.asking() ? autoUpdate.tag().c_str() : "");
|
||||
console.printf("update: gitea %s %s\n", g.status() == GiteaReleases::Status::Done ? "done" : g.status() == GiteaReleases::Status::Failed ? "failed" : g.status() == GiteaReleases::Status::Busy ? "busy" : "never asked", g.error().c_str());
|
||||
printReleases(false);
|
||||
} else if (args.startsWith("install ")) {
|
||||
@@ -849,8 +859,57 @@ static void screenshotKey() {
|
||||
}
|
||||
|
||||
// Every key goes through here, from the keyboard or from a console's `key`.
|
||||
// Installing a release by itself (issue #52, Settings > System > Install updates): once the daily
|
||||
// check has found one, wait until nothing would be cut by a restart and no key was pressed for a
|
||||
// while, then ask on the screen, over whatever is open. Left unanswered for 30 s, it is installed.
|
||||
|
||||
// Would a restart now cut something short?
|
||||
static bool busyForRestart() {
|
||||
return gnssService->tracking() || loraCapture->capturing() || upload.active() || fileOps->busy() ||
|
||||
(scpService && scpService->busy()) || (sshService && sshService->active()) || (webShare && webShare->running()) ||
|
||||
(noiseTest && noiseTest->running()) || update->phase() != UpdateService::Phase::Idle || update->onProbation() ||
|
||||
update->giteaBusy();
|
||||
}
|
||||
|
||||
static void autoUpdateStep(uint32_t now) {
|
||||
static int shownSeconds = -1;
|
||||
if (!settings.getBool(Setting::InstallUpdates) && (autoUpdate.waiting() || autoUpdate.asking())) autoUpdate.withdraw();
|
||||
std::string tag;
|
||||
if (update->takeOffer(tag)) autoUpdate.offer(tag);
|
||||
if (autoDialog && autoDialog->result() != DialogModel::kPending) autoUpdate.answer(autoDialog->result() == 1);
|
||||
switch (autoUpdate.step(now, busyForRestart(), now - lastKeyMs)) {
|
||||
case release::AutoUpdate::Action::None: break;
|
||||
case release::AutoUpdate::Action::Ask:
|
||||
autoDialog.reset(new DialogModel({"Cancel", "Accept"}));
|
||||
power->onNotification(now, now + release::AutoUpdate::kAskMs); // a screen that is off lights up for it
|
||||
autoRedraw = true;
|
||||
break;
|
||||
case release::AutoUpdate::Action::Dismiss:
|
||||
autoDialog.reset();
|
||||
autoRedraw = true;
|
||||
break;
|
||||
case release::AutoUpdate::Action::Install: {
|
||||
autoDialog.reset();
|
||||
autoRedraw = true;
|
||||
std::string why = update->requestInstall(autoUpdate.tag(), true);
|
||||
if (!why.empty())
|
||||
bus.publish(Event::withText(EventType::Notification, ("Update not installed: " + why).c_str(), static_cast<int32_t>(NotificationLevel::Warning)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
int seconds = autoUpdate.asking() ? autoUpdate.secondsLeft(now) : -1;
|
||||
if (seconds != shownSeconds) {
|
||||
shownSeconds = seconds;
|
||||
autoRedraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void handleKey(const KeyEvent& e) {
|
||||
if (e.key == Key::Screenshot) return screenshotKey();
|
||||
if (autoDialog) { // the question takes every key until it is answered
|
||||
autoDialog->onKey(e);
|
||||
return;
|
||||
}
|
||||
apps->handleKey(e);
|
||||
}
|
||||
|
||||
@@ -1534,6 +1593,7 @@ static void loopPass() {
|
||||
printListingWhenReady();
|
||||
M5Cardputer.update();
|
||||
if (M5Cardputer.Keyboard.isChange()) {
|
||||
lastKeyMs = now;
|
||||
bool swallow = M5Cardputer.Keyboard.isPressed() && power->onKey(now); // only woke the screen
|
||||
keyMapper.setTextEntry(apps->foreground().textEntryActive());
|
||||
auto events = keyMapper.update(readKeys()); // always, so held keys are tracked
|
||||
@@ -1549,6 +1609,7 @@ static void loopPass() {
|
||||
bus.dispatch();
|
||||
notifier->update(now);
|
||||
apps->update(now);
|
||||
autoUpdateStep(now);
|
||||
|
||||
if (now - lastLog > 10000) {
|
||||
lastLog = now;
|
||||
@@ -1594,10 +1655,15 @@ static void loopPass() {
|
||||
screen.invalidate();
|
||||
redrawAfterUpdate = true;
|
||||
}
|
||||
if (apps->takeRedraw() || toastChanged || status != lastStatus || redrawAfterUpdate) {
|
||||
if (apps->takeRedraw() || toastChanged || status != lastStatus || redrawAfterUpdate || autoRedraw) {
|
||||
lastStatus = status;
|
||||
redrawAfterUpdate = false;
|
||||
screen.render(*apps, status, toast);
|
||||
autoRedraw = false;
|
||||
if (autoDialog) {
|
||||
Screen::Question question{"Update to " + autoUpdate.tag() + "?",
|
||||
"It installs in " + std::to_string(autoUpdate.secondsLeft(now)) + " s unless you cancel, and the device restarts.", autoDialog.get()};
|
||||
screen.render(*apps, status, toast, &question);
|
||||
} else screen.render(*apps, status, toast);
|
||||
update->firstFrameDrawn();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user