diff --git a/modbus/modbustcpmaster.cpp b/modbus/modbustcpmaster.cpp index aeeba5f..48bce17 100644 --- a/modbus/modbustcpmaster.cpp +++ b/modbus/modbustcpmaster.cpp @@ -38,7 +38,7 @@ ModbusTCPMaster::ModbusTCPMaster(const QHostAddress &hostAddress, uint port, QOb m_modbusTcpClient = new QModbusTcpClient(this); m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, port); m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, hostAddress.toString()); - m_modbusTcpClient->setTimeout(100); + m_modbusTcpClient->setTimeout(1000); m_modbusTcpClient->setNumberOfRetries(3); connect(m_modbusTcpClient, &QModbusTcpClient::stateChanged, this, &ModbusTCPMaster::onModbusStateChanged); @@ -190,7 +190,7 @@ QUuid ModbusTCPMaster::writeHoldingRegisters(uint slaveAddress, uint registerAdd emit writeRequestError(requestId, reply->errorString()); reply->finished(); // To make sure it will be deleted }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); + QTimer::singleShot(2000, reply, &QModbusReply::deleteLater); } else { delete reply; // broadcast replies return immediately return ""; @@ -234,7 +234,7 @@ QUuid ModbusTCPMaster::readDiscreteInput(uint slaveAddress, uint registerAddress emit writeRequestError(requestId, reply->errorString()); reply->finished(); // To make sure it will be deleted }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); + QTimer::singleShot(2000, reply, &QModbusReply::deleteLater); } else { delete reply; // broadcast replies return immediately return ""; @@ -277,7 +277,7 @@ QUuid ModbusTCPMaster::readInputRegister(uint slaveAddress, uint registerAddress emit writeRequestError(requestId, reply->errorString()); reply->finished(); // To make sure it will be deleted }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); + QTimer::singleShot(2000, reply, &QModbusReply::deleteLater); } else { delete reply; // broadcast replies return immediately return ""; @@ -321,7 +321,7 @@ QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddre emit writeRequestError(requestId, reply->errorString()); reply->finished(); // To make sure it will be deleted }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); + QTimer::singleShot(2000, reply, &QModbusReply::deleteLater); } else { delete reply; // broadcast replies return immediately return ""; @@ -371,7 +371,7 @@ QUuid ModbusTCPMaster::writeCoils(uint slaveAddress, uint registerAddress, const emit writeRequestError(requestId, reply->errorString()); reply->finished(); // To make sure it will be deleted }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); + QTimer::singleShot(2000, reply, &QModbusReply::deleteLater); } else { delete reply; // broadcast replies return immediately return ""; @@ -397,7 +397,7 @@ void ModbusTCPMaster::onModbusErrorOccurred(QModbusDevice::Error error) void ModbusTCPMaster::onModbusStateChanged(QModbusDevice::State state) { - bool connected = (state != QModbusDevice::UnconnectedState); + bool connected = (state == QModbusDevice::ConnectedState); if (!connected) { //try to reconnect in 10 seconds m_reconnectTimer->start(10000); diff --git a/wallbe/discover.cpp b/wallbe/discover.cpp deleted file mode 100644 index 41d4034..0000000 --- a/wallbe/discover.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2020, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project 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 project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include "discover.h" -#include "extern-plugininfo.h" - -Discover::Discover(QStringList arguments, QObject *parent) : - QObject(parent), - m_arguments(arguments), - m_discoveryProcess(nullptr), - m_aboutToQuit(false) -{ -} - -Discover::~Discover() -{ - // Stop running processes - m_aboutToQuit = true; - - if (m_discoveryProcess && m_discoveryProcess->state() == QProcess::Running) { - qCDebug(dcWallbe()) << "Kill running discovery process"; - m_discoveryProcess->terminate(); - m_discoveryProcess->waitForFinished(5000); - } -} - -QStringList Discover::getDefaultTargets() -{ - QStringList targets; - foreach (const QHostAddress &interface, QNetworkInterface::allAddresses()) { - if (!interface.isLoopback() && interface.scopeId().isEmpty()) { - QPair pair = QHostAddress::parseSubnet(interface.toString() + "/24"); - targets << QString("%1/%2").arg(pair.first.toString()).arg(pair.second); - } - } - return targets; -} - -QList Discover::parseProcessOutput(const QByteArray &processData) -{ - m_reader.clear(); - m_reader.addData(processData); - - QList hosts; - - while (!m_reader.atEnd() && !m_reader.hasError()) { - - QXmlStreamReader::TokenType token = m_reader.readNext(); - if(token == QXmlStreamReader::StartDocument) - continue; - - if(token == QXmlStreamReader::StartElement && m_reader.name() == "host") { - Host host = parseHost(); - if (host.isValid()) { - hosts.append(host); - } - } - } - return hosts; -} - -Host Discover::parseHost() -{ - if (!m_reader.isStartElement() || m_reader.name() != "host") - return Host(); - - QString address; QString hostName; QString status; QString mac; - while(!(m_reader.tokenType() == QXmlStreamReader::EndElement && m_reader.name() == "host")){ - - m_reader.readNext(); - - if (m_reader.isStartElement() && m_reader.name() == "hostname") { - QString name = m_reader.attributes().value("name").toString(); - if (!name.isEmpty()) - hostName = name; - - m_reader.readNext(); - } - - if (m_reader.name() == "address") { - QString addr = m_reader.attributes().value("addr").toString(); - if (!addr.isEmpty()) - address = addr; - } - - if (m_reader.name() == "state") { - QString state = m_reader.attributes().value("state").toString(); - if (!state.isEmpty()) - status = state; - } - - if (m_reader.name() == "mac") { //TODO CHeck Keyword - QString macAddress = m_reader.attributes().value("state").toString(); - if (!macAddress.isEmpty()) - mac = macAddress; - } - } - return Host(hostName, address, mac, (status == "open" ? true : false)); -} - -void Discover::processFinished(int exitCode, QProcess::ExitStatus exitStatus) -{ - QProcess *process = static_cast(sender()); - - // If the process was killed because nymead is shutting down...we dont't care any more about the result - if (m_aboutToQuit) - return; - - // Discovery - if (process == m_discoveryProcess) { - - qCDebug(dcWallbe()) << "Discovery process finished"; - - process->deleteLater(); - m_discoveryProcess = nullptr; - - if (exitCode != 0 || exitStatus != QProcess::NormalExit) { - qCWarning(dcWallbe()) << "Network scan error:" << process->readAllStandardError(); - return; - } - - QByteArray outputData = process->readAllStandardOutput(); - emit devicesDiscovered(parseProcessOutput(outputData)); - - } -} - -bool Discover::getProcessStatus() -{ - return m_discoveryProcess; -} - -void Discover::onTimeout() -{ - -} diff --git a/wallbe/discovery.cpp b/wallbe/discovery.cpp new file mode 100644 index 0000000..a08cc68 --- /dev/null +++ b/wallbe/discovery.cpp @@ -0,0 +1,271 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project 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 project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "discovery.h" +#include "extern-plugininfo.h" + +#include +#include +#include +#include +#include + +Discovery::Discovery(QObject *parent) : QObject(parent) +{ + connect(&m_timeoutTimer, &QTimer::timeout, this, &Discovery::onTimeout); +} + +void Discovery::discoverHosts(int timeout) +{ + if (isRunning()) { + qCWarning(dcWallbe()) << "Discovery already running. Cannot start twice."; + return; + } + m_timeoutTimer.start(timeout * 1000); + + foreach (const QString &target, getDefaultTargets()) { + QProcess *discoveryProcess = new QProcess(this); + m_discoveryProcesses.append(discoveryProcess); + connect(discoveryProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(discoveryFinished(int,QProcess::ExitStatus))); + + QStringList arguments; + arguments << "-oX" << "-" << "-n" << "-sn"; + arguments << target; + + qCDebug(dcWallbe()) << "Scanning network:" << "nmap" << arguments.join(" "); + discoveryProcess->start(QStringLiteral("nmap"), arguments); + } +} + +void Discovery::abort() +{ + foreach (QProcess *discoveryProcess, m_discoveryProcesses) { + if (discoveryProcess->state() == QProcess::Running) { + qCDebug(dcWallbe()) << "Kill running discovery process"; + discoveryProcess->terminate(); + discoveryProcess->waitForFinished(5000); + } + } + foreach (QProcess *p, m_pendingArpLookups.keys()) { + p->terminate(); + delete p; + } + m_pendingArpLookups.clear(); + m_pendingNameLookups.clear(); + qDeleteAll(m_scanResults); + m_scanResults.clear(); +} + +bool Discovery::isRunning() const +{ + return !m_discoveryProcesses.isEmpty() || !m_pendingArpLookups.isEmpty() || !m_pendingNameLookups.isEmpty(); +} + +void Discovery::discoveryFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + QProcess *discoveryProcess = static_cast(sender()); + + if (exitCode != 0 || exitStatus != QProcess::NormalExit) { + qCWarning(dcWallbe()) << "Nmap error failed. Is nmap installed correctly?"; + m_discoveryProcesses.removeAll(discoveryProcess); + discoveryProcess->deleteLater(); + discoveryProcess = nullptr; + finishDiscovery(); + return; + } + + QByteArray data = discoveryProcess->readAll(); + m_discoveryProcesses.removeAll(discoveryProcess); + discoveryProcess->deleteLater(); + discoveryProcess = nullptr; + + QXmlStreamReader reader(data); + + int foundHosts = 0; + qCDebug(dcWallbe()) << "nmap finished network discovery:"; + while (!reader.atEnd() && !reader.hasError()) { + QXmlStreamReader::TokenType token = reader.readNext(); + if(token == QXmlStreamReader::StartDocument) + continue; + + if(token == QXmlStreamReader::StartElement && reader.name() == "host") { + bool isUp = false; + QString address; + QString macAddress; + QString vendor; + while (!reader.atEnd() && !reader.hasError() && !(token == QXmlStreamReader::EndElement && reader.name() == "host")) { + token = reader.readNext(); + + if (reader.name() == "address") { + QString addr = reader.attributes().value("addr").toString(); + QString type = reader.attributes().value("addrtype").toString(); + if (type == "ipv4" && !addr.isEmpty()) { + address = addr; + } else if (type == "mac") { + macAddress = addr; + vendor = reader.attributes().value("vendor").toString(); + } + } + + if (reader.name() == "status") { + QString state = reader.attributes().value("state").toString(); + if (!state.isEmpty()) + isUp = state == "up"; + } + } + + if (isUp) { + foundHosts++; + qCDebug(dcWallbe()) << " - host:" << vendor << address << macAddress; + + Host *host = new Host(); + host->setAddress(address); + + if (!macAddress.isEmpty()) { + host->setMacAddress(macAddress); + } else { + QProcess *arpLookup = new QProcess(this); + m_pendingArpLookups.insert(arpLookup, host); + connect(arpLookup, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(arpLookupDone(int,QProcess::ExitStatus))); + arpLookup->start("arp", {"-vn"}); + } + + host->setVendor(vendor); + QHostInfo::lookupHost(address, this, SLOT(hostLookupDone(QHostInfo))); + m_pendingNameLookups.insert(address, host); + + m_scanResults.append(host); + } + } + } + + if (foundHosts == 0 && m_discoveryProcesses.isEmpty()) { + qCDebug(dcWallbe()) << "Network scan successful but no hosts found in this network"; + finishDiscovery(); + } +} + +void Discovery::hostLookupDone(const QHostInfo &info) +{ + Host *host = m_pendingNameLookups.take(info.addresses().first().toString()); + if (!host) { + // Probably aborted... + return; + } + if (info.error() != QHostInfo::NoError) { + qWarning(dcWallbe()) << "Host lookup failed:" << info.errorString(); + } + if (host->hostName().isEmpty() || info.hostName() != host->address()) { + host->setHostName(info.hostName()); + } + + finishDiscovery(); +} + +void Discovery::arpLookupDone(int exitCode, QProcess::ExitStatus exitStatus) +{ + QProcess *p = static_cast(sender()); + p->deleteLater(); + + Host *host = m_pendingArpLookups.take(p); + + if (exitCode != 0 || exitStatus != QProcess::NormalExit) { + qCWarning(dcWallbe()) << "ARP lookup process failed for host" << host->address(); + finishDiscovery(); + return; + } + + QString data = QString::fromLatin1(p->readAll()); + foreach (QString line, data.split('\n')) { + line.replace(QRegExp("[ ]{1,}"), " "); + QStringList parts = line.split(" "); + if (parts.count() >= 3 && parts.first() == host->address() && parts.at(1) == "ether") { + host->setMacAddress(parts.at(2)); + break; + } + } + finishDiscovery(); +} + +void Discovery::onTimeout() +{ + qWarning(dcWallbe()) << "Timeout hit. Stopping discovery"; + while (!m_discoveryProcesses.isEmpty()) { + QProcess *discoveryProcess = m_discoveryProcesses.takeFirst(); + disconnect(this, SLOT(discoveryFinished(int,QProcess::ExitStatus))); + discoveryProcess->terminate(); + delete discoveryProcess; + } + foreach (QProcess *p, m_pendingArpLookups.keys()) { + p->terminate(); + m_scanResults.removeAll(m_pendingArpLookups.value(p)); + delete p; + } + m_pendingArpLookups.clear(); + m_pendingNameLookups.clear(); + finishDiscovery(); +} + +QStringList Discovery::getDefaultTargets() +{ + QStringList targets; + foreach (const QHostAddress &interface, QNetworkInterface::allAddresses()) { + if (!interface.isLoopback() && interface.scopeId().isEmpty() && interface.protocol() == QAbstractSocket::IPv4Protocol) { + QPair pair = QHostAddress::parseSubnet(interface.toString() + "/24"); + QString newTarget = QString("%1/%2").arg(pair.first.toString()).arg(pair.second); + if (!targets.contains(newTarget)) { + targets.append(newTarget); + } + } + } + return targets; +} + +void Discovery::finishDiscovery() +{ + if (m_discoveryProcesses.count() > 0 || m_pendingNameLookups.count() > 0 || m_pendingArpLookups.count() > 0) { + // Still busy... + return; + } + + QList hosts; + foreach (Host *host, m_scanResults) { + if (!host->macAddress().isEmpty()) { + hosts.append(*host); + } + } + qDeleteAll(m_scanResults); + m_scanResults.clear(); + + qCDebug(dcWallbe()) << "Found" << hosts.count() << "network devices"; + m_timeoutTimer.stop(); + emit finished(hosts); +} + diff --git a/wallbe/discover.h b/wallbe/discovery.h similarity index 69% rename from wallbe/discover.h rename to wallbe/discovery.h index 6e07191..02284c3 100644 --- a/wallbe/discover.h +++ b/wallbe/discovery.h @@ -28,49 +28,48 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef DISCOVER_H -#define DISCOVER_H +#ifndef DISCOVERY_H +#define DISCOVERY_H #include #include -#include +#include #include -#include #include "host.h" -class Discover : public QObject +class Discovery : public QObject { Q_OBJECT public: + explicit Discovery(QObject *parent = nullptr); - explicit Discover(QStringList arguments, QObject *parent = nullptr); - ~Discover(); - bool getProcessStatus(); - -private: - QTimer *m_timer; - QStringList m_arguments; - - QProcess * m_discoveryProcess; - QProcess * m_scanProcess; - - QXmlStreamReader m_reader; - - bool m_aboutToQuit; - - QStringList getDefaultTargets(); - void processFinished(int exitCode, QProcess::ExitStatus exitStatus); - - // Process parsing - QList parseProcessOutput(const QByteArray &processData); - Host parseHost(); + void discoverHosts(int timeout); + void abort(); + bool isRunning() const; signals: - void devicesDiscovered(QList); + void finished(const QList &hosts); + +private: + QStringList getDefaultTargets(); + + void finishDiscovery(); private slots: + void discoveryFinished(int exitCode, QProcess::ExitStatus exitStatus); + void hostLookupDone(const QHostInfo &info); + void arpLookupDone(int exitCode, QProcess::ExitStatus exitStatus); void onTimeout(); + +private: + QList m_discoveryProcesses; + QTimer m_timeoutTimer; + + QHash m_pendingArpLookups; + QHash m_pendingNameLookups; + QList m_scanResults; }; -#endif // DISCOVER_H +#endif // DISCOVERY_H + diff --git a/wallbe/host.cpp b/wallbe/host.cpp index 6eb0468..e746395 100644 --- a/wallbe/host.cpp +++ b/wallbe/host.cpp @@ -32,26 +32,8 @@ Host::Host() { - -} - -Host::Host(const QString &hostName, const QString &address, const QString &macAddress, const bool &reachable): - m_hostName(hostName), - m_address(address), - m_macAddress(macAddress), - m_reachable(reachable) -{ - -} - -QString Host::hostName() const -{ - return m_hostName; -} - -QString Host::address() const -{ - return m_address; + qRegisterMetaType(); + qRegisterMetaType >(); } QString Host::macAddress() const @@ -59,18 +41,64 @@ QString Host::macAddress() const return m_macAddress; } +void Host::setMacAddress(const QString &macAddress) +{ + m_macAddress = macAddress; +} + +QString Host::hostName() const +{ + return m_hostName; +} + +void Host::setHostName(const QString &hostName) +{ + m_hostName = hostName; +} + +QString Host::vendor() const +{ + return m_vendor; +} + +void Host::setVendor(const QString &vendor) +{ + m_vendor = vendor; +} + +QString Host::address() const +{ + return m_address; +} + +void Host::setAddress(const QString &address) +{ + m_address = address; +} + +void Host::seen() +{ + m_lastSeenTime = QDateTime::currentDateTime(); +} + +QDateTime Host::lastSeenTime() const +{ + return m_lastSeenTime; +} + bool Host::reachable() const { return m_reachable; } -bool Host::isValid() const +void Host::setReachable(bool reachable) { - return !m_hostName.isEmpty() && !m_address.isEmpty(); + m_reachable = reachable; } QDebug operator<<(QDebug dbg, const Host &host) { - dbg.nospace() << "Host(" << host.hostName() << ", " << host.address() << ", " << (host.reachable() ? "up" : "down") << ")"; + dbg.nospace() << "Host(" << host.macAddress() << "," << host.hostName() << ", " << host.address() << ", " << (host.reachable() ? "up" : "down") << ")"; return dbg.space(); } + diff --git a/wallbe/host.h b/wallbe/host.h index 41e5ac0..0c982b4 100644 --- a/wallbe/host.h +++ b/wallbe/host.h @@ -33,27 +33,42 @@ #include #include +#include class Host { public: Host(); - Host(const QString &hostName, const QString &address, const QString &macAddress, const bool &reachable); + + QString macAddress() const; + void setMacAddress(const QString &macAddress); QString hostName() const; - QString address() const; - QString macAddress() const; - bool reachable() const; + void setHostName(const QString &hostName); - bool isValid() const; + QString vendor() const; + void setVendor(const QString &vendor); + + QString address() const; + void setAddress(const QString &address); + + void seen(); + QDateTime lastSeenTime() const; + + bool reachable() const; + void setReachable(bool reachable); private: + QString m_macAddress; QString m_hostName; QString m_address; - QString m_macAddress; + QString m_vendor; + QDateTime m_lastSeenTime; bool m_reachable; }; +Q_DECLARE_METATYPE(Host) QDebug operator<<(QDebug dbg, const Host &host); #endif // HOST_H + diff --git a/wallbe/integrationpluginwallbe.cpp b/wallbe/integrationpluginwallbe.cpp index 27bb10b..6865beb 100644 --- a/wallbe/integrationpluginwallbe.cpp +++ b/wallbe/integrationpluginwallbe.cpp @@ -43,31 +43,33 @@ IntegrationPluginWallbe::IntegrationPluginWallbe() { } +void IntegrationPluginWallbe::init() { -void IntegrationPluginWallbe::setupThing(ThingSetupInfo *info) -{ - Thing *thing = info->thing(); - qCDebug(dcWallbe) << "Setting up a new device:" << thing->params(); + m_discovery = new Discovery(); + connect(m_discovery, &Discovery::finished, this, [this](const QList &hosts) { + foreach (const Host &host, hosts) { + if (!host.vendor().contains("Phoenix", Qt::CaseSensitivity::CaseInsensitive)) + continue; - QHostAddress address(thing->paramValue(wallbeEcoThingIpParamTypeId).toString()); + Q_FOREACH(Thing *existingThing, myThings()) { + if (existingThing->paramValue(wallbeEcoThingMacParamTypeId).toString().isEmpty()) { + //This device got probably manually setup, to enable auto rediscovery the MAC address needs to setup + if (existingThing->paramValue(wallbeEcoThingIpParamTypeId).toString() == host.address()) { + qCDebug(dcWallbe()) << "Wallbe Wallbox MAC Address has been discovered" << existingThing->name() << host.macAddress(); + existingThing->setParamValue(wallbeEcoThingMacParamTypeId, host.macAddress()); - if (address.isNull()){ - qCWarning(dcWallbe) << "IP address is not valid"; - info->finish(Thing::ThingErrorSetupFailed, tr("Invalid IP address")); - return; - } - ModbusTCPMaster *modbusTcpMaster = new ModbusTCPMaster(address, 502, this); - connect(modbusTcpMaster, &ModbusTCPMaster::connectionStateChanged, this, &IntegrationPluginWallbe::onConnectionStateChanged); - connect(modbusTcpMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &IntegrationPluginWallbe::onReceivedHoldingRegister); - connect(modbusTcpMaster, &ModbusTCPMaster::writeRequestExecuted, this, &IntegrationPluginWallbe::onWriteRequestExecuted); - connect(modbusTcpMaster, &ModbusTCPMaster::writeRequestError, this, &IntegrationPluginWallbe::onWriteRequestError); + } + } else if (existingThing->paramValue(wallbeEcoThingMacParamTypeId).toString() == host.macAddress()) { + if (existingThing->paramValue(wallbeEcoThingIpParamTypeId).toString() != host.address()) { + qCDebug(dcWallbe()) << "Wallbe Wallbox IP Address has changed, from" << existingThing->paramValue(wallbeEcoThingIpParamTypeId).toString() << "to" << host.address(); + existingThing->setParamValue(wallbeEcoThingIpParamTypeId, host.address()); - m_connections.insert(thing, modbusTcpMaster); - connect(modbusTcpMaster, &ModbusTCPMaster::connectionStateChanged, info, [this, info, modbusTcpMaster](bool connected) { - if(connected) { - info->finish(Thing::ThingErrorNoError); - } else { - info->finish(Thing::ThingErrorHardwareNotAvailable); + } else { + qCDebug(dcWallbe()) << "Wallbe Wallbox" << existingThing->name() << "IP address has not changed" << host.address(); + } + break; + } + } } }); } @@ -76,16 +78,26 @@ void IntegrationPluginWallbe::setupThing(ThingSetupInfo *info) void IntegrationPluginWallbe::discoverThings(ThingDiscoveryInfo *info) { if (info->thingClassId() == wallbeEcoThingClassId){ + qCDebug(dcWallbe) << "Start Wallbe eco discovery"; - Discover *discover = new Discover(QStringList("-xO" "-p 502")); - connect(discover, &Discover::devicesDiscovered, this, [info, this](QList hosts){ - foreach (Host host, hosts) { - ThingDescriptor descriptor; - foreach(Thing *thing, myThings().filterByParam(wallbeEcoThingMacParamTypeId, host.macAddress())) { - descriptor.setThingId(thing->id()); - break; + m_discovery->discoverHosts(50); + connect(m_discovery, &Discovery::finished, info, [this, info] (const QList &hosts) { + + foreach (const Host &host, hosts) { + if (!host.vendor().contains("Phoenix", Qt::CaseSensitivity::CaseInsensitive)) + continue; + + ThingDescriptor descriptor(wallbeEcoThingClassId); + // Rediscovery + foreach (Thing *existingThing, myThings()) { + if (existingThing->paramValue(wallbeEcoThingMacParamTypeId).toString() == host.macAddress()) { + qCDebug(dcWallbe()) << " - Device is already added"; + descriptor.setThingId(existingThing->id()); + break; + } } - descriptor.setTitle(host.hostName()); + descriptor.setTitle(host.hostName().remove(".localdomain")); + descriptor.setDescription(host.address()); ParamList params; params.append(Param(wallbeEcoThingIpParamTypeId, host.address())); params.append(Param(wallbeEcoThingMacParamTypeId, host.macAddress())); @@ -99,18 +111,63 @@ void IntegrationPluginWallbe::discoverThings(ThingDiscoveryInfo *info) } } -void IntegrationPluginWallbe::postSetupThing(Thing *thing) + +void IntegrationPluginWallbe::setupThing(ThingSetupInfo *info) { - if (!m_pluginTimer) { - m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(120); - connect(m_pluginTimer, &PluginTimer::timeout, this, [this] { - foreach(Thing *thing, m_connections.keys()) { - update(thing); + Thing *thing = info->thing(); + qCDebug(dcWallbe) << "Setting up a new device:" << thing->params(); + + if (thing->thingClassId() == wallbeEcoThingClassId) { + QHostAddress address(thing->paramValue(wallbeEcoThingIpParamTypeId).toString()); + + if (m_connections.contains(thing)) { + qCDebug(dcWallbe()) << "Setup after reconfiguration, cleaning up ..."; + m_connections.take(thing)->deleteLater(); + } + if (address.isNull()){ + qCWarning(dcWallbe) << "IP address is not valid"; + info->finish(Thing::ThingErrorSetupFailed, tr("Invalid IP address")); + return; + } + ModbusTCPMaster *modbusTcpMaster = new ModbusTCPMaster(address, 502, this); + connect(modbusTcpMaster, &ModbusTCPMaster::connectionStateChanged, this, &IntegrationPluginWallbe::onConnectionStateChanged); + connect(modbusTcpMaster, &ModbusTCPMaster::receivedCoil, this, &IntegrationPluginWallbe::onReceivedCoil); + connect(modbusTcpMaster, &ModbusTCPMaster::receivedInputRegister, this, &IntegrationPluginWallbe::onReceivedInputRegister); + connect(modbusTcpMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &IntegrationPluginWallbe::onReceivedHoldingRegister); + connect(modbusTcpMaster, &ModbusTCPMaster::writeRequestExecuted, this, &IntegrationPluginWallbe::onWriteRequestExecuted); + connect(modbusTcpMaster, &ModbusTCPMaster::writeRequestError, this, &IntegrationPluginWallbe::onWriteRequestError); + connect(info, &ThingSetupInfo::aborted, modbusTcpMaster, &ModbusTCPMaster::deleteLater); + + connect(modbusTcpMaster, &ModbusTCPMaster::connectionStateChanged, info, [this, info, modbusTcpMaster](bool connected) { + qCDebug(dcWallbe()) << "Modbus TCP connection changed, connected" << connected; + if(connected) { + m_connections.insert(info->thing(), modbusTcpMaster); + info->finish(Thing::ThingErrorNoError); } }); + if (!modbusTcpMaster->connectDevice()) { + qCWarning(dcWallbe()) << "Could not connect device"; + return info->finish(Thing::ThingErrorHardwareNotAvailable); + } } +} + + +void IntegrationPluginWallbe::postSetupThing(Thing *thing) +{ + qCDebug(dcWallbe()) << "Post setup thing" << thing->name(); if (thing->thingClassId() == wallbeEcoThingClassId){ + if (!m_pluginTimer) { + qCDebug(dcWallbe()) << "Starting plugin timer"; + m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); + connect(m_pluginTimer, &PluginTimer::timeout, this, [this] { + foreach(Thing *thing, m_connections.keys()) { + update(thing); + } + }); + } + thing->setStateValue(wallbeEcoConnectedStateTypeId, true); update(thing); } else { Q_ASSERT_X(false, "postSetupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); @@ -137,10 +194,8 @@ void IntegrationPluginWallbe::executeAction(ThingActionInfo *info) // get the param value of the charging action bool charging = action.param(wallbeEcoPowerActionPowerParamTypeId).value().toBool(); - qCDebug(dcWallbe) << "start Charging button" << thing->name() << "set power to" << charging; - QUuid requestId = modbusTcpMaster->writeCoil(0xff, WallbeRegisterAddress::ChargingStatus, charging); - // Set the "power" state - thing->setStateValue(wallbeEcoPowerStateTypeId, charging); + qCDebug(dcWallbe) << "Start Charging button" << thing->name() << "set power to" << charging; + QUuid requestId = modbusTcpMaster->writeCoil(m_slaveAddress, WallbeRegisterAddress::EnableCharging, charging); m_asyncActions.insert(requestId, info); connect(info, &ThingActionInfo::aborted, this, [this, requestId] {m_asyncActions.remove(requestId);}); @@ -148,8 +203,7 @@ void IntegrationPluginWallbe::executeAction(ThingActionInfo *info) uint16_t current = action.param(wallbeEcoMaxChargingCurrentEventMaxChargingCurrentParamTypeId).value().toUInt(); qCDebug(dcWallbe) << "Charging power set to" << current; - QUuid requestId = modbusTcpMaster->writeCoil(0xff, WallbeRegisterAddress::ChargingCurrent, current); - thing->setStateValue(wallbeEcoMaxChargingCurrentStateTypeId, current); + QUuid requestId = modbusTcpMaster->writeHoldingRegister(m_slaveAddress, WallbeRegisterAddress::ChargingCurrent, current); m_asyncActions.insert(requestId, info); connect(info, &ThingActionInfo::aborted, this, [this, requestId] {m_asyncActions.remove(requestId);}); @@ -180,12 +234,16 @@ void IntegrationPluginWallbe::thingRemoved(Thing *thing) void IntegrationPluginWallbe::update(Thing *thing) { ModbusTCPMaster *modbusTCPMaster = m_connections.value(thing); - if(!modbusTCPMaster) + if(!modbusTCPMaster) { + qCWarning(dcWallbe()) << "Modbus TCP connection not found for" << thing->name(); return; - modbusTCPMaster->readHoldingRegister(0xff, WallbeRegisterAddress::EVStatus); - modbusTCPMaster->readHoldingRegister(0xff, WallbeRegisterAddress::ChargingCurrent); - modbusTCPMaster->readHoldingRegister(0xff, WallbeRegisterAddress::ChargingStatus); - modbusTCPMaster->readHoldingRegister(0xff, WallbeRegisterAddress::ChargingTime); + } + modbusTCPMaster->readInputRegister(m_slaveAddress, WallbeRegisterAddress::EVStatus, 1); + modbusTCPMaster->readInputRegister(m_slaveAddress, WallbeRegisterAddress::FirmwareVersion, 2); + modbusTCPMaster->readInputRegister(m_slaveAddress, WallbeRegisterAddress::ChargingTime, 2); + + modbusTCPMaster->readHoldingRegister(m_slaveAddress, WallbeRegisterAddress::ChargingCurrent, 1); + modbusTCPMaster->readCoil(m_slaveAddress, WallbeRegisterAddress::EnableCharging, 1); } void IntegrationPluginWallbe::onConnectionStateChanged(bool status) @@ -197,16 +255,14 @@ void IntegrationPluginWallbe::onConnectionStateChanged(bool status) thing->setStateValue(wallbeEcoConnectedStateTypeId, status); } -void IntegrationPluginWallbe::onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector &value) +void IntegrationPluginWallbe::onReceivedInputRegister(int slaveAddress, int modbusRegister, const QVector &value) { Q_UNUSED(slaveAddress) ModbusTCPMaster *modbusTCPMaster = static_cast(sender()); Thing *thing = m_connections.key(modbusTCPMaster); if (!thing) return; - - switch (WallbeRegisterAddress(modbusRegister)) { - case WallbeRegisterAddress::EVStatus: + if (WallbeRegisterAddress(modbusRegister) == WallbeRegisterAddress::EVStatus) { //EV state - 16 bit ASCII (8bit) switch (value[0]) { case 65: @@ -230,28 +286,64 @@ void IntegrationPluginWallbe::onReceivedHoldingRegister(int slaveAddress, int mo default: thing->setStateValue(wallbeEcoEvStatusStateTypeId, "F - Supply equipment not available"); } - break; - case WallbeRegisterAddress::ChargingStatus: - thing->setStateValue(wallbeEcoPowerStateTypeId, value[0]); - break; - case WallbeRegisterAddress::ChargingTime: { + } else if (WallbeRegisterAddress(modbusRegister) == WallbeRegisterAddress::ChargingTime) { // Extract Input Register 102 - load time - 32bit integer - int minutes = (((uint32_t)(value[0]<<16)|(uint32_t)(value[1]))/60); //Converts to minutes - thing->setStateValue(wallbeEcoChargeTimeStateTypeId, minutes); + + if (value.length() >= 2) { + int minutes = (((uint32_t)(value[1]<<16)|(uint32_t)(value[0]))/60); //Converts to minutes + qCDebug(dcWallbe()) << " - Charging time:" << minutes << "[min]"; + thing->setStateValue(wallbeEcoChargeTimeStateTypeId, minutes); + } + } else if (WallbeRegisterAddress(modbusRegister) == WallbeRegisterAddress::FirmwareVersion) { + int firmware = (uint32_t)(value[1]<<16)|(uint32_t)(value[0]); + uint major = firmware/10000; + uint minor = (firmware%10000)/100; + uint patch = firmware%100; + QString firmwarestring = QString::number(major)+'.'+QString::number(minor)+'.'+QString::number(patch); + thing->setStateValue(wallbeEcoFirmwareVersionStateTypeId, firmwarestring); } - break; - case WallbeRegisterAddress::ChargingCurrent: +} + +void IntegrationPluginWallbe::onReceivedCoil(int slaveAddress, int modbusRegister, const QVector &value) +{ + Q_UNUSED(slaveAddress) + ModbusTCPMaster *modbusTCPMaster = static_cast(sender()); + Thing *thing = m_connections.key(modbusTCPMaster); + if (!thing) + return; + if (WallbeRegisterAddress(modbusRegister) == WallbeRegisterAddress::EnableCharging) { + qCDebug(dcWallbe()) << " - Enable charging:" << (value[0] != 0); + thing->setStateValue(wallbeEcoPowerStateTypeId, (value[0] != 0)); + } +} + +void IntegrationPluginWallbe::onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector &value) +{ + Q_UNUSED(slaveAddress) + ModbusTCPMaster *modbusTCPMaster = static_cast(sender()); + Thing *thing = m_connections.key(modbusTCPMaster); + if (!thing) + return; + + switch (WallbeRegisterAddress(modbusRegister)) { + + case WallbeRegisterAddress::ChargingCurrent: { + qCDebug(dcWallbe()) << " - Charging current:" << value[0] << "[A]"; thing->setStateValue(wallbeEcoMaxChargingCurrentStateTypeId, value[0]); - break; - case WallbeRegisterAddress::ErrorCode: + } break; + case WallbeRegisterAddress::ErrorCode: { qCDebug(dcWallbe()) << "Received Error Code modbus register" << value[0]; break; } + default: + break; + } } void IntegrationPluginWallbe::onWriteRequestExecuted(const QUuid &requestId, bool success) { if (m_asyncActions.contains(requestId)) { + qCDebug(dcWallbe()) << "Write request executed" << requestId << success; ThingActionInfo *info = m_asyncActions.value(requestId); if (success) { info->finish(Thing::ThingErrorNoError); diff --git a/wallbe/integrationpluginwallbe.h b/wallbe/integrationpluginwallbe.h index b6edb84..b55bd30 100644 --- a/wallbe/integrationpluginwallbe.h +++ b/wallbe/integrationpluginwallbe.h @@ -35,7 +35,7 @@ #include "plugintimer.h" #include "host.h" -#include "discover.h" +#include "discovery.h" #include "../modbus/modbustcpmaster.h" #include @@ -52,13 +52,19 @@ public: enum WallbeRegisterAddress { EVStatus = 100, ChargingTime = 102, + FirmwareVersion = 105, ErrorCode = 107, ChargingCurrent = 300, - ChargingStatus = 400, + EnableCharging = 400, + Output1 = 405, + Output2 = 406, + Output3 = 407, + Output4 = 408 }; + Q_ENUM(WallbeRegisterAddress) explicit IntegrationPluginWallbe(); - + void init() override; void discoverThings(ThingDiscoveryInfo *info) override; void setupThing(ThingSetupInfo *info) override; void postSetupThing(Thing *thing) override; @@ -66,14 +72,18 @@ public: void thingRemoved(Thing *thing) override; private: + Discovery *m_discovery = nullptr; QHash m_connections; PluginTimer *m_pluginTimer = nullptr; QHash m_asyncActions; + int m_slaveAddress = 180; void update(Thing *thing); private slots: void onConnectionStateChanged(bool status); + void onReceivedInputRegister(int slaveAddress, int modbusRegister, const QVector &value); + void onReceivedCoil(int slaveAddress, int modbusRegister, const QVector &value); void onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector &value); void onWriteRequestExecuted(const QUuid &requestId, bool success); diff --git a/wallbe/integrationpluginwallbe.json b/wallbe/integrationpluginwallbe.json index e7c5bd0..83608f0 100644 --- a/wallbe/integrationpluginwallbe.json +++ b/wallbe/integrationpluginwallbe.json @@ -12,7 +12,7 @@ "id": "e66c84f6-b398-47e9-8aeb-33840e7b4492", "displayName": "Wallbe eco 2.0", "name": "wallbeEco", - "createMethods": ["discovery"], + "createMethods": ["discovery", "user"], "interfaces": ["evcharger", "connectable"], "paramTypes": [ { @@ -27,7 +27,8 @@ "displayName": "MAC address", "name": "mac", "type": "QString", - "defaultValue": "" + "defaultValue": "", + "readOnly": true } ], "stateTypes":[ @@ -87,6 +88,14 @@ "maxValue": 80, "defaultValue": 6, "writable": true + }, + { + "id": "f4c822a0-454b-4782-85d2-8c60bacb4fe8", + "displayName": "Firmware version", + "displayNameEvent": "Firmware version changed", + "name": "firmwareVersion", + "type": "QString", + "defaultValue": "" } ] } diff --git a/wallbe/translations/0de5bbd2-0dad-4727-9a17-3ee149106048-de.ts b/wallbe/translations/0de5bbd2-0dad-4727-9a17-3ee149106048-de.ts index 10237e7..bec8a1b 100644 --- a/wallbe/translations/0de5bbd2-0dad-4727-9a17-3ee149106048-de.ts +++ b/wallbe/translations/0de5bbd2-0dad-4727-9a17-3ee149106048-de.ts @@ -4,7 +4,7 @@ IntegrationPluginWallbe - + Invalid IP address Ungültige IP-Adresse @@ -12,9 +12,9 @@ Wallbe - - - + + + Charging The name of the ParamType (ThingClass: wallbeEco, ActionType: power, ID: {26793adc-de10-426f-bb17-170c227891b2}) ---------- @@ -24,8 +24,8 @@ The name of the StateType ({26793adc-de10-426f-bb17-170c227891b2}) of ThingClass Laden - - + + Charging Time The name of the ParamType (ThingClass: wallbeEco, EventType: chargeTime, ID: {8dc2fef8-d16e-422a-8498-456b818f5752}) ---------- @@ -33,38 +33,38 @@ The name of the StateType ({8dc2fef8-d16e-422a-8498-456b818f5752}) of ThingClass Ladezeit - - - + + + Charging current - The name of the ParamType (ThingClass: wallbeEco, ActionType: chargeCurrent, ID: {60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) + The name of the ParamType (ThingClass: wallbeEco, ActionType: maxChargingCurrent, ID: {60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) ---------- -The name of the ParamType (ThingClass: wallbeEco, EventType: chargeCurrent, ID: {60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) +The name of the ParamType (ThingClass: wallbeEco, EventType: maxChargingCurrent, ID: {60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) ---------- The name of the StateType ({60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) of ThingClass wallbeEco Ladestrom - + Charging current changed The name of the EventType ({60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) of ThingClass wallbeEco Ladestrom geändert - + Charging status changed The name of the EventType ({26793adc-de10-426f-bb17-170c227891b2}) of ThingClass wallbeEco Ladestatus geändert - + Charging time changed The name of the EventType ({8dc2fef8-d16e-422a-8498-456b818f5752}) of ThingClass wallbeEco Ladezeit geändert - - + + Connected The name of the ParamType (ThingClass: wallbeEco, EventType: connected, ID: {39a8e92b-40e5-4648-b5a8-2ffcb5598081}) ---------- @@ -72,14 +72,14 @@ The name of the StateType ({39a8e92b-40e5-4648-b5a8-2ffcb5598081}) of ThingClass Verbunden - + Connected changed The name of the EventType ({39a8e92b-40e5-4648-b5a8-2ffcb5598081}) of ThingClass wallbeEco Verbunden geändert - - + + EV Status The name of the ParamType (ThingClass: wallbeEco, EventType: evStatus, ID: {2a95c4fb-9a15-4788-ae09-d34e71314da6}) ---------- @@ -87,49 +87,64 @@ The name of the StateType ({2a95c4fb-9a15-4788-ae09-d34e71314da6}) of ThingClass EV Status - + EV status changed The name of the EventType ({2a95c4fb-9a15-4788-ae09-d34e71314da6}) of ThingClass wallbeEco EV-Status geändert - + + + Firmware version + The name of the ParamType (ThingClass: wallbeEco, EventType: firmwareVersion, ID: {f4c822a0-454b-4782-85d2-8c60bacb4fe8}) +---------- +The name of the StateType ({f4c822a0-454b-4782-85d2-8c60bacb4fe8}) of ThingClass wallbeEco + + + + + Firmware version changed + The name of the EventType ({f4c822a0-454b-4782-85d2-8c60bacb4fe8}) of ThingClass wallbeEco + + + + IP address The name of the ParamType (ThingClass: wallbeEco, Type: thing, ID: {95f297a7-56a5-4789-9b14-6735717344b5}) IP Adresse - + MAC address The name of the ParamType (ThingClass: wallbeEco, Type: thing, ID: {551b03f0-dd70-4463-929b-3668dbd3290f}) MAC Adresse - + Petring The name of the vendor ({831b4b87-0a6c-4d51-b055-967bb6e5fab5}) Petring - + Set charging current The name of the ActionType ({60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) of ThingClass wallbeEco Setze Ladestrom - + Start charging The name of the ActionType ({26793adc-de10-426f-bb17-170c227891b2}) of ThingClass wallbeEco Starte Ladevorgang - + Wallbe The name of the plugin Wallbe ({0de5bbd2-0dad-4727-9a17-3ee149106048}) Wallbe - + Wallbe eco 2.0 The name of the ThingClass ({e66c84f6-b398-47e9-8aeb-33840e7b4492}) Wallbe evo 2.0 diff --git a/wallbe/translations/0de5bbd2-0dad-4727-9a17-3ee149106048-en_US.ts b/wallbe/translations/0de5bbd2-0dad-4727-9a17-3ee149106048-en_US.ts index f32ee22..be7591f 100644 --- a/wallbe/translations/0de5bbd2-0dad-4727-9a17-3ee149106048-en_US.ts +++ b/wallbe/translations/0de5bbd2-0dad-4727-9a17-3ee149106048-en_US.ts @@ -4,7 +4,7 @@ IntegrationPluginWallbe - + Invalid IP address @@ -12,9 +12,9 @@ Wallbe - - - + + + Charging The name of the ParamType (ThingClass: wallbeEco, ActionType: power, ID: {26793adc-de10-426f-bb17-170c227891b2}) ---------- @@ -24,8 +24,8 @@ The name of the StateType ({26793adc-de10-426f-bb17-170c227891b2}) of ThingClass - - + + Charging Time The name of the ParamType (ThingClass: wallbeEco, EventType: chargeTime, ID: {8dc2fef8-d16e-422a-8498-456b818f5752}) ---------- @@ -33,38 +33,38 @@ The name of the StateType ({8dc2fef8-d16e-422a-8498-456b818f5752}) of ThingClass - - - + + + Charging current - The name of the ParamType (ThingClass: wallbeEco, ActionType: chargeCurrent, ID: {60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) + The name of the ParamType (ThingClass: wallbeEco, ActionType: maxChargingCurrent, ID: {60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) ---------- -The name of the ParamType (ThingClass: wallbeEco, EventType: chargeCurrent, ID: {60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) +The name of the ParamType (ThingClass: wallbeEco, EventType: maxChargingCurrent, ID: {60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) ---------- The name of the StateType ({60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) of ThingClass wallbeEco - + Charging current changed The name of the EventType ({60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) of ThingClass wallbeEco - + Charging status changed The name of the EventType ({26793adc-de10-426f-bb17-170c227891b2}) of ThingClass wallbeEco - + Charging time changed The name of the EventType ({8dc2fef8-d16e-422a-8498-456b818f5752}) of ThingClass wallbeEco - - + + Connected The name of the ParamType (ThingClass: wallbeEco, EventType: connected, ID: {39a8e92b-40e5-4648-b5a8-2ffcb5598081}) ---------- @@ -72,14 +72,14 @@ The name of the StateType ({39a8e92b-40e5-4648-b5a8-2ffcb5598081}) of ThingClass - + Connected changed The name of the EventType ({39a8e92b-40e5-4648-b5a8-2ffcb5598081}) of ThingClass wallbeEco - - + + EV Status The name of the ParamType (ThingClass: wallbeEco, EventType: evStatus, ID: {2a95c4fb-9a15-4788-ae09-d34e71314da6}) ---------- @@ -87,49 +87,64 @@ The name of the StateType ({2a95c4fb-9a15-4788-ae09-d34e71314da6}) of ThingClass - + EV status changed The name of the EventType ({2a95c4fb-9a15-4788-ae09-d34e71314da6}) of ThingClass wallbeEco - + + + Firmware version + The name of the ParamType (ThingClass: wallbeEco, EventType: firmwareVersion, ID: {f4c822a0-454b-4782-85d2-8c60bacb4fe8}) +---------- +The name of the StateType ({f4c822a0-454b-4782-85d2-8c60bacb4fe8}) of ThingClass wallbeEco + + + + + Firmware version changed + The name of the EventType ({f4c822a0-454b-4782-85d2-8c60bacb4fe8}) of ThingClass wallbeEco + + + + IP address The name of the ParamType (ThingClass: wallbeEco, Type: thing, ID: {95f297a7-56a5-4789-9b14-6735717344b5}) - + MAC address The name of the ParamType (ThingClass: wallbeEco, Type: thing, ID: {551b03f0-dd70-4463-929b-3668dbd3290f}) - + Petring The name of the vendor ({831b4b87-0a6c-4d51-b055-967bb6e5fab5}) - + Set charging current The name of the ActionType ({60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) of ThingClass wallbeEco - + Start charging The name of the ActionType ({26793adc-de10-426f-bb17-170c227891b2}) of ThingClass wallbeEco - + Wallbe The name of the plugin Wallbe ({0de5bbd2-0dad-4727-9a17-3ee149106048}) - + Wallbe eco 2.0 The name of the ThingClass ({e66c84f6-b398-47e9-8aeb-33840e7b4492}) diff --git a/wallbe/wallbe.pro b/wallbe/wallbe.pro index 8edbe70..e0bca99 100644 --- a/wallbe/wallbe.pro +++ b/wallbe/wallbe.pro @@ -7,11 +7,11 @@ QT += \ SOURCES += \ integrationpluginwallbe.cpp \ ../modbus/modbustcpmaster.cpp \ - host.cpp \ - discover.cpp + discovery.cpp \ + host.cpp HEADERS += \ integrationpluginwallbe.h \ ../modbus/modbustcpmaster.h \ - host.h \ - discover.h + discovery.h \ + host.h