This commit is contained in:
Joshua King
2026-02-10 21:31:36 -05:00
parent b2752b8f72
commit 08a2ee0852
6 changed files with 64 additions and 20 deletions

View File

@@ -10,6 +10,9 @@ lib_deps =
adafruit/Adafruit SSD1306
bblanchon/ArduinoJson
; board_build.filesystem = spiffs
; board_build.partitions = default.csv
build_flags =
-D PB_VERSION=\"1.0.0\"
-D PB_HOSTNAME=\"faceplant\"

View File

@@ -3,11 +3,12 @@
void BatterySensor::begin() {
pinMode(PIN_BATTERY_ADC, INPUT);
pinMode(PIN_LBO, INPUT);
pinMode(PIN_CHG, INPUT_PULLUP); // CHG is LOW when charging
analogReadResolution(12); // 12-bit ADC (0-4095)
Serial.println("[Battery] Initialized");
Serial.println("[Battery] ADC on GPIO 2, LBO on GPIO 5");
Serial.println("[Battery] ADC on GPIO 2, LBO on GPIO 5, CHG on GPIO 4");
// Initial reading
_voltage = readBatteryVoltage();
@@ -29,30 +30,47 @@ void BatterySensor::loop() {
float prevVoltage = _voltage;
int prevPercent = _percent;
bool wasLow = _isLow;
bool wasCharging = _isCharging;
// Read battery voltage via ADC
_voltage = readBatteryVoltage();
_percent = voltageToPercent(_voltage);
// Check CHG pin (LOW when charging)
bool chgLow = !digitalRead(PIN_CHG);
_isCharging = chgLow;
// Check LBO pin as backup confirmation
bool lboHigh = digitalRead(PIN_LBO);
bool lboIndicatesLow = !lboHigh;
// Battery is low if either voltage is low OR LBO pin indicates low
_isLow = (_voltage < VOLTAGE_LOW) || lboIndicatesLow;
// Battery is low if either voltage is low OR LBO pin indicates low (and not charging)
_isLow = ((_voltage < VOLTAGE_LOW) || lboIndicatesLow) && !_isCharging;
// Log significant changes
if (abs(_percent - prevPercent) >= 5 || _isLow != wasLow) {
if (abs(_percent - prevPercent) >= 5 || _isLow != wasLow || _isCharging != wasCharging) {
Serial.print("[Battery] Voltage: ");
Serial.print(_voltage, 2);
Serial.print("V (");
Serial.print(_percent);
Serial.print("%) LBO: ");
Serial.print("%) ");
if (_isCharging) {
Serial.print("CHARGING ");
}
Serial.print("LBO: ");
Serial.println(lboHigh ? "OK" : "LOW");
if (_isLow && !wasLow) {
if (_isLow && !wasLow && !_isCharging) {
Serial.println("[Battery] ⚠️ LOW BATTERY WARNING - Please recharge!");
}
if (_isCharging && !wasCharging) {
Serial.println("[Battery] 🔌 Charging started");
} else if (!_isCharging && wasCharging) {
Serial.println("[Battery] ✓ Charging complete or disconnected");
}
}
}

View File

@@ -10,6 +10,7 @@ public:
int percent() const { return _percent; }
float voltage() const { return _voltage; }
bool isLow() const { return _isLow; }
bool isCharging() const { return _isCharging; }
bool shouldBlink() const;
// For display
@@ -18,6 +19,7 @@ public:
private:
static constexpr int PIN_BATTERY_ADC = 2; // Voltage divider input
static constexpr int PIN_LBO = 5; // PowerBoost LBO pin
static constexpr int PIN_CHG = 4; // PowerBoost CHG pin (LOW when charging)
static constexpr unsigned long CHECK_INTERVAL_MS = 2000;
static constexpr int SAMPLES = 10; // Number of ADC samples to average
@@ -33,6 +35,7 @@ private:
int _percent = 100;
float _voltage = 3.7;
bool _isLow = false;
bool _isCharging = false;
unsigned long _lastCheckMs = 0;
float readBatteryVoltage();

View File

@@ -60,11 +60,11 @@ _oled.display();
delay(2100);
}
void Display::drawBatteryIcon(int x, int y, int percent, bool blink) {
void Display::drawBatteryIcon(int x, int y, int percent, bool blink, bool charging) {
if (!_ok) return;
// Skip if blinking and blink state is off
if (blink && ((millis() / 500) % 2 == 1)) return;
// Skip if blinking and blink state is off (unless charging)
if (!charging && blink && ((millis() / 500) % 2 == 1)) return;
// Battery body: 14x7 rectangle
_oled.drawRect(x, y, 14, 7, 1);
@@ -74,13 +74,33 @@ void Display::drawBatteryIcon(int x, int y, int percent, bool blink) {
// Fill level: 12 pixels max width inside battery
int fillWidth = (percent * 12) / 100;
if (fillWidth > 0) {
_oled.fillRect(x + 1, y + 1, fillWidth, 5, 1);
}
// Low battery warning: blink outline
if (percent < 20 && blink) {
// Draw thicker outline for emphasis
_oled.drawRect(x - 1, y - 1, 16, 9, 1);
if (charging) {
// Draw animated lightning bolt when charging
bool phase = (millis() / 300) % 2 == 0;
int color = phase ? 1 : 0; // Blink between white and inverted
// Lightning bolt shape (simple zigzag)
_oled.drawLine(x + 7, y + 1, x + 5, y + 3, color); // Top diagonal
_oled.drawLine(x + 5, y + 3, x + 9, y + 3, color); // Middle horizontal
_oled.drawLine(x + 9, y + 3, x + 7, y + 5, color); // Bottom diagonal
// Always draw at least some fill when charging
if (fillWidth == 0 && phase) {
_oled.fillRect(x + 1, y + 1, 2, 5, 1); // Small pulse even at 0%
} else if (fillWidth > 0) {
_oled.fillRect(x + 1, y + 1, fillWidth, 5, 1);
}
} else {
// Normal fill level
if (fillWidth > 0) {
_oled.fillRect(x + 1, y + 1, fillWidth, 5, 1);
}
// Low battery warning: blink outline
if (percent < 20 && blink) {
// Draw thicker outline for emphasis
_oled.drawRect(x - 1, y - 1, 16, 9, 1);
}
}
}

View File

@@ -11,7 +11,7 @@ public:
void showStatus(const String& line1, const String& line2);
void bootAnimation();
void drawBatteryIcon(int x, int y, int percent, bool blink);
void drawBatteryIcon(int x, int y, int percent, bool blink, bool charging);
private:
static constexpr int PIN_SDA = 6;

View File

@@ -157,7 +157,7 @@ void FaceRenderer::renderDead(unsigned long now, const BatterySensor& battery) {
}
// Draw battery icon in top-right corner
_display->drawBatteryIcon(110, 2, battery.percent(), battery.shouldBlink());
_display->drawBatteryIcon(110, 2, battery.percent(), battery.shouldBlink(), battery.isCharging());
d.display();
}
@@ -199,7 +199,7 @@ void FaceRenderer::renderBatteryLow(unsigned long now, const BatterySensor& batt
drawMouthNervous();
// Draw battery icon in top-right corner (blinking)
_display->drawBatteryIcon(110, 2, battery.percent(), true);
_display->drawBatteryIcon(110, 2, battery.percent(), true, battery.isCharging());
d.display();
}
@@ -230,7 +230,7 @@ void FaceRenderer::renderNormal(unsigned long now, const BatterySensor& battery)
}
// Draw battery icon in top-right corner
_display->drawBatteryIcon(110, 2, battery.percent(), battery.shouldBlink());
_display->drawBatteryIcon(110, 2, battery.percent(), battery.shouldBlink(), battery.isCharging());
d.display();
}