Add button mode

This commit is contained in:
Simon Stürz 2019-10-08 17:56:14 +02:00
parent 1a369e1845
commit 09c782e3ec
6 changed files with 126 additions and 52 deletions

View File

@ -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: 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). 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 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 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 # Command line parameters
$ nymea-networkmanager --help $ 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. This daemon allows to configure a wifi network using a bluetooth low energy connection.
Copyright © 2018 - 2019 Simon Stürz <simon.stuerz@nymea.io> Copyright © 2018-2019 Simon Stürz <simon.stuerz@nymea.io>
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: Options:
-h, --help Displays this help. -h, --help Displays this help.
-v, --version Displays version information. -v, --version Displays version information.
-d, --debug Enable more debug output. -d, --debug Enable more debug output.
-a, --advertise-name <NAME> The name of the bluetooth -a, --advertise-name <NAME> The name of the bluetooth server. Default "BT
server. Default "BT WLAN setup". WLAN setup".
-p, --platform-name <NAME> The name of the platform this -p, --platform-name <NAME> The name of the platform this daemon is running.
daemon is running. Default Default "nymea-box".
"nymea-box". -g, --gpio <GPIO> The GPIO sysfs number for the button GPIO. This
-t, --timeout <SECONDS> The timeout of the bluetooth parameter is only needed for the "button" mode.
server. Minimum value is 10. -t, --timeout <SECONDS> The timeout of the bluetooth server. Minimum
Default "60". value is 10. Default "60".
-m, --mode <offline | once | always | start> Run the daemon in a specific -m, --mode <MODE> Run the daemon in a specific mode (offline,
mode. Default is "offline". once, always, button, start). Default is
- offline: this mode starts the "offline".
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.
# Bluetooth GATT profile # Bluetooth GATT profile
------------------------------------------- -------------------------------------------

View File

@ -3,3 +3,4 @@ Mode=offline
Timeout=60 Timeout=60
AdvertiseName=BT WLAN setup AdvertiseName=BT WLAN setup
PlatformName=nymea-box PlatformName=nymea-box
ButtonGpio=14

View File

@ -62,7 +62,7 @@ Core::Mode Core::mode() const
return m_mode; return m_mode;
} }
void Core::setMode(const Core::Mode &mode) void Core::setMode(Mode mode)
{ {
m_mode = mode; m_mode = mode;
} }
@ -92,11 +92,21 @@ int Core::advertisingTimeout() const
return m_advertisingTimeout; return m_advertisingTimeout;
} }
void Core::setAdvertisingTimeout(const int advertisingTimeout) void Core::setAdvertisingTimeout(int advertisingTimeout)
{ {
m_advertisingTimeout = advertisingTimeout; m_advertisingTimeout = advertisingTimeout;
} }
int Core::buttonGpio() const
{
return m_buttonGpio;
}
void Core::setButtonGpio(int buttonGpio)
{
m_buttonGpio = buttonGpio;
}
void Core::run() void Core::run()
{ {
// Start the networkmanager // 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."; qCDebug(dcApplication()) << "Not starting the bluetooth service because of \"once\" mode. There are" << m_networkManager->networkSettings()->connections().count() << "network configurations.";
} }
break; 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."; qCDebug(dcApplication()) << "Not starting the bluetooth service because of \"once\" mode. There are" << m_networkManager->networkSettings()->connections().count() << "network configurations.";
} }
break; 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."; qCDebug(dcApplication()) << "Not starting the bluetooth service because of \"once\" mode. There are" << m_networkManager->networkSettings()->connections().count() << "network configurations.";
} }
break; break;
case ModeButton:
break;
} }
} }
@ -344,6 +369,11 @@ void Core::onNetworkManagerStateChanged(NetworkManager::NetworkManagerState stat
evaluateNetworkManagerState(state); evaluateNetworkManagerState(state);
} }
void Core::onButtonLongPressed()
{
startService();
}
void Core::onNymeaServiceAvailableChanged(bool available) void Core::onNymeaServiceAvailableChanged(bool available)
{ {
if (available) if (available)

View File

@ -25,6 +25,7 @@
#include <QObject> #include <QObject>
#include "nymeadservice.h" #include "nymeadservice.h"
#include "nymea-gpio/gpiobutton.h"
#include "bluetooth/bluetoothserver.h" #include "bluetooth/bluetoothserver.h"
#include "nymea-networkmanager/networkmanager.h" #include "nymea-networkmanager/networkmanager.h"
#include "nymea-networkmanager/bluetooth/bluetoothserver.h" #include "nymea-networkmanager/bluetooth/bluetoothserver.h"
@ -38,7 +39,8 @@ public:
ModeAlways, ModeAlways,
ModeOffline, ModeOffline,
ModeOnce, ModeOnce,
ModeStart ModeStart,
ModeButton
}; };
Q_ENUM(Mode) Q_ENUM(Mode)
@ -50,7 +52,7 @@ public:
NymeadService *nymeaService() const; NymeadService *nymeaService() const;
Mode mode() const; Mode mode() const;
void setMode(const Mode &mode); void setMode(Mode mode);
QString advertiseName() const; QString advertiseName() const;
void setAdvertiseName(const QString &name); void setAdvertiseName(const QString &name);
@ -59,7 +61,10 @@ public:
void setPlatformName(const QString &name); void setPlatformName(const QString &name);
int advertisingTimeout() const; int advertisingTimeout() const;
void setAdvertisingTimeout(const int advertisingTimeout); void setAdvertisingTimeout(int advertisingTimeout);
int buttonGpio() const;
void setButtonGpio(int buttonGpio);
void run(); void run();
@ -73,6 +78,7 @@ private:
BluetoothServer *m_bluetoothServer = nullptr; BluetoothServer *m_bluetoothServer = nullptr;
NymeadService *m_nymeaService = nullptr; NymeadService *m_nymeaService = nullptr;
WirelessNetworkDevice *m_wirelessDevice = nullptr; WirelessNetworkDevice *m_wirelessDevice = nullptr;
GpioButton *m_button = nullptr;
QTimer *m_advertisingTimer = nullptr; QTimer *m_advertisingTimer = nullptr;
@ -81,6 +87,7 @@ private:
QString m_platformName; QString m_platformName;
int m_advertisingTimeout = 60; int m_advertisingTimeout = 60;
bool m_initRunning = true; bool m_initRunning = true;
int m_buttonGpio = -1;
void evaluateNetworkManagerState(NetworkManager::NetworkManagerState state); void evaluateNetworkManagerState(NetworkManager::NetworkManagerState state);
@ -98,6 +105,8 @@ private slots:
void onNetworkManagerAvailableChanged(bool available); void onNetworkManagerAvailableChanged(bool available);
void onNetworkManagerStateChanged(NetworkManager::NetworkManagerState state); void onNetworkManagerStateChanged(NetworkManager::NetworkManagerState state);
void onButtonLongPressed();
void onNymeaServiceAvailableChanged(bool available); void onNymeaServiceAvailableChanged(bool available);
}; };

View File

@ -84,6 +84,7 @@ int main(int argc, char *argv[])
// Default configuration: // Default configuration:
Core::Mode mode = Core::ModeOffline; Core::Mode mode = Core::ModeOffline;
int timeout = 60; int timeout = 60;
int buttonGpio = -1;
QString advertiseName = "BT WLAN setup"; QString advertiseName = "BT WLAN setup";
QString platformName = "nymea-box"; QString platformName = "nymea-box";
@ -96,8 +97,17 @@ int main(int argc, char *argv[])
QCommandLineParser parser; QCommandLineParser parser;
parser.addHelpOption(); parser.addHelpOption();
parser.addVersionOption(); parser.addVersionOption();
parser.setApplicationDescription(QString("\nThis daemon allows to configure a wifi network using a bluetooth low energy connection." \ parser.setApplicationDescription(QString("\nThis daemon allows to configure a wifi network using a bluetooth low energy connection.\n\n"
"\n\nCopyright %1 2018-2019 Simon Stürz <simon.stuerz@nymea.io>").arg(QChar(0xA9))); "Copyright %1 2018-2019 Simon Stürz <simon.stuerz@nymea.io>\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."); QCommandLineOption debugOption(QStringList() << "d" << "debug", "Enable more debug output.");
parser.addOption(debugOption); parser.addOption(debugOption);
@ -110,15 +120,15 @@ int main(int argc, char *argv[])
platformNameOption.setDefaultValue(platformName); platformNameOption.setDefaultValue(platformName);
parser.addOption(platformNameOption); 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"); 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)); timeoutOption.setDefaultValue(QString::number(timeout));
parser.addOption(timeoutOption); parser.addOption(timeoutOption);
QCommandLineOption modeOption(QStringList() << "m" << "mode", "Run the daemon in a specific mode. Default is \"offline\".\n\n" \ QCommandLineOption modeOption(QStringList() << "m" << "mode", "Run the daemon in a specific mode (offline, once, always, button, start). Default is \"offline\".", "MODE");
"- 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");
parser.addOption(modeOption); parser.addOption(modeOption);
parser.process(application); parser.process(application);
@ -132,6 +142,7 @@ int main(int argc, char *argv[])
QLoggingCategory::installFilter(loggingCategoryFilter); QLoggingCategory::installFilter(loggingCategoryFilter);
bool timeoutValueOk = true; bool timeoutValueOk = true;
bool gpioValueOk = true;
// Now read the cofig file, overriding defaults // Now read the cofig file, overriding defaults
QStringList configLocations; QStringList configLocations;
@ -152,10 +163,15 @@ int main(int argc, char *argv[])
mode = Core::ModeStart; mode = Core::ModeStart;
} else if (settings.value("Mode").toString().toLower() == "once") { } else if (settings.value("Mode").toString().toLower() == "once") {
mode = Core::ModeOnce; mode = Core::ModeOnce;
} else if (settings.value("Mode").toString().toLower() == "button") {
mode = Core::ModeButton;
} else { } else {
qCWarning(dcApplication()).noquote() << QString("The config file's mode \"%1\" does not match the allowed modes.").arg(settings.value("Mode").toString()); 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")) { if (settings.contains("Timeout")) {
timeout = settings.value("Timeout").toInt(&timeoutValueOk); timeout = settings.value("Timeout").toInt(&timeoutValueOk);
} }
@ -179,7 +195,10 @@ int main(int argc, char *argv[])
mode = Core::ModeStart; mode = Core::ModeStart;
} else if (parser.value(modeOption).toLower() == "once") { } else if (parser.value(modeOption).toLower() == "once") {
mode = Core::ModeOnce; 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)); qCWarning(dcApplication()).noquote() << QString("The given mode \"%1\" does not match the allowed modes.").arg(parser.value(modeOption));
parser.showHelp(1); parser.showHelp(1);
} }
@ -193,15 +212,27 @@ int main(int argc, char *argv[])
if (parser.isSet(timeoutOption)) { if (parser.isSet(timeoutOption)) {
timeout = parser.value(timeoutOption).toInt(&timeoutValueOk); timeout = parser.value(timeoutOption).toInt(&timeoutValueOk);
} }
if (parser.isSet(gpioOption)) {
buttonGpio = parser.value(gpioOption).toInt(&gpioValueOk);
}
// All parsed. Validate input: // All parsed. Validate input:
if (!timeoutValueOk) { if (!timeoutValueOk) {
qCCritical(dcApplication()) << QString("Invalid timeout value passed: \"%1\". Please pass an integer >= 10").arg(parser.value(timeoutOption)); 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) { if (timeout < 10) {
qCCritical(dcApplication()) << QString("Invalid timeout value passed: \"%1\". The minimal timeout is 10 [s].").arg(parser.value(timeoutOption)); 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()) << "====================================="; qCDebug(dcApplication()) << "=====================================";
@ -211,12 +242,15 @@ int main(int argc, char *argv[])
qCDebug(dcApplication()) << "Platform name:" << platformName; qCDebug(dcApplication()) << "Platform name:" << platformName;
qCDebug(dcApplication()) << "Mode:" << mode; qCDebug(dcApplication()) << "Mode:" << mode;
qCDebug(dcApplication()) << "Timeout:" << timeout; qCDebug(dcApplication()) << "Timeout:" << timeout;
if (mode == Core::ModeButton)
qCDebug(dcApplication()) << "Button GPIO:" << buttonGpio;
// Start core // Start core
Core::instance()->setMode(mode); Core::instance()->setMode(mode);
Core::instance()->setAdvertisingTimeout(timeout); Core::instance()->setAdvertisingTimeout(timeout);
Core::instance()->setAdvertiseName(advertiseName); Core::instance()->setAdvertiseName(advertiseName);
Core::instance()->setPlatformName(platformName); Core::instance()->setPlatformName(platformName);
Core::instance()->setButtonGpio(buttonGpio);
Core::instance()->run(); Core::instance()->run();

View File

@ -9,7 +9,7 @@ CONFIG += console link_pkgconfig
CONFIG -= app_bundle CONFIG -= app_bundle
TEMPLATE = app TEMPLATE = app
PKGCONFIG += nymea-networkmanager PKGCONFIG += nymea-networkmanager nymea-gpio
HEADERS += \ HEADERS += \
application.h \ application.h \