Add auto-sleep timeout setting and handle it in loop

Incremented settings count, added autoSleepMinutes to CrossPointSettings, updated save/load functions, and integrated auto-sleep logic based on the new setting.
This commit is contained in:
altsysrq 2026-01-03 22:27:02 -06:00
parent 490ae79ede
commit 9ab27f848c
10 changed files with 213 additions and 54 deletions

1
.envrc
View File

@ -1 +0,0 @@
use nix

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,174 @@
<TaskerData sr="" dvi="1" tv="6.5.11">
<Task sr="task6">
<cdate>1767235270638</cdate>
<edate>1767236697913</edate>
<id>6</id>
<nme>Upload EPUBs to CrossPoint</nme>
<Action sr="act0" ve="7">
<code>398</code>
<Str sr="arg0" ve="3">CrossPoint-Reader</Str>
</Action>
<Action sr="act1" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%READER_IP</Str>
<Str sr="arg1" ve="3">192.168.4.1</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
<Int sr="arg4" val="0"/>
<Int sr="arg5" val="3"/>
<Int sr="arg6" val="1"/>
</Action>
<Action sr="act10" ve="7">
<code>37</code>
<ConditionList sr="if">
<Condition sr="c0" ve="3">
<lhs>%file_list</lhs>
<op>13</op>
<rhs>"%filename"</rhs>
</Condition>
</ConditionList>
</Action>
<Action sr="act11" ve="7">
<code>339</code>
<se>false</se>
<Bundle sr="arg0">
<Vals sr="val">
<file>%epub_file:file</file>
<file-type>java.lang.String</file-type>
</Vals>
</Bundle>
<Int sr="arg1" val="1"/>
<Int sr="arg10" val="0"/>
<Int sr="arg11" val="0"/>
<Int sr="arg12" val="1"/>
<Str sr="arg2" ve="3">http://%READER_IP/upload?path=%TARGET_DIR</Str>
<Str sr="arg3" ve="3"/>
<Str sr="arg4" ve="3"/>
<Str sr="arg5" ve="3"/>
<Str sr="arg6" ve="3"/>
<Str sr="arg7" ve="3">%upload_response</Str>
<Int sr="arg8" val="60"/>
<Int sr="arg9" val="0"/>
</Action>
<Action sr="act12" ve="7">
<code>548</code>
<Str sr="arg0" ve="3">✓ %filename</Str>
<Int sr="arg1" val="0"/>
</Action>
<Action sr="act13" ve="7">
<code>43</code>
</Action>
<Action sr="act14" ve="7">
<code>40</code>
</Action>
<Action sr="act15" ve="7">
<code>523</code>
<Str sr="arg0" ve="3">Upload Complete</Str>
<Str sr="arg1" ve="3">Processed %EPUB_FILES(#) files</Str>
<Str sr="arg10" ve="3"/>
<Str sr="arg11" ve="3"/>
<Str sr="arg12" ve="3"/>
<Img sr="arg2" ve="2"/>
<Int sr="arg3" val="0"/>
<Int sr="arg4" val="0"/>
<Int sr="arg5" val="3"/>
<Int sr="arg6" val="0"/>
<Int sr="arg7" val="0"/>
<Int sr="arg8" val="0"/>
<Str sr="arg9" ve="3"/>
</Action>
<Action sr="act2" ve="7">
<code>30</code>
<Int sr="arg0" val="0"/>
<Int sr="arg1" val="5"/>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
<Int sr="arg4" val="0"/>
</Action>
<Action sr="act3" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%SOURCE_DIR</Str>
<Str sr="arg1" ve="3">/storage/emulated/0/Documents/ereader</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
<Int sr="arg4" val="0"/>
<Int sr="arg5" val="3"/>
<Int sr="arg6" val="1"/>
</Action>
<Action sr="act4" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%TARGET_DIR</Str>
<Str sr="arg1" ve="3">/books</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
<Int sr="arg4" val="0"/>
<Int sr="arg5" val="3"/>
<Int sr="arg6" val="1"/>
</Action>
<Action sr="act5" ve="7">
<code>412</code>
<Str sr="arg0" ve="3">%SOURCE_DIR</Str>
<Str sr="arg1" ve="3">*.epub</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
<Int sr="arg4" val="0"/>
<Str sr="arg5" ve="3">%EPUB_FILES</Str>
<Int sr="arg6" val="1"/>
</Action>
<Action sr="act6" ve="7">
<code>39</code>
<Str sr="arg0" ve="3">%epub_file</Str>
<Str sr="arg1" ve="3">%EPUB_FILES()</Str>
<Int sr="arg2" val="1"/>
</Action>
<Action sr="act7" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%epub_file</Str>
<Str sr="arg1" ve="3">/</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act8" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%filename</Str>
<Str sr="arg1" ve="3">%epub_file(#)</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
<Int sr="arg4" val="0"/>
<Int sr="arg5" val="3"/>
<Int sr="arg6" val="1"/>
</Action>
<Action sr="act9" ve="7">
<code>339</code>
<se>false</se>
<Bundle sr="arg0">
<Vals sr="val">
<net.dinglisch.android.tasker.RELEVANT_VARIABLES>&lt;StringArray sr=""&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES0&gt;%http_cookies
Cookies
The cookies the server sent in the response in the Cookie:COOKIE_VALUE format. You can use this directly in the 'Headers' field of the HTTP Request action&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES0&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES1&gt;%http_file_output
File Output
Will always contain the file's full path even if you specified a directory as the File to save.&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES1&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES2&gt;%http_response_code
Response Code
The HTTP Code the server responded&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES2&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES3&gt;%http_headers()
Response Headers
The HTTP Headers the server sent in the response. Each header is in the 'key:value' format&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES3&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES4&gt;%http_response_length
Response Length
The size of the response in bytes&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES4&gt;&lt;/StringArray&gt;</net.dinglisch.android.tasker.RELEVANT_VARIABLES>
<net.dinglisch.android.tasker.RELEVANT_VARIABLES-type>[Ljava.lang.String;</net.dinglisch.android.tasker.RELEVANT_VARIABLES-type>
</Vals>
</Bundle>
<Int sr="arg1" val="0"/>
<Int sr="arg10" val="0"/>
<Int sr="arg11" val="0"/>
<Int sr="arg12" val="1"/>
<Str sr="arg2" ve="3">http://%READER_IP/api/files?path=%TARGET_DIR</Str>
<Str sr="arg3" ve="3"/>
<Str sr="arg4" ve="3"/>
<Str sr="arg5" ve="3"/>
<Str sr="arg6" ve="3"/>
<Str sr="arg7" ve="3">%file_list</Str>
<Int sr="arg8" val="10"/>
<Int sr="arg9" val="0"/>
</Action>
</Task>
</TaskerData>

10
docs/test.sh Normal file
View File

@ -0,0 +1,10 @@
# Test 1: Check if curl exists
which curl
echo "---"
# Test 2: Try simple HTTP request
curl -v "http://192.168.4.1/" 2>&1
echo "---"
# Test 3: Try file upload with simple filename (no spaces)
echo "test" > /sdcard/test.txt
curl -v -X POST -F "file=@/sdcard/test.txt" "http://192.168.4.1/upload?path=/" 2>&1

View File

@ -1,32 +0,0 @@
{
description = "CrossPoint Reader - ESP32 E-Paper Firmware";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
platformio
python3
git
];
shellHook = ''
echo "CrossPoint Reader development environment"
echo "Commands:"
echo " pio run - Build firmware"
echo " pio run -t upload - Build and flash to device"
echo " pio run -t clean - Clean build artifacts"
'';
};
}
);
}

View File

@ -1,15 +0,0 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = with pkgs; [
platformio
python3
git
];
shellHook = ''
echo "PlatformIO development environment loaded"
echo "Run 'pio run' to build the firmware"
echo "Run 'pio run -t upload' to build and flash"
'';
}

View File

@ -12,7 +12,7 @@ CrossPointSettings CrossPointSettings::instance;
namespace {
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
// Increment this when adding new persisted settings fields
constexpr uint8_t SETTINGS_COUNT = 12;
constexpr uint8_t SETTINGS_COUNT = 13;
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
} // namespace
@ -39,6 +39,7 @@ bool CrossPointSettings::saveToFile() const {
serialization::writePod(outputFile, lineSpacing);
serialization::writePod(outputFile, bluetoothEnabled);
serialization::writePod(outputFile, useCoverArtPicker);
serialization::writePod(outputFile, autoSleepMinutes);
outputFile.close();
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
@ -89,6 +90,8 @@ bool CrossPointSettings::loadFromFile() {
if (++settingsRead >= fileSettingsCount) break;
serialization::readPod(inputFile, useCoverArtPicker);
if (++settingsRead >= fileSettingsCount) break;
serialization::readPod(inputFile, autoSleepMinutes);
if (++settingsRead >= fileSettingsCount) break;
} while (false);
inputFile.close();

View File

@ -66,6 +66,8 @@ class CrossPointSettings {
uint8_t bluetoothEnabled = 0;
// File browser settings
uint8_t useCoverArtPicker = 0;
// Auto-sleep timeout (enum index: 0=5min, 1=10min, 2=15min, 3=20min, 4=30min, 5=60min, 6=Never)
uint8_t autoSleepMinutes = 1; // Default to 10 minutes
~CrossPointSettings() = default;
@ -74,6 +76,19 @@ class CrossPointSettings {
uint16_t getPowerButtonDuration() const { return shortPwrBtn ? 10 : 400; }
int getReaderFontId() const;
unsigned long getAutoSleepTimeoutMs() const {
// Map enum index to milliseconds: 0=5min, 1=10min, 2=15min, 3=20min, 4=30min, 5=60min, 6=Never(0)
constexpr unsigned long timeouts[] = {
5UL * 60UL * 1000UL, // 0: 5 minutes
10UL * 60UL * 1000UL, // 1: 10 minutes (default)
15UL * 60UL * 1000UL, // 2: 15 minutes
20UL * 60UL * 1000UL, // 3: 20 minutes
30UL * 60UL * 1000UL, // 4: 30 minutes
60UL * 60UL * 1000UL, // 5: 60 minutes
0UL // 6: Never (disabled)
};
return (autoSleepMinutes < 7) ? timeouts[autoSleepMinutes] : timeouts[1];
}
bool saveToFile() const;
bool loadFromFile();

View File

@ -9,7 +9,7 @@
// Define the static settings list
namespace {
constexpr int settingsCount = 13;
constexpr int settingsCount = 14;
const SettingInfo settingsList[settingsCount] = {
// Should match with SLEEP_SCREEN_MODE
{"Sleep Screen", SettingType::ENUM, &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover"}},
@ -35,6 +35,10 @@ const SettingInfo settingsList[settingsCount] = {
{"Reader Font Size", SettingType::ENUM, &CrossPointSettings::fontSize, {"Small", "Medium", "Large", "X Large"}},
{"Reader Line Spacing", SettingType::ENUM, &CrossPointSettings::lineSpacing, {"Tight", "Normal", "Wide"}},
{"Cover Art Picker", SettingType::TOGGLE, &CrossPointSettings::useCoverArtPicker, {}},
{"Auto Sleep Timeout",
SettingType::ENUM,
&CrossPointSettings::autoSleepMinutes,
{"5 min", "10 min", "15 min", "20 min", "30 min", "60 min", "Never"}},
{"Bluetooth", SettingType::TOGGLE, &CrossPointSettings::bluetoothEnabled, {}},
{"Check for updates", SettingType::ACTION, nullptr, {}},
};

View File

@ -127,8 +127,6 @@ EpdFont ui12RegularFont(&ubuntu_12_regular);
EpdFont ui12BoldFont(&ubuntu_12_bold);
EpdFontFamily ui12FontFamily(&ui12RegularFont, &ui12BoldFont);
// Auto-sleep timeout (10 minutes of inactivity)
constexpr unsigned long AUTO_SLEEP_TIMEOUT_MS = 10 * 60 * 1000;
// measurement of power button press duration calibration value
unsigned long t1 = 0;
unsigned long t2 = 0;
@ -330,8 +328,10 @@ void loop() {
lastActivityTime = millis(); // Reset inactivity timer
}
if (millis() - lastActivityTime >= AUTO_SLEEP_TIMEOUT_MS) {
Serial.printf("[%lu] [SLP] Auto-sleep triggered after %lu ms of inactivity\n", millis(), AUTO_SLEEP_TIMEOUT_MS);
// Check auto-sleep timeout (if enabled - 0 means never sleep)
const unsigned long autoSleepTimeout = SETTINGS.getAutoSleepTimeoutMs();
if (autoSleepTimeout > 0 && millis() - lastActivityTime >= autoSleepTimeout) {
Serial.printf("[%lu] [SLP] Auto-sleep triggered after %lu ms of inactivity\n", millis(), autoSleepTimeout);
enterDeepSleep();
// This should never be hit as `enterDeepSleep` calls esp_deep_sleep_start
return;