nymea/libnymea/devices/device.cpp

463 lines
14 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015-2018 Simon Stürz <simon.stuerz@guh.io> *
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*!
\class Device
\brief A Device represents a installed and configured hardware device.
\ingroup devices
\inmodule libnymea
This class holds the values for configured devices. It is associated with a \{DeviceClass} which
can be used to get more details about the device.
\sa DeviceClass, DeviceDescriptor
*/
/*! \enum Device::DeviceError
This enum type specifies the errors that can happen when working with \l{Device}{Devices}.
\value DeviceErrorNoError
No Error. Everything went fine.
\value DeviceErrorPluginNotFound
Couldn't find the Plugin for the given id.
\value DeviceErrorVendorNotFound
Couldn't find the Vendor for the given id.
\value DeviceErrorDeviceNotFound
Couldn't find a \l{Device} for the given id.
\value DeviceErrorDeviceClassNotFound
Couldn't find a \l{DeviceClass} for the given id.
\value DeviceErrorActionTypeNotFound
Couldn't find the \l{ActionType} for the given id.
\value DeviceErrorStateTypeNotFound
Couldn't find the \l{StateType} for the given id.
\value DeviceErrorEventTypeNotFound
Couldn't find the \l{EventType} for the given id.
\value DeviceErrorDeviceDescriptorNotFound
Couldn't find the \l{DeviceDescriptor} for the given id.
\value DeviceErrorMissingParameter
Parameters do not comply to the template.
\value DeviceErrorInvalidParameter
One of the given parameter is not valid.
\value DeviceErrorSetupFailed
Error setting up the \l{Device}. It will not be functional.
\value DeviceErrorDuplicateUuid
Error setting up the \l{Device}. The given DeviceId already exists.
\value DeviceErrorCreationMethodNotSupported
Error setting up the \l{Device}. This \l{DeviceClass}{CreateMethod} is not supported for this \l{Device}.
\value DeviceErrorSetupMethodNotSupported
Error setting up the \l{Device}. This \l{DeviceClass}{SetupMethod} is not supported for this \l{Device}.
\value DeviceErrorHardwareNotAvailable
The Hardware of the \l{Device} is not available.
\value DeviceErrorHardwareFailure
The Hardware of the \l{Device} has an error.
\value DeviceErrorAsync
The response of the \l{Device} will be asynchronously.
\value DeviceErrorDeviceInUse
The \l{Device} is currently bussy.
\value DeviceErrorPairingTransactionIdNotFound
Couldn't find the PairingTransactionId for the given id.
\value DeviceErrorAuthentificationFailure
The device could not authentificate with something.
\value DeviceErrorDeviceIsChild
The device is a child device and can not be deleted directly.
\value DeviceErrorDeviceInRule
The device is in a rule and can not be deleted withou \l{nymeaserver::RuleEngine::RemovePolicy}.
\value DeviceErrorParameterNotWritable
One of the given device params is not writable.
*/
/*! \enum Device::DeviceSetupStatus
This enum type specifies the setup status of a \l{Device}.
\value DeviceSetupStatusSuccess
No Error. Everything went fine.
\value DeviceSetupStatusFailure
Something went wrong during the setup.
\value DeviceSetupStatusAsync
The status of the \l{Device} setup will be emitted asynchronous.
*/
/*! \fn void Device::stateValueChanged(const StateTypeId &stateTypeId, const QVariant &value)
This signal is emitted when the \l{State} with the given \a stateTypeId changed.
The \a value parameter describes the new value of the State.
*/
#include "device.h"
#include "deviceplugin.h"
#include "types/event.h"
#include "loggingcategories.h"
#include <QDebug>
/*! Construct an Device with the given \a pluginId, \a id, \a deviceClassId and \a parent. */
Device::Device(DevicePlugin *plugin, const DeviceClass &deviceClass, const DeviceId &id, QObject *parent):
QObject(parent),
m_deviceClass(deviceClass),
m_plugin(plugin),
m_id(id)
{
}
/*! Construct an Device with the given \a pluginId, \a deviceClassId and \a parent. A new DeviceId will be created for this Device. */
Device::Device(DevicePlugin *plugin, const DeviceClass &deviceClass, QObject *parent):
QObject(parent),
m_deviceClass(deviceClass),
m_plugin(plugin),
m_id(DeviceId::createDeviceId())
{
}
void Device::setupCompleted()
{
m_setupComplete = true;
}
/*! Returns the id of this Device. */
DeviceId Device::id() const
{
return m_id;
}
/*! Returns the deviceClassId of the associated \l{DeviceClass}. */
DeviceClassId Device::deviceClassId() const
{
return m_deviceClass.id();
}
/*! Returns the id of the \l{DevicePlugin} this Device is managed by. */
PluginId Device::pluginId() const
{
return m_plugin->pluginId();
}
/*! Returns the \l{DeviceClass} of this device. */
DeviceClass Device::deviceClass() const
{
return m_deviceClass;
}
/*! Returns the the \l{DevicePlugin} this Device is managed by. */
DevicePlugin *Device::plugin() const
{
return m_plugin;
}
/*! Returns the name of this Device. This is visible to the user. */
QString Device::name() const
{
return m_name;
}
/*! Set the \a name for this Device. This is visible to the user.*/
void Device::setName(const QString &name)
{
if (m_name != name) {
m_name = name;
emit nameChanged();
}
}
/*! Returns the parameter of this Device. It must match the parameter description in the associated \l{DeviceClass}. */
ParamList Device::params() const
{
return m_params;
}
/*! Sets the \a params of this Device. It must match the parameter description in the associated \l{DeviceClass}. */
void Device::setParams(const ParamList &params)
{
m_params = params;
}
/*! Returns the value of the \l{Param} of this Device with the given \a paramTypeId. */
QVariant Device::paramValue(const ParamTypeId &paramTypeId) const
{
foreach (const Param &param, m_params) {
if (param.paramTypeId() == paramTypeId) {
return param.value();
}
}
return QVariant();
}
/*! Sets the \a value of the \l{Param} with the given \a paramTypeId. */
void Device::setParamValue(const ParamTypeId &paramTypeId, const QVariant &value)
{
ParamList params;
foreach (Param param, m_params) {
if (param.paramTypeId() == paramTypeId) {
param.setValue(value);
}
params << param;
}
m_params = params;
}
ParamList Device::settings() const
{
return m_settings;
}
bool Device::hasSetting(const ParamTypeId &paramTypeId) const
{
return m_settings.hasParam(paramTypeId);
}
void Device::setSettings(const ParamList &settings)
{
m_settings = settings;
foreach (const Param &param, m_settings) {
emit settingChanged(param.paramTypeId(), param.value());
}
}
QVariant Device::setting(const ParamTypeId &paramTypeId) const
{
foreach (Param setting, m_settings) {
if (setting.paramTypeId() == paramTypeId) {
return setting.value();
}
}
return QVariant();
}
void Device::setSettingValue(const ParamTypeId &paramTypeId, const QVariant &value)
{
ParamList settings;
bool found = false;
bool changed = false;
foreach (Param param, m_settings) {
if (param.paramTypeId() == paramTypeId) {
found = true;
if (param.value() != value) {
param.setValue(value);
changed = true;
}
}
settings << param;
}
if (!found) {
qCWarning(dcDeviceManager()) << "Device" << m_name << "(" << m_id.toString() << ") does not have a setting with id" << paramTypeId;
return;
}
if (changed) {
m_settings = settings;
emit settingChanged(paramTypeId, value);
}
}
/*! Returns the states of this Device. It must match the \l{StateType} description in the associated \l{DeviceClass}. */
QList<State> Device::states() const
{
return m_states;
}
/*! Returns true, a \l{Param} with the given \a paramTypeId exists for this Device. */
bool Device::hasParam(const ParamTypeId &paramTypeId) const
{
return m_params.hasParam(paramTypeId);
}
/*! Set the \l{State}{States} of this \l{Device} to the given \a states.*/
void Device::setStates(const QList<State> &states)
{
m_states = states;
}
/*! Returns true, a \l{State} with the given \a stateTypeId exists for this Device. */
bool Device::hasState(const StateTypeId &stateTypeId) const
{
foreach (const State &state, m_states) {
if (state.stateTypeId() == stateTypeId) {
return true;
}
}
return false;
}
/*! For convenience, this finds the \l{State} matching the given \a stateTypeId and returns the current valie in this Device. */
QVariant Device::stateValue(const StateTypeId &stateTypeId) const
{
foreach (const State &state, m_states) {
if (state.stateTypeId() == stateTypeId) {
return state.value();
}
}
return QVariant();
}
/*! For convenience, this finds the \l{State} matching the given \a stateTypeId in this Device and sets the current value to \a value. */
void Device::setStateValue(const StateTypeId &stateTypeId, const QVariant &value)
{
for (int i = 0; i < m_states.count(); ++i) {
if (m_states.at(i).stateTypeId() == stateTypeId) {
if (m_states.at(i).value() == value)
return;
// TODO: check min/max value + possible values
// to prevent an invalid state type from the plugin side
State newState(stateTypeId, m_id);
newState.setValue(value);
m_states[i] = newState;
emit stateValueChanged(stateTypeId, value);
return;
}
}
qCWarning(dcDeviceManager) << "Failed setting state for" << m_name << value;
}
/*! Returns the \l{State} with the given \a stateTypeId of this Device. */
State Device::state(const StateTypeId &stateTypeId) const
{
for (int i = 0; i < m_states.count(); ++i) {
if (m_states.at(i).stateTypeId() == stateTypeId) {
return m_states.at(i);
}
}
return State(StateTypeId(), DeviceId());
}
/*! Returns the \l{DeviceId} of the parent Device from Device. If the parentId
is not set, this device is a parent device.
*/
DeviceId Device::parentId() const
{
return m_parentId;
}
/*! Sets the \a parentId of this Device. If the parentId
is not set, this device is a parent device.
*/
void Device::setParentId(const DeviceId &parentId)
{
m_parentId = parentId;
}
/*! Returns true, if setup of this Device is already completed. */
bool Device::setupComplete() const
{
return m_setupComplete;
}
/*! Returns true if this device has been auto-created (not created by the user) */
bool Device::autoCreated() const
{
return m_autoCreated;
}
void Device::setSetupComplete(bool complete)
{
m_setupComplete = complete;
}
Devices::Devices(const QList<Device*> &other)
{
foreach (Device* device, other) {
this->append(device);
}
}
Device *Devices::findById(const DeviceId &id)
{
foreach (Device *device, *this) {
if (device->id() == id) {
return device;
}
}
return nullptr;
}
/*! Find a certain device by its \a params. All parameters must
match or the device will not be found. Be prepared for nullptrs.
*/
Device *Devices::findByParams(const ParamList &params) const
{
foreach (Device *device, *this) {
bool matching = true;
foreach (const Param &param, params) {
if (device->paramValue(param.paramTypeId()) != param.value()) {
matching = false;
}
}
if (matching) {
return device;
}
}
return nullptr;
}
QDebug operator<<(QDebug dbg, Device *device)
{
dbg.nospace() << "Device(" << device->name();
dbg.nospace() << ", id: " << device->id().toString();
dbg.nospace() << ", deviceClassId: " << device->deviceClassId().toString() << ")";
return dbg.space();
}
/*! Filter a Devices list by a parameter. Only Devices having a parameter of the given
\a paramTypeId will be returned. If \a value is given and it is not null, only Devices
with the given \a paramTypeId and the same \a value will be returned.
*/
Devices Devices::filterByParam(const ParamTypeId &paramTypeId, const QVariant &value)
{
Devices ret;
foreach (Device* device, *this) {
if (paramTypeId != paramTypeId) {
continue;
}
if (!value.isNull() && device->paramValue(paramTypeId) != value) {
continue;
}
ret << device;
}
return ret;
}
Devices Devices::filterByDeviceClassId(const DeviceClassId &deviceClassId)
{
Devices ret;
foreach (Device* device, *this) {
if (device->deviceClassId() == deviceClassId) {
ret << device;
}
}
return ret;
}
Devices Devices::filterByParentDeviceId(const DeviceId &deviceId)
{
Devices ret;
foreach (Device *device, *this) {
if (device->parentId() == deviceId) {
ret << device;
}
}
return ret;
}