#include #include //shutdown suggestion level #define SHUTDOWN_SUGGESTION_DISABLED 0 #define SHUTDOWN_SUGGESTION_ON_BATT 1 #define SHUTDOWN_SUGGESTION_ON_BATT_75 2 #define SHUTDOWN_SUGGESTION_ON_BATT_50 3 #define SHUTDOWN_SUGGESTION_ON_BATT_25 4 #define SHUTDOWN_SUGGESTION_ON_BATT_CRITICAL 5 static volatile uint8_t cfgShutdownSuggestion = SHUTDOWN_SUGGESTION_ON_BATT_25; #define AUTO_POWER_OFF 0 #define AUTO_POWER_ON 1 #define AUTO_POWER_PERSIST 2 static volatile uint8_t cfgAutoOn = AUTO_POWER_ON;//AUTO_POWER_PERSIST;//AUTO_POWER_ON; #define SHUTDOWN_DURATION_DEFAULT 120 static volatile uint16_t cfgShutdownInSeconds = SHUTDOWN_DURATION_DEFAULT;//default time in seconds for shutdown //full charge trigger: #define INPUT_LOST_TRIGGER_CHARGE_NONE 0 #define INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_ALWAYS 1 //trigger full charge if below 100 percent #define INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_95 2 //trigger full charge if below 95 percent #define INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_90 3 //trigger full charge if below 90 percent #define INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_85 4 //trigger full charge if below 85 percent #define INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_80 5 //trigger full charge if below 80 percent static volatile uint8_t cfgInputLostTriggerChargeMode = INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_90; #define CHARGE_MODE_ALWAYS 0 #define CHARGE_MODE_RANGE_90_100 1 #define CHARGE_MODE_RANGE_85_100 2 #define CHARGE_MODE_RANGE_80_100 3 #define CHARGE_MODE_RANGE_90_95 4 #define CHARGE_MODE_RANGE_85_95 5 #define CHARGE_MODE_RANGE_80_95 6 #define CHARGE_MODE_RANGE_85_90 7 #define CHARGE_MODE_RANGE_80_90 8 #define CHARGE_MODE_RANGE_80_85 9 static volatile uint8_t cfgChargeMode = CHARGE_MODE_RANGE_85_90; static volatile uint8_t cfgChargeOvervoltageProtection = 1; static volatile uint8_t cfgChargeAutomaticReducer = 1; bool spiffsOk = false; // flag tetap bernama spiffsOk agar kompatibel dengan kode lain bool initConfigs(){ // Setup LittleFS spiffsOk = LittleFS.begin(); if (!spiffsOk){ Serial.println("LittleFS ERROR!"); }else{ // DEBUG: List all files in LittleFS Serial.println("=== LittleFS Files ==="); Dir dir = LittleFS.openDir("/"); int fileCount = 0; while (dir.next()) { fileCount++; Serial.print(" FILE: "); Serial.print(dir.fileName()); Serial.print(" ["); Serial.print(dir.fileSize()); Serial.println(" bytes]"); } if (fileCount == 0) Serial.println(" (no files found)"); Serial.println("=== End LittleFS ==="); } return spiffsOk; } void loadCfg(){ if (!spiffsOk) return; // Open file for reading File file = LittleFS.open("/cfg.json", "r"); if (!file) { Serial.println("Failed to open config"); return; } // Parse file contents as JSON DynamicJsonDocument jsonDoc(255); DeserializationError error = deserializeJson(jsonDoc, file); file.close(); if (error) { Serial.println("Failed to parse file settings"); return; } uint8_t tmpAutoOnMode = jsonDoc["auto"].as(); cfgAutoOn = tmpAutoOnMode; if (cfgAutoOn>AUTO_POWER_PERSIST) cfgAutoOn = AUTO_POWER_PERSIST; uint8_t v = jsonDoc["shut"].as(); if (v>SHUTDOWN_SUGGESTION_ON_BATT_CRITICAL) v = SHUTDOWN_SUGGESTION_ON_BATT_25; cfgShutdownSuggestion = v; v = jsonDoc["chgMode"].as(); if (v>CHARGE_MODE_RANGE_80_85) v = CHARGE_MODE_RANGE_90_100; cfgChargeMode = v; v = jsonDoc["chgILTC"].as(); if (v>INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_80) v = INPUT_LOST_TRIGGER_CHARGE_NONE; cfgInputLostTriggerChargeMode = v; v = jsonDoc["chgOVP"].as(); if (v>1) v = 1; cfgChargeOvervoltageProtection = v; v = jsonDoc["chgAR"].as(); if (v>1) v = 1; cfgChargeAutomaticReducer = v; } void saveCfg(){ if (!spiffsOk) return; DynamicJsonDocument jsonDoc(255); jsonDoc["auto"] = cfgAutoOn; jsonDoc["shut"] = cfgShutdownSuggestion; jsonDoc["chgMode"] = cfgChargeMode; jsonDoc["chgILTC"] = cfgInputLostTriggerChargeMode; jsonDoc["chgOVP"] = cfgChargeOvervoltageProtection; jsonDoc["chgAR"] = cfgChargeAutomaticReducer; File file = LittleFS.open("/cfg.json", "w"); if (file) { uint32_t sz = serializeJson(jsonDoc, file); file.close(); Serial.println("Configuration updated!"); } }