Add speedwire test interface

master
Simon Stürz 2021-12-03 14:16:21 +01:00
parent 2b3a44cd6c
commit cd9c048ebd
6 changed files with 222 additions and 4 deletions

View File

@ -84,8 +84,23 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
info->addThingDescriptors(descriptors);
info->finish(Thing::ThingErrorNoError);
});
}
} else if (info->thingClassId() == speedwireInverterThingClassId) {
SpeedwireInterface *speedwireDiscovery = new SpeedwireInterface(info);
if (!speedwireDiscovery->initialize()) {
qCWarning(dcSma()) << "Could not discovery inverter. The speedwire interface initialization failed.";
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Unable to discover the network."));
return;
}
connect(speedwireDiscovery, &SpeedwireInterface::discoveryFinished, this, [=](){
qCDebug(dcSma()) << "Speed wire discovery finished.";
speedwireDiscovery->deleteLater();
info->finish(Thing::ThingErrorNoError);
});
speedwireDiscovery->startDiscovery();
}
}
void IntegrationPluginSma::setupThing(ThingSetupInfo *info)

View File

@ -35,7 +35,7 @@
#include "plugintimer.h"
#include "sunnywebbox.h"
#include <QDebug>
#include "speedwireinterface.h"
class IntegrationPluginSma: public IntegrationPlugin {
Q_OBJECT

View File

@ -12,8 +12,8 @@
"id": "49304127-ce9b-45dd-8511-05030a4ac003",
"name": "sunnyWebBox",
"displayName": "Sunny WebBox",
"createMethods": ["user", "discovery"],
"interfaces": ["smartmeterproducer"],
"createMethods": ["discovery", "user"],
"interfaces": ["solarinverter"],
"paramTypes": [
{
"id": "864d4162-e3ce-48b8-b8ac-c1b971b52d42",
@ -85,6 +85,59 @@
"defaultValue": "None"
}
]
},
{
"id": "0c5097af-e136-4430-9fb4-0ccbb30c3e1c",
"name": "speedwireInverter",
"displayName": "SMA Inverter Speedwire",
"createMethods": ["discovery", "user"],
"interfaces": ["solarinverter"],
"paramTypes": [
{
"id": "d90193e6-a996-4e49-bf6d-564d596d7e74",
"name": "host",
"displayName": "Host address",
"type": "QString",
"inputType": "IPv4Address",
"defaultValue": "192.168.0.168"
},
{
"id": "2780eab7-1f1c-4cc7-a789-a8790329ca9e",
"name": "macAddress",
"displayName": "hardware address",
"type": "QString",
"inputType": "TextLine",
"readOnly": true
}
],
"stateTypes": [
{
"id": "35733d27-4fe0-439a-be71-7c1597481659",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"defaultValue": false
},
{
"id": "015868bd-cc35-44cf-b631-78ea7c73b967",
"name": "currentPower",
"displayName": "Current power",
"displayNameEvent": "Current power changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0
},
{
"id": "f29b6283-873b-45f5-8a14-622d34f11d4f",
"name": "totalEnergyProduced",
"displayName": "Total energy produced",
"displayNameEvent": "Total energy produced changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0
}
]
}
]
}

View File

@ -4,8 +4,10 @@ QT += network
SOURCES += \
integrationpluginsma.cpp \
speedwireinterface.cpp \
sunnywebbox.cpp
HEADERS += \
integrationpluginsma.h \
speedwireinterface.h \
sunnywebbox.h

111
sma/speedwireinterface.cpp Normal file
View File

@ -0,0 +1,111 @@
#include "speedwireinterface.h"
#include "extern-plugininfo.h"
#include <QTimer>
SpeedwireInterface::SpeedwireInterface(QObject *parent) :
QObject(parent)
{
m_socket = new QUdpSocket(this);
connect(m_socket, &QUdpSocket::readyRead, this, &SpeedwireInterface::readPendingDatagrams);
connect(m_socket, &QUdpSocket::stateChanged, this, &SpeedwireInterface::onSocketStateChanged);
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(onSocketError(QAbstractSocket::SocketError)));
}
SpeedwireInterface::~SpeedwireInterface()
{
if (m_initialized) {
if (!m_socket->leaveMulticastGroup(m_multicastAddress)) {
qCWarning(dcSma()) << "SpeedwireInterface: Failed to leave multicast group" << m_multicastAddress.toString();
}
m_socket->close();
}
}
bool SpeedwireInterface::initialize()
{
// If we already initialized the socket, we are done
if (m_initialized)
return true;
m_socket->close();
m_initialized = false;
if (!m_socket->bind(QHostAddress::AnyIPv4, m_port, QAbstractSocket::ShareAddress)) {
qCWarning(dcSma()) << "SpeedwireInterface: Cannot bind to port" << m_port << m_socket->errorString();
return false;
}
if (!m_socket->joinMulticastGroup(m_multicastAddress)) {
qCWarning(dcSma()) << "SpeedwireInterface: Failed to join multicast group" << m_multicastAddress.toString() << m_socket->errorString();
return false;
}
m_initialized = true;
return true;
}
bool SpeedwireInterface::initialized() const
{
return m_initialized;
}
bool SpeedwireInterface::startDiscovery()
{
if (m_discoveryRunning)
return true;
qCDebug(dcSma()) << "SpeedwireInterface: Start discovering network...";
if (!m_initialized) {
qCDebug(dcSma()) << "SpeedwireInterface: Failed to start discovery because the socket has not been initialized successfully.";
return false;
}
// Discovery message
QByteArray discoveryDatagram = QByteArray::fromHex("534d4100000402a0ffffffff0000002000000000");
if (m_socket->write(discoveryDatagram) < 0) {
qCWarning(dcSma()) << "SpeedwireInterface: Failed to send discovery datagram to multicast address" << m_multicastAddress.toString();
return false;
}
m_discoveryRunning = true;
QTimer::singleShot(10000, this, [=](){
qCDebug(dcSma()) << "SpeedwireInterface: Discovey finished.";
m_discoveryRunning = false;
emit discoveryFinished();
});
return true;
}
bool SpeedwireInterface::discoveryRunning() const
{
return m_discoveryRunning;
}
void SpeedwireInterface::readPendingDatagrams()
{
QUdpSocket *socket= qobject_cast<QUdpSocket *>(sender());
QByteArray datagram;
QHostAddress senderAddress;
quint16 senderPort;
while (socket->hasPendingDatagrams()) {
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort);
qCDebug(dcSma()) << "SpeedwireInterface: Data received from" << senderAddress.toString() << datagram.toHex();
//emit datagramReceived(senderAddress, datagram);
}
}
void SpeedwireInterface::onSocketError(QAbstractSocket::SocketError error)
{
qCDebug(dcSma()) << "SpeedwireInterface: Socket error" << error;
}
void SpeedwireInterface::onSocketStateChanged(QAbstractSocket::SocketState socketState)
{
qCDebug(dcSma()) << "SpeedwireInterface: Socket state changed" << socketState;
}

37
sma/speedwireinterface.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef SPEEDWIREINTERFACE_H
#define SPEEDWIREINTERFACE_H
#include <QObject>
#include <QUdpSocket>
class SpeedwireInterface : public QObject
{
Q_OBJECT
public:
explicit SpeedwireInterface(QObject *parent = nullptr);
~SpeedwireInterface();
bool initialize();
bool initialized() const;
bool startDiscovery();
bool discoveryRunning() const;
signals:
void discoveryFinished();
private:
QUdpSocket *m_socket = nullptr;
QHostAddress m_multicastAddress = QHostAddress("239.12.255.254");
quint16 m_port = 9522;
bool m_initialized = false;
bool m_discoveryRunning = false;
private slots:
void readPendingDatagrams();
void onSocketError(QAbstractSocket::SocketError error);
void onSocketStateChanged(QAbstractSocket::SocketState socketState);
};
#endif // SPEEDWIREINTERFACE_H