Add debian packaging and start implementing analog values

master
Simon Stürz 2022-03-15 16:43:58 +01:00
parent f65bf428d9
commit 0d8a5524d3
7 changed files with 243 additions and 118 deletions

13
debian/control vendored
View File

@ -846,6 +846,18 @@ Description: nymea.io plugin for USB relay
This package will install the nymea.io plugin for USB relay
Package: nymea-plugin-usbrly82
Architecture: any
Multi-Arch: same
Section: libs
Depends: ${shlibs:Depends},
${misc:Depends},
libudev1,
Description: nymea.io plugin for USB-RLY82 relay
This package will install the nymea.io integration plugin for USB-RLY82 relay
with 2 relays and 8 analog/digital inputs.
Package: nymea-plugin-wakeonlan
Architecture: any
Depends: ${shlibs:Depends},
@ -1218,6 +1230,7 @@ Depends: nymea-plugin-anel,
nymea-plugin-keba,
nymea-plugin-unifi,
nymea-plugin-usbrelay,
nymea-plugin-usbrly82,
nymea-plugin-yamahaavr,
Description: Plugins for nymea IoT server - the default plugin collection
The nymea daemon is a plugin based IoT (Internet of Things) server. The

View File

@ -0,0 +1,2 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginusbrly82.so
usbrly82/translations/*qm usr/share/nymea/translations/

View File

@ -72,9 +72,21 @@ void IntegrationPluginUsbRly82::setupThing(ThingSetupInfo *info)
qCDebug(dcUsbRly82()) << "Found serial port for" << thing << serialPortInfo;
UsbRly82 *relay = new UsbRly82(this);
relay->setAnlalogRefreshRate(thing->setting(usbRelaySettingsAnalogRefreshRateParamTypeId).toUInt());
connect(relay, &UsbRly82::availableChanged, thing, [=](bool available){
qCDebug(dcUsbRly82()) << thing << "available changed" << available;
thing->setStateValue("connected", available);
if (available) {
// Set the already fetched information
thing->setStateValue(usbRelayPowerRelay1StateTypeId, relay->powerRelay1());
thing->setStateValue(usbRelayPowerRelay2StateTypeId, relay->powerRelay2());
updateDigitalInuts(thing);
thing->setStateValue(usbRelayVersionStateTypeId, relay->softwareVersion());
}
});
connect(relay, &UsbRly82::powerRelay1Changed, thing, [=](bool power){
@ -84,15 +96,13 @@ void IntegrationPluginUsbRly82::setupThing(ThingSetupInfo *info)
connect(relay, &UsbRly82::powerRelay2Changed, thing, [=](bool power){
qCDebug(dcUsbRly82()) << thing << "relay 2 power changed" << power;
thing->setStateValue(usbRelayPowerRelay1StateTypeId, power);
thing->setStateValue(usbRelayPowerRelay2StateTypeId, power);
});
connect(relay, &UsbRly82::digitalInputsChanged, thing, [=](){
thing->setStateValue(usbRelayPowerRelay1StateTypeId, UsbRly82::checkBit());
updateDigitalInuts(thing);
});
if (!relay->connectRelay(serialPortInfo.systemLocation)) {
qCWarning(dcUsbRly82()) << "Setup failed. Could not connect to relay" << thing;
info->finish(Thing::ThingErrorHardwareFailure);
@ -102,6 +112,14 @@ void IntegrationPluginUsbRly82::setupThing(ThingSetupInfo *info)
m_relays.insert(thing, relay);
info->finish(Thing::ThingErrorNoError);
connect(thing, &Thing::settingChanged, this, [=](const ParamTypeId &paramTypeId, const QVariant &value){
if (paramTypeId == usbRelaySettingsAnalogRefreshRateParamTypeId) {
qCDebug(dcUsbRly82()) << "Refrsh rat changed for" << thing << value.toUInt() << "ms";
relay->setAnlalogRefreshRate(value.toUInt());
}
});
return;
}
}
@ -118,43 +136,6 @@ void IntegrationPluginUsbRly82::setupThing(ThingSetupInfo *info)
void IntegrationPluginUsbRly82::postSetupThing(Thing *thing)
{
qCDebug(dcUsbRly82()) << "Post setup thing" << thing;
// if (thing->thingClassId() == usbRelayConnectorThingClassId) {
// // Initialize the states
// UsbRelay *relay = m_relays.key(thing);
// if (!relay) {
// qCWarning(dcUsbRly82()) << "Could not find relay in post setup.";
// return;
// }
// thing->setStateValue(usbRelayConnectorConnectedStateTypeId, relay->connected());
// // Check if we have to create child devices (relays)
// if (myThings().filterByParentId(thing->id()).isEmpty()) {
// ThingDescriptors descriptors;
// for (int i = 0; i < relay->relayCount(); i++) {
// int relayNumber = i + 1;
// ThingDescriptor descriptor(usbRelayThingClassId, QString("Relay %1").arg(relayNumber), QString(), thing->id());
// ParamList params;
// params.append(Param(usbRelayThingRelayNumberParamTypeId, relayNumber));
// descriptor.setParams(params);
// descriptors.append(descriptor);
// }
// emit autoThingsAppeared(descriptors);
// }
// } else if (thing->thingClassId() == usbRelayThingClassId) {
// UsbRelay *relay = getRelayForDevice(thing);
// if (!relay) return;
// // Set the current states
// int relayNumber = thing->paramValue(usbRelayThingRelayNumberParamTypeId).toInt();
// thing->setStateValue(usbRelayConnectedStateTypeId, relay->connected());
// thing->setStateValue(usbRelayPowerStateTypeId, relay->relayPower(relayNumber));
// }
}
void IntegrationPluginUsbRly82::thingRemoved(Thing *thing)
@ -162,8 +143,9 @@ void IntegrationPluginUsbRly82::thingRemoved(Thing *thing)
qCDebug(dcUsbRly82()) << "Remove thing" << thing;
if (thing->thingClassId() == usbRelayThingClassId) {
UsbRly82 *relay = m_relays.take(thing);
if (!relay) return;
delete relay;
if (relay) {
delete relay;
}
}
}
@ -174,50 +156,50 @@ void IntegrationPluginUsbRly82::executeAction(ThingActionInfo *info)
if (info->thing()->thingClassId() == usbRelayThingClassId) {
Thing *thing = info->thing();
UsbRly82 *relay = m_relays.value(thing);
Thing *thing = info->thing();
UsbRly82 *relay = m_relays.value(thing);
if (!relay) {
qCWarning(dcUsbRly82()) << "Could execute action because could not find USB relay for" << thing;
info->finish(Thing::ThingErrorHardwareNotAvailable);
return;
}
if (!relay->available()) {
qCWarning(dcUsbRly82()) << "Relay is not connected";
info->finish(Thing::ThingErrorHardwareNotAvailable);
return;
}
if (info->action().actionTypeId() == usbRelayPowerRelay1ActionTypeId) {
bool power = info->action().paramValue(usbRelayPowerRelay1ActionPowerRelay1ParamTypeId).toBool();
UsbRly82Reply *reply = relay->setRelay1Power(power);
connect(reply, &UsbRly82Reply::finished, info, [=](){
if (reply->error() != UsbRly82Reply::ErrorNoError) {
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
info->finish(Thing::ThingErrorNoError);
});
return;
} else if (info->action().actionTypeId() == usbRelayPowerRelay2ActionTypeId) {
bool power = info->action().paramValue(usbRelayPowerRelay2ActionPowerRelay2ParamTypeId).toBool();
UsbRly82Reply *reply = relay->setRelay2Power(power);
connect(reply, &UsbRly82Reply::finished, info, [=](){
if (reply->error() != UsbRly82Reply::ErrorNoError) {
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
info->finish(Thing::ThingErrorNoError);
});
return;
}
info->finish(Thing::ThingErrorActionTypeNotFound);
if (!relay) {
qCWarning(dcUsbRly82()) << "Could execute action because could not find USB relay for" << thing;
info->finish(Thing::ThingErrorHardwareNotAvailable);
return;
}
if (!relay->available()) {
qCWarning(dcUsbRly82()) << "Cannot execute action. Relay is not available" << thing;
info->finish(Thing::ThingErrorHardwareNotAvailable);
return;
}
if (info->action().actionTypeId() == usbRelayPowerRelay1ActionTypeId) {
bool power = info->action().paramValue(usbRelayPowerRelay1ActionPowerRelay1ParamTypeId).toBool();
UsbRly82Reply *reply = relay->setRelay1Power(power);
connect(reply, &UsbRly82Reply::finished, info, [=](){
if (reply->error() != UsbRly82Reply::ErrorNoError) {
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
info->finish(Thing::ThingErrorNoError);
});
return;
} else if (info->action().actionTypeId() == usbRelayPowerRelay2ActionTypeId) {
bool power = info->action().paramValue(usbRelayPowerRelay2ActionPowerRelay2ParamTypeId).toBool();
UsbRly82Reply *reply = relay->setRelay2Power(power);
connect(reply, &UsbRly82Reply::finished, info, [=](){
if (reply->error() != UsbRly82Reply::ErrorNoError) {
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
info->finish(Thing::ThingErrorNoError);
});
return;
}
info->finish(Thing::ThingErrorActionTypeNotFound);
}
info->finish(Thing::ThingErrorThingClassNotFound);
}
@ -252,3 +234,21 @@ void IntegrationPluginUsbRly82::onSerialPortRemoved(const SerialPortMonitor::Ser
qCDebug(dcUsbRly82()) << "[-] Removed" << serialPortInfo;
}
}
void IntegrationPluginUsbRly82::updateDigitalInuts(Thing *thing)
{
UsbRly82 *relay = m_relays.value(thing);
if (!relay)
return;
qCDebug(dcUsbRly82()) << thing << "digital inputs changed:" << QString("%1").arg(relay->digitalInputs(), 8, 2, QChar('0'));
thing->setStateValue(usbRelayDigitalInputChannel1StateTypeId, UsbRly82::checkBit(relay->digitalInputs(), 0));
thing->setStateValue(usbRelayDigitalInputChannel2StateTypeId, UsbRly82::checkBit(relay->digitalInputs(), 1));
thing->setStateValue(usbRelayDigitalInputChannel3StateTypeId, UsbRly82::checkBit(relay->digitalInputs(), 2));
thing->setStateValue(usbRelayDigitalInputChannel4StateTypeId, UsbRly82::checkBit(relay->digitalInputs(), 3));
thing->setStateValue(usbRelayDigitalInputChannel5StateTypeId, UsbRly82::checkBit(relay->digitalInputs(), 4));
thing->setStateValue(usbRelayDigitalInputChannel6StateTypeId, UsbRly82::checkBit(relay->digitalInputs(), 5));
thing->setStateValue(usbRelayDigitalInputChannel7StateTypeId, UsbRly82::checkBit(relay->digitalInputs(), 6));
thing->setStateValue(usbRelayDigitalInputChannel8StateTypeId, UsbRly82::checkBit(relay->digitalInputs(), 7));
}

View File

@ -62,6 +62,7 @@ private slots:
void onSerialPortAdded(const SerialPortMonitor::SerialPortInfo &serialPortInfo);
void onSerialPortRemoved(const SerialPortMonitor::SerialPortInfo &serialPortInfo);
void updateDigitalInuts(Thing *thing);
};
#endif // INTEGRATIONPLUGINUSBRLY82_H

View File

@ -24,6 +24,16 @@
"defaultValue": ""
}
],
"settingsTypes": [
{
"id": "e426f3b1-e9bf-4bef-bc01-2aba6326d265",
"name": "analogRefreshRate",
"displayName": "Analog refresh interval",
"type": "uint",
"unit": "MilliSeconds",
"defaultValue": 1000
}
],
"stateTypes": [
{
"id": "b482b0ea-1901-4437-a309-be43833a1ad5",
@ -231,8 +241,8 @@
"name": "version",
"displayName": "Version",
"displayNameEvent": "Version changed",
"type": "bool",
"defaultValue": false
"type": "QString",
"defaultValue": ""
}
]
}

View File

@ -1,6 +1,7 @@
#include "usbrly82.h"
#include "usbrly82.h"
#include "extern-plugininfo.h"
#include <QDataStream>
UsbRly82Reply::Error UsbRly82Reply::error() const
{
@ -27,14 +28,17 @@ UsbRly82Reply::UsbRly82Reply(QObject *parent) : QObject(parent)
});
}
UsbRly82::UsbRly82(QObject *parent) : QObject(parent)
{
qRegisterMetaType<QSerialPort::SerialPortError>();
m_refreshTimer.setInterval(100);
m_refreshTimer.setSingleShot(false);
connect(&m_refreshTimer, &QTimer::timeout, this, &UsbRly82::poll);
m_digitalRefreshTimer.setInterval(50);
m_digitalRefreshTimer.setSingleShot(false);
connect(&m_digitalRefreshTimer, &QTimer::timeout, this, &UsbRly82::updateDigitalInputs);
m_analogRefreshTimer.setInterval(m_analogRefreshRate);
m_analogRefreshTimer.setSingleShot(false);
connect(&m_analogRefreshTimer, &QTimer::timeout, this, &UsbRly82::updateAnalogInputs);
}
bool UsbRly82::available() const
@ -42,6 +46,16 @@ bool UsbRly82::available() const
return m_available;
}
QString UsbRly82::serialNumber() const
{
return m_serialNumber;
}
QString UsbRly82::softwareVersion() const
{
return m_softwareVersion;
}
bool UsbRly82::powerRelay1() const
{
return m_powerRelay1;
@ -78,6 +92,25 @@ UsbRly82Reply *UsbRly82::setRelay2Power(bool power)
return reply;
}
uint UsbRly82::analogRefreshRate() const
{
return m_analogRefreshRate;
}
void UsbRly82::setAnlalogRefreshRate(uint analogRefreshRate)
{
m_analogRefreshRate = analogRefreshRate;
if (m_analogRefreshRate == 0) {
qCDebug(dcUsbRly82()) << "Refresh rate set to 0. Auto refreshing analog inputs disabled.";
m_analogRefreshTimer.stop();
} else {
m_analogRefreshTimer.setInterval(m_analogRefreshRate);
if (m_available) {
m_analogRefreshTimer.start();
}
}
}
quint8 UsbRly82::digitalInputs() const
{
return m_digitalInputs;
@ -155,10 +188,33 @@ bool UsbRly82::connectRelay(const QString &serialPort)
qCDebug(dcUsbRly82()) << "Relay 1:" << m_powerRelay1;
qCDebug(dcUsbRly82()) << "Relay 2:" << m_powerRelay2;
m_available = true;
emit availableChanged(m_available);
UsbRly82Reply *reply = getDigitalInputs();
connect(reply, &UsbRly82Reply::finished, this, [=](){
if (reply->error() != UsbRly82Reply::ErrorNoError) {
qCWarning(dcUsbRly82()) << "Reading digital inputs finished with error" << reply->error();
return;
}
m_refreshTimer.start();
if (reply->responseData().isEmpty())
return;
quint8 digitalInputs = reply->responseData().at(0);
if (m_digitalInputs != digitalInputs) {
qCDebug(dcUsbRly82()) << "Digital inputs changed";
m_digitalInputs = digitalInputs;
emit digitalInputsChanged();
}
m_available = true;
emit availableChanged(m_available);
m_digitalRefreshTimer.start();
if (m_analogRefreshRate != 0) {
m_analogRefreshTimer.start(m_analogRefreshRate);
} else {
qCDebug(dcUsbRly82()) << "Refresh rate set to 0. Auto refreshing analog inputs disabled.";
}
});
});
});
});
@ -175,7 +231,8 @@ void UsbRly82::disconnectRelay()
m_serialPort = nullptr;
}
m_refreshTimer.stop();
m_digitalRefreshTimer.stop();
m_analogRefreshTimer.stop();
m_available = false;
emit availableChanged(m_available);
@ -241,7 +298,7 @@ UsbRly82Reply *UsbRly82::createReply(const QByteArray &requestData, bool expects
if (!expectsResponse) {
m_replyQueue.enqueue(reply);
} else {
// Priorize requests without response (like switching the relay)
// Prioritize requests without response (like switching the relay)
m_replyQueue.prepend(reply);
}
return reply;
@ -256,7 +313,7 @@ void UsbRly82::sendNextRequest()
return;
m_currentReply = m_replyQueue.dequeue();
qCDebug(dcUsbRly82()) << "-->" << m_currentReply->requestData().toHex();
//qCDebug(dcUsbRly82()) << "-->" << m_currentReply->requestData().toHex();
m_serialPort->write(m_currentReply->requestData());
if (m_currentReply->m_expectsResponse) {
m_currentReply->m_timer.start(1000);
@ -274,7 +331,7 @@ bool UsbRly82::checkBit(quint8 byte, uint bitNumber)
void UsbRly82::onReadyRead()
{
QByteArray data = m_serialPort->readAll();
qCDebug(dcUsbRly82()) << "<--" << data.toHex();
//qCDebug(dcUsbRly82()) << "<--" << data.toHex();
if (m_currentReply) {
m_currentReply->m_responseData = data;
@ -297,37 +354,67 @@ void UsbRly82::onError(QSerialPort::SerialPortError error)
}
}
void UsbRly82::poll()
void UsbRly82::updateDigitalInputs()
{
if (m_replyQueue.count() > 10)
// Make sure the queue does not overflow
if (m_updateDigitalInputsReply)
return;
UsbRly82Reply *reply = getDigitalInputs();
connect(reply, &UsbRly82Reply::finished, this, [=](){
if (reply->error() != UsbRly82Reply::ErrorNoError) {
qCWarning(dcUsbRly82()) << "Reading digital inputs finished with error" << reply->error();
m_updateDigitalInputsReply = getDigitalInputs();
connect(m_updateDigitalInputsReply, &UsbRly82Reply::finished, this, [=](){
if (m_updateDigitalInputsReply->error() != UsbRly82Reply::ErrorNoError) {
qCWarning(dcUsbRly82()) << "Reading digital inputs finished with error" << m_updateDigitalInputsReply->error();
m_updateDigitalInputsReply = nullptr;
return;
}
if (reply->responseData().isEmpty())
if (m_updateDigitalInputsReply->responseData().isEmpty()) {
m_updateDigitalInputsReply = nullptr;
return;
}
quint8 digitalInputs = reply->responseData().at(0);
quint8 digitalInputs = m_updateDigitalInputsReply->responseData().at(0);
if (m_digitalInputs != digitalInputs) {
qCDebug(dcUsbRly82()) << "Digital inputs changed";
m_digitalInputs = digitalInputs;
emit digitalInputsChanged();
}
m_updateDigitalInputsReply = nullptr;
});
}
void UsbRly82::updateAnalogInputs()
{
// Make sure the queue does not overflow
if (m_updateAnalogInputsReply)
return;
reply = getAdcValues();
connect(reply, &UsbRly82Reply::finished, this, [=](){
if (reply->error() != UsbRly82Reply::ErrorNoError) {
qCWarning(dcUsbRly82()) << "Reading analog inputs finished with error" << reply->error();
m_updateAnalogInputsReply = getAdcValues();
connect(m_updateAnalogInputsReply, &UsbRly82Reply::finished, this, [=](){
if (m_updateAnalogInputsReply->error() != UsbRly82Reply::ErrorNoError) {
qCWarning(dcUsbRly82()) << "Reading analog inputs finished with error" << m_updateAnalogInputsReply->error();
m_updateAnalogInputsReply = nullptr;
return;
}
qCDebug(dcUsbRly82()) << "Analog inputs";
if (m_updateAnalogInputsReply->responseData().count() != 16) {
qCWarning(dcUsbRly82()) << "Reading analog inputs response returned invalid size" << m_updateAnalogInputsReply->responseData().count() << "(should be 16)";
m_updateAnalogInputsReply = nullptr;
return;
}
qCDebug(dcUsbRly82()) << "Analog inputs" << m_updateAnalogInputsReply->responseData().toHex();
QDataStream stream(m_updateAnalogInputsReply->responseData());
quint16 value = 0;
for (int i = 0; i < 8; i++) {
stream >> value;
m_analogValues.insert(i, value);
qCDebug(dcUsbRly82()) << "Channel" << i << ":" << value;
}
m_updateAnalogInputsReply = nullptr;
});
}

View File

@ -4,6 +4,7 @@
#include <QObject>
#include <QTimer>
#include <QQueue>
#include <QHash>
#include <QSerialPort>
class UsbRly82Reply : public QObject
@ -44,6 +45,8 @@ public:
explicit UsbRly82(QObject *parent = nullptr);
bool available() const;
QString serialNumber() const;
QString softwareVersion() const;
bool powerRelay1() const;
UsbRly82Reply *setRelay1Power(bool power);
@ -51,6 +54,9 @@ public:
bool powerRelay2() const;
UsbRly82Reply *setRelay2Power(bool power);
uint analogRefreshRate() const;
void setAnlalogRefreshRate(uint analogRefreshRate);
quint8 digitalInputs() const;
bool connectRelay(const QString &serialPort);
@ -66,7 +72,6 @@ public:
static bool checkBit(quint8 byte, uint bitNumber);
signals:
void availableChanged(bool available);
@ -76,31 +81,38 @@ signals:
void digitalInputsChanged();
private:
QTimer m_refreshTimer;
QTimer m_digitalRefreshTimer;
QTimer m_analogRefreshTimer;
QSerialPort *m_serialPort = nullptr;
bool m_available = false;
QString m_serialNumber;
QString m_softwareVersion;
uint m_analogRefreshRate = 1000;
bool m_powerRelay1 = false;
bool m_powerRelay2 = false;
UsbRly82Reply *m_currentReply = nullptr;
QQueue<UsbRly82Reply *> m_replyQueue;
UsbRly82Reply *m_updateDigitalInputsReply = nullptr;
UsbRly82Reply *m_updateAnalogInputsReply = nullptr;
UsbRly82Reply *createReply(const QByteArray &requestData, bool expectsResponse = true);
void sendNextRequest();
quint8 m_digitalInputs = 0x00;
QHash<int, quint16> m_analogValues;
private slots:
void onReadyRead();
void onError(QSerialPort::SerialPortError error);
void poll();
void updateDigitalInputs();
void updateAnalogInputs();
};
#endif // USBRLY82_H