diff --git a/libnymea-networkmanager/networkmanager.cpp b/libnymea-networkmanager/networkmanager.cpp index 9a8fcce..6c2795b 100644 --- a/libnymea-networkmanager/networkmanager.cpp +++ b/libnymea-networkmanager/networkmanager.cpp @@ -30,6 +30,10 @@ NetworkManager::NetworkManager(QObject *parent) : QObject(parent) { + // Get notification when network-manager appears/disappears on DBus + m_serviceWatcher = new QDBusServiceWatcher(NetworkManagerUtils::networkManagerServiceString(), QDBusConnection::systemBus(), QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration, this); + connect(m_serviceWatcher, &QDBusServiceWatcher::serviceRegistered, this, &NetworkManager::onServiceRegistered); + connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &NetworkManager::onServiceUnregistered); } @@ -229,6 +233,83 @@ bool NetworkManager::enableWireless(bool enabled) return m_networkManagerInterface->setProperty("WirelessEnabled", enabled); } +bool NetworkManager::init() +{ + if (!m_enabled) + return false; + + qCDebug(dcNetworkManager()) << "Initialize network manager"; + // Check DBus connection + if (!QDBusConnection::systemBus().isConnected()) { + qCWarning(dcNetworkManager()) << "System DBus not connected. NetworkManagre not available."; + setAvailable(false); + return false; + } + + // Create interface + m_networkManagerInterface = new QDBusInterface(NetworkManagerUtils::networkManagerServiceString(), NetworkManagerUtils::networkManagerPathString(), NetworkManagerUtils::networkManagerServiceString(), QDBusConnection::systemBus(), this); + if(!m_networkManagerInterface->isValid()) { + qCWarning(dcNetworkManager()) << "Invalid DBus network manager interface. NetworkManagre not available."; + m_networkManagerInterface->deleteLater(); + m_networkManagerInterface = nullptr; + setAvailable(false); + return false; + } + + // Init properties + setVersion(m_networkManagerInterface->property("Version").toString()); + setState((NetworkManagerState)m_networkManagerInterface->property("State").toUInt()); + setConnectivityState((NetworkManagerConnectivityState)m_networkManagerInterface->property("Connectivity").toUInt()); + setNetworkingEnabled(m_networkManagerInterface->property("NetworkingEnabled").toBool()); + setWirelessEnabled(m_networkManagerInterface->property("WirelessEnabled").toBool()); + + // Load network devices + loadDevices(); + + // Create settings + m_networkSettings = new NetworkSettings(this); + + // Connect signals + QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), NetworkManagerUtils::networkManagerPathString(), NetworkManagerUtils::networkManagerServiceString(), "StateChanged", this, SLOT(onStateChanged(uint))); + QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), NetworkManagerUtils::networkManagerPathString(), NetworkManagerUtils::networkManagerServiceString(), "DeviceAdded", this, SLOT(onDeviceAdded(QDBusObjectPath))); + QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), NetworkManagerUtils::networkManagerPathString(), NetworkManagerUtils::networkManagerServiceString(), "DeviceRemoved", this, SLOT(onDeviceRemoved(QDBusObjectPath))); + QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), NetworkManagerUtils::networkManagerPathString(), NetworkManagerUtils::networkManagerServiceString(), "PropertiesChanged", this, SLOT(onPropertiesChanged(QVariantMap))); + + setAvailable(true); + qCDebug(dcNetworkManager()) << "Network manager initialized successfully."; + + return true; +} + +void NetworkManager::deinit() +{ + foreach (NetworkDevice *device, m_networkDevices) { + onDeviceRemoved(device->objectPath()); + } + + m_wiredNetworkDevices.clear(); + m_wirelessNetworkDevices.clear(); + + if (m_networkSettings) { + delete m_networkSettings; + m_networkSettings = nullptr; + } + + if (m_networkManagerInterface) { + delete m_networkManagerInterface; + m_networkManagerInterface = nullptr; + } + + setVersion(QString()); + setState(NetworkManagerStateUnknown); + setConnectivityState(NetworkManagerConnectivityStateUnknown); + setNetworkingEnabled(false); + setWirelessEnabled(false); + setAvailable(false); + + qCDebug(dcNetworkManager()) << "Netowkmanager deinitialized successfully."; +} + void NetworkManager::loadDevices() { // Get network devices @@ -271,7 +352,7 @@ void NetworkManager::setAvailable(bool available) if (m_available == available) return; - qCDebug(dcNetworkManager()) << "Service is now" << (available ? "available" : "unavailable"); + qCDebug(dcNetworkManager()) << "The network manager is now" << (available ? "available" : "unavailable"); m_available = available; emit availableChanged(m_available); } @@ -319,13 +400,13 @@ void NetworkManager::setState(const NetworkManager::NetworkManagerState &state) void NetworkManager::onServiceRegistered() { qCDebug(dcNetworkManager()) << "DBus service registered and available."; - // TODO: init stuff + init(); } void NetworkManager::onServiceUnregistered() { qCWarning(dcNetworkManager()) << "DBus service unregistered."; - // TODO: deinit stuff + deinit(); } void NetworkManager::onDeviceAdded(const QDBusObjectPath &deviceObjectPath) @@ -432,84 +513,29 @@ void NetworkManager::onWiredDeviceChanged() bool NetworkManager::start() { - // Get notification when network-manager appears/disappears on DBus - m_serviceWatcher = new QDBusServiceWatcher(NetworkManagerUtils::networkManagerServiceString(), QDBusConnection::systemBus(), QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration, this); - connect(m_serviceWatcher, &QDBusServiceWatcher::serviceRegistered, this, &NetworkManager::onServiceRegistered); - connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &NetworkManager::onServiceUnregistered); + // We want the networkmanager to run, so enable it + m_enabled = true; - // Check DBus connection - if (!QDBusConnection::systemBus().isConnected()) { - qCWarning(dcNetworkManager()) << "System DBus not connected. NetworkManagre not available."; - m_serviceWatcher->deleteLater(); - m_serviceWatcher = nullptr; - return false; + qCDebug(dcNetworkManager()) << "Start the network manager."; + if (m_available) { + qCDebug(dcNetworkManager()) << "Networkmanager already running."; + return true; } - // Create interface - m_networkManagerInterface = new QDBusInterface(NetworkManagerUtils::networkManagerServiceString(), NetworkManagerUtils::networkManagerPathString(), NetworkManagerUtils::networkManagerServiceString(), QDBusConnection::systemBus(), this); - if(!m_networkManagerInterface->isValid()) { - qCWarning(dcNetworkManager()) << "Invalid DBus network manager interface. NetworkManagre not available."; - m_serviceWatcher->deleteLater(); - m_serviceWatcher = nullptr; - - m_networkManagerInterface->deleteLater(); - m_networkManagerInterface = nullptr; - return false; - } - - // Init properties - setVersion(m_networkManagerInterface->property("Version").toString()); - setState((NetworkManagerState)m_networkManagerInterface->property("State").toUInt()); - setConnectivityState((NetworkManagerConnectivityState)m_networkManagerInterface->property("Connectivity").toUInt()); - setNetworkingEnabled(m_networkManagerInterface->property("NetworkingEnabled").toBool()); - setWirelessEnabled(m_networkManagerInterface->property("WirelessEnabled").toBool()); - - // Load network devices - loadDevices(); - - // Create settings - m_networkSettings = new NetworkSettings(this); - - // Connect signals - QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), NetworkManagerUtils::networkManagerPathString(), NetworkManagerUtils::networkManagerServiceString(), "StateChanged", this, SLOT(onStateChanged(uint))); - QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), NetworkManagerUtils::networkManagerPathString(), NetworkManagerUtils::networkManagerServiceString(), "DeviceAdded", this, SLOT(onDeviceAdded(QDBusObjectPath))); - QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), NetworkManagerUtils::networkManagerPathString(), NetworkManagerUtils::networkManagerServiceString(), "DeviceRemoved", this, SLOT(onDeviceRemoved(QDBusObjectPath))); - QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), NetworkManagerUtils::networkManagerPathString(), NetworkManagerUtils::networkManagerServiceString(), "PropertiesChanged", this, SLOT(onPropertiesChanged(QVariantMap))); - - setAvailable(true); - return true; + return init(); } void NetworkManager::stop() { - foreach (NetworkDevice *device, m_networkDevices) { - onDeviceRemoved(device->objectPath()); + // We want the networkmanager to stop, so disable it + m_enabled = false; + + qCDebug(dcNetworkManager()) << "Stop the network manager."; + if (!m_available) { + qCDebug(dcNetworkManager()) << "Networkmanager already stopped."; + return; } - m_wiredNetworkDevices.clear(); - m_wirelessNetworkDevices.clear(); - - if (m_networkSettings) { - delete m_networkSettings; - m_networkSettings = nullptr; - } - - if (m_networkManagerInterface) { - delete m_networkManagerInterface; - m_networkManagerInterface = nullptr; - } - - if (m_serviceWatcher) { - delete m_serviceWatcher; - m_serviceWatcher = nullptr; - } - - m_version = QString(); - m_state = NetworkManagerStateUnknown; - m_connectivityState = NetworkManagerConnectivityStateUnknown; - m_networkingEnabled = false; - m_wirelessEnabled = false; - - setAvailable(false); + deinit(); } diff --git a/libnymea-networkmanager/networkmanager.h b/libnymea-networkmanager/networkmanager.h index 351f698..12e336f 100644 --- a/libnymea-networkmanager/networkmanager.h +++ b/libnymea-networkmanager/networkmanager.h @@ -118,12 +118,17 @@ private: QHash m_wiredNetworkDevices; bool m_available = false; + bool m_enabled = false; + QString m_version; NetworkManagerState m_state = NetworkManagerStateUnknown; NetworkManagerConnectivityState m_connectivityState = NetworkManagerConnectivityStateUnknown; bool m_networkingEnabled = false; bool m_wirelessEnabled = false; + bool init(); + void deinit(); + void loadDevices(); static QString networkManagerStateToString(const NetworkManagerState &state); diff --git a/nymea-networkmanager/bluetooth/bluetoothserver.cpp b/nymea-networkmanager/bluetooth/bluetoothserver.cpp index 147fff8..da6fd1e 100644 --- a/nymea-networkmanager/bluetooth/bluetoothserver.cpp +++ b/nymea-networkmanager/bluetooth/bluetoothserver.cpp @@ -342,7 +342,7 @@ void BluetoothServer::serviceError(const QLowEnergyService::ServiceError &error) qCWarning(dcBluetoothServer()) << "Service error:" << errorString; } -void BluetoothServer::start(WirelessNetworkDevice *wirelessDevice) +void BluetoothServer::start() { // Check if a user is connected if (connected()) { @@ -391,26 +391,7 @@ void BluetoothServer::start(WirelessNetworkDevice *wirelessDevice) // Create services m_networkService = new NetworkService(m_controller->addService(NetworkService::serviceData(), m_controller), m_controller); - m_wirelessService = new WirelessService(m_controller->addService(WirelessService::serviceData(), m_controller), wirelessDevice, m_controller); - - startAdvertising(); -} - -void BluetoothServer::restartServer() -{ - qCDebug(dcBluetoothServer()) << "-------------------------------------"; - qCDebug(dcBluetoothServer()) << "Restart bluetooth server"; - qCDebug(dcBluetoothServer()) << "-------------------------------------"; - - if (!m_controller || !m_localDevice) { - qCWarning(dcBluetoothServer()) << "Could not restart server. There is no controller object or local device object."; - return; - } - - if (m_controller->state() == QLowEnergyController::AdvertisingState) { - qCDebug(dcBluetoothServer()) << "Stop advertising;"; - m_controller->stopAdvertising(); - } + m_wirelessService = new WirelessService(m_controller->addService(WirelessService::serviceData(), m_controller), m_controller); startAdvertising(); } @@ -421,10 +402,23 @@ void BluetoothServer::stop() m_controller->disconnectFromDevice(); } + if (!m_running) + return; + qCDebug(dcBluetoothServer()) << "-------------------------------------"; qCDebug(dcBluetoothServer()) << "Stopping bluetooth server."; qCDebug(dcBluetoothServer()) << "-------------------------------------"; + if (m_networkService) { + m_networkService->deleteLater(); + m_networkService = nullptr; + } + + if (m_wirelessService) { + m_wirelessService->deleteLater(); + m_wirelessService = nullptr; + } + if (m_controller) { qCDebug(dcBluetoothServer()) << "Stop advertising."; m_controller->stopAdvertising(); @@ -435,10 +429,11 @@ void BluetoothServer::stop() if (m_localDevice) { qCDebug(dcBluetoothServer()) << "Set host mode to connectable."; m_localDevice->setHostMode(QBluetoothLocalDevice::HostConnectable); - delete m_localDevice; + m_localDevice->deleteLater(); m_localDevice = nullptr; } + setConnected(false); setRunning(false); } @@ -467,3 +462,15 @@ void BluetoothServer::onNetworkManagerStateChanged(const NetworkManager::Network m_networkService->setNetworkManagerState(state); } +void BluetoothServer::onWirelessDeviceBitRateChanged(int bitRate) +{ + if (m_wirelessService) + m_wirelessService->onWirelessDeviceBitRateChanged(bitRate); +} + +void BluetoothServer::onWirelessDeviceStateChanged(const NetworkDevice::NetworkDeviceState state) +{ + if (m_wirelessService) + m_wirelessService->onWirelessDeviceStateChanged(state); +} + diff --git a/nymea-networkmanager/bluetooth/bluetoothserver.h b/nymea-networkmanager/bluetooth/bluetoothserver.h index d7e8501..06750b3 100644 --- a/nymea-networkmanager/bluetooth/bluetoothserver.h +++ b/nymea-networkmanager/bluetooth/bluetoothserver.h @@ -109,8 +109,7 @@ private slots: void serviceError(const QLowEnergyService::ServiceError &error); public slots: - void start(WirelessNetworkDevice *wirelessDevice); - void restartServer(); + void start(); void stop(); // Network manager @@ -119,6 +118,10 @@ public slots: void onWirelessNetworkingEnabledChanged(bool enabled); void onNetworkManagerStateChanged(const NetworkManager::NetworkManagerState &state); + // Wireless device + void onWirelessDeviceBitRateChanged(int bitRate); + void onWirelessDeviceStateChanged(const NetworkDevice::NetworkDeviceState state); + }; #endif // BLUETOOTHSERVER_H diff --git a/nymea-networkmanager/bluetooth/wirelessservice.cpp b/nymea-networkmanager/bluetooth/wirelessservice.cpp index a0f480e..4549b22 100644 --- a/nymea-networkmanager/bluetooth/wirelessservice.cpp +++ b/nymea-networkmanager/bluetooth/wirelessservice.cpp @@ -30,10 +30,9 @@ #include #include -WirelessService::WirelessService(QLowEnergyService *service, WirelessNetworkDevice *wirelessDevice, QObject *parent) : +WirelessService::WirelessService(QLowEnergyService *service, QObject *parent) : QObject(parent), m_service(service), - m_device(wirelessDevice), m_readingInputData(false) { qCDebug(dcBluetoothServer()) << "Create WirelessService."; @@ -44,10 +43,6 @@ WirelessService::WirelessService(QLowEnergyService *service, WirelessNetworkDevi connect(m_service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic, QByteArray)), this, SLOT(characteristicWritten(QLowEnergyCharacteristic, QByteArray))); connect(m_service, SIGNAL(descriptorWritten(QLowEnergyDescriptor, QByteArray)), this, SLOT(descriptorWritten(QLowEnergyDescriptor, QByteArray))); connect(m_service, SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(serviceError(QLowEnergyService::ServiceError))); - - qCDebug(dcBluetoothServer()) << "WirelessService: Using" << m_device; - connect(m_device, &WirelessNetworkDevice::bitRateChanged, this, &WirelessService::onWirelessDeviceBitRateChanged); - connect(m_device, &WirelessNetworkDevice::stateChanged, this, &WirelessService::onWirelessDeviceStateChanged); } QLowEnergyService *WirelessService::service() @@ -99,7 +94,7 @@ WirelessService::WirelessServiceResponse WirelessService::checkWirelessErrors() return WirelessServiceResponseNetworkManagerNotAvailable; } - if (!m_device) { + if (!Core::instance()->networkManager()->wirelessAvailable()) { qCWarning(dcBluetoothServer()) << "WirelessService: There is no wireless device available."; return WirelessServiceResponseWirelessNotAvailable; } @@ -203,7 +198,7 @@ void WirelessService::commandGetNetworks(const QVariantMap &request) } QVariantList accessPointVariantList; - foreach (WirelessAccessPoint *accessPoint, m_device->accessPoints()) { + foreach (WirelessAccessPoint *accessPoint, Core::instance()->networkManager()->wirelessNetworkDevices().first()->accessPoints()) { QVariantMap accessPointVariantMap; accessPointVariantMap.insert("e", accessPoint->ssid()); accessPointVariantMap.insert("m", accessPoint->macAddress()); @@ -244,7 +239,7 @@ void WirelessService::commandConnect(const QVariantMap &request) return; } - Core::instance()->networkManager()->connectWifi(m_device->interface(), parameters.value("e").toString(), parameters.value("p").toString()); + Core::instance()->networkManager()->connectWifi(Core::instance()->networkManager()->wirelessNetworkDevices().first()->interface(), parameters.value("e").toString(), parameters.value("p").toString()); streamData(createResponse(WirelessServiceCommandConnect)); } @@ -260,7 +255,7 @@ void WirelessService::commandDisconnect(const QVariantMap &request) Q_UNUSED(request) if (!m_service) { - qCWarning(dcBluetoothServer()) << "WirelessService: Could not stream wireless network list. Service not valid"; + qCWarning(dcBluetoothServer()) << "WirelessService: Service not valid"; return; } @@ -270,7 +265,7 @@ void WirelessService::commandDisconnect(const QVariantMap &request) return; } - m_device->disconnectDevice(); + Core::instance()->networkManager()->wirelessNetworkDevices().first()->disconnectDevice(); streamData(createResponse(WirelessServiceCommandDisconnect)); } @@ -278,8 +273,10 @@ void WirelessService::commandScan(const QVariantMap &request) { Q_UNUSED(request) + qCDebug(dcBluetoothServer()) << "WirelessService: Execute command scan."; + if (!m_service) { - qCWarning(dcBluetoothServer()) << "WirelessService: Could not stream wireless network list. Service not valid"; + qCWarning(dcBluetoothServer()) << "WirelessService: Could scan wireless networks. Service not valid"; return; } @@ -289,16 +286,17 @@ void WirelessService::commandScan(const QVariantMap &request) return; } - m_device->scanWirelessNetworks(); + Core::instance()->networkManager()->wirelessNetworkDevices().first()->scanWirelessNetworks(); streamData(createResponse(WirelessServiceCommandScan)); } void WirelessService::commandGetCurrentConnection(const QVariantMap &request) { Q_UNUSED(request) + qCDebug(dcBluetoothServer()) << "WirelessService: Execute get current connection."; if (!m_service) { - qCWarning(dcBluetoothServer()) << "WirelessService: Could not stream wireless network list. Service not valid"; + qCWarning(dcBluetoothServer()) << "WirelessService: Service not valid"; return; } @@ -308,10 +306,12 @@ void WirelessService::commandGetCurrentConnection(const QVariantMap &request) return; } + WirelessNetworkDevice *device = Core::instance()->networkManager()->wirelessNetworkDevices().first(); + QVariantMap connectionDataMap; - QNetworkInterface wifiInterface = QNetworkInterface::interfaceFromName(m_device->interface()); - if (!m_device->activeAccessPoint() || !wifiInterface.isValid() || wifiInterface.addressEntries().isEmpty()) { - qCDebug(dcBluetoothServer()) << "There is currently no access active accesspoint"; + QNetworkInterface wifiInterface = QNetworkInterface::interfaceFromName(device->interface()); + if (!device->activeAccessPoint() || !wifiInterface.isValid() || wifiInterface.addressEntries().isEmpty()) { + qCDebug(dcBluetoothServer()) << "WirelessService: There is currently no access active accesspoint"; connectionDataMap.insert("e", ""); connectionDataMap.insert("m", ""); connectionDataMap.insert("s", 0); @@ -319,11 +319,11 @@ void WirelessService::commandGetCurrentConnection(const QVariantMap &request) connectionDataMap.insert("i", ""); } else { QHostAddress address = wifiInterface.addressEntries().first().ip(); - qCDebug(dcBluetoothServer()) << "Current connection:" << m_device->activeAccessPoint() << address.toString(); - connectionDataMap.insert("e", m_device->activeAccessPoint()->ssid()); - connectionDataMap.insert("m", m_device->activeAccessPoint()->macAddress()); - connectionDataMap.insert("s", m_device->activeAccessPoint()->signalStrength()); - connectionDataMap.insert("p", (int)m_device->activeAccessPoint()->isProtected()); + qCDebug(dcBluetoothServer()) << "WirelessService: Current connection:" << device->activeAccessPoint() << address.toString(); + connectionDataMap.insert("e", device->activeAccessPoint()->ssid()); + connectionDataMap.insert("m", device->activeAccessPoint()->macAddress()); + connectionDataMap.insert("s", device->activeAccessPoint()->signalStrength()); + connectionDataMap.insert("p", (int)device->activeAccessPoint()->isProtected()); connectionDataMap.insert("i", address.toString()); } @@ -483,8 +483,6 @@ void WirelessService::onWirelessDeviceBitRateChanged(const int &bitRate) void WirelessService::onWirelessDeviceStateChanged(const NetworkDevice::NetworkDeviceState &state) { - qCDebug(dcBluetoothServer()) << "WirelessService: Wireless network device state changed" << state; - if (!m_service) { qCWarning(dcBluetoothServer()) << "WirelessService: Could not update wireless network device state. Service not valid"; return; @@ -496,5 +494,6 @@ void WirelessService::onWirelessDeviceStateChanged(const NetworkDevice::NetworkD return; } + qCDebug(dcBluetoothServer()) << "WirelessService: Notify wireless state changed" << WirelessService::getWirelessNetworkDeviceState(state); m_service->writeCharacteristic(characteristic, WirelessService::getWirelessNetworkDeviceState(state)); } diff --git a/nymea-networkmanager/bluetooth/wirelessservice.h b/nymea-networkmanager/bluetooth/wirelessservice.h index 25648cf..d2ba966 100644 --- a/nymea-networkmanager/bluetooth/wirelessservice.h +++ b/nymea-networkmanager/bluetooth/wirelessservice.h @@ -61,7 +61,7 @@ public: }; Q_ENUM(WirelessServiceResponse) - explicit WirelessService(QLowEnergyService *service, WirelessNetworkDevice *wirelessDevice, QObject *parent = 0); + explicit WirelessService(QLowEnergyService *service, QObject *parent = 0); QLowEnergyService *service(); @@ -69,7 +69,6 @@ public: private: QLowEnergyService *m_service = nullptr; - WirelessNetworkDevice *m_device = nullptr; bool m_readingInputData = false; QByteArray m_inputDataStream; @@ -104,6 +103,7 @@ private slots: // Commands void processCommand(const QVariantMap &request); +public slots: // Wireless network device void onWirelessDeviceBitRateChanged(const int &bitRate); void onWirelessDeviceStateChanged(const NetworkDevice::NetworkDeviceState &state); diff --git a/nymea-networkmanager/core.cpp b/nymea-networkmanager/core.cpp index 1c92df8..8c79461 100644 --- a/nymea-networkmanager/core.cpp +++ b/nymea-networkmanager/core.cpp @@ -22,6 +22,8 @@ #include "core.h" #include "loggingcategories.h" +#include + Core* Core::s_instance = nullptr; Core *Core::instance() @@ -55,6 +57,16 @@ NymeadService *Core::nymeaService() const return m_nymeaService; } +Core::Mode Core::mode() const +{ + return m_mode; +} + +void Core::setMode(const Core::Mode &mode) +{ + m_mode = mode; +} + QString Core::advertiseName() const { return m_advertiseName; @@ -75,6 +87,16 @@ void Core::setPlatformName(const QString &name) m_platformName = name; } +int Core::advertisingTimeout() const +{ + return m_advertisingTimeout; +} + +void Core::setAdvertisingTimeout(const int advertisingTimeout) +{ + m_advertisingTimeout = advertisingTimeout; +} + bool Core::testingEnabled() const { return m_testing; @@ -87,12 +109,29 @@ void Core::setTestingEnabled(bool testing) void Core::run() { - // Start the networkmanager service - if (!m_networkManager->available()) { - m_networkManager->start(); - } else { - evaluateNetworkManagerState(m_networkManager->state()); + // Start the networkmanager + if (!m_networkManager->start()) { + qCWarning(dcApplication()) << "Could not start network manager. Please make sure the networkmanager is available."; + return; } + + switch (m_mode) { + case ModeAlways: + qCDebug(dcApplication()) << "Start the bluetooth service because of \"always\" mode."; + startService(); + break; + case ModeStart: + qCDebug(dcApplication()) << "Start the bluetooth service because of \"start\" mode."; + startService(); + m_advertisingTimer->start(m_advertisingTimeout * 1000); + break; + case ModeOffline: + evaluateNetworkManagerState(m_networkManager->state()); + break; + default: + break; + } + } Core::Core(QObject *parent) : @@ -103,6 +142,8 @@ Core::Core(QObject *parent) : connect(m_networkManager, &NetworkManager::stateChanged, this, &Core::onNetworkManagerStateChanged); connect(m_networkManager, &NetworkManager::networkingEnabledChanged, this, &Core::onNetworkManagerNetworkingEnabledChanged); connect(m_networkManager, &NetworkManager::wirelessEnabledChanged, this, &Core::onNetworkManagerWirelessEnabledChanged); + connect(m_networkManager, &NetworkManager::wirelessDeviceAdded, this, &Core::onNetworkManagerWirelessDeviceAdded); + connect(m_networkManager, &NetworkManager::wirelessDeviceRemoved, this, &Core::onNetworkManagerWirelessDeviceRemoved); m_bluetoothServer = new BluetoothServer(this); connect(m_bluetoothServer, &BluetoothServer::runningChanged, this, &Core::onBluetoothServerRunningChanged); @@ -110,6 +151,11 @@ Core::Core(QObject *parent) : m_nymeaService = new NymeadService(false, this); connect(m_nymeaService, &NymeadService::availableChanged, this, &Core::onNymeaServiceAvailableChanged); + + m_advertisingTimer = new QTimer(this); + m_advertisingTimer->setSingleShot(true); + + connect(m_advertisingTimer, &QTimer::timeout, this, &Core::onAdvertisingTimeout); } Core::~Core() @@ -128,20 +174,24 @@ Core::~Core() } void Core::evaluateNetworkManagerState(const NetworkManager::NetworkManagerState &state) -{ - if (m_testing && m_networkManager->available()) { - startService(); +{ + if (m_mode != ModeOffline) return; - } switch (state) { case NetworkManager::NetworkManagerStateConnectedGlobal: // We are online - stopService(); + if (m_bluetoothServer->running() && !m_bluetoothServer->connected()) { + qCDebug(dcApplication()) << "Stop the bluetooth service because of \"offline\" mode."; + stopService(); + } break; case NetworkManager::NetworkManagerStateConnectedSite: // We are somehow in the network - stopService(); + if (m_bluetoothServer->running() && !m_bluetoothServer->connected()) { + qCDebug(dcApplication()) << "Stop the bluetooth service because of \"offline\" mode."; + stopService(); + } break; case NetworkManager::NetworkManagerStateUnknown: @@ -149,9 +199,8 @@ void Core::evaluateNetworkManagerState(const NetworkManager::NetworkManagerState case NetworkManager::NetworkManagerStateDisconnected: case NetworkManager::NetworkManagerStateConnectedLocal: // Everything else is not connected, start the service - if (m_networkManager->available()) - startService(); - + qCDebug(dcApplication()) << "Start the bluetooth service because of \"offline\" mode."; + startService(); break; default: qCDebug(dcApplication()) << "Ignoring networkmanager state" << state; @@ -172,9 +221,6 @@ void Core::startService() return; } - if (m_bluetoothServer->running()) - return; - qCDebug(dcApplication()) << "Start service"; // Disable bluetooth on nymea in order to not crash with client connections @@ -184,21 +230,26 @@ void Core::startService() qCDebug(dcApplication()) << "Start bluetooth service"; m_bluetoothServer->setAdvertiseName(m_advertiseName); m_bluetoothServer->setMachineId(m_platformName); - m_bluetoothServer->start(m_networkManager->wirelessNetworkDevices().first()); + m_bluetoothServer->start(); } void Core::stopService() { - if (m_testing) { - return; - } - if (m_bluetoothServer->running()) qCDebug(dcApplication()) << "Stop bluetooth service"; m_bluetoothServer->stop(); } +void Core::onAdvertisingTimeout() +{ + if (m_mode != ModeStart) + return; + + qCDebug(dcApplication()) << "Advertising timeout. Shutting down the bluetooth server."; + stopService(); +} + void Core::onBluetoothServerRunningChanged(bool running) { qCDebug(dcApplication()) << "Bluetooth server" << (running ? "started" : "stopped"); @@ -206,6 +257,21 @@ void Core::onBluetoothServerRunningChanged(bool running) if (!running) { // Enable bluetooth on nymea m_nymeaService->enableBluetooth(true); + m_advertisingTimer->stop(); + + switch (m_mode) { + case ModeAlways: + qCDebug(dcApplication()) << "Restart the bluetooth service because of \"always\" mode."; + startService(); + break; + case ModeStart: + break; + case ModeOffline: + evaluateNetworkManagerState(m_networkManager->state()); + break; + default: + break; + } } } @@ -213,13 +279,15 @@ void Core::onBluetoothServerConnectedChanged(bool connected) { qCDebug(dcApplication()) << "Bluetooth client" << (connected ? "connected" : "disconnected"); if (connected) { + m_advertisingTimer->stop(); + m_bluetoothServer->onNetworkManagerAvailableChanged(m_networkManager->available()); m_bluetoothServer->onNetworkManagerStateChanged(m_networkManager->state()); m_bluetoothServer->onNetworkingEnabledChanged(m_networkManager->networkingEnabled()); m_bluetoothServer->onWirelessNetworkingEnabledChanged(m_networkManager->wirelessEnabled()); } else { - // Restart bluetooth server if a client disconnected - m_bluetoothServer->restartServer(); + m_advertisingTimer->stop(); + m_bluetoothServer->stop(); } } @@ -227,13 +295,26 @@ void Core::onNetworkManagerAvailableChanged(const bool &available) { if (!available) { qCWarning(dcApplication()) << "Networkmanager is not available any more."; - stopService(); + m_bluetoothServer->onNetworkManagerAvailableChanged(m_networkManager->available()); return; } qCDebug(dcApplication()) << "Networkmanager is now available."; m_bluetoothServer->onNetworkManagerAvailableChanged(available); - evaluateNetworkManagerState(m_networkManager->state()); + + switch (m_mode) { + case ModeAlways: + qCDebug(dcApplication()) << "Start the bluetooth service because of \"always\" mode."; + startService(); + break; + case ModeStart: + break; + case ModeOffline: + evaluateNetworkManagerState(m_networkManager->state()); + break; + default: + break; + } } void Core::onNetworkManagerNetworkingEnabledChanged(bool enabled) @@ -257,10 +338,44 @@ void Core::onNetworkManagerStateChanged(const NetworkManager::NetworkManagerStat evaluateNetworkManagerState(state); } -void Core::onNymeaServiceAvailableChanged(bool available) +void Core::onNetworkManagerWirelessDeviceAdded(WirelessNetworkDevice *wirelessDevice) { - if (available && m_bluetoothServer->running()) { - // Check if the bluetooth server is running, disable nymea bt functionality in that case - m_nymeaService->enableBluetooth(false); + if (m_wirelessDevice) { + // We already have a wireless device + return; + } + + m_wirelessDevice = wirelessDevice; + connect(m_wirelessDevice, &WiredNetworkDevice::stateChanged, this, &Core::onWirelessDeviceStateChanged); +} + +void Core::onNetworkManagerWirelessDeviceRemoved(const QString &interface) +{ + if (!m_wirelessDevice) { + // Have no wireless device... + return; + } + + if (m_wirelessDevice->interface() == interface) { + disconnect(m_wirelessDevice, &WiredNetworkDevice::stateChanged, this, &Core::onWirelessDeviceStateChanged); + m_wirelessDevice = nullptr; } } + +void Core::onWirelessDeviceBitRateChanged(int bitRate) +{ + qCDebug(dcApplication()) << "Wireless device changed bitrate" << bitRate; + m_bluetoothServer->onWirelessDeviceBitRateChanged(bitRate); +} + +void Core::onWirelessDeviceStateChanged(const NetworkDevice::NetworkDeviceState state) +{ + qCDebug(dcApplication()) << state; + m_bluetoothServer->onWirelessDeviceStateChanged(state); +} + +void Core::onNymeaServiceAvailableChanged(bool available) +{ + if (available) + m_nymeaService->enableBluetooth(!m_bluetoothServer->running()); +} diff --git a/nymea-networkmanager/core.h b/nymea-networkmanager/core.h index d9d3368..a9c330e 100644 --- a/nymea-networkmanager/core.h +++ b/nymea-networkmanager/core.h @@ -32,6 +32,14 @@ class Core : public QObject { Q_OBJECT public: + + enum Mode { + ModeAlways, + ModeOffline, + ModeStart + }; + Q_ENUM(Mode) + static Core* instance(); void destroy(); @@ -39,12 +47,18 @@ public: BluetoothServer *bluetoothServer() const; NymeadService *nymeaService() const; + Mode mode() const; + void setMode(const Mode &mode); + QString advertiseName() const; void setAdvertiseName(const QString &name); QString platformName() const; void setPlatformName(const QString &name); + int advertisingTimeout() const; + void setAdvertisingTimeout(const int advertisingTimeout); + bool testingEnabled() const; void setTestingEnabled(bool testing); @@ -59,9 +73,15 @@ private: NetworkManager *m_networkManager = nullptr; BluetoothServer *m_bluetoothServer = nullptr; NymeadService *m_nymeaService = nullptr; + WirelessNetworkDevice *m_wirelessDevice = nullptr; + QTimer *m_advertisingTimer = nullptr; + + Mode m_mode = ModeOffline; QString m_advertiseName; QString m_platformName; + int m_advertisingTimeout = 60; + bool m_testing = false; void evaluateNetworkManagerState(const NetworkManager::NetworkManagerState &state); @@ -70,6 +90,8 @@ private: void stopService(); private slots: + void onAdvertisingTimeout(); + void onBluetoothServerRunningChanged(bool running); void onBluetoothServerConnectedChanged(bool connected); @@ -77,6 +99,14 @@ private slots: void onNetworkManagerNetworkingEnabledChanged(bool enabled); void onNetworkManagerWirelessEnabledChanged(bool enabled); void onNetworkManagerStateChanged(const NetworkManager::NetworkManagerState &state); + void onNetworkManagerWirelessDeviceAdded(WirelessNetworkDevice *wirelessDevice); + void onNetworkManagerWirelessDeviceRemoved(const QString &interface); + + + + // Wireless device + void onWirelessDeviceBitRateChanged(int bitRate); + void onWirelessDeviceStateChanged(const NetworkDevice::NetworkDeviceState state); void onNymeaServiceAvailableChanged(bool available); diff --git a/nymea-networkmanager/main.cpp b/nymea-networkmanager/main.cpp index 187bc5f..4ee4ca9 100644 --- a/nymea-networkmanager/main.cpp +++ b/nymea-networkmanager/main.cpp @@ -80,13 +80,14 @@ int main(int argc, char *argv[]) Application application(argc, argv); application.setApplicationName("nymea-networkmanager"); application.setOrganizationName("nymea"); - application.setApplicationVersion("0.0.3"); + application.setApplicationVersion("0.1.0"); // Command line parser 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 Simon Stürz ").arg(QChar(0xA9))); + parser.setApplicationDescription(QString("\nThis daemon allows to configure a wifi network using a bluetooth low energy connection." \ + "\n\nCopyright %1 2018 Simon Stürz ").arg(QChar(0xA9))); QCommandLineOption debugOption(QStringList() << "d" << "debug", "Enable more debug output."); parser.addOption(debugOption); @@ -99,6 +100,16 @@ int main(int argc, char *argv[]) platformNameOption.setDefaultValue("nymea-box"); parser.addOption(platformNameOption); + QCommandLineOption timeoutOption(QStringList() << "t" << "timeout", "The timeout of the bluetooth server. Minimum value is 10. Default \"60\".", "SECONDS"); + timeoutOption.setDefaultValue("60"); + parser.addOption(timeoutOption); + + QCommandLineOption modeOption(QStringList() << "m" << "mode", "Run the daemon in a specific mode. Default \"offline\".\n\n" \ + "- offline: this mode starts the bluetooth server once the device is offline and not connected to any LAN network.\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 | always | start"); + parser.addOption(modeOption); + QCommandLineOption testingOption(QStringList() << "t" << "testing", "Advertise the bluetoothserver alyways for testing."); parser.addOption(testingOption); @@ -112,17 +123,49 @@ int main(int argc, char *argv[]) QLoggingCategory::installFilter(loggingCategoryFilter); + bool timeoutValueOk = false; + int timeout = parser.value(timeoutOption).toInt(&timeoutValueOk); + + if (!timeoutValueOk) { + qCCritical(dcApplication()) << QString("Invalid timeout value passed: \"%1\". Please pass an integer >= 10").arg(parser.value(timeoutOption)); + parser.showHelp(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); + } + + Core::Mode mode = Core::ModeOffline; + + if (parser.isSet(modeOption)) { + if (parser.value(modeOption).toLower() == "offline") { + mode = Core::ModeOffline; + } else if (parser.value(modeOption).toLower() == "always") { + mode = Core::ModeAlways; + } else if (parser.value(modeOption).toLower() == "start") { + mode = Core::ModeStart; + } else { + qCWarning(dcApplication()).noquote() << QString("The given mode \"%1\" does not match the allowed modes.").arg(parser.value(modeOption)); + parser.showHelp(1); + } + } + qCDebug(dcApplication()) << "====================================="; qCDebug(dcApplication()) << "Starting nymea-networkmanager" << application.applicationVersion(); qCDebug(dcApplication()) << "====================================="; qCDebug(dcApplication()) << "Advertising name:" << parser.value(advertiseNameOption); qCDebug(dcApplication()) << "Platform name:" << parser.value(platformNameOption); - qCDebug(dcApplication()) << "Testing mode:" << (parser.isSet(testingOption) ? "enabled" : "disabled"); + qCDebug(dcApplication()) << "Mode:" << parser.value(modeOption); + qCDebug(dcApplication()) << "Timeout:" << parser.value(timeoutOption); // Start core + Core::instance()->setMode(mode); + Core::instance()->setAdvertisingTimeout(timeout); Core::instance()->setAdvertiseName(parser.value(advertiseNameOption)); Core::instance()->setPlatformName(parser.value(platformNameOption)); Core::instance()->setTestingEnabled(parser.isSet(testingOption)); + Core::instance()->run(); return application.exec();