rework how auto devices are created

also updated plugins to work with new api
This commit is contained in:
Michael Zanetti 2014-06-24 00:16:29 +02:00
parent 1c00b4c3f9
commit ac77fc669c
13 changed files with 135 additions and 92 deletions

View File

@ -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::DeviceError, QString> 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<Device*> 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<DeviceSetupStatus, QString> 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<DeviceDescriptor> &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<DeviceSetupStatus, QString> 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<Device*>(sender());

View File

@ -108,10 +108,11 @@ private slots:
void loadPlugins();
void loadConfiguredDevices();
void storeConfiguredDevices();
void createNewAutoDevices();
void startMonitoringAutoDevices();
void slotDevicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> 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<DeviceDescriptor> &deviceDescriptors);
// Only connect this to Devices. It will query the sender()
void slotDeviceStateValueChanged(const QUuid &stateTypeId, const QVariant &value);

View File

@ -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<Device*> 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.

View File

@ -49,7 +49,7 @@ public:
virtual QList<DeviceClass> supportedDevices() const = 0;
virtual DeviceManager::HardwareResources requiredHardware() const = 0;
virtual bool configureAutoDevice(QList<Device *> loadedDevices, Device *device) const;
virtual void startMonitoringAutoDevices();
virtual DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const QList<Param> &params) const;
virtual QPair<DeviceManager::DeviceSetupStatus, QString> setupDevice(Device *device);

View File

@ -89,23 +89,35 @@ DeviceManager::HardwareResources DevicePluginBoblight::requiredHardware() const
return DeviceManager::HardwareResourceNone;
}
bool DevicePluginBoblight::configureAutoDevice(QList<Device *> 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<Device*> loadedDevices = deviceManager()->findConfiguredDevices(boblightDeviceClassId);
QList<DeviceDescriptor> deviceDescriptorList;
for (int i = loadedDevices.count(); i < m_bobClient->lightsCount(); i++) {
DeviceDescriptor deviceDescriptor(boblightDeviceClassId, "Boblight Channel " + QString::number(i));
QList<Param> 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<DeviceManager::DeviceSetupStatus, QString> 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

View File

@ -39,7 +39,8 @@ public:
QList<DeviceClass> supportedDevices() const override;
DeviceManager::HardwareResources requiredHardware() const override;
bool configureAutoDevice(QList<Device *> loadedDevices, Device *device) const override;
void startMonitoringAutoDevices() override;
QPair<DeviceManager::DeviceSetupStatus, QString> setupDevice(Device *device) override;
QString pluginName() const override;
PluginId pluginId() const override;

View File

@ -257,21 +257,19 @@ void DevicePluginMock::deviceRemoved(Device *device)
delete m_daemons.take(device);
}
bool DevicePluginMock::configureAutoDevice(QList<Device *> 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<Param> params;
Param param("httpport", 4242);
params.append(param);
device->setParams(params);
return true;
mockDescriptor.setParams(params);
QList<DeviceDescriptor> deviceDescriptorList;
deviceDescriptorList.append(mockDescriptor);
emit autoDevicesAppeared(mockDeviceAutoClassId, deviceDescriptorList);
}
QList<ParamType> DevicePluginMock::configurationDescription() const

View File

@ -47,7 +47,7 @@ public:
QPair<DeviceManager::DeviceSetupStatus, QString> setupDevice(Device *device) override;
void deviceRemoved(Device *device) override;
bool configureAutoDevice(QList<Device *> loadedDevices, Device *device) const override;
void startMonitoringAutoDevices() override;
QList<ParamType> configurationDescription() const override;

View File

@ -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<DeviceClass> 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<Device *> 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<Param> 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<DeviceManager::DeviceSetupStatus, QString> 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<DeviceDescriptor> descriptorList;
while (!m_unconfiguredLights.isEmpty()) {
Light *light = m_unconfiguredLights.takeFirst();
DeviceDescriptor descriptor(hueDeviceClassAutoId, light->name());
QList<Param> 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<DeviceDescriptor>, descriptorList));
}
return reportDeviceSetup(DeviceManager::DeviceSetupStatusAsync);
}
@ -296,10 +315,10 @@ void DevicePluginPhilipsHue::getLightsFinished(int id, const QVariant &params)
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 &params)

View File

@ -40,7 +40,7 @@ public:
QList<DeviceClass> supportedDevices() const override;
DeviceManager::HardwareResources requiredHardware() const override;
bool configureAutoDevice(QList<Device *> loadedDevices, Device *device) const override;
void startMonitoringAutoDevices() override;
QString pluginName() const override;
PluginId pluginId() const override;

View File

@ -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;

View File

@ -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;

View File

@ -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