feat: deep sleep single-fetch with probabilistic weighting

Refactor timerWakeCycle() to fetch a single random photo per wake
using cycle-mode-aware server-side filtering via Immich's
POST /api/search/random endpoint.

Changes:
- Add fetchOneRandomAssetId() to ImmichClient with support for
  isFavorite, takenAfter, takenBefore filter parameters
- Add timer_last_date NVS field for chronological cursor persistence
- Implement probabilistic filter selection per cycle mode:
  - Random: unfiltered size=1
  - Chronological/ReverseChronological: date cursor in NVS
  - FavoritesWeighted: 66% favorites, 33% unfiltered
  - WeightedChronological: 66% recent (30d), 33% unfiltered
  - WeightedReverseChronological: 66% older (30d), 33% unfiltered
- Add retry loop with filter relaxation on empty results
- Initialize hardware RTC (RX8130CE) firmware-wide:
  - Seed system clock from RTC at boot (immediate time)
  - NTP sync after WiFi connect, write back to RTC
- Add time_utils.h with isoNow(), isoNowMinus30d(), hasValidTime()

Normal mode (PhotoQueue + displayTask) is completely untouched.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-04 20:57:59 -04:00
parent 3483b9bef8
commit b9e5044fd2
8 changed files with 285 additions and 8 deletions

View File

@@ -26,6 +26,13 @@ struct RandomAsset {
String dateTime;
};
struct RandomFetchFilter {
std::vector<String> albumIds;
bool favoriteOnly = false;
String takenAfter; // ISO datetime, empty = no filter
String takenBefore; // ISO datetime, empty = no filter
};
class ImmichClient {
public:
void begin(const String& baseUrl, const String& apiKey);
@@ -36,6 +43,7 @@ public:
std::vector<RandomAsset> fetchRandomAssets(int count = 50,
const std::vector<String>& albumIds = {});
std::vector<String> fetchFavoriteAssetIds();
String fetchOneRandomAssetId(const RandomFetchFilter& filter);
AssetInfo fetchAssetInfo(const String& assetId);
bool downloadAsset(const String& assetId, ImageQuality quality,
uint8_t** outBuffer, size_t* outSize);