SMA: Improve speedwire interface handling and sharing
parent
8e32831047
commit
c5f3352c3e
|
|
@ -94,15 +94,15 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
|
|||
webBoxDiscovery->startDiscovery();
|
||||
|
||||
} else if (info->thingClassId() == speedwireMeterThingClassId) {
|
||||
|
||||
// Note: does not require the network device discovery...
|
||||
SpeedwireDiscovery *speedwireDiscovery = new SpeedwireDiscovery(hardwareManager()->networkDeviceDiscovery(), getLocalSerialNumber(), info);
|
||||
if (!speedwireDiscovery->initialize()) {
|
||||
SpeedwireInterface *speedwireInterface = getSpeedwireInterface();
|
||||
if (!speedwireInterface || !speedwireInterface->available()) {
|
||||
qCWarning(dcSma()) << "Could not discovery inverter. The speedwire interface initialization failed.";
|
||||
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Unable to discover the network."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: does not require the network device discovery...
|
||||
SpeedwireDiscovery *speedwireDiscovery = new SpeedwireDiscovery(hardwareManager()->networkDeviceDiscovery(), speedwireInterface, getLocalSerialNumber(), info);
|
||||
connect(speedwireDiscovery, &SpeedwireDiscovery::discoveryFinished, this, [=](){
|
||||
qCDebug(dcSma()) << "Speed wire discovery finished.";
|
||||
speedwireDiscovery->deleteLater();
|
||||
|
|
@ -110,7 +110,7 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
|
|||
ThingDescriptors descriptors;
|
||||
foreach (const SpeedwireDiscovery::SpeedwireDiscoveryResult &result, speedwireDiscovery->discoveryResult()) {
|
||||
|
||||
if (result.deviceType != SpeedwireInterface::DeviceTypeMeter)
|
||||
if (result.deviceType != Speedwire::DeviceTypeMeter)
|
||||
continue;
|
||||
|
||||
if (result.serialNumber == 0)
|
||||
|
|
@ -151,13 +151,14 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
|
|||
return;
|
||||
}
|
||||
|
||||
SpeedwireDiscovery *speedwireDiscovery = new SpeedwireDiscovery(hardwareManager()->networkDeviceDiscovery(), getLocalSerialNumber(), info);
|
||||
if (!speedwireDiscovery->initialize()) {
|
||||
SpeedwireInterface *speedwireInterface = getSpeedwireInterface();
|
||||
if (!speedwireInterface || !speedwireInterface->available()) {
|
||||
qCWarning(dcSma()) << "Could not discovery inverter. The speedwire interface initialization failed.";
|
||||
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Unable to discover the network."));
|
||||
return;
|
||||
}
|
||||
|
||||
SpeedwireDiscovery *speedwireDiscovery = new SpeedwireDiscovery(hardwareManager()->networkDeviceDiscovery(), speedwireInterface, getLocalSerialNumber(), info);
|
||||
connect(speedwireDiscovery, &SpeedwireDiscovery::discoveryFinished, this, [=](){
|
||||
qCDebug(dcSma()) << "Speed wire discovery finished.";
|
||||
speedwireDiscovery->deleteLater();
|
||||
|
|
@ -165,7 +166,7 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
|
|||
ThingDescriptors descriptors;
|
||||
foreach (const SpeedwireDiscovery::SpeedwireDiscoveryResult &result, speedwireDiscovery->discoveryResult()) {
|
||||
|
||||
if (result.deviceType != SpeedwireInterface::DeviceTypeInverter)
|
||||
if (result.deviceType != Speedwire::DeviceTypeInverter)
|
||||
continue;
|
||||
|
||||
if (result.serialNumber == 0)
|
||||
|
|
@ -302,9 +303,12 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||
|
||||
} else if (thing->thingClassId() == speedwireMeterThingClassId) {
|
||||
|
||||
// Create the multicast interface if not created already.
|
||||
if (!m_multicastInterface)
|
||||
m_multicastInterface = new SpeedwireInterface(true, getLocalSerialNumber(), this);
|
||||
SpeedwireInterface *speedwireInterface = getSpeedwireInterface();
|
||||
if (!speedwireInterface || !speedwireInterface->available()) {
|
||||
qCWarning(dcSma()) << "Could not set up speedwire meter. The speedwire interface is not available.";
|
||||
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Unable to communicate with the meter."));
|
||||
return;
|
||||
}
|
||||
|
||||
quint32 serialNumber = static_cast<quint32>(thing->paramValue(speedwireMeterThingSerialNumberParamTypeId).toUInt());
|
||||
quint16 modelId = static_cast<quint16>(thing->paramValue(speedwireMeterThingModelIdParamTypeId).toUInt());
|
||||
|
|
@ -313,14 +317,7 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||
if (m_speedwireMeters.contains(thing))
|
||||
m_speedwireMeters.take(thing)->deleteLater();
|
||||
|
||||
SpeedwireMeter *meter = new SpeedwireMeter(m_multicastInterface, modelId, serialNumber, this);
|
||||
if (!meter->initialize()) {
|
||||
meter->deleteLater();
|
||||
qCWarning(dcSma()) << "Setup failed. Could not initialize meter interface.";
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
SpeedwireMeter *meter = new SpeedwireMeter(speedwireInterface, modelId, serialNumber, this);
|
||||
connect(meter, &SpeedwireMeter::reachableChanged, thing, [=](bool reachable){
|
||||
thing->setStateValue(speedwireMeterConnectedStateTypeId, reachable);
|
||||
if (!reachable) {
|
||||
|
|
@ -358,6 +355,9 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||
} else if (thing->thingClassId() == speedwireInverterThingClassId) {
|
||||
|
||||
QHostAddress address = QHostAddress(thing->paramValue(speedwireInverterThingHostParamTypeId).toString());
|
||||
|
||||
// FIXME: use the monitor here since the IP might change
|
||||
|
||||
quint32 serialNumber = static_cast<quint32>(thing->paramValue(speedwireInverterThingSerialNumberParamTypeId).toUInt());
|
||||
quint16 modelId = static_cast<quint16>(thing->paramValue(speedwireInverterThingModelIdParamTypeId).toUInt());
|
||||
|
||||
|
|
@ -365,13 +365,7 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||
m_speedwireInverters.take(thing)->deleteLater();
|
||||
}
|
||||
|
||||
SpeedwireInverter *inverter = new SpeedwireInverter(address, modelId, serialNumber, this);
|
||||
if (!inverter->initialize()) {
|
||||
qCWarning(dcSma()) << "Setup failed. Could not initialize inverter interface.";
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
SpeedwireInverter *inverter = new SpeedwireInverter(getSpeedwireInterface(), address, modelId, serialNumber, this);
|
||||
qCDebug(dcSma()) << "Inverter: Interface initialized successfully.";
|
||||
|
||||
QString password;
|
||||
|
|
@ -620,10 +614,12 @@ void IntegrationPluginSma::thingRemoved(Thing *thing)
|
|||
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
|
||||
}
|
||||
|
||||
if (myThings().filterByThingClassId(speedwireMeterThingClassId).isEmpty() && m_multicastInterface) {
|
||||
if (myThings().filterByThingClassId(speedwireMeterThingClassId).isEmpty()
|
||||
&& myThings().filterByThingClassId(speedwireInverterThingClassId).isEmpty()
|
||||
&& myThings().filterByThingClassId(speedwireBatteryThingClassId).isEmpty()) {
|
||||
// Delete shared multicast socket...
|
||||
m_multicastInterface->deleteLater();
|
||||
m_multicastInterface = nullptr;
|
||||
m_speedwireInterface->deleteLater();
|
||||
m_speedwireInterface = nullptr;
|
||||
}
|
||||
|
||||
if (myThings().isEmpty()) {
|
||||
|
|
@ -823,6 +819,17 @@ void IntegrationPluginSma::setupModbusInverterConnection(ThingSetupInfo *info)
|
|||
connection->connectDevice();
|
||||
}
|
||||
|
||||
SpeedwireInterface *IntegrationPluginSma::getSpeedwireInterface()
|
||||
{
|
||||
if (!m_speedwireInterface)
|
||||
m_speedwireInterface = new SpeedwireInterface(getLocalSerialNumber(), this);
|
||||
|
||||
if (!m_speedwireInterface->available())
|
||||
m_speedwireInterface->initialize();
|
||||
|
||||
return m_speedwireInterface;
|
||||
}
|
||||
|
||||
void IntegrationPluginSma::markSpeedwireMeterAsDisconnected(Thing *thing)
|
||||
{
|
||||
thing->setStateValue(speedwireMeterCurrentPowerPhaseAStateTypeId, 0);
|
||||
|
|
|
|||
|
|
@ -82,8 +82,9 @@ private:
|
|||
|
||||
quint32 m_localSerialNumber = 0;
|
||||
|
||||
// Shared interface accross meters
|
||||
SpeedwireInterface *m_multicastInterface = nullptr;
|
||||
// Shared interface accross all speedwire devices
|
||||
SpeedwireInterface *m_speedwireInterface = nullptr;
|
||||
SpeedwireInterface *getSpeedwireInterface();
|
||||
|
||||
void markSpeedwireMeterAsDisconnected(Thing *thing);
|
||||
void markSpeedwireInverterAsDisconnected(Thing *thing);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,13 @@ class Speedwire
|
|||
{
|
||||
Q_GADGET
|
||||
public:
|
||||
enum DeviceType {
|
||||
DeviceTypeUnknown,
|
||||
DeviceTypeMeter,
|
||||
DeviceTypeInverter
|
||||
};
|
||||
Q_ENUM(DeviceType)
|
||||
|
||||
enum Command {
|
||||
CommandIdentify = 0x00000201,
|
||||
CommandQueryStatus = 0x51800200,
|
||||
|
|
|
|||
|
|
@ -30,12 +30,14 @@
|
|||
|
||||
#include "speedwirediscovery.h"
|
||||
#include "extern-plugininfo.h"
|
||||
#include "speedwire.h"
|
||||
|
||||
#include <QDataStream>
|
||||
|
||||
SpeedwireDiscovery::SpeedwireDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, quint32 localSerialNumber, QObject *parent) :
|
||||
SpeedwireDiscovery::SpeedwireDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, SpeedwireInterface *speedwireInterface, quint32 localSerialNumber, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_networkDeviceDiscovery(networkDeviceDiscovery),
|
||||
m_speedwireInterface(speedwireInterface),
|
||||
m_localSerialNumber(localSerialNumber)
|
||||
{
|
||||
// More details: https://github.com/RalfOGit/libspeedwire/
|
||||
|
|
@ -45,44 +47,14 @@ SpeedwireDiscovery::SpeedwireDiscovery(NetworkDeviceDiscovery *networkDeviceDisc
|
|||
|
||||
m_multicastSearchRequestTimer.setInterval(1000);
|
||||
m_multicastSearchRequestTimer.setSingleShot(false);
|
||||
|
||||
connect(m_speedwireInterface, &SpeedwireInterface::dataReceived, this, &SpeedwireDiscovery::processDatagram);
|
||||
connect(&m_multicastSearchRequestTimer, &QTimer::timeout, this, &SpeedwireDiscovery::sendDiscoveryRequest);
|
||||
}
|
||||
|
||||
SpeedwireDiscovery::~SpeedwireDiscovery()
|
||||
{
|
||||
if (m_initialized && m_multicastSocket) {
|
||||
if (!m_multicastSocket->leaveMulticastGroup(Speedwire::multicastAddress())) {
|
||||
qCWarning(dcSma()) << "SpeedwireDiscovery: Failed to leave multicast group" << Speedwire::multicastAddress().toString();
|
||||
}
|
||||
|
||||
m_multicastSocket->close();
|
||||
}
|
||||
}
|
||||
|
||||
bool SpeedwireDiscovery::initialize(SpeedwireInterface::DeviceType deviceType)
|
||||
{
|
||||
m_deviceType = deviceType;
|
||||
switch(deviceType) {
|
||||
case SpeedwireInterface::DeviceTypeMeter:
|
||||
m_initialized = setupMulticastSocket();
|
||||
break;
|
||||
case SpeedwireInterface::DeviceTypeInverter:
|
||||
m_initialized = setupUnicastSocket();
|
||||
break;
|
||||
default:
|
||||
m_initialized = setupMulticastSocket() && setupUnicastSocket();
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_initialized)
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Interfaces initialized successfully.";
|
||||
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
bool SpeedwireDiscovery::initialized() const
|
||||
{
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
bool SpeedwireDiscovery::startDiscovery()
|
||||
|
|
@ -90,20 +62,17 @@ bool SpeedwireDiscovery::startDiscovery()
|
|||
if (discoveryRunning())
|
||||
return true;
|
||||
|
||||
if (!m_initialized) {
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Failed to start discovery because the socket has not been initialized successfully.";
|
||||
if (!m_speedwireInterface->available()) {
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Failed to start discovery because the speedwire interface is not available.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start clean
|
||||
m_results.clear();
|
||||
m_networkDeviceInfos.clear();
|
||||
m_multicastRunning = false;
|
||||
m_unicastRunning = false;
|
||||
|
||||
startUnicastDiscovery();
|
||||
startMulticastDiscovery();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -117,49 +86,6 @@ QList<SpeedwireDiscovery::SpeedwireDiscoveryResult> SpeedwireDiscovery::discover
|
|||
return m_results;
|
||||
}
|
||||
|
||||
bool SpeedwireDiscovery::setupMulticastSocket()
|
||||
{
|
||||
if (m_multicastSocket)
|
||||
return true;
|
||||
|
||||
m_multicastSocket = new QUdpSocket(this);
|
||||
connect(m_multicastSocket, &QUdpSocket::readyRead, this, &SpeedwireDiscovery::readPendingDatagramsMulticast);
|
||||
connect(m_multicastSocket, &QUdpSocket::stateChanged, this, &SpeedwireDiscovery::onSocketStateChanged);
|
||||
connect(m_multicastSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(onSocketError(QAbstractSocket::SocketError)));
|
||||
|
||||
// Setup multicast socket
|
||||
if (!m_multicastSocket->bind(QHostAddress::AnyIPv4, Speedwire::port(), QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint)) {
|
||||
qCWarning(dcSma()) << "SpeedwireDiscovery: Initialization failed. Could not bind multicast socket to port" << Speedwire::port() << m_multicastSocket->errorString();
|
||||
m_multicastSocket->deleteLater();
|
||||
m_multicastSocket = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Join all available interfaces the multicast group
|
||||
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
|
||||
if(interface.isValid() && !interface.flags().testFlag(QNetworkInterface::IsLoopBack)
|
||||
&& interface.flags().testFlag(QNetworkInterface::CanMulticast)
|
||||
&& interface.flags().testFlag(QNetworkInterface::IsRunning)) {
|
||||
|
||||
QList<QNetworkAddressEntry> addressEntries = interface.addressEntries();
|
||||
for (int i = 0; i < addressEntries.length(); i++) {
|
||||
|
||||
|
||||
if (addressEntries.at(i).ip().protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
if (!m_multicastSocket->joinMulticastGroup(Speedwire::multicastAddress(), interface)) {
|
||||
qCWarning(dcSma()) << "SpeedwireDiscovery: Could not join multicast group" << Speedwire::multicastAddress().toString() << "on interface" << interface << m_multicastSocket->errorString();
|
||||
} else {
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Joined successfully multicast group on" << interface;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpeedwireDiscovery::startMulticastDiscovery()
|
||||
{
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Start multicast discovery...";
|
||||
|
|
@ -170,26 +96,6 @@ void SpeedwireDiscovery::startMulticastDiscovery()
|
|||
sendDiscoveryRequest();
|
||||
}
|
||||
|
||||
bool SpeedwireDiscovery::setupUnicastSocket()
|
||||
{
|
||||
if (m_unicastSocket)
|
||||
return true;
|
||||
|
||||
m_unicastSocket = new QUdpSocket(this);
|
||||
connect(m_unicastSocket, &QUdpSocket::readyRead, this, &SpeedwireDiscovery::readPendingDatagramsUnicast);
|
||||
connect(m_unicastSocket, &QUdpSocket::stateChanged, this, &SpeedwireDiscovery::onSocketStateChanged);
|
||||
connect(m_unicastSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(onSocketError(QAbstractSocket::SocketError)));
|
||||
|
||||
// Setup unicast socket
|
||||
if (!m_unicastSocket->bind(QHostAddress::AnyIPv4, Speedwire::port(), QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint)) {
|
||||
qCWarning(dcSma()) << "SpeedwireDiscovery: Initialization failed. Could not bind to port" << Speedwire::port() << m_multicastSocket->errorString();
|
||||
m_unicastSocket->deleteLater();
|
||||
m_unicastSocket = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpeedwireDiscovery::startUnicastDiscovery()
|
||||
{
|
||||
|
|
@ -218,70 +124,14 @@ void SpeedwireDiscovery::startUnicastDiscovery()
|
|||
|
||||
void SpeedwireDiscovery::sendUnicastDiscoveryRequest(const QHostAddress &targetHostAddress)
|
||||
{
|
||||
if (m_unicastSocket->writeDatagram(Speedwire::pingRequest(Speedwire::sourceModelId(), m_localSerialNumber), targetHostAddress, Speedwire::port()) < 0) {
|
||||
qCWarning(dcSma()) << "SpeedwireDiscovery: Failed to send unicast discovery datagram to address" << targetHostAddress.toString();
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Sent successfully the discovery request to unicast address" << targetHostAddress.toString();
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Sent discovery request to unicast address" << targetHostAddress.toString();
|
||||
m_speedwireInterface->sendDataUnicast(targetHostAddress, Speedwire::pingRequest(Speedwire::sourceModelId(), m_localSerialNumber));
|
||||
}
|
||||
|
||||
void SpeedwireDiscovery::readPendingDatagramsMulticast()
|
||||
void SpeedwireDiscovery::processDatagram(const QHostAddress &senderAddress, quint16 senderPort, const QByteArray &datagram, bool multicast)
|
||||
{
|
||||
QUdpSocket *socket = qobject_cast<QUdpSocket *>(sender());
|
||||
Q_UNUSED(multicast)
|
||||
|
||||
QByteArray datagram;
|
||||
QHostAddress senderAddress;
|
||||
quint16 senderPort;
|
||||
|
||||
while (socket->hasPendingDatagrams()) {
|
||||
datagram.resize(socket->pendingDatagramSize());
|
||||
socket->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort);
|
||||
|
||||
// Ignore our own requests
|
||||
if (QNetworkInterface::allAddresses().contains(senderAddress))
|
||||
continue;
|
||||
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Received multicast data from" << QString("%1:%2").arg(senderAddress.toString()).arg(senderPort);
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: " << datagram.toHex();
|
||||
processDatagram(senderAddress, senderPort, datagram);
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedwireDiscovery::readPendingDatagramsUnicast()
|
||||
{
|
||||
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);
|
||||
|
||||
// Ignore our own requests
|
||||
if (QNetworkInterface::allAddresses().contains(senderAddress))
|
||||
continue;
|
||||
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Received unicast data from" << QString("%1:%2").arg(senderAddress.toString()).arg(senderPort);
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: " << datagram.toHex();
|
||||
processDatagram(senderAddress, senderPort, datagram);
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedwireDiscovery::onSocketError(QAbstractSocket::SocketError error)
|
||||
{
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Socket error" << error;
|
||||
}
|
||||
|
||||
void SpeedwireDiscovery::onSocketStateChanged(QAbstractSocket::SocketState socketState)
|
||||
{
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Socket state changed" << socketState;
|
||||
}
|
||||
|
||||
void SpeedwireDiscovery::processDatagram(const QHostAddress &senderAddress, quint16 senderPort, const QByteArray &datagram)
|
||||
{
|
||||
// Check min size of SMA datagrams
|
||||
if (datagram.size() < 18) {
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Received datagram is to short to be a SMA speedwire message. Ignoring data...";
|
||||
|
|
@ -324,7 +174,7 @@ void SpeedwireDiscovery::processDatagram(const QHostAddress &senderAddress, quin
|
|||
if (!m_resultMeters.contains(senderAddress)) {
|
||||
SpeedwireDiscoveryResult result;
|
||||
result.address = senderAddress;
|
||||
result.deviceType = SpeedwireInterface::DeviceTypeMeter;
|
||||
result.deviceType = Speedwire::DeviceTypeMeter;
|
||||
m_resultMeters.insert(senderAddress, result);
|
||||
}
|
||||
|
||||
|
|
@ -342,7 +192,7 @@ void SpeedwireDiscovery::processDatagram(const QHostAddress &senderAddress, quin
|
|||
if (!m_resultInverters.contains(senderAddress)) {
|
||||
SpeedwireDiscoveryResult result;
|
||||
result.address = senderAddress;
|
||||
result.deviceType = SpeedwireInterface::DeviceTypeInverter;
|
||||
result.deviceType = Speedwire::DeviceTypeInverter;
|
||||
m_resultInverters.insert(senderAddress, result);
|
||||
}
|
||||
|
||||
|
|
@ -359,20 +209,20 @@ void SpeedwireDiscovery::processDatagram(const QHostAddress &senderAddress, quin
|
|||
if (m_inverters.contains(senderAddress)) {
|
||||
inverter = m_inverters.value(senderAddress);
|
||||
} else {
|
||||
inverter = new SpeedwireInverter(senderAddress, Speedwire::sourceModelId(), m_localSerialNumber, this);
|
||||
inverter = new SpeedwireInverter(m_speedwireInterface, senderAddress, Speedwire::sourceModelId(), m_localSerialNumber, this);
|
||||
m_inverters.insert(senderAddress, inverter);
|
||||
}
|
||||
|
||||
SpeedwireInverterReply *reply = inverter->sendIdentifyRequest();
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: send identify request to" << senderAddress.toString();
|
||||
connect(reply, &SpeedwireInverterReply::finished, this, [this, inverter, senderAddress, reply](){
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: identify request finished from" << senderAddress.toString() << reply->error();
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Send identify request to" << senderAddress.toString();
|
||||
connect(reply, &SpeedwireInverterReply::finished, this, [/*this, inverter,*/ senderAddress, reply](){
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Identify request finished from" << senderAddress.toString() << reply->error();
|
||||
|
||||
SpeedwireInverterReply *loginReply = inverter->sendLoginRequest();
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: make login attempt using the default password.";
|
||||
connect(loginReply, &SpeedwireInverterReply::finished, this, [loginReply, senderAddress](){
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: login attempt finished" << senderAddress.toString() << loginReply->error();
|
||||
});
|
||||
// SpeedwireInverterReply *loginReply = inverter->sendLoginRequest();
|
||||
// qCDebug(dcSma()) << "SpeedwireDiscovery: make login attempt using the default password.";
|
||||
// connect(loginReply, &SpeedwireInverterReply::finished, this, [loginReply, senderAddress](){
|
||||
// qCDebug(dcSma()) << "SpeedwireDiscovery: login attempt finished" << senderAddress.toString() << loginReply->error();
|
||||
// });
|
||||
});
|
||||
|
||||
} else {
|
||||
|
|
@ -383,12 +233,8 @@ void SpeedwireDiscovery::processDatagram(const QHostAddress &senderAddress, quin
|
|||
|
||||
void SpeedwireDiscovery::sendDiscoveryRequest()
|
||||
{
|
||||
if (m_multicastSocket->writeDatagram(Speedwire::discoveryDatagramMulticast(), Speedwire::multicastAddress(), Speedwire::port()) < 0) {
|
||||
qCWarning(dcSma()) << "SpeedwireDiscovery: Failed to send discovery datagram to multicast address" << Speedwire::multicastAddress().toString();
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Sent successfully the discovery request to multicast address" << Speedwire::multicastAddress().toString();
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Sent discovery request to multicast address" << Speedwire::multicastAddress().toString();
|
||||
m_speedwireInterface->sendDataMulticast(Speedwire::discoveryDatagramMulticast());
|
||||
}
|
||||
|
||||
void SpeedwireDiscovery::evaluateDiscoveryFinished()
|
||||
|
|
@ -405,23 +251,6 @@ void SpeedwireDiscovery::finishDiscovery()
|
|||
qCDebug(dcSma()) << "SpeedwireDiscovery: Discovey finished. Found" << m_results.count() << "SMA devices in the network";
|
||||
m_multicastSearchRequestTimer.stop();
|
||||
|
||||
if (m_multicastSocket) {
|
||||
if (!m_multicastSocket->leaveMulticastGroup(Speedwire::multicastAddress())) {
|
||||
qCWarning(dcSma()) << "SpeedwireDiscovery: Failed to leave multicast group" << Speedwire::multicastAddress().toString();
|
||||
}
|
||||
|
||||
m_multicastSocket->close();
|
||||
m_multicastSocket->deleteLater();
|
||||
m_multicastSocket = nullptr;
|
||||
}
|
||||
|
||||
if (m_unicastSocket) {
|
||||
m_unicastSocket->close();
|
||||
m_unicastSocket->deleteLater();
|
||||
m_unicastSocket = nullptr;
|
||||
}
|
||||
|
||||
|
||||
foreach (const SpeedwireDiscoveryResult &result, m_results) {
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: ============================================";
|
||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Device type:" << result.deviceType;
|
||||
|
|
|
|||
|
|
@ -48,17 +48,14 @@ public:
|
|||
typedef struct SpeedwireDiscoveryResult {
|
||||
QHostAddress address;
|
||||
NetworkDeviceInfo networkDeviceInfo;
|
||||
SpeedwireInterface::DeviceType deviceType = SpeedwireInterface::DeviceTypeUnknown;
|
||||
Speedwire::DeviceType deviceType = Speedwire::DeviceTypeUnknown;
|
||||
quint16 modelId = 0;
|
||||
quint32 serialNumber = 0;
|
||||
} SpeedwireDiscoveryResult;
|
||||
|
||||
explicit SpeedwireDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, quint32 localSerialNumber, QObject *parent = nullptr);
|
||||
explicit SpeedwireDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, SpeedwireInterface *speedwireInterface, quint32 localSerialNumber, QObject *parent = nullptr);
|
||||
~SpeedwireDiscovery();
|
||||
|
||||
bool initialize(SpeedwireInterface::DeviceType deviceType = SpeedwireInterface::DeviceTypeUnknown);
|
||||
bool initialized() const;
|
||||
|
||||
bool startDiscovery();
|
||||
bool discoveryRunning() const;
|
||||
|
||||
|
|
@ -69,11 +66,8 @@ signals:
|
|||
|
||||
private:
|
||||
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
|
||||
SpeedwireInterface::DeviceType m_deviceType = SpeedwireInterface::DeviceTypeUnknown;
|
||||
QUdpSocket *m_multicastSocket = nullptr;
|
||||
QUdpSocket *m_unicastSocket = nullptr;
|
||||
SpeedwireInterface *m_speedwireInterface = nullptr;
|
||||
quint32 m_localSerialNumber = 0;
|
||||
bool m_initialized = false;
|
||||
|
||||
// Discovery
|
||||
QTimer m_multicastSearchRequestTimer;
|
||||
|
|
@ -81,34 +75,21 @@ private:
|
|||
QList<SpeedwireDiscoveryResult> m_results;
|
||||
QHash<QHostAddress, SpeedwireDiscoveryResult> m_resultMeters;
|
||||
QHash<QHostAddress, SpeedwireDiscoveryResult> m_resultInverters;
|
||||
bool m_unicastRunning = false;
|
||||
bool m_multicastRunning = false;
|
||||
|
||||
QHash<QHostAddress, SpeedwireInverter *> m_inverters;
|
||||
|
||||
bool m_multicastRunning = false;
|
||||
bool m_unicastRunning = false;
|
||||
|
||||
bool setupMulticastSocket();
|
||||
void startMulticastDiscovery();
|
||||
|
||||
bool setupUnicastSocket();
|
||||
void startUnicastDiscovery();
|
||||
|
||||
void sendUnicastDiscoveryRequest(const QHostAddress &targetHostAddress);
|
||||
|
||||
private slots:
|
||||
void readPendingDatagramsMulticast();
|
||||
void readPendingDatagramsUnicast();
|
||||
void onSocketError(QAbstractSocket::SocketError error);
|
||||
void onSocketStateChanged(QAbstractSocket::SocketState socketState);
|
||||
void startUnicastDiscovery();
|
||||
void startMulticastDiscovery();
|
||||
|
||||
void processDatagram(const QHostAddress &senderAddress, quint16 senderPort, const QByteArray &datagram);
|
||||
void processDatagram(const QHostAddress &senderAddress, quint16 senderPort, const QByteArray &datagram, bool multicast);
|
||||
|
||||
void sendDiscoveryRequest();
|
||||
|
||||
void evaluateDiscoveryFinished();
|
||||
|
||||
void finishDiscovery();
|
||||
|
||||
};
|
||||
|
||||
#endif // SPEEDWIREDISCOVERY_H
|
||||
|
|
|
|||
|
|
@ -31,74 +31,117 @@
|
|||
#include "speedwireinterface.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
SpeedwireInterface::SpeedwireInterface(bool multicast, quint32 sourceSerialNumber, QObject *parent) :
|
||||
#include <QNetworkInterface>
|
||||
|
||||
SpeedwireInterface::SpeedwireInterface(quint32 sourceSerialNumber, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_multicast(multicast),
|
||||
m_sourceSerialNumber(sourceSerialNumber)
|
||||
{
|
||||
m_unicast = new QUdpSocket(this);
|
||||
connect(m_unicast, &QUdpSocket::readyRead, this, [=](){
|
||||
QByteArray datagram;
|
||||
QHostAddress senderAddress;
|
||||
quint16 senderPort;
|
||||
|
||||
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)));
|
||||
while (m_unicast->hasPendingDatagrams()) {
|
||||
datagram.resize(m_unicast->pendingDatagramSize());
|
||||
m_unicast->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort);
|
||||
|
||||
qCDebug(dcSma()).noquote() << "SpeedwireInterface: Unicast socket received data from" << QString("%1:%2").arg(senderAddress.toString()).arg(senderPort);
|
||||
qCDebug(dcSma()) << "SpeedwireInterface: " << datagram.toHex();
|
||||
emit dataReceived(senderAddress, senderPort, datagram, false);
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_unicast, &QUdpSocket::stateChanged, this, [=](QAbstractSocket::SocketState socketState){
|
||||
qCDebug(dcSma()) << "SpeedwireInterface: Unicast socket state changed" << socketState;
|
||||
});
|
||||
|
||||
connect(m_unicast, static_cast<void (QUdpSocket::*)( QAbstractSocket::SocketError )>(&QAbstractSocket::error), this, [=](QAbstractSocket::SocketError error){
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Unicast socket error occurred" << error << m_unicast->errorString();
|
||||
});
|
||||
|
||||
|
||||
m_multicast = new QUdpSocket(this);
|
||||
connect(m_multicast, &QUdpSocket::readyRead, this, [=](){
|
||||
QByteArray datagram;
|
||||
QHostAddress senderAddress;
|
||||
quint16 senderPort;
|
||||
|
||||
while (m_multicast->hasPendingDatagrams()) {
|
||||
datagram.resize(m_multicast->pendingDatagramSize());
|
||||
m_multicast->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort);
|
||||
|
||||
qCDebug(dcSma()).noquote() << "SpeedwireInterface: Multicast socket received data from" << QString("%1:%2").arg(senderAddress.toString()).arg(senderPort);
|
||||
//qCDebug(dcSma()) << "SpeedwireInterface: " << datagram.toHex();
|
||||
emit dataReceived(senderAddress, senderPort, datagram, true);
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_multicast, &QUdpSocket::stateChanged, this, [=](QAbstractSocket::SocketState socketState){
|
||||
qCDebug(dcSma()) << "SpeedwireInterface: Multicast socket state changed" << socketState;
|
||||
});
|
||||
connect(m_multicast, static_cast<void (QUdpSocket::*)( QAbstractSocket::SocketError )>(&QAbstractSocket::error), this, [=](QAbstractSocket::SocketError error){
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Multicast socket error occurred" << error << m_multicast->errorString();
|
||||
});
|
||||
|
||||
if (initialize()) {
|
||||
qCDebug(dcSma()) << "SpeedwireInterface: Initialized sucessfully unicast and multicast interface.";
|
||||
} else {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Failed to initialize.";
|
||||
}
|
||||
}
|
||||
|
||||
SpeedwireInterface::~SpeedwireInterface()
|
||||
{
|
||||
deinitialize();
|
||||
}
|
||||
if (m_unicast)
|
||||
m_unicast->close();
|
||||
|
||||
bool SpeedwireInterface::initialize(const QHostAddress &address)
|
||||
{
|
||||
if (m_initialized && !m_multicast) {
|
||||
qCWarning(dcSma()) << "Try to initialize an already initialized speed wire interface. Please deinitialize() before calling this method again.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// If already initialized and multicast, nothing could have changed...done here
|
||||
if (m_initialized && m_multicast)
|
||||
return true;
|
||||
|
||||
|
||||
if (!m_socket->bind(QHostAddress::AnyIPv4, Speedwire::port(), QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint)) {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Initialization failed. Could not bind to port" << Speedwire::port();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_multicast && !m_socket->joinMulticastGroup(Speedwire::multicastAddress())) {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Initialization failed. Could not join multicast group" << Speedwire::multicastAddress().toString() << m_socket->errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
qCDebug(dcSma()) << "SpeedwireInterface: Interface initialized successfully for" << address.toString() << (m_multicast ? "multicast" : "unicast");
|
||||
m_address = address;
|
||||
m_initialized = true;
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
void SpeedwireInterface::deinitialize()
|
||||
{
|
||||
if (m_initialized) {
|
||||
if (m_multicast) {
|
||||
if (!m_socket->leaveMulticastGroup(Speedwire::multicastAddress())) {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Failed to leave multicast group" << Speedwire::multicastAddress().toString();
|
||||
}
|
||||
if (m_multicast) {
|
||||
if (!m_multicast->leaveMulticastGroup(Speedwire::multicastAddress())) {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Failed to leave multicast group" << Speedwire::multicastAddress().toString();
|
||||
}
|
||||
|
||||
m_address = QHostAddress();
|
||||
m_socket->close();
|
||||
m_initialized = false;
|
||||
m_multicast->close();
|
||||
}
|
||||
}
|
||||
|
||||
bool SpeedwireInterface::multicast() const
|
||||
bool SpeedwireInterface::available() const
|
||||
{
|
||||
return m_multicast;
|
||||
return m_available;
|
||||
}
|
||||
|
||||
bool SpeedwireInterface::initialized() const
|
||||
void SpeedwireInterface::reconfigureMulticastGroup()
|
||||
{
|
||||
return m_initialized;
|
||||
qCDebug(dcSma()) << "Reconfigure multicast interfaces";
|
||||
if (m_multicast->joinMulticastGroup(Speedwire::multicastAddress())) {
|
||||
qCDebug(dcSma()) << "SpeedwireInterface: Joined successfully multicast group" << Speedwire::multicastAddress().toString();
|
||||
} else {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Failed to join multicast group" << Speedwire::multicastAddress().toString() << m_multicast->errorString() << "Retrying in 5 seconds...";
|
||||
// FIXME: It would probably be better to monitor the network interfaces and re-join if necessary
|
||||
QTimer::singleShot(5000, this, &SpeedwireInterface::reconfigureMulticastGroup);
|
||||
}
|
||||
|
||||
// foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
|
||||
// if(interface.isValid() && !interface.flags().testFlag(QNetworkInterface::IsLoopBack)
|
||||
// && interface.flags().testFlag(QNetworkInterface::CanMulticast)
|
||||
// && interface.flags().testFlag(QNetworkInterface::IsRunning)) {
|
||||
|
||||
// QList<QNetworkAddressEntry> addressEntries = interface.addressEntries();
|
||||
// for (int i = 0; i < addressEntries.length(); i++) {
|
||||
// if (addressEntries.at(i).ip().protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
|
||||
// if (!m_multicast->joinMulticastGroup(Speedwire::multicastAddress(), interface)) {
|
||||
// qCWarning(dcSma()) << "SpeedwireInterface: Could not join multicast group" << Speedwire::multicastAddress().toString() << "on interface" << interface << m_multicast->errorString();
|
||||
// } else {
|
||||
// qCDebug(dcSma()) << "SpeedwireInterface: Joined successfully multicast group" << Speedwire::multicastAddress().toString() << "on interface" << interface ;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// qCDebug(dcSma()) << "Multicast outgoing interface" << m_multicast->multicastInterface();
|
||||
}
|
||||
|
||||
quint32 SpeedwireInterface::sourceSerialNumber() const
|
||||
|
|
@ -106,40 +149,53 @@ quint32 SpeedwireInterface::sourceSerialNumber() const
|
|||
return m_sourceSerialNumber;
|
||||
}
|
||||
|
||||
void SpeedwireInterface::sendData(const QByteArray &data)
|
||||
bool SpeedwireInterface::initialize()
|
||||
{
|
||||
qCDebug(dcSma()) << "SpeedwireInterface: -->" << m_address.toString() << Speedwire::port() << data.toHex();
|
||||
if (m_socket->writeDatagram(data, m_address, Speedwire::port()) < 0) {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: failed to send data" << m_socket->errorString();
|
||||
bool success = true;
|
||||
if (m_unicast->state() != QUdpSocket::BoundState) {
|
||||
m_unicast->close();
|
||||
if (!m_unicast->bind(QHostAddress::AnyIPv4, Speedwire::port(), QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint)) {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Unicast socket could not be bound to port" << Speedwire::port();
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_multicast->state() != QUdpSocket::BoundState) {
|
||||
if (!m_multicast->bind(QHostAddress::AnyIPv4, Speedwire::port(), QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint)) {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Unicast socket could not be bound to port" << Speedwire::port();
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
reconfigureMulticastGroup();
|
||||
m_available = success;
|
||||
return success;
|
||||
}
|
||||
|
||||
void SpeedwireInterface::sendDataUnicast(const QHostAddress &address, const QByteArray &data)
|
||||
{
|
||||
qCDebug(dcSma()) << "SpeedwireInterface: Unicast -->" << address.toString() << Speedwire::port() << data.toHex();
|
||||
|
||||
if (!m_unicast) {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Failed to send unicast data, the socket is not available";
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_unicast->writeDatagram(data, address, Speedwire::port()) < 0) {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Failed to send unicast data to" << address.toString() << m_unicast->errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedwireInterface::readPendingDatagrams()
|
||||
void SpeedwireInterface::sendDataMulticast(const QByteArray &data)
|
||||
{
|
||||
QByteArray datagram;
|
||||
QHostAddress senderAddress;
|
||||
quint16 senderPort;
|
||||
qCDebug(dcSma()) << "SpeedwireInterface: Multicast -->" << Speedwire::multicastAddress().toString() << Speedwire::port() << data.toHex();
|
||||
if (!m_multicast) {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Failed to send multicast data, the socket is not available";
|
||||
return;
|
||||
}
|
||||
|
||||
while (m_socket->hasPendingDatagrams()) {
|
||||
datagram.resize(m_socket->pendingDatagramSize());
|
||||
m_socket->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort);
|
||||
|
||||
// Process only data coming from our target address if there is any
|
||||
if (!m_address.isNull() && senderAddress != m_address)
|
||||
continue;
|
||||
|
||||
qCDebug(dcSma()) << "SpeedwireInterface: Received data from" << QString("%1:%2").arg(senderAddress.toString()).arg(senderPort);
|
||||
//qCDebug(dcSma()) << "SpeedwireInterface: " << datagram.toHex();
|
||||
emit dataReceived(senderAddress, senderPort, datagram);
|
||||
if (m_multicast->writeDatagram(data, Speedwire::multicastAddress(), Speedwire::port()) < 0) {
|
||||
qCWarning(dcSma()) << "SpeedwireInterface: Failed to send multicast data to" << Speedwire::multicastAddress().toString() << m_multicast->errorString();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <QObject>
|
||||
#include <QUdpSocket>
|
||||
#include <QDataStream>
|
||||
#include <QTimer>
|
||||
|
||||
#include "speedwire.h"
|
||||
|
||||
|
|
@ -41,46 +42,32 @@ class SpeedwireInterface : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum DeviceType {
|
||||
DeviceTypeUnknown,
|
||||
DeviceTypeMeter,
|
||||
DeviceTypeInverter
|
||||
};
|
||||
Q_ENUM(DeviceType)
|
||||
|
||||
explicit SpeedwireInterface(bool multicast, quint32 sourceSerialNumber, QObject *parent = nullptr);
|
||||
explicit SpeedwireInterface(quint32 sourceSerialNumber, QObject *parent = nullptr);
|
||||
~SpeedwireInterface();
|
||||
|
||||
bool initialize(const QHostAddress &address = QHostAddress());
|
||||
void deinitialize();
|
||||
bool available() const;
|
||||
|
||||
bool multicast() const;
|
||||
|
||||
bool initialized() const;
|
||||
|
||||
quint16 sourceModelId() const;
|
||||
quint32 sourceSerialNumber() const;
|
||||
|
||||
bool initialize();
|
||||
|
||||
public slots:
|
||||
void sendData(const QByteArray &data);
|
||||
void sendDataUnicast(const QHostAddress &address, const QByteArray &data);
|
||||
void sendDataMulticast(const QByteArray &data);
|
||||
|
||||
signals:
|
||||
void dataReceived(const QHostAddress &senderAddress, quint16 senderPort, const QByteArray &data);
|
||||
|
||||
private:
|
||||
QUdpSocket *m_socket = nullptr;
|
||||
QHostAddress m_address;
|
||||
bool m_multicast = false;
|
||||
bool m_initialized = false;
|
||||
|
||||
// Requester
|
||||
quint32 m_sourceSerialNumber = 0;
|
||||
void dataReceived(const QHostAddress &senderAddress, quint16 senderPort, const QByteArray &data, bool multicast = false);
|
||||
|
||||
private slots:
|
||||
void readPendingDatagrams();
|
||||
void onSocketError(QAbstractSocket::SocketError error);
|
||||
void onSocketStateChanged(QAbstractSocket::SocketState socketState);
|
||||
void reconfigureMulticastGroup();
|
||||
|
||||
private:
|
||||
QUdpSocket *m_unicast = nullptr;
|
||||
QUdpSocket *m_multicast = nullptr;
|
||||
quint32 m_sourceSerialNumber = 0;
|
||||
bool m_available = false;
|
||||
QTimer m_multicastReconfigureationTimer;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -33,25 +33,15 @@
|
|||
|
||||
#include <QDateTime>
|
||||
|
||||
SpeedwireInverter::SpeedwireInverter(const QHostAddress &address, quint16 modelId, quint32 serialNumber, QObject *parent) :
|
||||
SpeedwireInverter::SpeedwireInverter(SpeedwireInterface *speedwireInterface, const QHostAddress &address, quint16 modelId, quint32 serialNumber, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_speedwireInterface(speedwireInterface),
|
||||
m_address(address),
|
||||
m_modelId(modelId),
|
||||
m_serialNumber(serialNumber)
|
||||
{
|
||||
qCDebug(dcSma()) << "Inverter: setup interface on" << m_address.toString();
|
||||
m_interface = new SpeedwireInterface(false, serialNumber, this);
|
||||
connect(m_interface, &SpeedwireInterface::dataReceived, this, &SpeedwireInverter::processData);
|
||||
}
|
||||
|
||||
bool SpeedwireInverter::initialize()
|
||||
{
|
||||
return m_interface->initialize(m_address);
|
||||
}
|
||||
|
||||
bool SpeedwireInverter::initialized() const
|
||||
{
|
||||
return m_interface->initialized();
|
||||
connect(m_speedwireInterface, &SpeedwireInterface::dataReceived, this, &SpeedwireInverter::processData);
|
||||
}
|
||||
|
||||
SpeedwireInverter::State SpeedwireInverter::state() const
|
||||
|
|
@ -270,7 +260,7 @@ SpeedwireInverterReply *SpeedwireInverter::sendLogoutRequest()
|
|||
|
||||
// Source
|
||||
stream << Speedwire::sourceModelId();
|
||||
stream << m_interface->sourceSerialNumber();
|
||||
stream << m_speedwireInterface->sourceSerialNumber();
|
||||
stream << static_cast<quint16>(0x0300);
|
||||
|
||||
stream << static_cast<quint16>(0);
|
||||
|
|
@ -413,7 +403,7 @@ void SpeedwireInverter::sendNextReply()
|
|||
// Pick the next reply and send request
|
||||
m_currentReply = m_replyQueue.dequeue();
|
||||
qCDebug(dcSma()) << "Inverter: --> Sending" << m_currentReply->request().command() << "packet ID:" << m_currentReply->request().packetId();
|
||||
m_interface->sendData(m_currentReply->request().requestData());
|
||||
m_speedwireInterface->sendDataUnicast(m_address, m_currentReply->request().requestData());
|
||||
m_currentReply->startWaiting();
|
||||
}
|
||||
|
||||
|
|
@ -489,7 +479,7 @@ void SpeedwireInverter::buildPacket(QDataStream &stream, quint32 command, quint1
|
|||
// Destination Ctrl
|
||||
stream << static_cast<quint16>(0x0100);
|
||||
// Source
|
||||
stream << Speedwire::sourceModelId() << m_interface->sourceSerialNumber();
|
||||
stream << Speedwire::sourceModelId() << m_speedwireInterface->sourceSerialNumber();
|
||||
// Destination Ctrl
|
||||
stream << static_cast<quint16>(0x0100);
|
||||
|
||||
|
|
@ -1176,10 +1166,12 @@ void SpeedwireInverter::setBatteryAvailable(bool available)
|
|||
|
||||
void SpeedwireInverter::processData(const QHostAddress &senderAddress, quint16 senderPort, const QByteArray &data)
|
||||
{
|
||||
// Note: the interface is already filtering out data from other hosts m_address
|
||||
Q_UNUSED(senderAddress)
|
||||
Q_UNUSED(senderPort)
|
||||
|
||||
// Process only data coming from our target address if there is any
|
||||
if (!m_address.isNull() && senderAddress != m_address)
|
||||
return;
|
||||
|
||||
if (data.size() < 18) {
|
||||
qCDebug(dcSma()) << "Inverter: The received datagram is to short to be a SMA speedwire message. Ignoring data...";
|
||||
return;
|
||||
|
|
@ -1193,7 +1185,7 @@ void SpeedwireInverter::processData(const QHostAddress &senderAddress, quint16 s
|
|||
}
|
||||
|
||||
if (header.protocolId != Speedwire::ProtocolIdInverter) {
|
||||
qCWarning(dcSma()) << "Inverter: Received datagram from different protocol" << header.protocolId << "Ignoring data...";
|
||||
//qCWarning(dcSma()) << "Inverter: Received datagram from different protocol" << header.protocolId << "Ignoring data...";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1478,6 +1470,7 @@ void SpeedwireInverter::setState(State state)
|
|||
qCDebug(dcSma()) << "Inverter: Failed to query battery info from inverter:" << reply->request().command() << reply->error();
|
||||
setBatteryAvailable(false);
|
||||
setState(StateIdle);
|
||||
return;
|
||||
} else {
|
||||
qCDebug(dcSma()) << "Inverter: Process battery info response" << reply->responsePayload().toHex();
|
||||
processBatteryInfoResponse(reply->responsePayload());
|
||||
|
|
@ -1490,6 +1483,7 @@ void SpeedwireInverter::setState(State state)
|
|||
qCWarning(dcSma()) << "Inverter: Failed to query battery charge status from inverter:" << reply->request().command() << reply->error();
|
||||
setBatteryAvailable(false);
|
||||
setState(StateIdle);
|
||||
return;
|
||||
} else {
|
||||
qCDebug(dcSma()) << "Inverter: Process battery charge status response" << reply->responsePayload().toHex();
|
||||
processBatteryChargeResponse(reply->responsePayload());
|
||||
|
|
|
|||
|
|
@ -54,10 +54,7 @@ public:
|
|||
};
|
||||
Q_ENUM(State)
|
||||
|
||||
explicit SpeedwireInverter(const QHostAddress &address, quint16 modelId, quint32 serialNumber, QObject *parent = nullptr);
|
||||
|
||||
bool initialize();
|
||||
bool initialized() const;
|
||||
explicit SpeedwireInverter(SpeedwireInterface *speedwireInterface, const QHostAddress &address, quint16 modelId, quint32 serialNumber, QObject *parent = nullptr);
|
||||
|
||||
State state() const;
|
||||
|
||||
|
|
@ -124,7 +121,7 @@ signals:
|
|||
void batteryValuesUpdated();
|
||||
|
||||
private:
|
||||
SpeedwireInterface *m_interface = nullptr;
|
||||
SpeedwireInterface *m_speedwireInterface = nullptr;
|
||||
QHostAddress m_address;
|
||||
QString m_password;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@
|
|||
|
||||
#include "sma.h"
|
||||
|
||||
SpeedwireMeter::SpeedwireMeter(SpeedwireInterface *multicastInterface, quint16 modelId, quint32 serialNumber, QObject *parent) :
|
||||
SpeedwireMeter::SpeedwireMeter(SpeedwireInterface *speedwireInterface, quint16 modelId, quint32 serialNumber, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_interface(multicastInterface),
|
||||
m_speedwireInterface(speedwireInterface),
|
||||
m_modelId(modelId),
|
||||
m_serialNumber(serialNumber)
|
||||
{
|
||||
connect(m_interface, &SpeedwireInterface::dataReceived, this, &SpeedwireMeter::processData);
|
||||
connect(m_speedwireInterface, &SpeedwireInterface::dataReceived, this, &SpeedwireMeter::processData);
|
||||
|
||||
// Reachable timestamp
|
||||
m_timer.setInterval(5000);
|
||||
|
|
@ -47,20 +47,6 @@ SpeedwireMeter::SpeedwireMeter(SpeedwireInterface *multicastInterface, quint16 m
|
|||
connect(&m_timer, &QTimer::timeout, this, &SpeedwireMeter::evaluateReachable);
|
||||
}
|
||||
|
||||
bool SpeedwireMeter::initialize()
|
||||
{
|
||||
bool initSuccess = m_interface->initialize();
|
||||
if (initSuccess)
|
||||
m_timer.start();
|
||||
|
||||
return initSuccess;
|
||||
}
|
||||
|
||||
bool SpeedwireMeter::initialized() const
|
||||
{
|
||||
return m_interface->initialized();
|
||||
}
|
||||
|
||||
bool SpeedwireMeter::reachable() const
|
||||
{
|
||||
return m_reachable;
|
||||
|
|
@ -186,8 +172,10 @@ void SpeedwireMeter::evaluateReachable()
|
|||
}
|
||||
}
|
||||
|
||||
void SpeedwireMeter::processData(const QHostAddress &senderAddress, quint16 senderPort, const QByteArray &data)
|
||||
void SpeedwireMeter::processData(const QHostAddress &senderAddress, quint16 senderPort, const QByteArray &data, bool multicast)
|
||||
{
|
||||
Q_UNUSED(multicast)
|
||||
|
||||
QDataStream stream(data);
|
||||
stream.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
|
|
@ -220,7 +208,7 @@ void SpeedwireMeter::processData(const QHostAddress &senderAddress, quint16 send
|
|||
qCDebug(dcSma()) << "Meter: ======================= Meter measurements";
|
||||
quint32 timestamp;
|
||||
stream >> timestamp;
|
||||
qCDebug(dcSma()) << "Meter: Timestamp:" << timestamp << QDateTime::fromMSecsSinceEpoch(timestamp * 1000);
|
||||
qCDebug(dcSma()) << "Meter: Timestamp:" << timestamp << QDateTime::fromMSecsSinceEpoch(static_cast<qulonglong>(timestamp) * 1000);
|
||||
|
||||
// Obis data
|
||||
//00 01 04 00 00000000 00 01 08 00 0000002139122910 00 02 04 00 00004415 00 02 08 00 0000001575a137d8 00 03 04 00 00000000 00 03 08 00 00000003debed0e8 00040400000017c6000408000000001008c2070000090400000000000009080000000027c77bed20000a04000000481d000a08000000001722823410000d0400000003b00015040000000000001508000000000d1e1e0e3000160400000015120016080000000006c5a2d8b800170400000000000017080000000001bd6f680000180400000007990018080000000004def712b8001d040000000000001d08000000000eeefaafd0001e040000001666001e0800000000074b38bf88001f040000000a300020040000037bcb00210400000003ad0029040000000000002908000000000a9b1afec8002a040000001a81002a08000000000803e62b88002b040000000000002b080000000001511459b8002c0400000006d5002c0800000000052c8455b80031040000000000003108000000000cf83b37100032040000001b5f0032080000000008a6e257f80033040000000c3f003404000003747900350400000003c8003d040000000000003d08000000000a53d0ba08003e040000001482003e080000000007800fd188003f040000000000003f080000000001185820c8004004000000095800400800000000064563b1900045040000000000004508000000000d26d3eae0004604000000168900460800000000082b4fc5a80047040000000a440048040000037ed1004904000000038e90000000 01020852 00000000
|
||||
|
|
|
|||
|
|
@ -41,10 +41,7 @@ class SpeedwireMeter : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SpeedwireMeter(SpeedwireInterface *multicastInterface, quint16 modelId, quint32 serialNumber, QObject *parent = nullptr);
|
||||
|
||||
bool initialize();
|
||||
bool initialized() const;
|
||||
explicit SpeedwireMeter(SpeedwireInterface *speedwireInterface, quint16 modelId, quint32 serialNumber, QObject *parent = nullptr);
|
||||
|
||||
bool reachable() const;
|
||||
|
||||
|
|
@ -79,7 +76,7 @@ signals:
|
|||
void valuesUpdated();
|
||||
|
||||
private:
|
||||
SpeedwireInterface *m_interface = nullptr;
|
||||
SpeedwireInterface *m_speedwireInterface = nullptr;
|
||||
QHostAddress m_address;
|
||||
bool m_initialized = false;
|
||||
quint16 m_modelId = 0;
|
||||
|
|
@ -118,7 +115,7 @@ private:
|
|||
|
||||
private slots:
|
||||
void evaluateReachable();
|
||||
void processData(const QHostAddress &senderAddress, quint16 senderPort, const QByteArray &data);
|
||||
void processData(const QHostAddress &senderAddress, quint16 senderPort, const QByteArray &data, bool multicast);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue