diff --git a/src/components/battery/BatteryController.cpp b/src/components/battery/BatteryController.cpp index dc15612e3d..ead3e43b47 100644 --- a/src/components/battery/BatteryController.cpp +++ b/src/components/battery/BatteryController.cpp @@ -86,10 +86,20 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { newPercent = std::min(aprox.GetValue(voltage), isCharging ? uint8_t {99} : uint8_t {100}); } + if (isPowerPresent) { + batteryLowNotified = false; + } + if ((isPowerPresent && newPercent > percentRemaining) || (!isPowerPresent && newPercent < percentRemaining) || firstMeasurement) { firstMeasurement = false; percentRemaining = newPercent; systemTask->PushMessage(System::Messages::BatteryPercentageUpdated); + + // warn about low battery when not charging and below threshold + if (BatteryIsLow() && !isPowerPresent && !batteryLowNotified) { + systemTask->PushMessage(System::Messages::LowBattery); + batteryLowNotified = true; + } } nrfx_saadc_uninit(); diff --git a/src/components/battery/BatteryController.h b/src/components/battery/BatteryController.h index 5a7394c4d4..627ca7d41d 100644 --- a/src/components/battery/BatteryController.h +++ b/src/components/battery/BatteryController.h @@ -17,6 +17,9 @@ namespace Pinetime { uint8_t PercentRemaining() const { return percentRemaining; } + bool BatteryIsLow() const { + return percentRemaining <= lowBatteryThreshold; + } uint16_t Voltage() const { return voltage; @@ -39,6 +42,7 @@ namespace Pinetime { static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7; uint16_t voltage = 0; uint8_t percentRemaining = 0; + bool batteryLowNotified = false; bool isFull = false; bool isCharging = false; @@ -50,6 +54,8 @@ namespace Pinetime { void SaadcEventHandler(nrfx_saadc_evt_t const* p_event); static void AdcCallbackStatic(nrfx_saadc_evt_t const* event); + static constexpr uint8_t lowBatteryThreshold {15}; + bool isReading = false; Pinetime::System::SystemTask* systemTask = nullptr; diff --git a/src/displayapp/screens/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp index 9febda61a9..87d1f2e181 100644 --- a/src/displayapp/screens/BatteryInfo.cpp +++ b/src/displayapp/screens/BatteryInfo.cpp @@ -59,7 +59,7 @@ void BatteryInfo::Refresh() { } else if (batteryPercent == 100) { lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE); lv_label_set_text_static(status, "Fully charged"); - } else if (batteryPercent < 10) { + } else if (batteryController.BatteryIsLow()) { lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW); lv_label_set_text_static(status, "Battery low"); } else { diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h index d730d74f30..1883c396c1 100644 --- a/src/systemtask/Messages.h +++ b/src/systemtask/Messages.h @@ -29,6 +29,7 @@ namespace Pinetime { StopRinging, MeasureBatteryTimerExpired, BatteryPercentageUpdated, + LowBattery, StartFileTransfer, StopFileTransfer, BleRadioEnableToggle diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 01056a9add..73f573fa0e 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -18,6 +18,8 @@ #include "BootErrors.h" #include +#include +#include using namespace Pinetime::System; @@ -424,6 +426,16 @@ void SystemTask::Work() { case Messages::BatteryPercentageUpdated: nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining()); break; + case Messages::LowBattery: { + Pinetime::Controllers::NotificationManager::Notification notif; + constexpr char message[] = "Low Battery\0Charge your watch to prevent data loss.\0"; + constexpr size_t messageSize = std::min(sizeof(message), Pinetime::Controllers::NotificationManager::MaximumMessageSize()); + std::memcpy(notif.message.data(), message, messageSize); + notif.size = messageSize; + notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert; + notificationManager.Push(std::move(notif)); + PushMessage(Messages::OnNewNotification); + } break; case Messages::OnPairing: if (state == SystemTaskState::Sleeping) { GoToRunning();