mirror of https://github.com/nymea/nymea.git
error handling for devices and deviceclasses resource
parent
e070138e4b
commit
8cd6866ffb
2
guh.pri
2
guh.pri
|
|
@ -2,7 +2,7 @@
|
|||
GUH_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"')
|
||||
|
||||
# define protocol versions
|
||||
JSON_PROTOCOL_VERSION=28
|
||||
JSON_PROTOCOL_VERSION=29
|
||||
REST_API_VERSION=1
|
||||
|
||||
DEFINES += GUH_VERSION_STRING=\\\"$${GUH_VERSION_STRING}\\\" \
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@
|
|||
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
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ public:
|
|||
enum DeviceError {
|
||||
DeviceErrorNoError,
|
||||
DeviceErrorPluginNotFound,
|
||||
DeviceErrorVendorNotFound,
|
||||
DeviceErrorDeviceNotFound,
|
||||
DeviceErrorDeviceClassNotFound,
|
||||
DeviceErrorActionTypeNotFound,
|
||||
|
|
|
|||
|
|
@ -47,12 +47,12 @@ HttpReply *DeviceClassesResource::proccessRequest(const HttpRequest &request, co
|
|||
DeviceClassId deviceClassId = DeviceClassId(urlTokens.at(3));
|
||||
if (deviceClassId.isNull()) {
|
||||
qCWarning(dcRest) << "Could not parse DeviceClassId:" << urlTokens.at(3);
|
||||
return createErrorReply(HttpReply::BadRequest);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorDeviceClassNotFound);
|
||||
}
|
||||
m_deviceClass = GuhCore::instance()->findDeviceClass(deviceClassId);
|
||||
if (!m_deviceClass.isValid()) {
|
||||
qCWarning(dcRest) << "DeviceClassId" << deviceClassId.toString() << "not found";
|
||||
return createErrorReply(HttpReply::NotFound);
|
||||
return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorDeviceClassNotFound);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ HttpReply *DeviceClassesResource::proccessGetRequest(const HttpRequest &request,
|
|||
vendorId = VendorId(request.urlQuery().queryItemValue("vendorId"));
|
||||
if (vendorId.isNull()) {
|
||||
qCWarning(dcRest) << "Could not parse VendorId:" << request.urlQuery().queryItemValue("vendorId");
|
||||
return createErrorReply(HttpReply::BadRequest);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorVendorNotFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ HttpReply *DeviceClassesResource::proccessGetRequest(const HttpRequest &request,
|
|||
ActionTypeId actionTypeId = ActionTypeId(urlTokens.at(5));
|
||||
if (actionTypeId.isNull()) {
|
||||
qCWarning(dcRest) << "Could not parse ActionTypeId:" << urlTokens.at(5);
|
||||
return createErrorReply(HttpReply::BadRequest);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorActionTypeNotFound);
|
||||
}
|
||||
return getActionType(actionTypeId);
|
||||
}
|
||||
|
|
@ -115,7 +115,7 @@ HttpReply *DeviceClassesResource::proccessGetRequest(const HttpRequest &request,
|
|||
StateTypeId stateTypeId = StateTypeId(urlTokens.at(5));
|
||||
if (stateTypeId.isNull()) {
|
||||
qCWarning(dcRest) << "Could not parse StateTypeId:" << urlTokens.at(5);
|
||||
return createErrorReply(HttpReply::BadRequest);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorStateTypeNotFound);
|
||||
}
|
||||
return getStateType(stateTypeId);
|
||||
}
|
||||
|
|
@ -129,7 +129,7 @@ HttpReply *DeviceClassesResource::proccessGetRequest(const HttpRequest &request,
|
|||
EventTypeId eventTypeId = EventTypeId(urlTokens.at(5));
|
||||
if (eventTypeId.isNull()) {
|
||||
qCWarning(dcRest) << "Could not parse EventTypeId:" << urlTokens.at(5);
|
||||
return createErrorReply(HttpReply::BadRequest);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorEventTypeNotFound);
|
||||
}
|
||||
return getEventType(eventTypeId);
|
||||
}
|
||||
|
|
@ -182,7 +182,7 @@ HttpReply *DeviceClassesResource::getActionType(const ActionTypeId &actionTypeId
|
|||
return reply;
|
||||
}
|
||||
}
|
||||
return createErrorReply(HttpReply::NotFound);
|
||||
return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorActionTypeNotFound);
|
||||
}
|
||||
|
||||
HttpReply *DeviceClassesResource::getStateTypes()
|
||||
|
|
@ -206,7 +206,7 @@ HttpReply *DeviceClassesResource::getStateType(const StateTypeId &stateTypeId)
|
|||
return reply;
|
||||
}
|
||||
}
|
||||
return createErrorReply(HttpReply::NotFound);
|
||||
return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorStateTypeNotFound);
|
||||
}
|
||||
|
||||
HttpReply *DeviceClassesResource::getEventTypes()
|
||||
|
|
@ -230,7 +230,7 @@ HttpReply *DeviceClassesResource::getEventType(const EventTypeId &eventTypeId)
|
|||
return reply;
|
||||
}
|
||||
}
|
||||
return createErrorReply(HttpReply::NotFound);
|
||||
return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorEventTypeNotFound);
|
||||
}
|
||||
|
||||
HttpReply *DeviceClassesResource::getDiscoverdDevices(const ParamList &discoveryParams)
|
||||
|
|
@ -247,7 +247,7 @@ HttpReply *DeviceClassesResource::getDiscoverdDevices(const ParamList &discovery
|
|||
}
|
||||
|
||||
if (status != DeviceManager::DeviceErrorNoError)
|
||||
return createErrorReply(HttpReply::InternalServerError);
|
||||
return createDeviceErrorReply(HttpReply::InternalServerError, status);
|
||||
|
||||
return createSuccessReply();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,12 +51,12 @@ HttpReply *DevicesResource::proccessRequest(const HttpRequest &request, const QS
|
|||
DeviceId deviceId = DeviceId(urlTokens.at(3));
|
||||
if (deviceId.isNull()) {
|
||||
qCWarning(dcRest) << "Could not parse DeviceId:" << urlTokens.at(3);
|
||||
return createErrorReply(HttpReply::BadRequest);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorDeviceNotFound);
|
||||
}
|
||||
m_device = GuhCore::instance()->findConfiguredDevice(deviceId);
|
||||
if (!m_device) {
|
||||
qCWarning(dcRest) << "Could find any device with DeviceId:" << urlTokens.at(3);
|
||||
return createErrorReply(HttpReply::NotFound);
|
||||
return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorDeviceNotFound);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,12 +106,12 @@ HttpReply *DevicesResource::proccessGetRequest(const HttpRequest &request, const
|
|||
StateTypeId stateTypeId = StateTypeId(urlTokens.at(5));
|
||||
if (stateTypeId.isNull()) {
|
||||
qCWarning(dcRest) << "Could not parse StateTypeId:" << urlTokens.at(5);
|
||||
return createErrorReply(HttpReply::BadRequest);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorStateTypeNotFound);
|
||||
}
|
||||
|
||||
if (!m_device->hasState(stateTypeId)){
|
||||
qCWarning(dcRest) << "This device has no StateTypeId:" << urlTokens.at(5);
|
||||
return createErrorReply(HttpReply::NotFound);
|
||||
return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorStateTypeNotFound);
|
||||
}
|
||||
return getDeviceStateValue(m_device, stateTypeId);
|
||||
}
|
||||
|
|
@ -172,7 +172,7 @@ HttpReply *DevicesResource::proccessPostRequest(const HttpRequest &request, cons
|
|||
ActionTypeId actionTypeId = ActionTypeId(urlTokens.at(5));
|
||||
if (actionTypeId.isNull()) {
|
||||
qCWarning(dcRest) << "Could not parse ActionTypeId:" << urlTokens.at(5);
|
||||
return createErrorReply(HttpReply::BadRequest);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorActionTypeNotFound);
|
||||
}
|
||||
bool found = false;
|
||||
DeviceClass deviceClass = GuhCore::instance()->findDeviceClass(m_device->deviceClassId());
|
||||
|
|
@ -184,7 +184,7 @@ HttpReply *DevicesResource::proccessPostRequest(const HttpRequest &request, cons
|
|||
}
|
||||
if (!found) {
|
||||
qCWarning(dcRest) << "Could not find ActionTypeId:" << actionTypeId.toString();
|
||||
return createErrorReply(HttpReply::NotFound);
|
||||
return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorActionTypeNotFound);
|
||||
}
|
||||
|
||||
return executeAction(m_device, actionTypeId, request.payload());
|
||||
|
|
@ -263,10 +263,10 @@ HttpReply *DevicesResource::removeDevice(Device *device) const
|
|||
// TODO: /api/v1/devices/{deviceId}?ruleId={ruleId}&removePolicy={RemovePolicy}
|
||||
|
||||
if (result == DeviceManager::DeviceErrorNoError) {
|
||||
HttpReply *reply = createSuccessReply();
|
||||
HttpReply *reply = createDeviceErrorReply(HttpReply::Ok, result);
|
||||
return reply;
|
||||
}
|
||||
return createErrorReply(HttpReply::Forbidden);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, result);
|
||||
}
|
||||
|
||||
HttpReply *DevicesResource::executeAction(Device *device, const ActionTypeId &actionTypeId, const QByteArray &payload) const
|
||||
|
|
@ -295,9 +295,9 @@ HttpReply *DevicesResource::executeAction(Device *device, const ActionTypeId &ac
|
|||
}
|
||||
|
||||
if (status != DeviceManager::DeviceErrorNoError)
|
||||
return createErrorReply(HttpReply::InternalServerError);
|
||||
return createDeviceErrorReply(HttpReply::InternalServerError, status);
|
||||
|
||||
return createSuccessReply();
|
||||
return createDeviceErrorReply(HttpReply::Ok, status);
|
||||
}
|
||||
|
||||
HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const
|
||||
|
|
@ -310,7 +310,7 @@ HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const
|
|||
|
||||
DeviceClassId deviceClassId(params.value("deviceClassId").toString());
|
||||
if (deviceClassId.isNull())
|
||||
return createErrorReply(HttpReply::BadRequest);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorDeviceClassNotFound);
|
||||
|
||||
DeviceId newDeviceId = DeviceId::createDeviceId();
|
||||
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
|
||||
|
|
@ -332,7 +332,7 @@ HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const
|
|||
}
|
||||
|
||||
if (status != DeviceManager::DeviceErrorNoError)
|
||||
return createErrorReply(HttpReply::InternalServerError);
|
||||
return createDeviceErrorReply(HttpReply::InternalServerError, status);
|
||||
|
||||
QVariant result = JsonTypes::packDevice(GuhCore::instance()->findConfiguredDevice(newDeviceId));
|
||||
HttpReply *reply = createSuccessReply();
|
||||
|
|
@ -354,7 +354,7 @@ HttpReply *DevicesResource::pairDevice(const QByteArray &payload) const
|
|||
|
||||
if (deviceClassId.isNull()) {
|
||||
qCWarning(dcRest) << "Could not find deviceClassId" << params.value("deviceClassId").toString();
|
||||
return createErrorReply(HttpReply::BadRequest);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorDeviceClassNotFound);
|
||||
}
|
||||
|
||||
qCDebug(dcRest) << "Pair device with deviceClassId" << deviceClassId.toString();
|
||||
|
|
@ -370,7 +370,7 @@ HttpReply *DevicesResource::pairDevice(const QByteArray &payload) const
|
|||
}
|
||||
|
||||
if (status != DeviceManager::DeviceErrorNoError)
|
||||
return createErrorReply(HttpReply::BadRequest);
|
||||
return createDeviceErrorReply(HttpReply::BadRequest, status);
|
||||
|
||||
QVariantMap returns;
|
||||
returns.insert("displayMessage", deviceClass.pairingInfo());
|
||||
|
|
@ -402,9 +402,9 @@ HttpReply *DevicesResource::confirmPairDevice(const QByteArray &payload) const
|
|||
}
|
||||
|
||||
if (status != DeviceManager::DeviceErrorNoError)
|
||||
return createErrorReply(HttpReply::InternalServerError);
|
||||
return createDeviceErrorReply(HttpReply::InternalServerError, status);
|
||||
|
||||
return createSuccessReply();
|
||||
return createDeviceErrorReply(HttpReply::Ok, DeviceManager::DeviceErrorNoError);
|
||||
}
|
||||
|
||||
HttpReply *DevicesResource::editDevice(Device *device, const QByteArray &payload) const
|
||||
|
|
@ -435,9 +435,9 @@ HttpReply *DevicesResource::editDevice(Device *device, const QByteArray &payload
|
|||
}
|
||||
|
||||
if (status != DeviceManager::DeviceErrorNoError)
|
||||
return createErrorReply(HttpReply::InternalServerError);
|
||||
return createDeviceErrorReply(HttpReply::InternalServerError, status);
|
||||
|
||||
return createSuccessReply();
|
||||
return createDeviceErrorReply(HttpReply::Ok, DeviceManager::DeviceErrorNoError);
|
||||
}
|
||||
|
||||
void DevicesResource::actionExecuted(const ActionId &actionId, DeviceManager::DeviceError status)
|
||||
|
|
@ -445,13 +445,21 @@ void DevicesResource::actionExecuted(const ActionId &actionId, DeviceManager::De
|
|||
if (!m_asyncActionExecutions.contains(actionId))
|
||||
return; // Not the action we are waiting for.
|
||||
|
||||
QVariantMap response;
|
||||
response.insert("error", JsonTypes::deviceErrorToString(status));
|
||||
|
||||
HttpReply *reply = m_asyncActionExecutions.take(actionId);
|
||||
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
|
||||
if (status == DeviceManager::DeviceErrorNoError) {
|
||||
qCDebug(dcRest) << "Action execution finished successfully";
|
||||
reply->setHttpStatusCode(HttpReply::Ok);
|
||||
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
|
||||
} else {
|
||||
qCDebug(dcRest) << "Action execution finished with error" << status;
|
||||
QVariantMap response;
|
||||
response.insert("error", JsonTypes::deviceErrorToString(status));
|
||||
reply->setHttpStatusCode(HttpReply::InternalServerError);
|
||||
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
|
||||
}
|
||||
|
||||
reply->finished();
|
||||
|
|
@ -462,13 +470,19 @@ void DevicesResource::deviceSetupFinished(Device *device, DeviceManager::DeviceE
|
|||
if (!m_asyncDeviceAdditions.contains(device->id()))
|
||||
return; // Not the device we are waiting for.
|
||||
|
||||
QVariantMap response;
|
||||
response.insert("error", JsonTypes::deviceErrorToString(status));
|
||||
|
||||
HttpReply *reply = m_asyncDeviceAdditions.take(device->id());
|
||||
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
|
||||
if (status == DeviceManager::DeviceErrorNoError) {
|
||||
qCDebug(dcRest) << "Device setup finished successfully";
|
||||
reply->setHttpStatusCode(HttpReply::Ok);
|
||||
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
|
||||
} else {
|
||||
qCDebug(dcRest) << "Device setup finished with error" << status;
|
||||
reply->setHttpStatusCode(HttpReply::InternalServerError);
|
||||
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
|
||||
}
|
||||
|
||||
QVariant result = JsonTypes::packDevice(device);
|
||||
|
|
@ -482,13 +496,19 @@ void DevicesResource::deviceEditFinished(Device *device, DeviceManager::DeviceEr
|
|||
if (!m_asyncEditDevice.contains(device))
|
||||
return; // Not the device we are waiting for.
|
||||
|
||||
QVariantMap response;
|
||||
response.insert("error", JsonTypes::deviceErrorToString(status));
|
||||
|
||||
HttpReply *reply = m_asyncEditDevice.take(device);
|
||||
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
|
||||
if (status == DeviceManager::DeviceErrorNoError) {
|
||||
qCDebug(dcRest) << "Device edit finished successfully";
|
||||
reply->setHttpStatusCode(HttpReply::Ok);
|
||||
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
|
||||
} else {
|
||||
qCDebug(dcRest) << "Device edit finished with error" << status;
|
||||
reply->setHttpStatusCode(HttpReply::InternalServerError);
|
||||
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
|
||||
}
|
||||
|
||||
reply->finished();
|
||||
|
|
@ -499,10 +519,15 @@ void DevicesResource::pairingFinished(const PairingTransactionId &pairingTransac
|
|||
if (!m_asyncPairingRequests.contains(pairingTransactionId))
|
||||
return; // Not the device pairing we are waiting for.
|
||||
|
||||
QVariantMap response;
|
||||
response.insert("error", JsonTypes::deviceErrorToString(status));
|
||||
|
||||
HttpReply *reply = m_asyncPairingRequests.take(pairingTransactionId);
|
||||
if (status != DeviceManager::DeviceErrorNoError) {
|
||||
qCDebug(dcRest) << "Pairing device finished with error.";
|
||||
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
|
||||
reply->setHttpStatusCode(HttpReply::InternalServerError);
|
||||
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
|
||||
reply->finished();
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@
|
|||
#include "restresource.h"
|
||||
#include "httprequest.h"
|
||||
#include "loggingcategories.h"
|
||||
#include "devicemanager.h"
|
||||
#include "guhcore.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
|
|
@ -105,6 +106,37 @@ HttpReply *RestResource::createErrorReply(const HttpReply::HttpStatusCode &statu
|
|||
return reply;
|
||||
}
|
||||
|
||||
/*! Returns the pointer to a new created error \l{HttpReply} initialized with the given \a statusCode, \l{HttpReply::TypeSync} and the \a deviceError. */
|
||||
HttpReply *RestResource::createDeviceErrorReply(const HttpReply::HttpStatusCode &statusCode, const DeviceManager::DeviceError &deviceError)
|
||||
{
|
||||
HttpReply *reply = new HttpReply(statusCode, HttpReply::TypeSync);
|
||||
QVariantMap response;
|
||||
response.insert("error", JsonTypes::deviceErrorToString(deviceError));
|
||||
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
|
||||
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
|
||||
return reply;
|
||||
}
|
||||
|
||||
HttpReply *RestResource::createRuleErrorReply(const HttpReply::HttpStatusCode &statusCode, const RuleEngine::RuleError &ruleError)
|
||||
{
|
||||
HttpReply *reply = new HttpReply(statusCode, HttpReply::TypeSync);
|
||||
QVariantMap response;
|
||||
response.insert("error", JsonTypes::ruleErrorToString(ruleError));
|
||||
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
|
||||
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
|
||||
return reply;
|
||||
}
|
||||
|
||||
HttpReply *RestResource::createLoggingErrorReply(const HttpReply::HttpStatusCode &statusCode, const Logging::LoggingError &loggingError)
|
||||
{
|
||||
HttpReply *reply = new HttpReply(statusCode, HttpReply::TypeSync);
|
||||
QVariantMap response;
|
||||
response.insert("error", JsonTypes::loggingErrorToString(loggingError));
|
||||
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
|
||||
reply->setPayload(QJsonDocument::fromVariant(response).toJson());
|
||||
return reply;
|
||||
}
|
||||
|
||||
/*! Returns the pointer to a new created \l{HttpReply} initialized with \l{HttpReply::Ok} and \l{HttpReply::TypeAsync}. */
|
||||
HttpReply *RestResource::createAsyncReply()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "httpreply.h"
|
||||
#include "httprequest.h"
|
||||
#include "jsontypes.h"
|
||||
|
||||
class QVariant;
|
||||
|
||||
|
|
@ -45,6 +46,9 @@ public:
|
|||
static HttpReply *createSuccessReply();
|
||||
static HttpReply *createCorsSuccessReply();
|
||||
static HttpReply *createErrorReply(const HttpReply::HttpStatusCode &statusCode);
|
||||
static HttpReply *createDeviceErrorReply(const HttpReply::HttpStatusCode &statusCode, const DeviceManager::DeviceError &deviceError);
|
||||
static HttpReply *createRuleErrorReply(const HttpReply::HttpStatusCode &statusCode, const RuleEngine::RuleError &ruleError);
|
||||
static HttpReply *createLoggingErrorReply(const HttpReply::HttpStatusCode &statusCode, const Logging::LoggingError &loggingError);
|
||||
static HttpReply *createAsyncReply();
|
||||
static QPair<bool, QVariant> verifyPayload(const QByteArray &payload);
|
||||
|
||||
|
|
|
|||
|
|
@ -566,6 +566,7 @@
|
|||
"DeviceError": [
|
||||
"DeviceErrorNoError",
|
||||
"DeviceErrorPluginNotFound",
|
||||
"DeviceErrorVendorNotFound",
|
||||
"DeviceErrorDeviceNotFound",
|
||||
"DeviceErrorDeviceClassNotFound",
|
||||
"DeviceErrorActionTypeNotFound",
|
||||
|
|
|
|||
Loading…
Reference in New Issue