From 09c782e3ec5186e00220df2aaf0c322661c6d6a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 8 Oct 2019 17:56:14 +0200 Subject: [PATCH] Add button mode --- README.md | 72 +++++++++---------- nymea-networkmanager.conf | 1 + nymea-networkmanager/core.cpp | 34 ++++++++- nymea-networkmanager/core.h | 15 +++- nymea-networkmanager/main.cpp | 54 +++++++++++--- nymea-networkmanager/nymea-networkmanager.pro | 2 +- 6 files changed, 126 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index f98d6b4..66eb4ee 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,15 @@ if the system is currently not connected to any network. Once the system is conn First you have to install build dependencies: -> Note: the libnymea-networkmanager-dev package can be installed from the [nymea repository](https://nymea.io/en/wiki/nymea/master/install/debian) or built +> Note: the `libnymea-networkmanager-dev` package can be installed from the [nymea repository](https://nymea.io/en/wiki/nymea/master/install/debian) or built and installed from [source](https://github.com/nymea/libnymea-networkmanager). + +> Note: the `libnymea-gpio-dev` package can be installed from the [nymea repository](https://nymea.io/en/wiki/nymea/master/install/debian) or built +and installed from [source](https://github.com/nymea/nymea-gpio). + $ sudo apt update - $ sudo apt install qt5-default qtbase5-dev qtbase5-dev-tools libqt5bluetooth5 qtconnectivity5-dev libnymea-networkmanager-dev git + $ sudo apt install qt5-default qtbase5-dev qtbase5-dev-tools libqt5bluetooth5 qtconnectivity5-dev libnymea-networkmanager-dev libnymea-gpio-dev git Clone the source code and change into the source directory @@ -63,45 +67,41 @@ this repository and it will be installed to /etc/nymea-networkmanager.conf with # Command line parameters $ nymea-networkmanager --help - Usage:nymea-networkmanager [options] + Usage: ./nymea-networkmanager [options] This daemon allows to configure a wifi network using a bluetooth low energy connection. - Copyright © 2018 - 2019 Simon Stürz + Copyright © 2018-2019 Simon Stürz + + Modes: + - offline This mode starts the bluetooth server once the device is offline + and not connected to any LAN network. + - once This mode starts the bluetooth server only if no network configuration exists. + Once a network connection exists the server will never start again. + - button This mode enables the bluetooth server when a GPIO button has been pressed for + the configured timeout periode. + - always This mode enables the bluetooth server as long the application is running. + - start This mode starts the bluetooth server for 3 minutes on start and shuts down after a connection. + + Options: - -h, --help Displays this help. - -v, --version Displays version information. - -d, --debug Enable more debug output. - -a, --advertise-name The name of the bluetooth - server. Default "BT WLAN setup". - -p, --platform-name The name of the platform this - daemon is running. Default - "nymea-box". - -t, --timeout The timeout of the bluetooth - server. Minimum value is 10. - Default "60". - -m, --mode Run the daemon in a specific - mode. Default is "offline". - - offline: this mode starts the - bluetooth server once the device - is offline and not connected to - any LAN network. - - once: this mode starts the - bluetooth server only if no - network configuration exists. - Once a network connection exists - the server will never start - again. - - always: this mode enables the - bluetooth server as long the - application is running. - - start: this mode starts the - bluetooth server for 3 minutes - on start and shuts down after a - connection. - - + -h, --help Displays this help. + -v, --version Displays version information. + -d, --debug Enable more debug output. + -a, --advertise-name The name of the bluetooth server. Default "BT + WLAN setup". + -p, --platform-name The name of the platform this daemon is running. + Default "nymea-box". + -g, --gpio The GPIO sysfs number for the button GPIO. This + parameter is only needed for the "button" mode. + -t, --timeout The timeout of the bluetooth server. Minimum + value is 10. Default "60". + -m, --mode Run the daemon in a specific mode (offline, + once, always, button, start). Default is + "offline". + + # Bluetooth GATT profile ------------------------------------------- diff --git a/nymea-networkmanager.conf b/nymea-networkmanager.conf index 7a81a10..a6753c2 100644 --- a/nymea-networkmanager.conf +++ b/nymea-networkmanager.conf @@ -3,3 +3,4 @@ Mode=offline Timeout=60 AdvertiseName=BT WLAN setup PlatformName=nymea-box +ButtonGpio=14 diff --git a/nymea-networkmanager/core.cpp b/nymea-networkmanager/core.cpp index 3a8f899..124f0e5 100644 --- a/nymea-networkmanager/core.cpp +++ b/nymea-networkmanager/core.cpp @@ -62,7 +62,7 @@ Core::Mode Core::mode() const return m_mode; } -void Core::setMode(const Core::Mode &mode) +void Core::setMode(Mode mode) { m_mode = mode; } @@ -92,11 +92,21 @@ int Core::advertisingTimeout() const return m_advertisingTimeout; } -void Core::setAdvertisingTimeout(const int advertisingTimeout) +void Core::setAdvertisingTimeout(int advertisingTimeout) { m_advertisingTimeout = advertisingTimeout; } +int Core::buttonGpio() const +{ + return m_buttonGpio; +} + +void Core::setButtonGpio(int buttonGpio) +{ + m_buttonGpio = buttonGpio; +} + void Core::run() { // Start the networkmanager @@ -243,6 +253,17 @@ void Core::postRun() qCDebug(dcApplication()) << "Not starting the bluetooth service because of \"once\" mode. There are" << m_networkManager->networkSettings()->connections().count() << "network configurations."; } break; + case ModeButton: + // Enable button + m_button = new GpioButton(m_buttonGpio, this); + m_button->setLongPressedTimeout(2000); + connect(m_button, &GpioButton::longPressed, this, &Core::onButtonLongPressed); + if (!m_button->enable()) { + qCCritical(dcApplication()) << "Could not not enable GPIO button for" << m_buttonGpio; + m_button->deleteLater(); + m_button = nullptr; + } + break; } } @@ -288,6 +309,8 @@ void Core::onBluetoothServerRunningChanged(bool running) qCDebug(dcApplication()) << "Not starting the bluetooth service because of \"once\" mode. There are" << m_networkManager->networkSettings()->connections().count() << "network configurations."; } break; + case ModeButton: + break; } } } @@ -336,6 +359,8 @@ void Core::onNetworkManagerAvailableChanged(bool available) qCDebug(dcApplication()) << "Not starting the bluetooth service because of \"once\" mode. There are" << m_networkManager->networkSettings()->connections().count() << "network configurations."; } break; + case ModeButton: + break; } } @@ -344,6 +369,11 @@ void Core::onNetworkManagerStateChanged(NetworkManager::NetworkManagerState stat evaluateNetworkManagerState(state); } +void Core::onButtonLongPressed() +{ + startService(); +} + void Core::onNymeaServiceAvailableChanged(bool available) { if (available) diff --git a/nymea-networkmanager/core.h b/nymea-networkmanager/core.h index 86227dd..961bb51 100644 --- a/nymea-networkmanager/core.h +++ b/nymea-networkmanager/core.h @@ -25,6 +25,7 @@ #include #include "nymeadservice.h" +#include "nymea-gpio/gpiobutton.h" #include "bluetooth/bluetoothserver.h" #include "nymea-networkmanager/networkmanager.h" #include "nymea-networkmanager/bluetooth/bluetoothserver.h" @@ -38,7 +39,8 @@ public: ModeAlways, ModeOffline, ModeOnce, - ModeStart + ModeStart, + ModeButton }; Q_ENUM(Mode) @@ -50,7 +52,7 @@ public: NymeadService *nymeaService() const; Mode mode() const; - void setMode(const Mode &mode); + void setMode(Mode mode); QString advertiseName() const; void setAdvertiseName(const QString &name); @@ -59,7 +61,10 @@ public: void setPlatformName(const QString &name); int advertisingTimeout() const; - void setAdvertisingTimeout(const int advertisingTimeout); + void setAdvertisingTimeout(int advertisingTimeout); + + int buttonGpio() const; + void setButtonGpio(int buttonGpio); void run(); @@ -73,6 +78,7 @@ private: BluetoothServer *m_bluetoothServer = nullptr; NymeadService *m_nymeaService = nullptr; WirelessNetworkDevice *m_wirelessDevice = nullptr; + GpioButton *m_button = nullptr; QTimer *m_advertisingTimer = nullptr; @@ -81,6 +87,7 @@ private: QString m_platformName; int m_advertisingTimeout = 60; bool m_initRunning = true; + int m_buttonGpio = -1; void evaluateNetworkManagerState(NetworkManager::NetworkManagerState state); @@ -98,6 +105,8 @@ private slots: void onNetworkManagerAvailableChanged(bool available); void onNetworkManagerStateChanged(NetworkManager::NetworkManagerState state); + void onButtonLongPressed(); + void onNymeaServiceAvailableChanged(bool available); }; diff --git a/nymea-networkmanager/main.cpp b/nymea-networkmanager/main.cpp index 8155674..c30497c 100644 --- a/nymea-networkmanager/main.cpp +++ b/nymea-networkmanager/main.cpp @@ -84,6 +84,7 @@ int main(int argc, char *argv[]) // Default configuration: Core::Mode mode = Core::ModeOffline; int timeout = 60; + int buttonGpio = -1; QString advertiseName = "BT WLAN setup"; QString platformName = "nymea-box"; @@ -96,8 +97,17 @@ int main(int argc, char *argv[]) QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); - parser.setApplicationDescription(QString("\nThis daemon allows to configure a wifi network using a bluetooth low energy connection." \ - "\n\nCopyright %1 2018-2019 Simon Stürz ").arg(QChar(0xA9))); + parser.setApplicationDescription(QString("\nThis daemon allows to configure a wifi network using a bluetooth low energy connection.\n\n" + "Copyright %1 2018-2019 Simon Stürz \n\n" + "Modes: \n" + " - offline This mode starts the bluetooth server once the device is offline\n" + " and not connected to any LAN network.\n" + " - once This mode starts the bluetooth server only if no network configuration exists.\n" + " Once a network connection exists the server will never start again.\n" + " - button This mode enables the bluetooth server when a GPIO button has been pressed for\n" + " the configured timeout periode.\n" + " - always This mode enables the bluetooth server as long the application is running.\n" + " - start This mode starts the bluetooth server for 3 minutes on start and shuts down after a connection.\n\n").arg(QChar(0xA9))); QCommandLineOption debugOption(QStringList() << "d" << "debug", "Enable more debug output."); parser.addOption(debugOption); @@ -110,15 +120,15 @@ int main(int argc, char *argv[]) platformNameOption.setDefaultValue(platformName); parser.addOption(platformNameOption); + QCommandLineOption gpioOption(QStringList() << "g" << "gpio", QString("The GPIO sysfs number for the button GPIO. This parameter is only needed for the \"button\" mode."), "GPIO"); + platformNameOption.setDefaultValue("-1"); + parser.addOption(gpioOption); + QCommandLineOption timeoutOption(QStringList() << "t" << "timeout", QString("The timeout of the bluetooth server. Minimum value is 10. Default \"%1\".").arg(timeout), "SECONDS"); timeoutOption.setDefaultValue(QString::number(timeout)); parser.addOption(timeoutOption); - QCommandLineOption modeOption(QStringList() << "m" << "mode", "Run the daemon in a specific mode. Default is \"offline\".\n\n" \ - "- offline: this mode starts the bluetooth server once the device is offline and not connected to any LAN network.\n\n" \ - "- once: this mode starts the bluetooth server only if no network configuration exists. Once a network connection exists the server will never start again.\n\n" \ - "- always: this mode enables the bluetooth server as long the application is running.\n\n" \ - "- start: this mode starts the bluetooth server for 3 minutes on start and shuts down after a connection.\n\n", "offline | once | always | start"); + QCommandLineOption modeOption(QStringList() << "m" << "mode", "Run the daemon in a specific mode (offline, once, always, button, start). Default is \"offline\".", "MODE"); parser.addOption(modeOption); parser.process(application); @@ -132,6 +142,7 @@ int main(int argc, char *argv[]) QLoggingCategory::installFilter(loggingCategoryFilter); bool timeoutValueOk = true; + bool gpioValueOk = true; // Now read the cofig file, overriding defaults QStringList configLocations; @@ -152,10 +163,15 @@ int main(int argc, char *argv[]) mode = Core::ModeStart; } else if (settings.value("Mode").toString().toLower() == "once") { mode = Core::ModeOnce; + } else if (settings.value("Mode").toString().toLower() == "button") { + mode = Core::ModeButton; } else { qCWarning(dcApplication()).noquote() << QString("The config file's mode \"%1\" does not match the allowed modes.").arg(settings.value("Mode").toString()); } } + if (settings.contains("ButtonGpio")) { + buttonGpio = settings.value("ButtonGpio", -1).toInt(&gpioValueOk); + } if (settings.contains("Timeout")) { timeout = settings.value("Timeout").toInt(&timeoutValueOk); } @@ -179,7 +195,10 @@ int main(int argc, char *argv[]) mode = Core::ModeStart; } else if (parser.value(modeOption).toLower() == "once") { mode = Core::ModeOnce; - } else { + } else if (parser.value(modeOption).toLower() == "button") { + mode = Core::ModeButton; + + } else { qCWarning(dcApplication()).noquote() << QString("The given mode \"%1\" does not match the allowed modes.").arg(parser.value(modeOption)); parser.showHelp(1); } @@ -193,15 +212,27 @@ int main(int argc, char *argv[]) if (parser.isSet(timeoutOption)) { timeout = parser.value(timeoutOption).toInt(&timeoutValueOk); } + if (parser.isSet(gpioOption)) { + buttonGpio = parser.value(gpioOption).toInt(&gpioValueOk); + } // All parsed. Validate input: if (!timeoutValueOk) { qCCritical(dcApplication()) << QString("Invalid timeout value passed: \"%1\". Please pass an integer >= 10").arg(parser.value(timeoutOption)); - parser.showHelp(1); + return(1); + } + if (!gpioValueOk) { + qCCritical(dcApplication()) << QString("Invalid GPIO number value passed: \"%1\". Please pass an integer > 0").arg(parser.value(gpioOption)); + return(1); } if (timeout < 10) { qCCritical(dcApplication()) << QString("Invalid timeout value passed: \"%1\". The minimal timeout is 10 [s].").arg(parser.value(timeoutOption)); - parser.showHelp(1); + return(1); + } + + if (mode == Core::ModeButton && buttonGpio <= 0) { + qCCritical(dcApplication()) << "Button mode selected but no valid GPIO passed."; + return(1); } qCDebug(dcApplication()) << "====================================="; @@ -211,12 +242,15 @@ int main(int argc, char *argv[]) qCDebug(dcApplication()) << "Platform name:" << platformName; qCDebug(dcApplication()) << "Mode:" << mode; qCDebug(dcApplication()) << "Timeout:" << timeout; + if (mode == Core::ModeButton) + qCDebug(dcApplication()) << "Button GPIO:" << buttonGpio; // Start core Core::instance()->setMode(mode); Core::instance()->setAdvertisingTimeout(timeout); Core::instance()->setAdvertiseName(advertiseName); Core::instance()->setPlatformName(platformName); + Core::instance()->setButtonGpio(buttonGpio); Core::instance()->run(); diff --git a/nymea-networkmanager/nymea-networkmanager.pro b/nymea-networkmanager/nymea-networkmanager.pro index c49bd3e..fd84155 100644 --- a/nymea-networkmanager/nymea-networkmanager.pro +++ b/nymea-networkmanager/nymea-networkmanager.pro @@ -9,7 +9,7 @@ CONFIG += console link_pkgconfig CONFIG -= app_bundle TEMPLATE = app -PKGCONFIG += nymea-networkmanager +PKGCONFIG += nymea-networkmanager nymea-gpio HEADERS += \ application.h \