From be28bb2b5602a2b4b1e36f65e2d9488299ff19d3 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 22 May 2019 15:52:50 +0200 Subject: [PATCH] Add a helper to control the rpi's backlight --- nymea-app/nymea-app.pro | 2 + nymea-app/platformhelper.cpp | 15 +++ nymea-app/platformhelper.h | 7 ++ .../generic/platformhelpergeneric.cpp | 20 +++- .../generic/platformhelpergeneric.h | 11 +- .../generic/raspberrypihelper.cpp | 106 ++++++++++++++++++ .../generic/raspberrypihelper.h | 29 +++++ .../appsettings/LookAndFeelSettingsPage.qml | 29 +++++ 8 files changed, 215 insertions(+), 4 deletions(-) create mode 100644 nymea-app/platformintegration/generic/raspberrypihelper.cpp create mode 100644 nymea-app/platformintegration/generic/raspberrypihelper.h diff --git a/nymea-app/nymea-app.pro b/nymea-app/nymea-app.pro index 6b142c18..71cab753 100644 --- a/nymea-app/nymea-app.pro +++ b/nymea-app/nymea-app.pro @@ -17,6 +17,7 @@ linux:!android:LIBS += -lavahi-client -lavahi-common PRE_TARGETDEPS += ../libnymea-app-core ../libnymea-common HEADERS += \ + platformintegration/generic/raspberrypihelper.h \ stylecontroller.h \ pushnotifications.h \ platformhelper.h \ @@ -24,6 +25,7 @@ HEADERS += \ applogcontroller.h SOURCES += main.cpp \ + platformintegration/generic/raspberrypihelper.cpp \ stylecontroller.cpp \ pushnotifications.cpp \ platformhelper.cpp \ diff --git a/nymea-app/platformhelper.cpp b/nymea-app/platformhelper.cpp index 8e276a31..b45f1e9b 100644 --- a/nymea-app/platformhelper.cpp +++ b/nymea-app/platformhelper.cpp @@ -4,3 +4,18 @@ PlatformHelper::PlatformHelper(QObject *parent) : QObject(parent) { } + +bool PlatformHelper::canControlScreen() const +{ + return false; +} + +int PlatformHelper::screenTimeout() const +{ + return 0; +} + +void PlatformHelper::setScreenTimeout(int screenTimeout) +{ + Q_UNUSED(screenTimeout) +} diff --git a/nymea-app/platformhelper.h b/nymea-app/platformhelper.h index eb756e0a..02f23858 100644 --- a/nymea-app/platformhelper.h +++ b/nymea-app/platformhelper.h @@ -12,6 +12,8 @@ class PlatformHelper : public QObject Q_PROPERTY(QString deviceModel READ deviceModel CONSTANT) Q_PROPERTY(QString deviceManufacturer READ deviceManufacturer CONSTANT) Q_PROPERTY(QString machineHostname READ machineHostname CONSTANT) + Q_PROPERTY(bool canControlScreen READ canControlScreen CONSTANT) + Q_PROPERTY(int screenTimeout READ screenTimeout WRITE setScreenTimeout NOTIFY screenTimeoutChanged) public: enum HapticsFeedback { @@ -35,10 +37,15 @@ public: virtual QString deviceModel() const = 0; virtual QString deviceManufacturer() const = 0; + virtual bool canControlScreen() const; + virtual int screenTimeout() const; + virtual void setScreenTimeout(int screenTimeout); + Q_INVOKABLE virtual void vibrate(HapticsFeedback feedbackType) = 0; signals: void permissionsRequestFinished(); + void screenTimeoutChanged(); }; #endif // PLATFORMHELPER_H diff --git a/nymea-app/platformintegration/generic/platformhelpergeneric.cpp b/nymea-app/platformintegration/generic/platformhelpergeneric.cpp index d0b13bf6..1ea004ba 100644 --- a/nymea-app/platformintegration/generic/platformhelpergeneric.cpp +++ b/nymea-app/platformintegration/generic/platformhelpergeneric.cpp @@ -2,7 +2,7 @@ PlatformHelperGeneric::PlatformHelperGeneric(QObject *parent) : PlatformHelper(parent) { - + m_piHelper = new RaspberryPiHelper(this); } void PlatformHelperGeneric::requestPermissions() @@ -49,6 +49,24 @@ QString PlatformHelperGeneric::deviceManufacturer() const return QSysInfo::productType(); } +bool PlatformHelperGeneric::canControlScreen() const +{ + return m_piHelper->active(); +} + +int PlatformHelperGeneric::screenTimeout() const +{ + return m_piHelper->screenTimeout(); +} + +void PlatformHelperGeneric::setScreenTimeout(int timeout) +{ + if (m_piHelper->screenTimeout() != timeout) { + m_piHelper->setScreenTimeout(timeout); + emit screenTimeoutChanged(); + } +} + void PlatformHelperGeneric::vibrate(PlatformHelper::HapticsFeedback feedbyckType) { Q_UNUSED(feedbyckType) diff --git a/nymea-app/platformintegration/generic/platformhelpergeneric.h b/nymea-app/platformintegration/generic/platformhelpergeneric.h index a418e937..49a49252 100644 --- a/nymea-app/platformintegration/generic/platformhelpergeneric.h +++ b/nymea-app/platformintegration/generic/platformhelpergeneric.h @@ -3,6 +3,7 @@ #include #include "platformhelper.h" +#include "raspberrypihelper.h" class PlatformHelperGeneric : public PlatformHelper { @@ -21,10 +22,14 @@ public: virtual QString deviceModel() const override; virtual QString deviceManufacturer() const override; - Q_INVOKABLE virtual void vibrate(HapticsFeedback feedbyckType) override; -signals: + virtual bool canControlScreen() const override; + virtual int screenTimeout() const override; + virtual void setScreenTimeout(int timeout) override; -public slots: + Q_INVOKABLE virtual void vibrate(HapticsFeedback feedbyckType) override; + +private: + RaspberryPiHelper *m_piHelper = nullptr; }; #endif // PLATFORMHELPERGENERIC_H diff --git a/nymea-app/platformintegration/generic/raspberrypihelper.cpp b/nymea-app/platformintegration/generic/raspberrypihelper.cpp new file mode 100644 index 00000000..84ee7d15 --- /dev/null +++ b/nymea-app/platformintegration/generic/raspberrypihelper.cpp @@ -0,0 +1,106 @@ +#include "raspberrypihelper.h" + +#include +#include +#include +#include + +RaspberryPiHelper::RaspberryPiHelper(QObject *parent) : QObject(parent) +{ + m_sysFsFile.setFileName("/sys/class/backlight/rpi_backlight/bl_power"); + bool available = m_sysFsFile.open(QFile::ReadWrite | QFile::Text); + + if (!available) { + return; + } + + qDebug() << "Raspberry Pi detected. Enabling backlight control"; + + screenOn(); + + foreach (QWindow *w, qApp->topLevelWindows()) { + w->installEventFilter(this); + } + + QSettings settings; + m_screenOffTimer.setInterval(settings.value("screenOffTimeout", 15000).toInt()); + m_screenOffTimer.setSingleShot(true); + connect(&m_screenOffTimer, &QTimer::timeout, this, &RaspberryPiHelper::screenOff); + if (m_screenOffTimer.interval() > 0) { + m_screenOffTimer.start(); + } +} + +bool RaspberryPiHelper::active() const +{ + return m_sysFsFile.isOpen(); +} + +int RaspberryPiHelper::screenTimeout() const +{ + return m_screenOffTimer.interval(); +} + +void RaspberryPiHelper::setScreenTimeout(int timeout) +{ + m_screenOffTimer.setInterval(timeout); + QSettings settings; + settings.setValue("screenOffTimeout", timeout); + if (timeout > 0) { + m_screenOffTimer.start(); + } else { + m_screenOffTimer.stop(); + } +} + +bool RaspberryPiHelper::eventFilter(QObject *watched, QEvent *event) +{ + if (m_screenOffTimer.interval() == 0) { + return QObject::eventFilter(watched, event); + } + + QList watchedTypes = { + QEvent::ActivationChange, + QEvent::ApplicationStateChange, + QEvent::KeyPress, + QEvent::KeyRelease, + QEvent::MouseButtonPress, + QEvent::MouseButtonRelease, + QEvent::MouseMove, + QEvent::Show, + QEvent::TouchBegin, + QEvent::TouchEnd, + QEvent::TouchUpdate, + }; + if (!watchedTypes.contains(event->type())) { + return QObject::eventFilter(watched, event); + } + + if (!m_screenOffTimer.isActive()) { + screenOn(); + m_screenOffTimer.start(); + return true; + } + m_screenOffTimer.start( ); + return QObject::eventFilter(watched, event); +} + +void RaspberryPiHelper::screenOn() +{ + qDebug() << "Turning screen on"; + int ret = m_sysFsFile.write("0\n"); + m_sysFsFile.flush(); + if (ret < 0) { + qWarning() << "Failed to power on screen"; + } +} + +void RaspberryPiHelper::screenOff() +{ + qDebug() << "Turning screen off"; + int ret = m_sysFsFile.write("1\n"); + m_sysFsFile.flush(); + if (ret < 0) { + qWarning() << "Failed to power off screen"; + } +} diff --git a/nymea-app/platformintegration/generic/raspberrypihelper.h b/nymea-app/platformintegration/generic/raspberrypihelper.h new file mode 100644 index 00000000..9830aaee --- /dev/null +++ b/nymea-app/platformintegration/generic/raspberrypihelper.h @@ -0,0 +1,29 @@ +#ifndef RASPBERRYPIHELPER_H +#define RASPBERRYPIHELPER_H + +#include +#include +#include + +class RaspberryPiHelper : public QObject +{ + Q_OBJECT +public: + explicit RaspberryPiHelper(QObject *parent = nullptr); + + bool active() const; + int screenTimeout() const; + void setScreenTimeout(int timeout); + + bool eventFilter(QObject *watched, QEvent *event) override; + +private slots: + void screenOn(); + void screenOff(); + +private: + QTimer m_screenOffTimer; + QFile m_sysFsFile; +}; + +#endif // RASPBERRYPIHELPER_H diff --git a/nymea-app/ui/appsettings/LookAndFeelSettingsPage.qml b/nymea-app/ui/appsettings/LookAndFeelSettingsPage.qml index f4d1d824..46c2c783 100644 --- a/nymea-app/ui/appsettings/LookAndFeelSettingsPage.qml +++ b/nymea-app/ui/appsettings/LookAndFeelSettingsPage.qml @@ -89,6 +89,35 @@ Page { checked: settings.showConnectionTabs onClicked: settings.showConnectionTabs = checked } + CheckDelegate { + id: screenOffCheck + Layout.fillWidth: true + text: qsTr("Turn screen off when idle") + visible: PlatformHelper.canControlScreen + checked: PlatformHelper.screenTimeout > 0 + onClicked: PlatformHelper.screenTimeout = (checked ? 15000 : 0) + } + ItemDelegate { + Layout.fillWidth: true + Layout.preferredHeight: screenOffCheck.height + visible: PlatformHelper.screenTimeout > 0 + topPadding: 0 + contentItem: RowLayout { + Label { + Layout.fillWidth: true + text: qsTr("Screen off timeout") + } + SpinBox { + value: PlatformHelper.screenTimeout / 1000 + onValueModified: { + PlatformHelper.screenTimeout = value * 1000 + } + } + Label { + text: qsTr("seconds") + } + } + } } Component {