~aleteoryx/muditaos

1e04adae408fbdc611f98d8b9e50e867428c8e03 — Mateusz Piesta 4 years ago 5ebb014
[BH-1248] Battery charger events handling

[BH-1249][BH-1248] Added handling of battery charger async
events to the home screen.
[BH-1276] Enter battery status from snooze active window.
[BH-1278] Proper latch state handling when in battery critical state.
Fixed various minor bugs spotted along the way.
M module-apps/apps-common/windows/AppWindow.hpp => module-apps/apps-common/windows/AppWindow.hpp +1 -1
@@ 76,7 76,7 @@ namespace gui
        bool updateBluetooth(sys::bluetooth::BluetoothMode mode);
        bool updateAlarmClock(bool status);
        bool updateSim();
        bool updateBatteryStatus();
        virtual bool updateBatteryStatus();
        bool updateSignalStrength();
        bool updateNetworkAccessTechnology();
        void updatePhoneMode(sys::phone_modes::PhoneMode mode);

M products/BellHybrid/apps/application-bell-main/ApplicationBellMain.cpp => products/BellHybrid/apps/application-bell-main/ApplicationBellMain.cpp +1 -4
@@ 165,10 165,7 @@ namespace app

    bool ApplicationBellMain::isPopupPermitted([[maybe_unused]] gui::popup::ID popupId) const
    {
        if (blockAllPopups) {
            return false;
        }
        return true;
        return !blockAllPopups;
    }

    void ApplicationBellMain::handleLowBatteryNotification(manager::actions::ActionParamsPtr &&data)

M products/BellHybrid/apps/application-bell-main/presenters/HomeScreenPresenter.cpp => products/BellHybrid/apps/application-bell-main/presenters/HomeScreenPresenter.cpp +18 -27
@@ 24,23 24,7 @@ namespace app::home_screen
                                             std::unique_ptr<AbstractTimeModel> timeModel)
        : app{app}, alarmModel{std::move(alarmModel)}, batteryModel{std::move(batteryModel)},
          temperatureModel{std::move(temperatureModel)}, timeModel{std::move(timeModel)}
    {
        constexpr int timeout = pdMS_TO_TICKS(1500);

        auto response =
            app->bus.sendUnicastSync(std::make_shared<sevm::LatchStatusRequest>(), service::name::evt_manager, timeout);

        if (response.first == sys::ReturnCodes::Success) {
            auto msgState = dynamic_cast<sevm::LatchStatusResponse *>(response.second.get());
            if (msgState == nullptr) {
                return;
            }

            if (msgState->getStatus() == sevm::LatchStatus::PRESSED) {
                latchPressed = true;
            }
        }
    }
    {}

    void HomeScreenPresenter::handleUpdateTimeEvent()
    {


@@ 108,7 92,6 @@ namespace app::home_screen
    }
    void HomeScreenPresenter::handleAlarmModelReady()
    {
        setStartupAlarmState();
        getView()->setAlarmTime(alarmModel->getAlarmTime());
        stateController->handleAlarmModelReady();
    }


@@ 144,18 127,22 @@ namespace app::home_screen
        return batteryModel->getLevelState().state == Store::Battery::State::Charging;
    }

    bool HomeScreenPresenter::isStartupDeepPress()
    bool HomeScreenPresenter::isAlarmActivatedByLatch() const
    {
        return latchPressed;
    }
        constexpr auto timeout = pdMS_TO_TICKS(1500);

    void HomeScreenPresenter::setStartupAlarmState()
    {
        static auto isStartup = true;
        if (isStartup) {
            alarmModel->activate(!latchPressed);
            isStartup = false;
        auto response =
            app->bus.sendUnicastSync(std::make_shared<sevm::LatchStatusRequest>(), service::name::evt_manager, timeout);

        if (response.first == sys::ReturnCodes::Success) {
            auto msgState = dynamic_cast<sevm::LatchStatusResponse *>(response.second.get());
            if (msgState != nullptr) {
                return msgState->getStatus() != sevm::LatchStatus::PRESSED;
            }
        }

        LOG_FATAL("Couldn't fetch latch state");
        return false;
    }

    void HomeScreenPresenter::handleCyclicDeepRefresh()


@@ 169,4 156,8 @@ namespace app::home_screen
        }
        refreshCount++;
    }
    void HomeScreenPresenter::handleBatteryStatus()
    {
        stateController->handleBatteryStatus();
    }
} // namespace app::home_screen

M products/BellHybrid/apps/application-bell-main/presenters/HomeScreenPresenter.hpp => products/BellHybrid/apps/application-bell-main/presenters/HomeScreenPresenter.hpp +7 -8
@@ 93,13 93,14 @@ namespace app::home_screen
        virtual void detachTimer()                                                               = 0;
        virtual void handleAlarmRingingEvent()                                                   = 0;
        virtual void handleAlarmModelReady()                                                     = 0;
        virtual void handleBatteryStatus()                                                       = 0;
        virtual void setSnoozeTimer(std::unique_ptr<app::ProgressTimerWithSnoozeTimer> &&_timer) = 0;
        virtual void startSnoozeTimer(std::chrono::seconds snoozeDuration)                       = 0;
        virtual void stopSnoozeTimer()                                                           = 0;
        virtual void restartSnoozeTimer(std::chrono::seconds snoozeDuration)                     = 0;
        virtual std::uint32_t getBatteryLvl() const                                              = 0;
        virtual bool isBatteryCharging() const                                                   = 0;
        virtual bool isStartupDeepPress()                                                        = 0;
        virtual bool isAlarmActivatedByLatch() const                                             = 0;

        static constexpr auto defaultTimeout = std::chrono::milliseconds{5000};
    };


@@ 130,14 131,15 @@ namespace app::home_screen
        void detachTimer() override;
        void handleAlarmRingingEvent() override;
        void handleAlarmModelReady() override;
        void handleBatteryStatus() override;

        void setSnoozeTimer(std::unique_ptr<app::ProgressTimerWithSnoozeTimer> &&_timer) override;
        void startSnoozeTimer(std::chrono::seconds snoozeDuration);
        void stopSnoozeTimer();
        void restartSnoozeTimer(std::chrono::seconds snoozeDuration);
        void startSnoozeTimer(std::chrono::seconds snoozeDuration) override;
        void stopSnoozeTimer() override;
        void restartSnoozeTimer(std::chrono::seconds snoozeDuration) override;
        std::uint32_t getBatteryLvl() const override;
        bool isBatteryCharging() const override;
        bool isStartupDeepPress() override;
        bool isAlarmActivatedByLatch() const override;

      private:
        ApplicationCommon *app;


@@ 148,9 150,6 @@ namespace app::home_screen
        std::unique_ptr<AbstractTimeModel> timeModel;
        std::shared_ptr<AbstractController> stateController;
        std::unique_ptr<ProgressTimerWithSnoozeTimer> snoozeTimer;
        bool latchPressed = false;

        void setStartupAlarmState();

        void handleCyclicDeepRefresh();


M products/BellHybrid/apps/application-bell-main/presenters/StateController.cpp => products/BellHybrid/apps/application-bell-main/presenters/StateController.cpp +127 -83
@@ 13,7 13,6 @@

#include <boost/sml.hpp>
#include <time/time_conversion.hpp>
#include <time/time_constants.hpp>

#include <random>



@@ 32,31 31,48 @@ namespace app::home_screen
    {
        namespace Helpers
        {
            auto isDeactivated = [](AbstractAlarmModel &alarmModel) {
                return alarmModel.getAlarmStatus() == alarms::AlarmStatus::Deactivated;
            auto shouldSwitchToSnooze = [](AbstractAlarmModel &alarmModel, AbstractPresenter &presenter) {
                return presenter.isAlarmActivatedByLatch() &&
                       alarmModel.getAlarmStatus() == alarms::AlarmStatus::Snoozed;
            };
            auto isActivated = [](AbstractAlarmModel &alarmModel) {
                return alarmModel.getAlarmStatus() == alarms::AlarmStatus::Activated;

            auto shouldSwitchToRinging = [](AbstractAlarmModel &alarmModel, AbstractPresenter &presenter) {
                return presenter.isAlarmActivatedByLatch() &&
                       alarmModel.getAlarmStatus() == alarms::AlarmStatus::Ringing;
            };
            auto isSnoozed = [](AbstractAlarmModel &alarmModel) {
                return alarmModel.getAlarmStatus() == alarms::AlarmStatus::Snoozed;

            auto shouldSwitchToActivated = [](AbstractAlarmModel &alarmModel, AbstractPresenter &presenter) {
                if (not presenter.isAlarmActivatedByLatch()) {
                    return false;
                }

                if (alarmModel.getAlarmStatus() != alarms::AlarmStatus::Activated) {
                    alarmModel.activate(true);
                }
                return true;
            };
            auto isRinging = [](AbstractAlarmModel &alarmModel) {
                return alarmModel.getAlarmStatus() == alarms::AlarmStatus::Ringing;

            auto shouldSwitchToDeactivated = [](AbstractAlarmModel &alarmModel, AbstractPresenter &presenter) {
                if (presenter.isAlarmActivatedByLatch()) {
                    return false;
                }

                if (alarmModel.getAlarmStatus() != alarms::AlarmStatus::Deactivated) {
                    alarmModel.activate(false);
                }
                return true;
            };

            auto switchToMenu          = [](AbstractView &view) { view.switchToMenu(); };
            auto makeAlarmEditable     = [](AbstractView &view) { view.setAlarmEdit(true); };
            auto makeAlarmNonEditable  = [](AbstractView &view) { view.setAlarmEdit(false); };
            auto switchToBatteryStatus = [](AbstractView &view) { view.switchToBatteryStatus(); };
            auto updateBottomStats =
                [](AbstractView &view, AbstractBatteryModel &batteryModel, AbstractTemperatureModel &temperatureModel) {
                    view.setTemperature(temperatureModel.getTemperature());
                    view.setBatteryLevelState(batteryModel.getLevelState());
                };
            auto setNewAlarmTime = [](AbstractView &view,
                                      AbstractAlarmModel &alarmModel,
                                      AbstractPresenter &presenter) { alarmModel.setAlarmTime(view.getAlarmTime()); };
            auto updateTemperature     = [](AbstractView &view, AbstractTemperatureModel &temperatureModel) {
                view.setTemperature(temperatureModel.getTemperature());
            };
            auto setNewAlarmTime = [](AbstractView &view, AbstractAlarmModel &alarmModel) {
                alarmModel.setAlarmTime(view.getAlarmTime());
            };

            auto isAlarmActive   = [](AbstractAlarmModel &alarmModel) -> bool { return alarmModel.isActive(); };
            auto isSnoozeAllowed = [](AbstractAlarmModel &alarmModel, AbstractController &controller) -> bool {


@@ 78,12 94,11 @@ namespace app::home_screen
                }
                return greetingCollection[Helpers::getRand(0, greetingCollection.size() - 1)];
            };
            auto setDefaultAlarmTime = [](AbstractAlarmModel &alarmModel, AbstractView &view) {
                alarmModel.turnOff();
                alarmModel.setDefaultAlarmTime();
                view.setAlarmTime(alarmModel.getAlarmTime());
            };
            auto turnOffRingingAlarm = [](AbstractAlarmModel &alarmModel) { alarmModel.turnOff(); };
            auto updateBatteryStatus = [](AbstractView &view, AbstractBatteryModel &batteryModel) {
                view.setBatteryLevelState(batteryModel.getLevelState());
            };

        } // namespace Helpers

        namespace Events


@@ 112,7 127,7 @@ namespace app::home_screen
            {};
            struct ModelReady
            {};
            struct Reset
            struct BatteryUpdate
            {};
        } // namespace Events



@@ 137,13 152,13 @@ namespace app::home_screen
            auto entry = [](AbstractController &controller,
                            AbstractView &view,
                            AbstractTemperatureModel &temperatureModel,
                            AbstractAlarmModel &alarmModel,
                            AbstractTimeModel &timeModel) {
                            AbstractBatteryModel &batteryModel) {
                controller.snooze(false);
                view.setAlarmEdit(false);
                view.setAlarmActive(false);
                view.setHeaderViewMode(HeaderViewMode::Empty);
                view.setTemperature(temperatureModel.getTemperature());
                view.setBatteryLevelState(batteryModel.getLevelState());
            };
        } // namespace Deactivated



@@ 218,12 233,14 @@ namespace app::home_screen
            auto entry = [](AbstractController &controller,
                            AbstractView &view,
                            AbstractAlarmModel &alarmModel,
                            AbstractTemperatureModel &temperatureModel) {
                            AbstractTemperatureModel &temperatureModel,
                            AbstractBatteryModel &batteryModel) {
                controller.snooze(false);
                view.setTemperature(temperatureModel.getTemperature());
                view.setAlarmActive(true);
                view.setHeaderViewMode(HeaderViewMode::AlarmIconAndTime);
                view.setAlarmTime(alarmModel.getAlarmTime());
                view.setBatteryLevelState(batteryModel.getLevelState());
            };
        } // namespace Activated



@@ 268,12 285,15 @@ namespace app::home_screen

        namespace AlarmSnoozed
        {
            auto entry =
                [](AbstractView &view, AbstractAlarmModel &alarmModel, AbstractTemperatureModel &temperatureModel) {
                    view.setHeaderViewMode(HeaderViewMode::SnoozeCountdown);
                    view.setTemperature(temperatureModel.getTemperature());
                    view.setSnoozeTime(alarmModel.getTimeOfNextSnooze());
                };
            auto entry = [](AbstractView &view,
                            AbstractAlarmModel &alarmModel,
                            AbstractTemperatureModel &temperatureModel,
                            AbstractBatteryModel &batteryModel) {
                view.setHeaderViewMode(HeaderViewMode::SnoozeCountdown);
                view.setTemperature(temperatureModel.getTemperature());
                view.setSnoozeTime(alarmModel.getTimeOfNextSnooze());
                view.setBatteryLevelState(batteryModel.getLevelState());
            };
            auto exit = [](AbstractPresenter &presenter) { presenter.stopSnoozeTimer(); };
        } // namespace AlarmSnoozed



@@ 285,23 305,22 @@ namespace app::home_screen
                using namespace sml;
                // clang-format off
                return make_transition_table(*"Init"_s + sml::on_entry<_> / Init::entry,
                                             "Init"_s + event<Events::ModelReady> [Helpers::isDeactivated] = "Deactivated"_s,
                                             "Init"_s + event<Events::ModelReady> [Helpers::isActivated] = "Activated"_s,
                                             "Init"_s + event<Events::ModelReady> [Helpers::isSnoozed] = "AlarmSnoozed"_s,
                                             "Init"_s + event<Events::ModelReady> [Helpers::isRinging] = "AlarmRinging"_s,
                                             "Init"_s + event<Events::ModelReady> [Helpers::shouldSwitchToSnooze] = "AlarmSnoozed"_s,
                                             "Init"_s + event<Events::ModelReady> [Helpers::shouldSwitchToRinging] = "AlarmRinging"_s,
                                             "Init"_s + event<Events::ModelReady> [Helpers::shouldSwitchToDeactivated] = "Deactivated"_s,
                                             "Init"_s + event<Events::ModelReady> [Helpers::shouldSwitchToActivated] = "Activated"_s,

                                             "Deactivated"_s + sml::on_entry<_> / Deactivated::entry,
                                             "Deactivated"_s + event<Events::Reset> = "Init"_s,
                                             "Deactivated"_s + event<Events::LightPress>/ Helpers::switchToMenu,
                                             "Deactivated"_s + event<Events::RotateLeftPress> / Helpers::makeAlarmEditable = "DeactivatedEdit"_s,
                                             "Deactivated"_s + event<Events::RotateRightPress> / Helpers::makeAlarmEditable = "DeactivatedEdit"_s,
                                             "Deactivated"_s + event<Events::DeepUpPress> = "ActivatedWait"_s,
                                             "Deactivated"_s + event<Events::TimeUpdate> / Helpers::updateBottomStats,
                                             "Deactivated"_s + event<Events::TimeUpdate> / Helpers::updateTemperature,
                                             "Deactivated"_s + event<Events::LongBackPress>  / Helpers::switchToBatteryStatus,
                                             "Deactivated"_s + event<Events::BatteryUpdate>  / Helpers::updateBatteryStatus,

                                             "DeactivatedWait"_s + sml::on_entry<_> / DeactivatedWait::entry,
                                             "DeactivatedWait"_s + sml::on_exit<_> / DeactivatedWait::exit,
                                             "DeactivatedWait"_s + event<Events::Reset> = "Init"_s,
                                             "DeactivatedWait"_s + event<Events::Timer> = "Deactivated"_s,
                                             "DeactivatedWait"_s + event<Events::LightPress>/ Helpers::switchToMenu = "Deactivated"_s,
                                             "DeactivatedWait"_s + event<Events::DeepUpPress> = "ActivatedWait"_s,


@@ 311,18 330,17 @@ namespace app::home_screen

                                             "DeactivatedEdit"_s + sml::on_entry<_> / AlarmEdit::entry,
                                             "DeactivatedEdit"_s + sml::on_exit<_> / AlarmEdit::exit,
                                             "DeactivatedEdit"_s + event<Events::Reset> = "Init"_s,
                                             "DeactivatedEdit"_s + event<Events::TimeUpdate> / Helpers::updateBottomStats,
                                             "DeactivatedEdit"_s + event<Events::TimeUpdate> / Helpers::updateTemperature,
                                             "DeactivatedEdit"_s + event<Events::Timer> = "Deactivated"_s,
                                             "DeactivatedEdit"_s + event<Events::RotateLeftPress> / AlarmEdit::processRotateLeft,
                                             "DeactivatedEdit"_s + event<Events::RotateRightPress> / AlarmEdit::processRotateRight,
                                             "DeactivatedEdit"_s + event<Events::DeepUpPress> / Helpers::setNewAlarmTime = "ActivatedWait"_s,
                                             "DeactivatedEdit"_s + event<Events::LightPress> / Helpers::setNewAlarmTime = "WaitForConfirmation"_s,
                                             "DeactivatedEdit"_s + event<Events::BackPress> = "Deactivated"_s,
                                             "DeactivatedEdit"_s + event<Events::BatteryUpdate>  / Helpers::updateBatteryStatus,

                                             "WaitForConfirmation"_s + sml::on_entry<_> / WaitForConfirmation::entry,
                                             "WaitForConfirmation"_s + sml::on_exit<_> / WaitForConfirmation::exit,
                                             "WaitForConfirmation"_s + event<Events::Reset> = "Init"_s,
                                             "WaitForConfirmation"_s + event<Events::Timer> / Helpers::makeAlarmNonEditable = "Deactivated"_s,
                                             "WaitForConfirmation"_s + event<Events::DeepUpPress> / WaitForConfirmation::action = "ActivatedWait"_s,
                                             "WaitForConfirmation"_s + event<Events::LightPress>/ Helpers::switchToMenu = "Deactivated"_s,


@@ 332,7 350,6 @@ namespace app::home_screen

                                             "ActivatedWait"_s + sml::on_entry<_> / ActivatedWait::entry,
                                             "ActivatedWait"_s + sml::on_exit<_> / ActivatedWait::exit,
                                             "ActivatedWait"_s + event<Events::Reset> = "Init"_s,
                                             "ActivatedWait"_s + event<Events::Timer> / Helpers::makeAlarmNonEditable = "Activated"_s,
                                             "ActivatedWait"_s + event<Events::LightPress>/ Helpers::switchToMenu = "Activated"_s,
                                             "ActivatedWait"_s + event<Events::DeepDownPress> = "DeactivatedWait"_s,


@@ 342,30 359,29 @@ namespace app::home_screen
                                             "ActivatedWait"_s + event<Events::AlarmRinging>  = "AlarmRinging"_s,

                                             "Activated"_s + sml::on_entry<_> / Activated::entry,
                                             "Activated"_s + event<Events::Reset> = "Init"_s,
                                             "Activated"_s [not Helpers::isAlarmActive] = "Deactivated"_s,
                                             "Activated"_s + event<Events::LightPress>/ Helpers::switchToMenu = "Activated"_s,
                                             "Activated"_s + event<Events::RotateLeftPress> / Helpers::makeAlarmEditable = "ActivatedEdit"_s,
                                             "Activated"_s + event<Events::RotateRightPress> / Helpers::makeAlarmEditable = "ActivatedEdit"_s,
                                             "Activated"_s + event<Events::TimeUpdate> / Helpers::updateBottomStats,
                                             "Activated"_s + event<Events::TimeUpdate> / Helpers::updateTemperature,
                                             "Activated"_s + event<Events::DeepDownPress>  = "DeactivatedWait"_s,
                                             "Activated"_s + event<Events::AlarmRinging>  = "AlarmRinging"_s,
                                             "Activated"_s + event<Events::LongBackPress>  / Helpers::switchToBatteryStatus,
                                             "Activated"_s + event<Events::BatteryUpdate>  / Helpers::updateBatteryStatus,

                                             "ActivatedEdit"_s + sml::on_entry<_> / AlarmEdit::entry,
                                             "ActivatedEdit"_s + sml::on_exit<_> / AlarmEdit::exit,
                                             "ActivatedEdit"_s + event<Events::Reset> = "Init"_s,
                                             "ActivatedEdit"_s + event<Events::TimeUpdate> / Helpers::updateBottomStats,
                                             "ActivatedEdit"_s + event<Events::TimeUpdate> / Helpers::updateTemperature,
                                             "ActivatedEdit"_s + event<Events::Timer> = "Activated"_s,
                                             "ActivatedEdit"_s + event<Events::RotateLeftPress> / AlarmEdit::processRotateLeft,
                                             "ActivatedEdit"_s + event<Events::RotateRightPress> / AlarmEdit::processRotateRight,
                                             "ActivatedEdit"_s + event<Events::LightPress> / Helpers::setNewAlarmTime = "ActivatedWait"_s,
                                             "ActivatedEdit"_s + event<Events::BackPress> = "Activated"_s,
                                             "ActivatedEdit"_s + event<Events::DeepDownPress> = "DeactivatedWait"_s,
                                             "ActivatedEdit"_s + event<Events::BatteryUpdate>  / Helpers::updateBatteryStatus,

                                             "AlarmRinging"_s + sml::on_entry<_> / AlarmRinging::entry,
                                             "AlarmRinging"_s + sml::on_exit<_> / AlarmRinging::exit,
                                             "AlarmRinging"_s + event<Events::Reset> = "Init"_s,
                                             "AlarmRinging"_s + event<Events::Timer> [Helpers::isSnoozeAllowed] / Helpers::snooze = "AlarmSnoozedWait"_s,
                                             "AlarmRinging"_s + event<Events::Timer> [not Helpers::isSnoozeAllowed] / Helpers::turnOffRingingAlarm = "ActivatedWait"_s,
                                             "AlarmRinging"_s + event<Events::LightPress> [Helpers::isSnoozeAllowed] = "AlarmSnoozedWait"_s,


@@ 380,7 396,6 @@ namespace app::home_screen

                                             "AlarmRingingDeactivatedWait"_s + sml::on_entry<_> / AlarmRingingDeactivatedWait::entry,
                                             "AlarmRingingDeactivatedWait"_s + sml::on_exit<_> / AlarmRingingDeactivatedWait::exit,
                                             "AlarmRingingDeactivatedWait"_s + event<Events::Reset> = "Init"_s,
                                             "AlarmRingingDeactivatedWait"_s + event<Events::Timer> = "Deactivated"_s,
                                             "AlarmRingingDeactivatedWait"_s + event<Events::DeepUpPress> = "ActivatedWait"_s,
                                             "AlarmRingingDeactivatedWait"_s + event<Events::BackPress> = "Deactivated"_s,


@@ 390,7 405,6 @@ namespace app::home_screen

                                             "AlarmSnoozedWait"_s + sml::on_entry<_> / AlarmSnoozedWait::entry,
                                             "AlarmSnoozedWait"_s + sml::on_exit<_> / AlarmSnoozedWait::exit,
                                             "AlarmSnoozedWait"_s + event<Events::Reset> = "Init"_s,
                                             "AlarmSnoozedWait"_s + event<Events::Timer> = "AlarmSnoozed"_s,
                                             "AlarmSnoozedWait"_s + event<Events::DeepDownPress> = "DeactivatedWait"_s,
                                             "AlarmSnoozedWait"_s + event<Events::LightPress>/ Helpers::switchToMenu = "AlarmSnoozed"_s,


@@ 398,12 412,13 @@ namespace app::home_screen

                                             "AlarmSnoozed"_s + sml::on_entry<_> / AlarmSnoozed::entry,
                                             "AlarmSnoozed"_s + sml::on_entry<_> / AlarmSnoozed::exit,
                                             "AlarmSnoozed"_s + event<Events::Reset> = "Init"_s,
                                             "AlarmSnoozed"_s + event<Events::ModelReady> [not Helpers::isSnoozeActive] = "Activated"_s,
                                             "AlarmSnoozed"_s + event<Events::AlarmRinging>  = "AlarmRinging"_s,
                                             "AlarmSnoozed"_s + event<Events::DeepDownPress> = "DeactivatedWait"_s,
                                             "AlarmSnoozed"_s + event<Events::LightPress>/Helpers::switchToMenu,
                                             "AlarmSnoozed"_s + event<Events::TimeUpdate> / Helpers::updateBottomStats
                                             "AlarmSnoozed"_s + event<Events::TimeUpdate> / Helpers::updateTemperature,
                                             "AlarmSnoozed"_s + event<Events::BatteryUpdate>  / Helpers::updateBatteryStatus,
                                             "AlarmSnoozed"_s + event<Events::LongBackPress>  / Helpers::switchToBatteryStatus
                    );
                // clang-format on
            }


@@ 413,6 428,13 @@ namespace app::home_screen
    class StateController::Impl
    {
      public:
#ifdef DEBUG_STATE_MACHINE
        using SM = sml::sm<StateMachine, sml::logger<Logger>>;
        Logger smLogger;
#else
        using SM = sml::sm<StateMachine>;
#endif

        Impl(AbstractController &controller,
             AbstractView &view,
             AbstractPresenter &presenter,


@@ 420,27 442,44 @@ namespace app::home_screen
             AbstractTemperatureModel &temperatureModel,
             AbstractAlarmModel &alarmModel,
             AbstractTimeModel &timeModel)
            : sm{
#ifdef DEBUG_STATE_MACHINE
                  smLogger,
#endif
                  controller,
                  view,
                  presenter,
                  batteryModel,
                  temperatureModel,
                  alarmModel,
                  timeModel}
        {}
            : controller{controller}, view{view}, presenter{presenter}, batteryModel{batteryModel},
              temperatureModel{temperatureModel}, alarmModel{alarmModel}, timeModel{timeModel}
        {
            resetSM();
        }

        void resetSM()
        {
            sm.emplace(generate());
        }

        std::optional<SM> sm;
        std::uint32_t snoozeCount{};
        static constexpr auto maxSnoozeCount = 3U;

      private:
        SM generate() const
        {
            return SM{
#ifdef DEBUG_STATE_MACHINE
        using SM = sml::sm<StateMachine, sml::logger<Logger>>;
        Logger smLogger;
#else
        using SM = sml::sm<StateMachine>;
                smLogger,
#endif
        SM sm;
        std::uint32_t snoozeCount;
        static constexpr auto maxSnoozeCount = 3U;
                controller,
                view,
                presenter,
                batteryModel,
                temperatureModel,
                alarmModel,
                timeModel};
        }

        AbstractController &controller;
        AbstractView &view;
        AbstractPresenter &presenter;
        AbstractBatteryModel &batteryModel;
        AbstractTemperatureModel &temperatureModel;
        AbstractAlarmModel &alarmModel;
        AbstractTimeModel &timeModel;
    };

    StateController::StateController(AbstractView &view,


@@ 463,26 502,26 @@ namespace app::home_screen
        switch (key) {
        case KeyMap::Back:
            if (inputEvent.getState() == gui::InputEvent::State::keyReleasedLong) {
                pimpl->sm.process_event(Events::LongBackPress{});
                pimpl->sm->process_event(Events::LongBackPress{});
            }
            else {
                pimpl->sm.process_event(Events::BackPress{});
                pimpl->sm->process_event(Events::BackPress{});
            }
            break;
        case KeyMap::LightPress:
            pimpl->sm.process_event(Events::LightPress{});
            pimpl->sm->process_event(Events::LightPress{});
            break;
        case KeyMap::RotateRight:
            pimpl->sm.process_event(Events::RotateRightPress{});
            pimpl->sm->process_event(Events::RotateRightPress{});
            break;
        case KeyMap::RotateLeft:
            pimpl->sm.process_event(Events::RotateLeftPress{});
            pimpl->sm->process_event(Events::RotateLeftPress{});
            break;
        case KeyMap::DeepPressUp:
            pimpl->sm.process_event(Events::DeepUpPress{});
            pimpl->sm->process_event(Events::DeepUpPress{});
            break;
        case KeyMap::DeepPressDown:
            pimpl->sm.process_event(Events::DeepDownPress{});
            pimpl->sm->process_event(Events::DeepDownPress{});
            break;
        default:
            break;


@@ 493,26 532,26 @@ namespace app::home_screen

    bool StateController::handleTimerEvent()
    {
        pimpl->sm.process_event(Events::Timer{});
        pimpl->sm->process_event(Events::Timer{});
        presenter.refreshWindow();
        return true;
    }

    bool StateController::handleTimeUpdateEvent()
    {
        pimpl->sm.process_event(Events::TimeUpdate{});
        pimpl->sm->process_event(Events::TimeUpdate{});
        return true;
    }

    bool StateController::handleAlarmRingingEvent()
    {
        pimpl->sm.process_event(Events::AlarmRinging{});
        pimpl->sm->process_event(Events::AlarmRinging{});
        return true;
    }

    bool StateController::handleAlarmModelReady()
    {
        pimpl->sm.process_event(Events::ModelReady{});
        pimpl->sm->process_event(Events::ModelReady{});
        return true;
    }
    bool StateController::isSnoozeAllowed()


@@ 531,7 570,12 @@ namespace app::home_screen

    void StateController::resetStateMachine()
    {
        pimpl->sm.process_event(Events::Reset{});
        pimpl->resetSM();
    }
    bool StateController::handleBatteryStatus()
    {
        pimpl->sm->process_event(Events::BatteryUpdate{});
        return true;
    }

} // namespace app::home_screen

M products/BellHybrid/apps/application-bell-main/presenters/StateController.hpp => products/BellHybrid/apps/application-bell-main/presenters/StateController.hpp +2 -0
@@ 35,6 35,7 @@ namespace app::home_screen
        virtual bool handleTimeUpdateEvent()                             = 0;
        virtual bool handleAlarmRingingEvent()                           = 0;
        virtual bool handleAlarmModelReady()                             = 0;
        virtual bool handleBatteryStatus()                               = 0;
        virtual bool isSnoozeAllowed()                                   = 0;
        virtual void snooze(bool ctrl)                                   = 0;
    };


@@ 56,6 57,7 @@ namespace app::home_screen
        bool handleTimeUpdateEvent() override;
        bool handleAlarmRingingEvent() override;
        bool handleAlarmModelReady() override;
        bool handleBatteryStatus() override;
        bool isSnoozeAllowed() override;
        void snooze(bool ctrl) override;


M products/BellHybrid/apps/application-bell-main/widgets/BellBattery.cpp => products/BellHybrid/apps/application-bell-main/widgets/BellBattery.cpp +1 -6
@@ 53,12 53,7 @@ namespace gui
                setVisible(false);
            }
            else {
                if (level > 10) {
                    img->set(battery::battery_low, gui::ImageTypeSpecifier::W_M);
                }
                else {
                    img->set(battery::battery_critical, gui::ImageTypeSpecifier::W_M);
                }
                img->set(result->image, gui::ImageTypeSpecifier::W_M);
                percentText->setText(std::to_string(level) + "%");
                setVisible(true);
            }

M products/BellHybrid/apps/application-bell-main/windows/BellHomeScreenWindow.cpp => products/BellHybrid/apps/application-bell-main/windows/BellHomeScreenWindow.cpp +8 -1
@@ 267,11 267,13 @@ namespace gui

    void BellHomeScreenWindow::onBeforeShow(ShowMode, SwitchData *data)
    {
        presenter->onBeforeShow();
        const auto alarmRingingSwitchData = dynamic_cast<app::actions::AlarmRingingData *>(data);
        if (alarmRingingSwitchData != nullptr) {
            presenter->handleAlarmRingingEvent();
        }
        else {
            presenter->onBeforeShow();
        }
    }

    std::time_t BellHomeScreenWindow::getAlarmTime() const


@@ 331,5 333,10 @@ namespace gui
    {
        snoozeTimer->setTime(newTime);
    }
    bool BellHomeScreenWindow::updateBatteryStatus()
    {
        presenter->handleBatteryStatus();
        return true;
    }

} // namespace gui

M products/BellHybrid/apps/application-bell-main/windows/BellHomeScreenWindow.hpp => products/BellHybrid/apps/application-bell-main/windows/BellHomeScreenWindow.hpp +2 -0
@@ 65,6 65,8 @@ namespace gui
        void switchToMenu() override;
        void switchToBatteryStatus() override;

        bool updateBatteryStatus() override;

        BellBaseLayout *body{};

        TimeSetFmtSpinner *time{};

M products/BellHybrid/services/evtmgr/EventManager.cpp => products/BellHybrid/services/evtmgr/EventManager.cpp +4 -4
@@ 20,7 20,6 @@
#include <service-evtmgr/ScreenLightControlMessage.hpp>
#include <service-evtmgr/WorkerEventCommon.hpp>
#include <sys/messages/AlarmActivationStatusChangeRequest.hpp>
#include <switches/LatchStatusRequest.hpp>
#include <switches/LatchState.hpp>

namespace


@@ 41,6 40,7 @@ EventManager::EventManager(LogDumpFunction logDumpFunction, const std::string &n
      temperatureSource{hal::temperature::AbstractTemperatureSource::Factory::create()},
      backlightHandler(settings, this), userActivityHandler(std::make_shared<sys::CpuSentinel>(name, this), this)
{
    latchStatus = bsp::bell_switches::isLatchPressed() ? sevm::LatchStatus::PRESSED : sevm::LatchStatus::RELEASED;
    buildKeySequences();
    updateTemperature(*temperatureSource);



@@ 116,9 116,7 @@ void EventManager::initProductEvents()
    });

    connect(sevm::LatchStatusRequest(), [&](sys::Message *msgl) {
        sevm::LatchStatus state =
            bsp::bell_switches::isLatchPressed() ? sevm::LatchStatus::PRESSED : sevm::LatchStatus::RELEASED;
        auto msg = std::make_shared<sevm::LatchStatusResponse>(state);
        auto msg = std::make_shared<sevm::LatchStatusResponse>(latchStatus);
        return msg;
    });
}


@@ 155,6 153,7 @@ void EventManager::buildKeySequences()

    auto alarmActivateSeq      = std::make_unique<AlarmActivateSequence>();
    alarmActivateSeq->onAction = [this]() {
        latchStatus = sevm::LatchStatus::RELEASED;
        bus.sendUnicast(
            std::make_shared<sys::AlarmActivationStatusChangeRequest>(sys::AlarmActivationStatus::ACTIVATED),
            service::name::system_manager);


@@ 163,6 162,7 @@ void EventManager::buildKeySequences()

    auto alarmDeactivateSeq      = std::make_unique<AlarmDeactivateSequence>();
    alarmDeactivateSeq->onAction = [this]() {
        latchStatus = sevm::LatchStatus::PRESSED;
        bus.sendUnicast(
            std::make_shared<sys::AlarmActivationStatusChangeRequest>(sys::AlarmActivationStatus::DEACTIVATED),
            service::name::system_manager);

M products/BellHybrid/services/evtmgr/include/evtmgr/EventManager.hpp => products/BellHybrid/services/evtmgr/include/evtmgr/EventManager.hpp +3 -0
@@ 3,6 3,7 @@

#pragma once

#include <bsp/switches/LatchStatusRequest.hpp>
#include <service-evtmgr/EventManagerCommon.hpp>

#include "backlight-handler/BacklightHandler.hpp"


@@ 32,6 33,8 @@ class EventManager : public EventManagerCommon
    evm::UserActivityHandler userActivityHandler;

    std::shared_ptr<KeySequenceMgr> keySequenceMgr;

    sevm::LatchStatus latchStatus{};
};

namespace sys