diff --git a/libguh/devicemanager.cpp b/libguh/devicemanager.cpp index d216c9f2..2e18a947 100644 --- a/libguh/devicemanager.cpp +++ b/libguh/devicemanager.cpp @@ -106,7 +106,7 @@ DeviceManager::DeviceManager(QObject *parent) : // Give hardware a chance to start up before loading plugins etc. QMetaObject::invokeMethod(this, "loadPlugins", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "loadConfiguredDevices", Qt::QueuedConnection); - QMetaObject::invokeMethod(this, "createNewAutoDevices", Qt::QueuedConnection); + QMetaObject::invokeMethod(this, "startMonitoringAutoDevices", Qt::QueuedConnection); // Make sure this is always emitted after plugins and devices are loaded QMetaObject::invokeMethod(this, "loaded", Qt::QueuedConnection); } @@ -149,7 +149,6 @@ QPair DeviceManager::setPluginConfig(const } settings.endGroup(); settings.endGroup(); - createNewAutoDevices(); return result; } @@ -540,6 +539,7 @@ void DeviceManager::loadPlugins() connect(pluginIface, &DevicePlugin::deviceSetupFinished, this, &DeviceManager::slotDeviceSetupFinished); connect(pluginIface, &DevicePlugin::actionExecutionFinished, this, &DeviceManager::actionExecutionFinished); connect(pluginIface, &DevicePlugin::pairingFinished, this, &DeviceManager::slotPairingFinished); + connect(pluginIface, &DevicePlugin::autoDevicesAppeared, this, &DeviceManager::autoDevicesAppeared); } } } @@ -595,36 +595,10 @@ void DeviceManager::storeConfiguredDevices() settings.endGroup(); } -void DeviceManager::createNewAutoDevices() +void DeviceManager::startMonitoringAutoDevices() { - bool haveNewDevice = false; - foreach (const DeviceClass &deviceClass, m_supportedDevices) { - if (deviceClass.createMethod() != DeviceClass::CreateMethodAuto) { - continue; - } - - qDebug() << "found auto device class" << deviceClass.name(); - DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId()); - bool success = false; - do { - QList loadedDevices = findConfiguredDevices(deviceClass.id()); - Device *device = new Device(plugin->pluginId(), DeviceId::createDeviceId(), deviceClass.id()); - success = plugin->configureAutoDevice(loadedDevices, device); - if (success) { - qDebug() << "New device detected for" << deviceClass.name() << device->name(); - haveNewDevice = true; - - // We'll always add auto devices, even if setup fails in order to keep track of them. - QPair setupStatus = setupDevice(device); - m_configuredDevices.append(device); - } else { - qDebug() << "No newly detected devices for" << deviceClass.name(); - delete device; - } - } while (success); - } - if (haveNewDevice) { - storeConfiguredDevices(); + foreach (DevicePlugin *plugin, m_devicePlugins) { + plugin->startMonitoringAutoDevices(); } } @@ -770,6 +744,41 @@ void DeviceManager::slotPairingFinished(const QUuid &pairingTransactionId, Devic emit deviceSetupFinished(device, DeviceError::DeviceErrorNoError, QString()); } +void DeviceManager::autoDevicesAppeared(const DeviceClassId &deviceClassId, const QList &deviceDescriptors) +{ + DeviceClass deviceClass = findDeviceClass(deviceClassId); + if (!deviceClass.isValid()) { + return; + } + DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId()); + if (!plugin) { + return; + } + + foreach (const DeviceDescriptor &deviceDescriptor, deviceDescriptors) { + Device *device = new Device(plugin->pluginId(), deviceClassId, this); + device->setName(deviceClass.name()); + device->setParams(deviceDescriptor.params()); + + QPair setupStatus = setupDevice(device); + switch (setupStatus.first) { + case DeviceSetupStatusFailure: + qWarning() << "Device setup failed. Not adding device to system."; + emit deviceSetupFinished(device, DeviceError::DeviceErrorSetupFailed, QString("Device setup failed: %1").arg(setupStatus.second)); + delete device; + break; + case DeviceSetupStatusAsync: + break; + case DeviceSetupStatusSuccess: + qDebug() << "Device setup complete."; + emit deviceSetupFinished(device, DeviceError::DeviceErrorNoError, QString()); + m_configuredDevices.append(device); + storeConfiguredDevices(); + break; + } + } +} + void DeviceManager::slotDeviceStateValueChanged(const QUuid &stateTypeId, const QVariant &value) { Device *device = qobject_cast(sender()); diff --git a/libguh/devicemanager.h b/libguh/devicemanager.h index e09a7ef5..78e00f42 100644 --- a/libguh/devicemanager.h +++ b/libguh/devicemanager.h @@ -108,10 +108,11 @@ private slots: void loadPlugins(); void loadConfiguredDevices(); void storeConfiguredDevices(); - void createNewAutoDevices(); + void startMonitoringAutoDevices(); void slotDevicesDiscovered(const DeviceClassId &deviceClassId, const QList deviceDescriptors); void slotDeviceSetupFinished(Device *device, DeviceManager::DeviceSetupStatus status, const QString &errorMessage); void slotPairingFinished(const QUuid &pairingTransactionId, DeviceManager::DeviceSetupStatus status, const QString &errorMessage); + void autoDevicesAppeared(const DeviceClassId &deviceClassId, const QList &deviceDescriptors); // Only connect this to Devices. It will query the sender() void slotDeviceStateValueChanged(const QUuid &stateTypeId, const QVariant &value); diff --git a/libguh/plugin/deviceplugin.cpp b/libguh/plugin/deviceplugin.cpp index 8e1aa195..f749bc60 100644 --- a/libguh/plugin/deviceplugin.cpp +++ b/libguh/plugin/deviceplugin.cpp @@ -127,24 +127,14 @@ DevicePlugin::~DevicePlugin() /*! Override this if your plugin supports Device with DeviceClass::CreationMethodAuto. This will be called at startup, after the configured devices have been loaded. - You should walk through loadedDevices and check whether all the detected devices - are contained in there. If all the detected devices are already contained, return - false. If instead you've found a new device which isn't known to the system yet, - fill in the parameters of the passed device with some details that makes it possible - for you to match this Device object with the detected hardware. After that, return true. - The DeviceManager will then insert the device into its database and call setupDevice() - for this device. Therefore you should not do any hardware initialisation in this state yet - but rather wait for the subsequent setupDevice() call to set it up like in any other - case where Device can be created. - Returning false will cause the passed device object to be destroyed. - If you have detected multiple new devices, just load them one by one. The DeviceManager - will continue to call this method until you return false. + This is the earliest time you should start emitting autoDevicesAppeared(). If you + are monitoring some hardware/service for devices to appear, start monitoring now. + If you are building the devices based on a static list, you may emit + autoDevicesAppeard() in here. */ -bool DevicePlugin::configureAutoDevice(QList loadedDevices, Device *device) const +void DevicePlugin::startMonitoringAutoDevices() { - Q_UNUSED(loadedDevices) - Q_UNUSED(device) - return false; + } /*! Reimplement this if you support a DeviceClass with createMethod CreateMethodDiscovery. diff --git a/libguh/plugin/deviceplugin.h b/libguh/plugin/deviceplugin.h index 1d2367a9..a5860dc0 100644 --- a/libguh/plugin/deviceplugin.h +++ b/libguh/plugin/deviceplugin.h @@ -49,7 +49,7 @@ public: virtual QList supportedDevices() const = 0; virtual DeviceManager::HardwareResources requiredHardware() const = 0; - virtual bool configureAutoDevice(QList loadedDevices, Device *device) const; + virtual void startMonitoringAutoDevices(); virtual DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const QList ¶ms) const; virtual QPair setupDevice(Device *device); diff --git a/plugins/deviceplugins/boblight/devicepluginboblight.cpp b/plugins/deviceplugins/boblight/devicepluginboblight.cpp index 9f6c8186..02de49f3 100644 --- a/plugins/deviceplugins/boblight/devicepluginboblight.cpp +++ b/plugins/deviceplugins/boblight/devicepluginboblight.cpp @@ -89,23 +89,35 @@ DeviceManager::HardwareResources DevicePluginBoblight::requiredHardware() const return DeviceManager::HardwareResourceNone; } -bool DevicePluginBoblight::configureAutoDevice(QList loadedDevices, Device *device) const +void DevicePluginBoblight::startMonitoringAutoDevices() { if (!m_bobClient->connected()) { - return false; + return; } - if (loadedDevices.count() < m_bobClient->lightsCount()) { - int index = loadedDevices.count(); - device->setName("Boblight Channel " + QString::number(index)); + + QList loadedDevices = deviceManager()->findConfiguredDevices(boblightDeviceClassId); + + QList deviceDescriptorList; + for (int i = loadedDevices.count(); i < m_bobClient->lightsCount(); i++) { + DeviceDescriptor deviceDescriptor(boblightDeviceClassId, "Boblight Channel " + QString::number(i)); QList params; Param param("channel"); - param.setValue(index); + param.setValue(i); params.append(param); - device->setParams(params); - device->setStateValue(colorStateTypeId, m_bobClient->currentColor(index)); - return true; + deviceDescriptor.setParams(params); + deviceDescriptorList.append(deviceDescriptor); } - return false; + emit autoDevicesAppeared(boblightDeviceClassId, deviceDescriptorList); +} + +QPair DevicePluginBoblight::setupDevice(Device *device) +{ + if (!m_bobClient->connected()) { + return reportDeviceSetup(DeviceManager::DeviceSetupStatusFailure, "Cannot connect to Boblight"); + } + + m_bobClient->currentColor(device->paramValue("channel").toInt()); + return reportDeviceSetup(); } QString DevicePluginBoblight::pluginName() const diff --git a/plugins/deviceplugins/boblight/devicepluginboblight.h b/plugins/deviceplugins/boblight/devicepluginboblight.h index 2e89cfac..3025e9fb 100644 --- a/plugins/deviceplugins/boblight/devicepluginboblight.h +++ b/plugins/deviceplugins/boblight/devicepluginboblight.h @@ -39,7 +39,8 @@ public: QList supportedDevices() const override; DeviceManager::HardwareResources requiredHardware() const override; - bool configureAutoDevice(QList loadedDevices, Device *device) const override; + void startMonitoringAutoDevices() override; + QPair setupDevice(Device *device) override; QString pluginName() const override; PluginId pluginId() const override; diff --git a/plugins/deviceplugins/mock/devicepluginmock.cpp b/plugins/deviceplugins/mock/devicepluginmock.cpp index 0be48622..d41a10e5 100644 --- a/plugins/deviceplugins/mock/devicepluginmock.cpp +++ b/plugins/deviceplugins/mock/devicepluginmock.cpp @@ -257,21 +257,19 @@ void DevicePluginMock::deviceRemoved(Device *device) delete m_daemons.take(device); } -bool DevicePluginMock::configureAutoDevice(QList loadedDevices, Device *device) const +void DevicePluginMock::startMonitoringAutoDevices() { - Q_ASSERT(device->deviceClassId() == mockDeviceAutoClassId); + DeviceDescriptor mockDescriptor(mockDeviceAutoClassId, "Mock Device (Auto created)"); - // We only want to have one auto mock device. So if there's already anything in loadedDevices, don't crearte a new one. - if (loadedDevices.count() > 0) { - return false; - } - - device->setName("Mock Device (Auto created)"); QList params; Param param("httpport", 4242); params.append(param); - device->setParams(params); - return true; + mockDescriptor.setParams(params); + + QList deviceDescriptorList; + deviceDescriptorList.append(mockDescriptor); + + emit autoDevicesAppeared(mockDeviceAutoClassId, deviceDescriptorList); } QList DevicePluginMock::configurationDescription() const diff --git a/plugins/deviceplugins/mock/devicepluginmock.h b/plugins/deviceplugins/mock/devicepluginmock.h index 0d21843c..e7fe37c5 100644 --- a/plugins/deviceplugins/mock/devicepluginmock.h +++ b/plugins/deviceplugins/mock/devicepluginmock.h @@ -47,7 +47,7 @@ public: QPair setupDevice(Device *device) override; void deviceRemoved(Device *device) override; - bool configureAutoDevice(QList loadedDevices, Device *device) const override; + void startMonitoringAutoDevices() override; QList configurationDescription() const override; diff --git a/plugins/deviceplugins/philipshue/devicepluginphilipshue.cpp b/plugins/deviceplugins/philipshue/devicepluginphilipshue.cpp index cfa25146..53ea460f 100644 --- a/plugins/deviceplugins/philipshue/devicepluginphilipshue.cpp +++ b/plugins/deviceplugins/philipshue/devicepluginphilipshue.cpp @@ -31,6 +31,7 @@ VendorId hueVendorId = VendorId("0ae1e001-2aa6-47ed-b8c0-334c3728a68f"); PluginId huePluginUuid = PluginId("5f2e634b-b7f3-48ee-976a-b5ae22aa5c55"); DeviceClassId hueDeviceClassId = DeviceClassId("d8f4c397-e05e-47c1-8917-8e72d4d0d47c"); +DeviceClassId hueDeviceClassAutoId = DeviceClassId("9cce5981-50a1-4873-a374-c53c095feb3b"); StateTypeId hueColorStateTypeId = StateTypeId("d25423e7-b924-4b20-80b6-77eecc65d089"); ActionTypeId hueSetColorActionTypeId = ActionTypeId("29cc299a-818b-47b2-817f-c5a6361545e4"); @@ -114,6 +115,20 @@ QList DevicePluginPhilipsHue::supportedDevices() const ret.append(deviceClassHue); + // Now create the same device again with CreateMethodAuto + // When we pair a bridge, one discovered device is created. + // The other light bulbs connected to the bridge will + // then appear as auto devices. + DeviceClass deviceClassHueAuto(pluginId(), hueVendorId, hueDeviceClassAutoId); + deviceClassHueAuto.setName("Hue"); + deviceClassHueAuto.setCreateMethod(DeviceClass::CreateMethodAuto); + deviceClassHueAuto.setParamTypes(paramTypes); + deviceClassHueAuto.setStateTypes(hueStates); + deviceClassHueAuto.setActions(hueActons); + + ret.append(deviceClassHueAuto); + + return ret; } @@ -122,23 +137,10 @@ DeviceManager::HardwareResources DevicePluginPhilipsHue::requiredHardware() cons return DeviceManager::HardwareResourceNone; } -bool DevicePluginPhilipsHue::configureAutoDevice(QList loadedDevices, Device *device) const +void DevicePluginPhilipsHue::startMonitoringAutoDevices() { -// if (!m_bobClient->connected()) { -// return false; -// } -// if (loadedDevices.count() < m_bobClient->lightsCount()) { -// int index = loadedDevices.count(); -// device->setName("Boblight Channel " + QString::number(index)); -// QList params; -// Param param("channel"); -// param.setValue(index); -// params.append(param); -// device->setParams(params); -// device->setStateValue(colorStateTypeId, m_bobClient->currentColor(index)); -// return true; -// } - return false; + // TODO: We could call the bridge to discover new light bulbs here maybe? + // Although we maybe want to think of a user triggered approach to do such things. } QString DevicePluginPhilipsHue::pluginName() const @@ -189,6 +191,23 @@ QPair DevicePluginPhilipsHue::setupDe m_lights.insert(light, device); m_asyncSetups.insert(light, device); + // If we have more unconfigured lights around, lets add them as auto devices + QList descriptorList; + while (!m_unconfiguredLights.isEmpty()) { + Light *light = m_unconfiguredLights.takeFirst(); + DeviceDescriptor descriptor(hueDeviceClassAutoId, light->name()); + QList params; + params.append(Param("number", light->id())); + params.append(Param("ip", light->ip().toString())); + params.append(Param("username", light->username())); + descriptor.setParams(params); + descriptorList.append(descriptor); + } + if (!descriptorList.isEmpty()) { + qDebug() << "adding" << descriptorList.count() << "autodevices"; + metaObject()->invokeMethod(this, "autoDevicesAppeared", Qt::QueuedConnection, Q_ARG(DeviceClassId, hueDeviceClassAutoId), Q_ARG(QList, descriptorList)); + } + return reportDeviceSetup(DeviceManager::DeviceSetupStatusAsync); } @@ -296,10 +315,10 @@ void DevicePluginPhilipsHue::getLightsFinished(int id, const QVariant ¶ms) emit pairingFinished(pairingInfo.pairingTransactionId, DeviceManager::DeviceSetupStatusSuccess, QString()); -// // If we have more than one device on that bridge, tell DeviceManager that there are more. -// if (params.count() > 1) { + // If we have more than one device on that bridge, tell DeviceManager that there are more. + if (params.toMap().count() > 1) { // emit autoDevicesAppeared(); -// } + } } void DevicePluginPhilipsHue::getFinished(int id, const QVariant ¶ms) diff --git a/plugins/deviceplugins/philipshue/devicepluginphilipshue.h b/plugins/deviceplugins/philipshue/devicepluginphilipshue.h index 56bf00ea..b13e0f69 100644 --- a/plugins/deviceplugins/philipshue/devicepluginphilipshue.h +++ b/plugins/deviceplugins/philipshue/devicepluginphilipshue.h @@ -40,7 +40,7 @@ public: QList supportedDevices() const override; DeviceManager::HardwareResources requiredHardware() const override; - bool configureAutoDevice(QList loadedDevices, Device *device) const override; + void startMonitoringAutoDevices() override; QString pluginName() const override; PluginId pluginId() const override; diff --git a/plugins/deviceplugins/philipshue/light.cpp b/plugins/deviceplugins/philipshue/light.cpp index a0eaa108..e9d0b6e3 100644 --- a/plugins/deviceplugins/philipshue/light.cpp +++ b/plugins/deviceplugins/philipshue/light.cpp @@ -40,6 +40,16 @@ Light::Light(const QHostAddress &ip, const QString &username, int id, QObject *p { } +QHostAddress Light::ip() const +{ + return m_ip; +} + +QString Light::username() const +{ + return m_username; +} + int Light::id() const { return m_id; diff --git a/plugins/deviceplugins/philipshue/light.h b/plugins/deviceplugins/philipshue/light.h index 1a1999bf..fa7b18a0 100644 --- a/plugins/deviceplugins/philipshue/light.h +++ b/plugins/deviceplugins/philipshue/light.h @@ -39,6 +39,9 @@ public: Light(const QHostAddress &ip, const QString &username, int id, QObject *parent = 0); + QHostAddress ip() const; + QString username() const; + int id() const; QString name() const; diff --git a/tests/scripts/cmdmgr.py b/tests/scripts/cmdmgr.py index 7415ed60..384403db 100755 --- a/tests/scripts/cmdmgr.py +++ b/tests/scripts/cmdmgr.py @@ -165,7 +165,7 @@ def discover_device(deviceClassId = None): params = {} params['deviceClassId'] = deviceClassId - discoveryParams = read_params(deviceClass['paramTypes']) + discoveryParams = read_params(deviceClass['discoveryParamTypes']) if len(discoveryParams) > 0: params['discoveryParams'] = discoveryParams