added a plugin to detect wifi devices in range

This commit is contained in:
Michael Zanetti 2014-01-06 17:22:36 +01:00
parent 9e3f55ab21
commit 822f63861a
21 changed files with 283 additions and 32 deletions

View File

@ -4,4 +4,3 @@ SUBDIRS += libhive server plugins
server.depends = libhive plugins
plugins.depends = libhive

View File

@ -1,5 +1,7 @@
#include "device.h"
#include <QDebug>
Device::Device(const QUuid &pluginId, const QUuid &id, const QUuid &deviceClassId, QObject *parent):
QObject(parent),
m_id(id),
@ -75,12 +77,16 @@ QVariant Device::stateValue(const QUuid &stateTypeId) const
void Device::setStateValue(const QUuid &stateTypeId, const QVariant &value)
{
qDebug() << "setting state for id" << stateTypeId;
for (int i = 0; i < m_states.count(); ++i) {
qDebug() << "got state id" << m_states.at(i).stateTypeId();
if (m_states.at(i).stateTypeId() == stateTypeId) {
State newState(stateTypeId, m_id);
newState.setValue(value);
m_states[i] = newState;
qDebug() << "set state for device" << value;
return;
}
}
qDebug() << "failed setting state" << value;
}

View File

@ -15,13 +15,15 @@
Q_IMPORT_PLUGIN(DevicePluginElro)
Q_IMPORT_PLUGIN(DevicePluginIntertechno)
Q_IMPORT_PLUGIN(DevicePluginMeisterAnker)
Q_IMPORT_PLUGIN(DevicePluginWifiDetector)
DeviceManager::DeviceManager(QObject *parent) :
QObject(parent)
QObject(parent),
m_radio433(0)
{
m_radio433 = new Radio433(this);
connect(m_radio433, &Radio433::dataReceived, this, &DeviceManager::radio433SignalReceived);
m_pluginTimer.setInterval(15000);
connect(&m_pluginTimer, &QTimer::timeout, this, &DeviceManager::timerEvent);
QMetaObject::invokeMethod(this, "loadPlugins", Qt::QueuedConnection);
QMetaObject::invokeMethod(this, "loadConfiguredDevices", Qt::QueuedConnection);
@ -66,7 +68,12 @@ DeviceManager::DeviceError DeviceManager::addConfiguredDevice(const QUuid &devic
Device *device = new Device(plugin->pluginId(), deviceClassId, this);
device->setName(deviceClass.name());
device->setParams(params);
m_configuredDevices.append(device);
if (setupDevice(device)) {
m_configuredDevices.append(device);
} else {
qWarning() << "Failed to set up device.";
return DeviceErrorSetupFailed;
}
storeConfiguredDevices();
@ -160,6 +167,9 @@ void DeviceManager::loadConfiguredDevices()
device->setName(settings.value("devicename").toString());
device->setParams(settings.value("params").toMap());
settings.endGroup();
setupDevice(device);
m_configuredDevices.append(device);
qDebug() << "found stored device" << device->name() << idString;
}
@ -183,8 +193,50 @@ void DeviceManager::radio433SignalReceived(QList<int> rawData)
foreach (Device *device, m_configuredDevices) {
DeviceClass deviceClass = m_supportedDevices.value(device->deviceClassId());
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
if (plugin->requiredHardware() == HardwareResourceRadio433) {
plugin->receiveData(rawData);
if (plugin->requiredHardware().testFlag(HardwareResourceRadio433)) {
plugin->radioData(rawData);
}
}
}
void DeviceManager::timerEvent()
{
foreach (Device *device, m_configuredDevices) {
DeviceClass deviceClass = m_supportedDevices.value(device->deviceClassId());
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
if (plugin->requiredHardware().testFlag(HardwareResourceTimer)) {
plugin->hiveTimer();
}
}
}
bool DeviceManager::setupDevice(Device *device)
{
DeviceClass deviceClass = findDeviceClass(device->deviceClassId());
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
QList<State> states;
foreach (const StateType &stateType, deviceClass.states()) {
State state(stateType.id(), device->id());
state.setValue(stateType.defaultValue());
states.append(state);
}
device->setStates(states);
if (plugin->requiredHardware().testFlag(HardwareResourceRadio433)) {
if (!m_radio433) {
m_radio433 = new Radio433();
connect(m_radio433, &Radio433::dataReceived, this, &DeviceManager::radio433SignalReceived);
}
}
if (plugin->requiredHardware().testFlag(HardwareResourceTimer)) {
if (!m_pluginTimer.isActive()) {
m_pluginTimer.start();
// Additionally fire off one event to initialize stuff
QTimer::singleShot(0, this, SLOT(timerEvent()));
}
}
return true;
}

View File

@ -6,6 +6,7 @@
#include "action.h"
#include <QObject>
#include <QTimer>
class Device;
class DevicePlugin;
@ -16,16 +17,20 @@ class DeviceManager : public QObject
Q_OBJECT
public:
enum HardwareResource {
HardwareResourceNone = 0x00,
HardwareResourceRadio433 = 0x01,
HardwareResourceRadio868 = 0x02
HardwareResourceRadio868 = 0x02,
HardwareResourceTimer = 0x04
};
Q_DECLARE_FLAGS(HardwareResources, HardwareResource)
enum DeviceError {
DeviceErrorNoError,
DeviceErrorDeviceNotFound,
DeviceErrorDeviceClassNotFound,
DeviceErrorMissingParameter,
DeviceErrorPluginNotFound
DeviceErrorPluginNotFound,
DeviceErrorSetupFailed
};
explicit DeviceManager(QObject *parent = 0);
@ -54,16 +59,22 @@ private slots:
void storeConfiguredDevices();
void radio433SignalReceived(QList<int> rawData);
void timerEvent();
private:
bool setupDevice(Device *device);
QHash<QUuid, DeviceClass> m_supportedDevices;
QList<Device*> m_configuredDevices;
QHash<QUuid, DevicePlugin*> m_devicePlugins;
// Hardware Resources
Radio433* m_radio433;
QTimer m_pluginTimer;
friend class DevicePlugin;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(DeviceManager::HardwareResources)
#endif // DEVICEMANAGER_H

View File

@ -26,16 +26,18 @@ public:
virtual QUuid pluginId() const = 0;
virtual QList<DeviceClass> supportedDevices() const = 0;
virtual DeviceManager::HardwareResource requiredHardware() const = 0;
virtual DeviceManager::HardwareResources requiredHardware() const = 0;
// Hardware input
virtual void receiveData(QList<int> rawData) = 0;
virtual void radioData(QList<int> rawData) {Q_UNUSED(rawData)}
virtual void hiveTimer() {}
virtual QVariantMap configuration() const;
virtual void setConfiguration(const QVariantMap &configuration);
public slots:
virtual void executeAction(Device *device, const Action &action) = 0;
virtual void executeAction(Device *device, const Action &action) {Q_UNUSED(device) Q_UNUSED(action)}
signals:
void emitTrigger(const Trigger &trigger);

View File

@ -29,3 +29,13 @@ void StateType::setType(const QVariant::Type &type)
{
m_type = type;
}
QVariant StateType::defaultValue() const
{
return m_defaultValue;
}
void StateType::setDefaultValue(const QVariant &defaultValue)
{
m_defaultValue = defaultValue;
}

View File

@ -17,10 +17,14 @@ public:
QVariant::Type type() const;
void setType(const QVariant::Type &type);
QVariant defaultValue() const;
void setDefaultValue(const QVariant &defaultValue);
private:
QUuid m_id;
QString m_name;
QVariant::Type m_type;
QVariant m_defaultValue;
};
#endif // STATETYPE_H

View File

@ -139,7 +139,7 @@ QList<DeviceClass> DevicePluginElro::supportedDevices() const
return ret;
}
DeviceManager::HardwareResource DevicePluginElro::requiredHardware() const
DeviceManager::HardwareResources DevicePluginElro::requiredHardware() const
{
return DeviceManager::HardwareResourceRadio433;
}
@ -249,7 +249,7 @@ void DevicePluginElro::executeAction(Device *device, const Action &action)
transmitData(rawData);
}
void DevicePluginElro::receiveData(QList<int> rawData)
void DevicePluginElro::radioData(QList<int> rawData)
{
// filter right here a wrong signal length
if(rawData.length() != 49){

View File

@ -14,12 +14,12 @@ public:
explicit DevicePluginElro();
QList<DeviceClass> supportedDevices() const override;
DeviceManager::HardwareResource requiredHardware() const override;
DeviceManager::HardwareResources requiredHardware() const override;
QString pluginName() const;
QUuid pluginId() const;
QString pluginName() const override;
QUuid pluginId() const override;
void receiveData(QList<int> rawData);
void radioData(QList<int> rawData) override;
public slots:
void executeAction(Device *device, const Action &action) override;

View File

@ -176,7 +176,7 @@ QList<DeviceClass> DevicePluginIntertechno::supportedDevices() const
return ret;
}
DeviceManager::HardwareResource DevicePluginIntertechno::requiredHardware() const
DeviceManager::HardwareResources DevicePluginIntertechno::requiredHardware() const
{
return DeviceManager::HardwareResourceRadio433;
}
@ -315,7 +315,7 @@ void DevicePluginIntertechno::executeAction(Device *device, const Action &action
}
void DevicePluginIntertechno::receiveData(QList<int> rawData)
void DevicePluginIntertechno::radioData(QList<int> rawData)
{

View File

@ -14,12 +14,12 @@ public:
explicit DevicePluginIntertechno();
QList<DeviceClass> supportedDevices() const override;
DeviceManager::HardwareResource requiredHardware() const override;
DeviceManager::HardwareResources requiredHardware() const override;
QString pluginName() const;
QUuid pluginId() const;
QString pluginName() const override;
QUuid pluginId() const override;
void receiveData(QList<int> rawData);
void radioData(QList<int> rawData) override;
public slots:
void executeAction(Device *device, const Action &action) override;

View File

@ -83,7 +83,7 @@ QList<DeviceClass> DevicePluginMeisterAnker::supportedDevices() const
return ret;
}
DeviceManager::HardwareResource DevicePluginMeisterAnker::requiredHardware() const
DeviceManager::HardwareResources DevicePluginMeisterAnker::requiredHardware() const
{
return DeviceManager::HardwareResourceRadio433;
}
@ -103,7 +103,7 @@ void DevicePluginMeisterAnker::executeAction(Device *device, const Action &actio
}
void DevicePluginMeisterAnker::receiveData(QList<int> rawData)
void DevicePluginMeisterAnker::radioData(QList<int> rawData)
{
// filter right here a wrong signal length
if(rawData.length() != 49){

View File

@ -15,12 +15,12 @@ public:
explicit DevicePluginMeisterAnker();
QList<DeviceClass> supportedDevices() const override;
DeviceManager::HardwareResource requiredHardware() const override;
DeviceManager::HardwareResources requiredHardware() const override;
QString pluginName() const;
QUuid pluginId() const;
QString pluginName() const override;
QUuid pluginId() const override;
void receiveData(QList<int> rawData);
void radioData(QList<int> rawData) override;
public slots:
void executeAction(Device *device, const Action &action) override;

View File

@ -1,3 +1,3 @@
TEMPLATE = subdirs
SUBDIRS += devicepluginelro devicepluginintertechno devicepluginmeisteranker
SUBDIRS += devicepluginelro devicepluginintertechno devicepluginmeisteranker devicepluginwifidetector

View File

@ -0,0 +1,118 @@
#include "devicepluginwifidetector.h"
#include "device.h"
#include "devicemanager.h"
#include <QDebug>
#include <QStringList>
QUuid pluginUuid = QUuid("8e0f791e-b273-4267-8605-b7c2f55a68ab");
QUuid detectorId = QUuid("bd216356-f1ec-4324-9785-6982d2174e17");
QUuid inRangeStateTypeId = QUuid("cb43e1b5-4f61-4538-bfa2-c33055c542cf");
QUuid inRangeTriggerTypeId = QUuid("7cae711a-a0af-41b4-b3bf-38d3e23b41ba");
DevicePluginWifiDetector::DevicePluginWifiDetector()
{
}
QList<DeviceClass> DevicePluginWifiDetector::supportedDevices() const
{
QList<DeviceClass> ret;
DeviceClass deviceClassWifiDetector(pluginId(), detectorId);
deviceClassWifiDetector.setName("WiFi Device");
QVariantList detectorParams;
QVariantMap macParam;
macParam.insert("name", "mac");
macParam.insert("type", "string");
detectorParams.append(macParam);
deviceClassWifiDetector.setParams(detectorParams);
QList<StateType> detectorStates;
StateType inRangeState(inRangeStateTypeId);
inRangeState.setName("inRange");
inRangeState.setType(QVariant::Bool);
inRangeState.setDefaultValue(false);
detectorStates.append(inRangeState);
deviceClassWifiDetector.setStates(detectorStates);
QList<TriggerType> detectorTriggers;
QVariantList detectorTriggerParams;
QVariantMap paramInRange;
paramInRange.insert("name", "inRange");
paramInRange.insert("type", "bool");
detectorTriggerParams.append(paramInRange);
TriggerType inRangeTrigger(inRangeTriggerTypeId);
inRangeTrigger.setName("inRange");
inRangeTrigger.setParameters(detectorTriggerParams);
detectorTriggers.append(inRangeTrigger);
deviceClassWifiDetector.setTriggers(detectorTriggers);
ret.append(deviceClassWifiDetector);
return ret;
}
DeviceManager::HardwareResources DevicePluginWifiDetector::requiredHardware() const
{
return DeviceManager::HardwareResourceTimer;
}
QString DevicePluginWifiDetector::pluginName() const
{
return "WiFi Detector";
}
QUuid DevicePluginWifiDetector::pluginId() const
{
return pluginUuid;
}
void DevicePluginWifiDetector::hiveTimer()
{
QProcess *p = new QProcess(this);
connect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(processFinished(int,QProcess::ExitStatus)));
p->start(QStringLiteral("arp-scan"), QStringList() << "--localnet" << "-I" << "eth2" );
}
void DevicePluginWifiDetector::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
QProcess *p = static_cast<QProcess*>(sender());
p->deleteLater();
QList<Device*> watchedDevices = deviceManager()->findConfiguredDevices(supportedDevices().first().id());
if (watchedDevices.isEmpty()) {
return;
}
QStringList foundDevices;
while(p->canReadLine()) {
QString result = QString::fromLatin1(p->readLine());
QStringList lineParts = result.split('\t');
if (lineParts.count() > 1) {
QString addr = lineParts.at(1);
foundDevices << addr;
}
}
foreach (Device *device, watchedDevices) {
bool wasInRange = device->stateValue(inRangeStateTypeId).toBool();
bool wasFound = foundDevices.contains(device->params().value("mac").toString());
if (wasInRange != wasFound) {
device->setStateValue(inRangeStateTypeId, wasFound);
QVariantMap params;
params.insert("inRange", wasFound);
Trigger trigger(inRangeTriggerTypeId, device->id(), params);
qDebug() << "Device" << device->name() << QStringLiteral("is now ") + (wasFound ? "in" : "out of") + " range";
emit emitTrigger(trigger);
}
}
}

View File

@ -0,0 +1,30 @@
#ifndef DEVICEPLUGINWIFIDETECTOR_H
#define DEVICEPLUGINWIFIDETECTOR_H
#include "deviceplugin.h"
#include <QProcess>
class DevicePluginWifiDetector : public DevicePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.hiveyourhome.DevicePlugin" FILE "devicepluginwifidetector.json")
Q_INTERFACES(DevicePlugin)
public:
explicit DevicePluginWifiDetector();
QList<DeviceClass> supportedDevices() const override;
DeviceManager::HardwareResources requiredHardware() const override;
QString pluginName() const override;
QUuid pluginId() const override;
void hiveTimer() override;
private slots:
void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
};
#endif // DEVICEPLUGINWIFIDETECTOR_H

View File

@ -0,0 +1,11 @@
include(../../plugins.pri)
TARGET = $$qtLibraryTarget(hive_devicepluginwifidetector)
SOURCES += \
devicepluginwifidetector.cpp
HEADERS += \
devicepluginwifidetector.h

View File

@ -105,6 +105,9 @@ void JsonRPCServer::handleDevicesMessage(int clientId, int commandId, const QStr
case DeviceManager::DeviceErrorMissingParameter:
sendErrorResponse(clientId, commandId, "Error creating device. Missing parameter.");
break;
case DeviceManager::DeviceErrorSetupFailed:
sendErrorResponse(clientId, commandId, "Error creating device. Device setup failed.");
break;
default:
sendErrorResponse(clientId, commandId, "Unknown error.");
}

View File

@ -28,3 +28,4 @@ HEADERS += hivecore.h \
LIBS += -L../plugins/deviceplugins/devicepluginelro/ -lhive_devicepluginelro
LIBS += -L../plugins/deviceplugins/devicepluginintertechno/ -lhive_devicepluginintertechno
LIBS += -L../plugins/deviceplugins/devicepluginmeisteranker/ -lhive_devicepluginmeisteranker
LIBS += -L../plugins/deviceplugins/devicepluginwifidetector/ -lhive_devicepluginwifidetector

View File

@ -4,7 +4,7 @@
if [ -z $1 ]; then
echo "usage $0 host device"
elif [ $1 == "list" ]; then
echo "elroremote elroswitch intertechnoremote meisteranker"
echo "elroremote elroswitch intertechnoremote meisteranker wifidetector"
elif [ -z $2 ]; then
echo "usage $0 host device"
else
@ -20,5 +20,8 @@ else
elif [ $2 == "meisteranker" ]; then
# Adds an intertechno remote control
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClass": "{e37e9f34-95b9-4a22-ae4f-e8b874eec871}","params":{"id":"1"}}}'; sleep 1) | nc $1 1234
elif [ $2 == "wifidetector" ]; then
# Adds a WiFi detector
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClass": "{bd216356-f1ec-4324-9785-6982d2174e17}","params":{"mac":"90:cf:15:1b:ce:bb"}}}'; sleep 1) | nc $1 1234
fi
fi