Merge PR #219: New plugin: USB relay
This commit is contained in:
commit
01adff2cd9
20
debian/control
vendored
20
debian/control
vendored
@ -15,6 +15,8 @@ Build-depends: libboblight-dev,
|
|||||||
qtconnectivity5-dev,
|
qtconnectivity5-dev,
|
||||||
libow-dev,
|
libow-dev,
|
||||||
libsodium-dev,
|
libsodium-dev,
|
||||||
|
libudev-dev,
|
||||||
|
libhidapi-dev,
|
||||||
Standards-Version: 3.9.3
|
Standards-Version: 3.9.3
|
||||||
|
|
||||||
|
|
||||||
@ -687,6 +689,23 @@ Description: nymea.io plugin for unitec
|
|||||||
This package will install the nymea.io plugin for unitec
|
This package will install the nymea.io plugin for unitec
|
||||||
|
|
||||||
|
|
||||||
|
Package: nymea-plugin-usbrelay
|
||||||
|
Architecture: any
|
||||||
|
Multi-Arch: same
|
||||||
|
Section: libs
|
||||||
|
Depends: ${shlibs:Depends},
|
||||||
|
${misc:Depends},
|
||||||
|
libudev1,
|
||||||
|
libhidapi-hidraw0,
|
||||||
|
Description: nymea.io plugin for USB relay
|
||||||
|
The nymea daemon is a plugin based IoT (Internet of Things) server. The
|
||||||
|
server works like a translator for devices, things and services and
|
||||||
|
allows them to interact.
|
||||||
|
With the powerful rule engine you are able to connect any device available
|
||||||
|
in the system and create individual scenes and behaviors for your environment.
|
||||||
|
.
|
||||||
|
This package will install the nymea.io plugin for USB relay
|
||||||
|
|
||||||
|
|
||||||
Package: nymea-plugin-wakeonlan
|
Package: nymea-plugin-wakeonlan
|
||||||
Architecture: any
|
Architecture: any
|
||||||
@ -970,6 +989,7 @@ Depends: nymea-plugin-anel,
|
|||||||
nymea-plugin-tado,
|
nymea-plugin-tado,
|
||||||
nymea-plugin-keba,
|
nymea-plugin-keba,
|
||||||
nymea-plugin-unifi,
|
nymea-plugin-unifi,
|
||||||
|
nymea-plugin-usbrelay,
|
||||||
Replaces: guh-plugins
|
Replaces: guh-plugins
|
||||||
Description: Plugins for nymea IoT server - the default plugin collection
|
Description: Plugins for nymea IoT server - the default plugin collection
|
||||||
The nymea daemon is a plugin based IoT (Internet of Things) server. The
|
The nymea daemon is a plugin based IoT (Internet of Things) server. The
|
||||||
|
|||||||
1
debian/copyright
vendored
1
debian/copyright
vendored
@ -59,6 +59,7 @@ Files: avahimonitor/*
|
|||||||
senic/*
|
senic/*
|
||||||
udpcommander/*
|
udpcommander/*
|
||||||
unitec/*
|
unitec/*
|
||||||
|
usbrelay/*
|
||||||
wemo/*
|
wemo/*
|
||||||
License: LGPL-2.1
|
License: LGPL-2.1
|
||||||
Copyright: 2014-2017, Simon Stürz <simon.stuerz@guh.io>
|
Copyright: 2014-2017, Simon Stürz <simon.stuerz@guh.io>
|
||||||
|
|||||||
1
debian/nymea-plugin-usbrelay.install.in
vendored
Normal file
1
debian/nymea-plugin-usbrelay.install.in
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_devicepluginusbrelay.so
|
||||||
@ -55,6 +55,7 @@ PLUGIN_DIRS = \
|
|||||||
udpcommander \
|
udpcommander \
|
||||||
unifi \
|
unifi \
|
||||||
unitec \
|
unitec \
|
||||||
|
usbrelay \
|
||||||
wakeonlan \
|
wakeonlan \
|
||||||
wemo \
|
wemo \
|
||||||
ws2812fx \
|
ws2812fx \
|
||||||
|
|||||||
5
usbrelay/README.md
Normal file
5
usbrelay/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# usbrelay
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
This plugin eneblas you to control low-cost USB HID relays. The plugin creates a power device for each relay and can be controlled using the `power?? interface.
|
||||||
|
Examples of USB relay hardware can be found [here](http://vusb.wikidot.com/project:driver-less-usb-relays-hid-interface).
|
||||||
298
usbrelay/devicepluginusbrelay.cpp
Normal file
298
usbrelay/devicepluginusbrelay.cpp
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#include "plugininfo.h"
|
||||||
|
#include "devicepluginusbrelay.h"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
#include <hidapi/hidapi.h>
|
||||||
|
|
||||||
|
DevicePluginUsbRelay::DevicePluginUsbRelay()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginUsbRelay::init()
|
||||||
|
{
|
||||||
|
// Initialize/create objects
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginUsbRelay::startMonitoringAutoDevices()
|
||||||
|
{
|
||||||
|
// Start seaching for devices which can be discovered and added automatically
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginUsbRelay::postSetupDevice(Device *device)
|
||||||
|
{
|
||||||
|
qCDebug(dcUsbRelay()) << "Post setup device" << device;
|
||||||
|
|
||||||
|
if (device->deviceClassId() == usbRelayConnectorDeviceClassId) {
|
||||||
|
|
||||||
|
// Initialize the states
|
||||||
|
UsbRelay *relay = m_relayDevices.key(device);
|
||||||
|
if (!relay) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not find relay in post setup.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->setStateValue(usbRelayConnectorConnectedStateTypeId, relay->connected());
|
||||||
|
|
||||||
|
// Check if we have to create child devices (relays)
|
||||||
|
if (myDevices().filterByParentDeviceId(device->id()).isEmpty()) {
|
||||||
|
|
||||||
|
DeviceDescriptors descriptors;
|
||||||
|
for (int i = 0; i < relay->relayCount(); i++) {
|
||||||
|
int relayNumber = i + 1;
|
||||||
|
DeviceDescriptor descriptor(usbRelayDeviceClassId, QString("Relay %1").arg(relayNumber), QString(), device->id());
|
||||||
|
ParamList params;
|
||||||
|
params.append(Param(usbRelayDeviceRelayNumberParamTypeId, relayNumber));
|
||||||
|
descriptor.setParams(params);
|
||||||
|
descriptors.append(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit autoDevicesAppeared(descriptors);
|
||||||
|
}
|
||||||
|
} else if (device->deviceClassId() == usbRelayDeviceClassId) {
|
||||||
|
|
||||||
|
UsbRelay *relay = getRelayForDevice(device);
|
||||||
|
if (!relay) return;
|
||||||
|
|
||||||
|
// Set the current states
|
||||||
|
int relayNumber = device->paramValue(usbRelayDeviceRelayNumberParamTypeId).toInt();
|
||||||
|
device->setStateValue(usbRelayConnectedStateTypeId, relay->connected());
|
||||||
|
device->setStateValue(usbRelayPowerStateTypeId, relay->relayPower(relayNumber));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginUsbRelay::deviceRemoved(Device *device)
|
||||||
|
{
|
||||||
|
qCDebug(dcUsbRelay()) << "Remove device" << device;
|
||||||
|
if (device->deviceClassId() == usbRelayConnectorDeviceClassId) {
|
||||||
|
UsbRelay *relay = m_relayDevices.key(device);
|
||||||
|
if (!relay) return;
|
||||||
|
m_relayDevices.remove(relay);
|
||||||
|
delete relay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginUsbRelay::discoverDevices(DeviceDiscoveryInfo *info)
|
||||||
|
{
|
||||||
|
// Init
|
||||||
|
if (hid_init() < 0) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not initialize HID.";
|
||||||
|
info->finish(Device::DeviceErrorHardwareFailure, QT_TR_NOOP("Cannot discover USB devices. HID initialisation failed on this system."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enumerate hid devices
|
||||||
|
struct hid_device_info *devices = nullptr;
|
||||||
|
struct hid_device_info *currentDevice = nullptr;
|
||||||
|
devices = hid_enumerate(0x16c0, 0x05df);
|
||||||
|
int relayCount = 0;
|
||||||
|
currentDevice = devices;
|
||||||
|
|
||||||
|
for (relayCount = 0; currentDevice != nullptr; relayCount++) {
|
||||||
|
currentDevice = currentDevice->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcUsbRelay()) << "Found" << relayCount << "usb relay devices";
|
||||||
|
currentDevice = devices;
|
||||||
|
for (int i = 0; i < relayCount; i++) {
|
||||||
|
QString path = QString::fromLatin1(currentDevice->path);
|
||||||
|
QString manufacturer = QString::fromWCharArray(currentDevice->manufacturer_string);
|
||||||
|
QString product = QString::fromWCharArray(currentDevice->product_string);
|
||||||
|
QString serialnumber = QString::fromWCharArray(currentDevice->serial_number);
|
||||||
|
quint16 releaseNumber = static_cast<quint16>(currentDevice->release_number);
|
||||||
|
quint16 productId = static_cast<quint16>(currentDevice->product_id);
|
||||||
|
quint16 vendorId = static_cast<quint16>(currentDevice->vendor_id);
|
||||||
|
int relayCount = QString(product.at(product.count() -1)).toInt();
|
||||||
|
|
||||||
|
qCDebug(dcUsbRelay()) << path << manufacturer << product << serialnumber << "Relay count" << relayCount << QString("%1:%2").arg(QString::number(vendorId, 16)).arg(QString::number(productId, 16)) << releaseNumber;
|
||||||
|
|
||||||
|
// Open it to get more details
|
||||||
|
hid_device *hidDevice = nullptr;
|
||||||
|
hidDevice = hid_open_path(currentDevice->path);
|
||||||
|
if (!hidDevice) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not create HID device for" << path;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char buf[9];
|
||||||
|
buf[0] = 0x01;
|
||||||
|
int ret = hid_get_feature_report(hidDevice, buf, sizeof(buf));
|
||||||
|
if (ret < 0) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not create HID device hidDevice for" << path;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint8 relayStatus = static_cast<quint8>(buf[7]);
|
||||||
|
for (int i = 0; i < relayCount; i++) {
|
||||||
|
int relayNumber = i + 1;
|
||||||
|
bool power = static_cast<bool>(relayStatus & 1 << i);
|
||||||
|
qCDebug(dcUsbRelay()) << "--> Relay" << relayNumber << ":" << power;
|
||||||
|
}
|
||||||
|
|
||||||
|
hid_close(hidDevice);
|
||||||
|
|
||||||
|
DeviceDescriptor descriptor(usbRelayConnectorDeviceClassId, "USB Relay Connector", QString("%1 (%2)").arg(product).arg(path));
|
||||||
|
ParamList params;
|
||||||
|
params.append(Param(usbRelayConnectorDevicePathParamTypeId, path));
|
||||||
|
params.append(Param(usbRelayConnectorDeviceRelayCountParamTypeId, relayCount));
|
||||||
|
descriptor.setParams(params);
|
||||||
|
|
||||||
|
// Set the current device id if we already have a device on this path
|
||||||
|
foreach (Device *existingDevice, myDevices()) {
|
||||||
|
if (existingDevice->paramValue(usbRelayConnectorDevicePathParamTypeId).toString() == path &&
|
||||||
|
existingDevice->paramValue(usbRelayConnectorDeviceRelayCountParamTypeId).toInt() == relayCount) {
|
||||||
|
descriptor.setDeviceId(existingDevice->id());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info->addDeviceDescriptor(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
hid_free_enumeration(devices);
|
||||||
|
hid_exit();
|
||||||
|
|
||||||
|
info->finish(Device::DeviceErrorNoError);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginUsbRelay::setupDevice(DeviceSetupInfo *info)
|
||||||
|
{
|
||||||
|
qCDebug(dcUsbRelay()) << "Setup device" << info->device();
|
||||||
|
|
||||||
|
// Relay connector
|
||||||
|
if (info->device()->deviceClassId() == usbRelayConnectorDeviceClassId) {
|
||||||
|
Device *device = info->device();
|
||||||
|
QString path = device->paramValue(usbRelayConnectorDevicePathParamTypeId).toString();
|
||||||
|
int relayCount = device->paramValue(usbRelayConnectorDeviceRelayCountParamTypeId).toInt();
|
||||||
|
|
||||||
|
UsbRelay *relay = new UsbRelay(path, relayCount, this);
|
||||||
|
m_relayDevices.insert(relay, device);
|
||||||
|
|
||||||
|
connect(relay, &UsbRelay::connectedChanged, this, [this, device, relay](bool connected) {
|
||||||
|
qCDebug(dcUsbRelay()) << "Device" << device->name() << (connected ? "connected" : "disconnected");
|
||||||
|
device->setStateValue(usbRelayConnectorConnectedStateTypeId, connected);
|
||||||
|
|
||||||
|
// Set the connected state of all child devices
|
||||||
|
foreach (Device *childDevice, myDevices().filterByParentDeviceId(device->id())) {
|
||||||
|
if (childDevice->deviceClassId() == usbRelayDeviceClassId && childDevice->setupComplete()) {
|
||||||
|
childDevice->setStateValue(usbRelayConnectedStateTypeId, connected);
|
||||||
|
if (connected) {
|
||||||
|
childDevice->setStateValue(usbRelayPowerStateTypeId, relay->relayPower(childDevice->paramValue(usbRelayDeviceRelayNumberParamTypeId).toInt()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(relay, &UsbRelay::relayPowerChanged, this, [this, device](int relayNumber, bool power) {
|
||||||
|
Device *relayDevice = getRelayDevice(device, relayNumber);
|
||||||
|
if (!relayDevice) {
|
||||||
|
// Note: probably not set up yet
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not find USB relay child device for" << device << relayNumber;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
relayDevice->setStateValue(usbRelayPowerStateTypeId, power);
|
||||||
|
});
|
||||||
|
|
||||||
|
info->finish(Device::DeviceErrorNoError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relay
|
||||||
|
if (info->device()->deviceClassId() == usbRelayDeviceClassId) {
|
||||||
|
info->finish(Device::DeviceErrorNoError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->finish(Device::DeviceErrorSetupFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginUsbRelay::executeAction(DeviceActionInfo *info)
|
||||||
|
{
|
||||||
|
qCDebug(dcUsbRelay()) << "Executing action for device" << info->device() << info->action().actionTypeId().toString() << info->action().params();
|
||||||
|
|
||||||
|
if (info->device()->deviceClassId() == usbRelayDeviceClassId) {
|
||||||
|
|
||||||
|
Device *device = info->device();
|
||||||
|
UsbRelay *relay = getRelayForDevice(device);
|
||||||
|
|
||||||
|
if (!relay) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could execute action because could not find USB relay for" << device;
|
||||||
|
info->finish(Device::DeviceErrorHardwareNotAvailable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!relay->connected()) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Relay is not connected";
|
||||||
|
info->finish(Device::DeviceErrorHardwareNotAvailable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int relayNumber = device->paramValue(usbRelayDeviceRelayNumberParamTypeId).toInt();
|
||||||
|
|
||||||
|
if (info->action().actionTypeId() == usbRelayPowerActionTypeId) {
|
||||||
|
bool power = info->action().param(usbRelayPowerActionPowerParamTypeId).value().toBool();
|
||||||
|
if (!relay->setRelayPower(relayNumber, power)) {
|
||||||
|
info->finish(Device::DeviceErrorHardwareFailure);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
info->finish(Device::DeviceErrorNoError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->finish(Device::DeviceErrorActionTypeNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
info->finish(Device::DeviceErrorDeviceClassNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
Device *DevicePluginUsbRelay::getRelayDevice(Device *parentDevice, int relayNumber)
|
||||||
|
{
|
||||||
|
foreach (Device *childDevice, myDevices().filterByParentDeviceId(parentDevice->id())) {
|
||||||
|
if (childDevice->deviceClassId() == usbRelayDeviceClassId) {
|
||||||
|
if (childDevice->paramValue(usbRelayDeviceRelayNumberParamTypeId).toInt() == relayNumber) {
|
||||||
|
return childDevice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UsbRelay *DevicePluginUsbRelay::getRelayForDevice(Device *relayDevice)
|
||||||
|
{
|
||||||
|
Device *parentDevice = myDevices().findById(relayDevice->parentId());
|
||||||
|
if (!parentDevice) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not find the parent device for" << relayDevice;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UsbRelay *relay = m_relayDevices.key(parentDevice);
|
||||||
|
if (!relay) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not find USB relay for" << relayDevice;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return relay;
|
||||||
|
}
|
||||||
58
usbrelay/devicepluginusbrelay.h
Normal file
58
usbrelay/devicepluginusbrelay.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#ifndef DEVICEPLUGINUSBRELAY_H
|
||||||
|
#define DEVICEPLUGINUSBRELAY_H
|
||||||
|
|
||||||
|
#include "usbrelay.h"
|
||||||
|
#include "devices/deviceplugin.h"
|
||||||
|
|
||||||
|
class DevicePluginUsbRelay: public DevicePlugin
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "devicepluginusbrelay.json")
|
||||||
|
Q_INTERFACES(DevicePlugin)
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DevicePluginUsbRelay();
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
void startMonitoringAutoDevices() override;
|
||||||
|
void postSetupDevice(Device *device) override;
|
||||||
|
void deviceRemoved(Device *device) override;
|
||||||
|
|
||||||
|
void discoverDevices(DeviceDiscoveryInfo *info) override;
|
||||||
|
void setupDevice(DeviceSetupInfo *info) override;
|
||||||
|
void executeAction(DeviceActionInfo *info) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<UsbRelay *, Device *> m_relayDevices;
|
||||||
|
|
||||||
|
Device *getRelayDevice(Device *parentDevice, int relayNumber);
|
||||||
|
UsbRelay *getRelayForDevice(Device *relayDevice);
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEVICEPLUGINUSBRELAY_H
|
||||||
88
usbrelay/devicepluginusbrelay.json
Normal file
88
usbrelay/devicepluginusbrelay.json
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
{
|
||||||
|
"name": "UsbRelay",
|
||||||
|
"displayName": "USB relay",
|
||||||
|
"id": "ed0035d3-561c-498e-bdb2-2b574cbd0a2f",
|
||||||
|
"vendors": [
|
||||||
|
{
|
||||||
|
"displayName": "USB Relay",
|
||||||
|
"name": "usbrelay",
|
||||||
|
"id": "d699b81a-621a-4db6-a137-6adbb5c9c091",
|
||||||
|
"deviceClasses": [
|
||||||
|
{
|
||||||
|
"name": "usbRelayConnector",
|
||||||
|
"displayName": "USB Relay Connector",
|
||||||
|
"id": "f48ff4db-d207-4221-963a-3fcb635102d8",
|
||||||
|
"setupMethod": "JustAdd",
|
||||||
|
"createMethods": ["Discovery"],
|
||||||
|
"interfaces": [ "gateway" ],
|
||||||
|
"paramTypes": [
|
||||||
|
{
|
||||||
|
"id": "a9fffbb9-f1c3-439c-9168-8c3fdfab29c8",
|
||||||
|
"name": "path",
|
||||||
|
"displayName": "System path",
|
||||||
|
"type": "QString",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "406e1396-e3a3-4200-9045-2146381041b3",
|
||||||
|
"name": "relayCount",
|
||||||
|
"displayName": "Relay count",
|
||||||
|
"type": "uint",
|
||||||
|
"defaultValue": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateTypes": [
|
||||||
|
{
|
||||||
|
"id": "4cb1cf1f-76fd-4a9c-9397-b5f07b123050",
|
||||||
|
"name": "connected",
|
||||||
|
"displayName": "Connected",
|
||||||
|
"displayNameEvent": "Connected changed",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "usbRelay",
|
||||||
|
"displayName": "USB Relay",
|
||||||
|
"id": "6e01190d-ed9e-4dab-97d1-dc357c740db8",
|
||||||
|
"setupMethod": "JustAdd",
|
||||||
|
"createMethods": ["Auto"],
|
||||||
|
"interfaces": [ "power", "connectable" ],
|
||||||
|
"paramTypes": [
|
||||||
|
{
|
||||||
|
"id": "48d6e667-643f-4f9f-ae12-5308d23a36d7",
|
||||||
|
"name": "relayNumber",
|
||||||
|
"displayName": "Relay number",
|
||||||
|
"type": "uint",
|
||||||
|
"defaultValue": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateTypes": [
|
||||||
|
{
|
||||||
|
"id": "fd5338f8-f02b-4f99-8677-365cfc98221d",
|
||||||
|
"name": "connected",
|
||||||
|
"displayName": "Connected",
|
||||||
|
"displayNameEvent": "Connected changed",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b22ec763-cb41-4d1b-846d-7b2cbe5e433d",
|
||||||
|
"name": "power",
|
||||||
|
"displayName": "Power",
|
||||||
|
"displayNameEvent": "Power",
|
||||||
|
"displayNameAction": "Set power",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": false,
|
||||||
|
"writable": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
163
usbrelay/rawhiddevicewatcher.cpp
Normal file
163
usbrelay/rawhiddevicewatcher.cpp
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#include "rawhiddevicewatcher.h"
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
|
RawHidDeviceWatcher::RawHidDeviceWatcher(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
m_udev = udev_new();
|
||||||
|
if (!m_udev) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not initialize udev";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create udev monitor
|
||||||
|
m_monitor = udev_monitor_new_from_netlink(m_udev, "udev");
|
||||||
|
if (!m_monitor) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not initialize udev monitor.";
|
||||||
|
udev_unref(m_udev);
|
||||||
|
m_udev = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set monitor filter to USB subsystem
|
||||||
|
if (udev_monitor_filter_add_match_subsystem_devtype(m_monitor, "hidraw", nullptr) < 0) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not set seubsystem device type filter to usb_device.";
|
||||||
|
udev_monitor_unref(m_monitor);
|
||||||
|
m_monitor = nullptr;
|
||||||
|
udev_unref(m_udev);
|
||||||
|
m_udev = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable the monitor
|
||||||
|
if (udev_monitor_enable_receiving(m_monitor) < 0) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not enable udev monitor.";
|
||||||
|
udev_monitor_unref(m_monitor);
|
||||||
|
m_monitor = nullptr;
|
||||||
|
udev_unref(m_udev);
|
||||||
|
m_udev = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read initially all devices
|
||||||
|
struct udev_enumerate *enumerate;
|
||||||
|
struct udev_list_entry *devices, *dev_list_entry;
|
||||||
|
enumerate = udev_enumerate_new(m_udev);
|
||||||
|
if (!enumerate) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not create udev enumerate for initial device reading.";
|
||||||
|
udev_monitor_unref(m_monitor);
|
||||||
|
m_monitor = nullptr;
|
||||||
|
udev_unref(m_udev);
|
||||||
|
m_udev = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
udev_enumerate_add_match_subsystem(enumerate, "hidraw");
|
||||||
|
udev_enumerate_scan_devices(enumerate);
|
||||||
|
|
||||||
|
devices = udev_enumerate_get_list_entry(enumerate);
|
||||||
|
if (!devices) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Failed to get hidraw devices from udev enumerate.";
|
||||||
|
udev_monitor_unref(m_monitor);
|
||||||
|
m_monitor = nullptr;
|
||||||
|
udev_unref(m_udev);
|
||||||
|
m_udev = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
udev_list_entry_foreach(dev_list_entry, devices) {
|
||||||
|
struct udev_device *device;
|
||||||
|
const char *path;
|
||||||
|
path = udev_list_entry_get_name(dev_list_entry);
|
||||||
|
device = udev_device_new_from_syspath(m_udev, path);
|
||||||
|
|
||||||
|
QString devicePath = QString::fromLatin1(udev_device_get_property_value(device,"DEVNAME"));
|
||||||
|
udev_device_unref(device);
|
||||||
|
|
||||||
|
qCDebug(dcUsbRelay()) << "[+]" << devicePath;
|
||||||
|
m_devicePaths.append(devicePath);
|
||||||
|
emit deviceAdded(devicePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
udev_enumerate_unref(enumerate);
|
||||||
|
|
||||||
|
// Create socket notifier for read
|
||||||
|
m_notifier = new QSocketNotifier(udev_monitor_get_fd(m_monitor), QSocketNotifier::Read, this );
|
||||||
|
connect(m_notifier, &QSocketNotifier::activated, this, [this](int socket){
|
||||||
|
|
||||||
|
Q_UNUSED(socket)
|
||||||
|
|
||||||
|
// Create udev device
|
||||||
|
udev_device *device = udev_monitor_receive_device(m_monitor);
|
||||||
|
if (!device) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Got socket sotification but could not read device information.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString actionString = QString::fromLatin1(udev_device_get_action(device));
|
||||||
|
QString devicePath = QString::fromLatin1(udev_device_get_property_value(device,"DEVNAME"));
|
||||||
|
|
||||||
|
// Clean udev device
|
||||||
|
udev_device_unref(device);
|
||||||
|
|
||||||
|
if (actionString.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (actionString == "add") {
|
||||||
|
qCDebug(dcUsbRelay()) << "[+]" << devicePath;
|
||||||
|
if (!m_devicePaths.contains(devicePath)) {
|
||||||
|
m_devicePaths.append(devicePath);
|
||||||
|
emit deviceAdded(devicePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionString == "remove") {
|
||||||
|
qCDebug(dcUsbRelay()) << "[-]" << devicePath;
|
||||||
|
if (m_devicePaths.contains(devicePath)) {
|
||||||
|
m_devicePaths.removeAll(devicePath);
|
||||||
|
emit deviceRemoved(devicePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
m_notifier->setEnabled(true);
|
||||||
|
qCDebug(dcUsbRelay()) << "Usb device watcher initialized successfully.";
|
||||||
|
}
|
||||||
|
|
||||||
|
RawHidDeviceWatcher::~RawHidDeviceWatcher()
|
||||||
|
{
|
||||||
|
if (m_monitor)
|
||||||
|
udev_monitor_unref(m_monitor);
|
||||||
|
|
||||||
|
if (m_udev)
|
||||||
|
udev_unref(m_udev);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList RawHidDeviceWatcher::devicePaths() const
|
||||||
|
{
|
||||||
|
return m_devicePaths;
|
||||||
|
}
|
||||||
|
|
||||||
53
usbrelay/rawhiddevicewatcher.h
Normal file
53
usbrelay/rawhiddevicewatcher.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#ifndef USBDEVICEWATCHER_H
|
||||||
|
#define USBDEVICEWATCHER_H
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
|
||||||
|
#include <libudev.h>
|
||||||
|
|
||||||
|
class RawHidDeviceWatcher : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit RawHidDeviceWatcher(QObject *parent = nullptr);
|
||||||
|
~RawHidDeviceWatcher();
|
||||||
|
|
||||||
|
QStringList devicePaths() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct udev *m_udev = nullptr;
|
||||||
|
struct udev_monitor *m_monitor = nullptr;
|
||||||
|
QSocketNotifier *m_notifier = nullptr;
|
||||||
|
QStringList m_devicePaths;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void deviceAdded(const QString &devicePath);
|
||||||
|
void deviceRemoved(const QString &devicePath);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // USBDEVICEWATCHER_H
|
||||||
@ -0,0 +1,100 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE TS>
|
||||||
|
<TS version="2.1">
|
||||||
|
<context>
|
||||||
|
<name>MaveoUsbRelay</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="39"/>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="42"/>
|
||||||
|
<source>Connected</source>
|
||||||
|
<extracomment>The name of the ParamType (DeviceClass: usbRelay, EventType: connected, ID: {ccb0ab2e-5507-4742-b2e0-0cd2aec95df6})
|
||||||
|
----------
|
||||||
|
The name of the StateType ({ccb0ab2e-5507-4742-b2e0-0cd2aec95df6}) of DeviceClass usbRelay</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="45"/>
|
||||||
|
<source>Connected changed</source>
|
||||||
|
<extracomment>The name of the EventType ({ccb0ab2e-5507-4742-b2e0-0cd2aec95df6}) of DeviceClass usbRelay</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="48"/>
|
||||||
|
<source>Impulse relay 1</source>
|
||||||
|
<extracomment>The name of the ActionType ({35590728-12ff-4afe-a6be-7ba69ce81b63}) of DeviceClass usbRelay</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="51"/>
|
||||||
|
<source>Impulse relay 2</source>
|
||||||
|
<extracomment>The name of the ActionType ({63bfdae2-1c0f-4548-81cd-f64be5303f20}) of DeviceClass usbRelay</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="54"/>
|
||||||
|
<source>Maveo USB Relay</source>
|
||||||
|
<extracomment>The name of the DeviceClass ({942a187f-bdec-4527-8696-45d4891e7d6b})</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="57"/>
|
||||||
|
<source>Maveo USB relay</source>
|
||||||
|
<extracomment>The name of the plugin MaveoUsbRelay ({ddb4823d-0918-498e-87bc-6ae1a652538c})</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="60"/>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="63"/>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="66"/>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="69"/>
|
||||||
|
<source>Power relay 1</source>
|
||||||
|
<extracomment>The name of the ParamType (DeviceClass: usbRelay, ActionType: powerOne, ID: {39d85190-739f-474f-b04c-e0627d681bb2})
|
||||||
|
----------
|
||||||
|
The name of the ParamType (DeviceClass: usbRelay, EventType: powerOne, ID: {39d85190-739f-474f-b04c-e0627d681bb2})
|
||||||
|
----------
|
||||||
|
The name of the EventType ({39d85190-739f-474f-b04c-e0627d681bb2}) of DeviceClass usbRelay
|
||||||
|
----------
|
||||||
|
The name of the StateType ({39d85190-739f-474f-b04c-e0627d681bb2}) of DeviceClass usbRelay</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="72"/>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="75"/>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="78"/>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="81"/>
|
||||||
|
<source>Power relay 2</source>
|
||||||
|
<extracomment>The name of the ParamType (DeviceClass: usbRelay, ActionType: powerTwo, ID: {294376f7-7d21-4989-8803-ad5bffe08c48})
|
||||||
|
----------
|
||||||
|
The name of the ParamType (DeviceClass: usbRelay, EventType: powerTwo, ID: {294376f7-7d21-4989-8803-ad5bffe08c48})
|
||||||
|
----------
|
||||||
|
The name of the EventType ({294376f7-7d21-4989-8803-ad5bffe08c48}) of DeviceClass usbRelay
|
||||||
|
----------
|
||||||
|
The name of the StateType ({294376f7-7d21-4989-8803-ad5bffe08c48}) of DeviceClass usbRelay</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="84"/>
|
||||||
|
<source>Set power relay 1</source>
|
||||||
|
<extracomment>The name of the ActionType ({39d85190-739f-474f-b04c-e0627d681bb2}) of DeviceClass usbRelay</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="87"/>
|
||||||
|
<source>Set power relay 2</source>
|
||||||
|
<extracomment>The name of the ActionType ({294376f7-7d21-4989-8803-ad5bffe08c48}) of DeviceClass usbRelay</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="90"/>
|
||||||
|
<source>System path</source>
|
||||||
|
<extracomment>The name of the ParamType (DeviceClass: usbRelay, Type: device, ID: {a3644b93-1c37-472e-9303-a116feb33067})</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../build-maveousbrelay-Desktop-Debug/plugininfo.h" line="93"/>
|
||||||
|
<source>maveo</source>
|
||||||
|
<extracomment>The name of the vendor ({e77e72ae-1228-42a3-85cd-34c6f3a8d494})</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
</TS>
|
||||||
188
usbrelay/usbrelay.cpp
Normal file
188
usbrelay/usbrelay.cpp
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#include "usbrelay.h"
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
|
UsbRelay::UsbRelay(const QString &path, int relayCount, QObject *parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_path(path),
|
||||||
|
m_relayCount(relayCount)
|
||||||
|
{
|
||||||
|
m_deviceWatcher = new RawHidDeviceWatcher(this);
|
||||||
|
|
||||||
|
connect(m_deviceWatcher, &RawHidDeviceWatcher::deviceAdded, this, &UsbRelay::onDeviceAdded);
|
||||||
|
connect(m_deviceWatcher, &RawHidDeviceWatcher::deviceRemoved, this, &UsbRelay::onDeviceRemoved);
|
||||||
|
|
||||||
|
if (m_deviceWatcher->devicePaths().contains(m_path)) {
|
||||||
|
setConnected(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create initial relay map
|
||||||
|
for (int i = 0; i < m_relayCount; i++) {
|
||||||
|
m_relayMap.insert(i + 1, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UsbRelay::~UsbRelay()
|
||||||
|
{
|
||||||
|
if (m_hidDevice)
|
||||||
|
hid_close(m_hidDevice);
|
||||||
|
|
||||||
|
hid_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString UsbRelay::path() const
|
||||||
|
{
|
||||||
|
return m_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UsbRelay::relayCount() const
|
||||||
|
{
|
||||||
|
return m_relayCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsbRelay::connected() const
|
||||||
|
{
|
||||||
|
return m_connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsbRelay::relayPower(int relayNumber) const
|
||||||
|
{
|
||||||
|
return m_relayMap[relayNumber];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsbRelay::setRelayPower(int relayNumber, bool power)
|
||||||
|
{
|
||||||
|
if (!m_connected) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not set power of relay" << relayNumber << "because the device is not connected.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relayNumber > m_relayCount) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not set power of relay power because the relay number is invalid" << relayNumber << ">" << m_relayCount;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return switchRelay(relayNumber, power);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsbRelay::setConnected(bool connected)
|
||||||
|
{
|
||||||
|
if (m_connected == connected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcUsbRelay()) << m_path << (connected ? "connected" : "disconnected");
|
||||||
|
if (connected) {
|
||||||
|
// Initialize the device
|
||||||
|
m_hidDevice = hid_open_path(m_path.toLatin1().data());
|
||||||
|
if (!m_hidDevice) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could nor open HID device for" << m_path;
|
||||||
|
m_connected = false;
|
||||||
|
emit connectedChanged(m_connected);
|
||||||
|
}
|
||||||
|
|
||||||
|
readStatus();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Deinitialize
|
||||||
|
if (m_hidDevice) {
|
||||||
|
hid_close(m_hidDevice);
|
||||||
|
m_hidDevice = nullptr;
|
||||||
|
hid_exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_connected = connected;
|
||||||
|
emit connectedChanged(m_connected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsbRelay::setRelayPowerInternally(int relayNumber, bool power)
|
||||||
|
{
|
||||||
|
if (m_relayMap[relayNumber] == power)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcUsbRelay()) << "Relay power changed" << relayNumber << power;
|
||||||
|
m_relayMap[relayNumber] = power;
|
||||||
|
emit relayPowerChanged(relayNumber, power);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsbRelay::readStatus()
|
||||||
|
{
|
||||||
|
qCDebug(dcUsbRelay()) << "Read relay status of" << m_path;
|
||||||
|
unsigned char buf[9];
|
||||||
|
buf[0] = 0x01;
|
||||||
|
int ret = hid_get_feature_report(m_hidDevice, buf, sizeof(buf));
|
||||||
|
if (ret < 0) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Could not create HID device for reading" << m_path;
|
||||||
|
hid_close(m_hidDevice);
|
||||||
|
m_hidDevice = nullptr;
|
||||||
|
|
||||||
|
m_connected = false;
|
||||||
|
emit connectedChanged(m_connected);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint8 relayStatus = static_cast<quint8>(buf[7]);
|
||||||
|
|
||||||
|
for (int i = 0; i < m_relayCount; i++) {
|
||||||
|
int relayNumber = i + 1;
|
||||||
|
bool power = static_cast<bool>(relayStatus & 1 << i);
|
||||||
|
qCDebug(dcUsbRelay()) << "--> Relay" << relayNumber << power;
|
||||||
|
setRelayPowerInternally(relayNumber, power);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsbRelay::switchRelay(int relayNumber, bool power)
|
||||||
|
{
|
||||||
|
if (!m_hidDevice) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Cannot switch power for" << m_path << "because there is no HID device.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char buf[9]; // 1 extra byte for the report ID
|
||||||
|
memset(buf, 0x00, sizeof (buf));
|
||||||
|
buf[1] = power ? 0xff : 0xfd;
|
||||||
|
buf[2] = static_cast<unsigned char>(relayNumber); // Relay number
|
||||||
|
|
||||||
|
if (hid_write(m_hidDevice, buf, sizeof(buf)) <= 0) {
|
||||||
|
qCWarning(dcUsbRelay()) << "Cannot switch power for" << m_path << "because could not write to HID device.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
readStatus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsbRelay::onDeviceAdded(const QString &devicePath)
|
||||||
|
{
|
||||||
|
if (devicePath == m_path) {
|
||||||
|
setConnected(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsbRelay::onDeviceRemoved(const QString &devicePath)
|
||||||
|
{
|
||||||
|
if (devicePath == m_path) {
|
||||||
|
setConnected(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
77
usbrelay/usbrelay.h
Normal file
77
usbrelay/usbrelay.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#ifndef USBRELAY_H
|
||||||
|
#define USBRELAY_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <hidapi/hidapi.h>
|
||||||
|
|
||||||
|
#include "rawhiddevicewatcher.h"
|
||||||
|
|
||||||
|
class UsbRelay : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit UsbRelay(const QString &path, int relayCount, QObject *parent = nullptr);
|
||||||
|
~UsbRelay();
|
||||||
|
|
||||||
|
QString path() const;
|
||||||
|
int relayCount() const;
|
||||||
|
|
||||||
|
bool connected() const;
|
||||||
|
|
||||||
|
bool relayPower(int relayNumber) const;
|
||||||
|
bool setRelayPower(int relayNumber, bool power);
|
||||||
|
|
||||||
|
private:
|
||||||
|
RawHidDeviceWatcher *m_deviceWatcher = nullptr;
|
||||||
|
hid_device *m_hidDevice = nullptr;
|
||||||
|
|
||||||
|
QString m_path;
|
||||||
|
int m_relayCount = 0;
|
||||||
|
bool m_connected = false;
|
||||||
|
bool m_relayOnePower = false;
|
||||||
|
bool m_relayTwoPower = false;
|
||||||
|
|
||||||
|
void setConnected(bool connected);
|
||||||
|
|
||||||
|
// Relay map <relay number>, bool value
|
||||||
|
QHash<int, bool> m_relayMap;
|
||||||
|
|
||||||
|
void setRelayPowerInternally(int relayNumber, bool power);
|
||||||
|
|
||||||
|
void readStatus();
|
||||||
|
|
||||||
|
bool switchRelay(int relayNumber, bool power);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void connectedChanged(bool connected);
|
||||||
|
void relayPowerChanged(int relayNumber, bool power);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onDeviceAdded(const QString &devicePath);
|
||||||
|
void onDeviceRemoved(const QString &devicePath);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // USBRELAY_H
|
||||||
14
usbrelay/usbrelay.pro
Normal file
14
usbrelay/usbrelay.pro
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
include(../plugins.pri)
|
||||||
|
|
||||||
|
PKGCONFIG += hidapi-hidraw libudev
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
devicepluginusbrelay.cpp \
|
||||||
|
rawhiddevicewatcher.cpp \
|
||||||
|
usbrelay.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
devicepluginusbrelay.h \
|
||||||
|
rawhiddevicewatcher.h \
|
||||||
|
usbrelay.h
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user