Merge PR #13: New plugin: Webasto

This commit is contained in:
Jenkins nymea 2021-02-19 01:34:30 +01:00
commit db097c16f2
17 changed files with 1885 additions and 0 deletions

15
debian/control vendored
View File

@ -110,6 +110,21 @@ Description: nymea.io plugin for wallbe ev charging stations
.
This package will install the nymea.io plugin for wallbe
Package: nymea-plugin-webasto
Architecture: any
Section: libs
Depends: ${shlibs:Depends},
${misc:Depends},
nymea-plugins-modbus-translations
Description: nymea.io plugin for Webasto Live EV charging stations
The nymea daemon is a plugin based IoT (Internet of Things) server. The
server works like a translator for devices, things and services and
allows them to interact.
With the powerful rule engine you are able to connect any device available
in the system and create individual scenes and behaviors for your environment.
.
This package will install the nymea.io plugin for webasto
Package: nymea-plugins-modbus-translations
Section: misc

View File

@ -0,0 +1 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginwebasto.so

272
discovery/discovery.cpp Normal file
View File

@ -0,0 +1,272 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 <QDebug>
#include <QXmlStreamReader>
#include <QNetworkInterface>
#include <QHostInfo>
#include <QTimer>
#include <loggingcategories.h>
NYMEA_LOGGING_CATEGORY(dcDiscovery, "Discovery")
Discovery::Discovery(QObject *parent) : QObject(parent)
{
connect(&m_timeoutTimer, &QTimer::timeout, this, &Discovery::onTimeout);
}
void Discovery::discoverHosts(int timeout)
{
if (isRunning()) {
qCWarning(dcDiscovery()) << "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(dcDiscovery()) << "Scanning network:" << "nmap" << arguments.join(" ");
discoveryProcess->start(QStringLiteral("nmap"), arguments);
}
}
void Discovery::abort()
{
foreach (QProcess *discoveryProcess, m_discoveryProcesses) {
if (discoveryProcess->state() == QProcess::Running) {
qCDebug(dcDiscovery()) << "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<QProcess*>(sender());
if (exitCode != 0 || exitStatus != QProcess::NormalExit) {
qCWarning(dcDiscovery()) << "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(dcDiscovery()) << "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(dcDiscovery()) << " - host:" << address;
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->setHostName(vendor);
QHostInfo::lookupHost(address, this, SLOT(hostLookupDone(QHostInfo)));
m_pendingNameLookups.insert(address, host);
m_scanResults.append(host);
}
}
}
if (foundHosts == 0 && m_discoveryProcesses.isEmpty()) {
qCDebug(dcDiscovery()) << "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(dcDiscovery()) << "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<QProcess*>(sender());
p->deleteLater();
Host *host = m_pendingArpLookups.take(p);
if (exitCode != 0 || exitStatus != QProcess::NormalExit) {
qCWarning(dcDiscovery()) << "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(dcDiscovery()) << "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<QHostAddress, int> 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<Host> hosts;
foreach (Host *host, m_scanResults) {
if (!host->macAddress().isEmpty()) {
hosts.append(*host);
}
}
qDeleteAll(m_scanResults);
m_scanResults.clear();
qCDebug(dcDiscovery()) << "Found" << hosts.count() << "network devices";
m_timeoutTimer.stop();
emit finished(hosts);
}

75
discovery/discovery.h Normal file
View File

@ -0,0 +1,75 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef DISCOVERY_H
#define DISCOVERY_H
#include <QObject>
#include <QProcess>
#include <QHostInfo>
#include <QTimer>
#include "host.h"
class Discovery : public QObject
{
Q_OBJECT
public:
explicit Discovery(QObject *parent = nullptr);
void discoverHosts(int timeout);
void abort();
bool isRunning() const;
signals:
void finished(const QList<Host> &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<QProcess*> m_discoveryProcesses;
QTimer m_timeoutTimer;
QHash<QProcess*, Host*> m_pendingArpLookups;
QHash<QString, Host*> m_pendingNameLookups;
QList<Host*> m_scanResults;
};
#endif // DISCOVERY_H

94
discovery/host.cpp Normal file
View File

@ -0,0 +1,94 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 "host.h"
Host::Host()
{
qRegisterMetaType<Host>();
qRegisterMetaType<QList<Host> >();
}
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::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;
}
void Host::setReachable(bool reachable)
{
m_reachable = reachable;
}
QDebug operator<<(QDebug dbg, const Host &host)
{
dbg.nospace() << "Host(" << host.macAddress() << "," << host.hostName() << ", " << host.address() << ", " << (host.reachable() ? "up" : "down") << ")";
return dbg.space();
}

70
discovery/host.h Normal file
View File

@ -0,0 +1,70 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef HOST_H
#define HOST_H
#include <QString>
#include <QDebug>
#include <QDateTime>
class Host
{
public:
Host();
QString macAddress() const;
void setMacAddress(const QString &macAddress);
QString hostName() const;
void setHostName(const QString &hostName);
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;
QDateTime m_lastSeenTime;
bool m_reachable;
};
Q_DECLARE_METATYPE(Host)
QDebug operator<<(QDebug dbg, const Host &host);
#endif // HOST_H

View File

@ -7,6 +7,7 @@ PLUGIN_DIRS = \
sunspec \
unipi \
wallbe \
webasto \
message(============================================)
message("Qt version:" $$[QT_VERSION])

17
webasto/README.md Normal file
View File

@ -0,0 +1,17 @@
# Webasto
## Supported Things
* AC Wallbox Live
## Requirements
* The packages 'nymea-plugin-webasto' must be installed.
* The modbus server must be enabled
* The setting 'Modbus Slave Register Address Set' must be set to 'TQ-DM100'
* The setting 'Modbus TCP Server Port Number' must be set to 502
## More
https://dealers.webasto.com/Sections/Public/Documents.aspx?SectionId=6&CategoryId=9&ProductTypeId=66&ProductId=630&ShowResult=true

View File

@ -0,0 +1,463 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 "integrationpluginwebasto.h"
#include "plugininfo.h"
#include "types/param.h"
#include <QDebug>
#include <QStringList>
#include <QJsonDocument>
#include <QNetworkInterface>
IntegrationPluginWebasto::IntegrationPluginWebasto()
{
}
void IntegrationPluginWebasto::init()
{
m_discovery = new Discovery(this);
connect(m_discovery, &Discovery::finished, this, [this](const QList<Host> &hosts) {
foreach (const Host &host, hosts) {
if (!host.hostName().contains("webasto", Qt::CaseSensitivity::CaseInsensitive))
continue;
foreach (Thing *existingThing, myThings()) {
if (existingThing->paramValue(liveWallboxThingMacAddressParamTypeId).toString().isEmpty()) {
//This device got probably manually setup, to enable auto rediscovery the MAC address needs to setup
if (existingThing->paramValue(liveWallboxThingIpAddressParamTypeId).toString() == host.address()) {
qCDebug(dcWebasto()) << "Wallbox MAC Address has been discovered" << existingThing->name() << host.macAddress();
existingThing->setParamValue(liveWallboxThingMacAddressParamTypeId, host.macAddress());
}
} else if (existingThing->paramValue(liveWallboxThingMacAddressParamTypeId).toString() == host.macAddress()) {
if (existingThing->paramValue(liveWallboxThingIpAddressParamTypeId).toString() != host.address()) {
qCDebug(dcWebasto()) << "Wallbox IP Address has changed, from" << existingThing->paramValue(liveWallboxThingIpAddressParamTypeId).toString() << "to" << host.address();
existingThing->setParamValue(liveWallboxThingIpAddressParamTypeId, host.address());
} else {
qCDebug(dcWebasto()) << "Wallbox" << existingThing->name() << "IP address has not changed" << host.address();
}
break;
}
}
}
});
}
void IntegrationPluginWebasto::discoverThings(ThingDiscoveryInfo *info)
{
qCDebug(dcWebasto()) << "Discover things";
if (info->thingClassId() == liveWallboxThingClassId) {
m_discovery->discoverHosts(25);
connect(m_discovery, &Discovery::finished, info, [this, info] (const QList<Host> &hosts) {
foreach (const Host &host, hosts) {
if (!host.hostName().contains("webasto", Qt::CaseSensitivity::CaseInsensitive))
continue;
qCDebug(dcWebasto()) << " - " << host.hostName() << host.address() << host.macAddress();
ThingDescriptor descriptor(liveWallboxThingClassId, "Wallbox", host.address() + " (" + host.macAddress() + ")");
// Rediscovery
foreach (Thing *existingThing, myThings()) {
if (existingThing->paramValue(liveWallboxThingMacAddressParamTypeId).toString() == host.macAddress()) {
qCDebug(dcWebasto()) << " - Device is already added";
descriptor.setThingId(existingThing->id());
break;
}
}
ParamList params;
params << Param(liveWallboxThingMacAddressParamTypeId, host.macAddress());
params << Param(liveWallboxThingIpAddressParamTypeId, host.address());
descriptor.setParams(params);
info->addThingDescriptor(descriptor);
}
info->finish(Thing::ThingErrorNoError);
});
} else {
Q_ASSERT_X(false, "discoverThings", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8());
}
}
void IntegrationPluginWebasto::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
qCDebug(dcWebasto()) << "Setup thing" << thing->name();
if (thing->thingClassId() == liveWallboxThingClassId) {
if (m_webastoConnections.contains(thing)) {
// Clean up after reconfiguration
m_webastoConnections.take(thing)->deleteLater();
}
QHostAddress address = QHostAddress(thing->paramValue(liveWallboxThingIpAddressParamTypeId).toString());
Webasto *webasto = new Webasto(address, 502, thing);
m_webastoConnections.insert(thing, webasto);
connect(webasto, &Webasto::destroyed, this, [thing, this] {m_webastoConnections.remove(thing);});
connect(webasto, &Webasto::connectionStateChanged, this, &IntegrationPluginWebasto::onConnectionChanged);
connect(webasto, &Webasto::receivedRegister, this, &IntegrationPluginWebasto::onReceivedRegister);
connect(webasto, &Webasto::writeRequestError, this, &IntegrationPluginWebasto::onWriteRequestError);
connect(webasto, &Webasto::writeRequestExecuted, this, &IntegrationPluginWebasto::onWriteRequestExecuted);
if (!webasto->connectDevice()) {
qCWarning(dcWebasto()) << "Could not connect to device";
info->finish(Thing::ThingErrorSetupFailed);
}
connect(webasto, &Webasto::connectionStateChanged, info, [info] (bool connected) {
if (connected)
info->finish(Thing::ThingErrorNoError);
});
} else {
Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
}
}
void IntegrationPluginWebasto::postSetupThing(Thing *thing)
{
qCDebug(dcWebasto()) << "Post setup thing" << thing->name();
if (!m_pluginTimer) {
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(1);
connect(m_pluginTimer, &PluginTimer::timeout, this, [this] {
Q_FOREACH(Webasto *connection, m_webastoConnections) {
if (connection->connected())
update(connection);
}
});
}
if (thing->thingClassId() == liveWallboxThingClassId) {
Webasto *connection = m_webastoConnections.value(thing);
if (!connection) {
qCWarning(dcWebasto()) << "Can't find connection to thing";
}
update(connection);
} else {
Q_ASSERT_X(false, "postSetupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
}
}
void IntegrationPluginWebasto::executeAction(ThingActionInfo *info)
{
Thing *thing = info->thing();
Action action = info->action();
if (thing->thingClassId() == liveWallboxThingClassId) {
Webasto *connection = m_webastoConnections.value(thing);
if (!connection) {
qCWarning(dcWebasto()) << "Can't find connection to thing";
return info->finish(Thing::ThingErrorHardwareNotAvailable);
}
if (action.actionTypeId() == liveWallboxPowerActionTypeId) {
bool enabled = action.paramValue(liveWallboxPowerActionPowerParamTypeId).toBool();
thing->setStateValue(liveWallboxPowerActionTypeId, enabled);
int ampere = 0;
if (enabled) {
ampere = thing->stateValue(liveWallboxMaxChargingCurrentStateTypeId).toInt();
}
QUuid requestId = connection->setChargeCurrent(ampere);
if (requestId.isNull()) {
info->finish(Thing::ThingErrorHardwareFailure);
} else {
m_asyncActions.insert(requestId, info);
}
} else if (action.actionTypeId() == liveWallboxMaxChargingCurrentActionTypeId) {
int ampere = action.paramValue(liveWallboxMaxChargingCurrentActionMaxChargingCurrentParamTypeId).toInt();
thing->setStateValue(liveWallboxMaxChargingCurrentStateTypeId, ampere);
QUuid requestId = connection->setChargeCurrent(ampere);
if (requestId.isNull()) {
info->finish(Thing::ThingErrorHardwareFailure);
} else {
m_asyncActions.insert(requestId, info);
}
} else {
Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8());
}
} else {
Q_ASSERT_X(false, "executeAction", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
}
}
void IntegrationPluginWebasto::thingRemoved(Thing *thing)
{
qCDebug(dcWebasto()) << "Delete thing" << thing->name();
if (thing->thingClassId() == liveWallboxThingClassId) {
}
if (myThings().isEmpty()) {
//Stop timer
}
}
void IntegrationPluginWebasto::update(Webasto *webasto)
{
webasto->getRegister(Webasto::TqChargePointState);
webasto->getRegister(Webasto::TqCableState);
webasto->getRegister(Webasto::TqEVSEError);
webasto->getRegister(Webasto::TqCurrentL1);
webasto->getRegister(Webasto::TqCurrentL2);
webasto->getRegister(Webasto::TqCurrentL3);
webasto->getRegister(Webasto::TqActivePower, 2);
webasto->getRegister(Webasto::TqEnergyMeter, 2);
webasto->getRegister(Webasto::TqMaxCurrent);
webasto->getRegister(Webasto::TqChargedEnergy);
webasto->getRegister(Webasto::TqChargingTime, 2);
webasto->getRegister(Webasto::TqUserId, 10);
}
void IntegrationPluginWebasto::onConnectionChanged(bool connected)
{
Webasto *connection = static_cast<Webasto *>(sender());
Thing *thing = m_webastoConnections.key(connection);
if (!thing) {
qCWarning(dcWebasto()) << "On connection changed, thing not found for connection";
return;
}
thing->setStateValue(liveWallboxConnectedStateTypeId, connected);
}
void IntegrationPluginWebasto::onWriteRequestExecuted(const QUuid &requestId, bool success)
{
if (m_asyncActions.contains(requestId)) {
ThingActionInfo *info = m_asyncActions.take(requestId);
if (success) {
info->finish(Thing::ThingErrorNoError);
} else {
info->finish(Thing::ThingErrorHardwareFailure);
}
}
}
void IntegrationPluginWebasto::onWriteRequestError(const QUuid &requestId, const QString &error)
{
Q_UNUSED(requestId);
qCWarning(dcWebasto()) << "Write request error" << error;
}
void IntegrationPluginWebasto::onReceivedRegister(Webasto::TqModbusRegister modbusRegister, const QVector<quint16> &data)
{
Webasto *connection = static_cast<Webasto *>(sender());
Thing *thing = m_webastoConnections.key(connection);
if (!thing) {
qCWarning(dcWebasto()) << "On basic information received, thing not found for connection";
return;
}
if (thing->thingClassId() == liveWallboxThingClassId) {
switch (modbusRegister) {
case Webasto::TqChargePointState:
qCDebug(dcWebasto()) << " - Charge point state:" << Webasto::ChargePointState(data[0]);
switch (Webasto::ChargePointState(data[0])) {
case Webasto::ChargePointStateNoVehicleAttached:
thing->setStateValue(liveWallboxChargePointStateStateTypeId, "No vehicle attached");
break;
case Webasto::ChargePointStateVehicleAttachedNoPermission:
thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Vehicle attached, no permission");
break;
case Webasto::ChargePointStateChargingAuthorized:
thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging authorized");
break;
case Webasto::ChargePointStateCharging:
thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging");
break;
case Webasto::ChargePointStateChargingPaused:
thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging paused");
break;
case Webasto::ChargePointStateChargeSuccessfulCarStillAttached:
thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charge successful (car still attached)");
break;
case Webasto::ChargePointStateChargingStoppedByUserCarStillAttached:
thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging stopped by user (car still attached)");
break;
case Webasto::ChargePointStateChargingErrorCarStillAttached:
thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging error (car still attached)");
break;
case Webasto::ChargePointStateChargingStationReservedNorCarAttached:
thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging station reserved (No car attached)");
break;
case Webasto::ChargePointStateUserNotAuthorizedCarAttached:
thing->setStateValue(liveWallboxChargePointStateStateTypeId, "User not authorized (car attached)");
break;
}
break;
case Webasto::TqChargeState:
qCDebug(dcWebasto()) << " - Charge state:" << data[0];
break;
case Webasto::TqEVSEState:
qCDebug(dcWebasto()) << " - EVSE state:" << data[0];
break;
case Webasto::TqCableState:
qCDebug(dcWebasto()) << " - Cable state:" << Webasto::CableState(data[0]);
switch (Webasto::CableState(data[0])) {
case Webasto::CableStateNoCableAttached:
thing->setStateValue(liveWallboxCableStateStateTypeId, "No cable attached");
break;
case Webasto::CableStateCableAttachedNoCarAttached:
thing->setStateValue(liveWallboxCableStateStateTypeId, "Cable attached but no car attached)");
break;
case Webasto::CableStateCableAttachedCarAttached:
thing->setStateValue(liveWallboxCableStateStateTypeId, "Cable attached and car attached");
break;
case Webasto::CableStateCableAttachedCarAttachedLockActive:
thing->setStateValue(liveWallboxCableStateStateTypeId, "Cable attached, car attached and lock active");
break;
}
break;
case Webasto::TqEVSEError:
qCDebug(dcWebasto()) << " - EVSE error:" << data[0];
thing->setStateValue(liveWallboxErrorStateTypeId, data[0]);
break;
case Webasto::TqCurrentL1:
qCDebug(dcWebasto()) << " - Current L1:" << data[0];
thing->setStateValue(liveWallboxCurrentPhase1StateTypeId, data[0]);
break;
case Webasto::TqCurrentL2:
qCDebug(dcWebasto()) << " - Current L2:" << data[0];
thing->setStateValue(liveWallboxCurrentPhase2StateTypeId, data[0]);
break;
case Webasto::TqCurrentL3:
qCDebug(dcWebasto()) << " - Current L3:" << data[0];
thing->setStateValue(liveWallboxCurrentPhase3StateTypeId, data[0]);
break;
case Webasto::TqActivePower: {
if (data.count() < 2)
return;
int power = (static_cast<quint32>(data[0])<<16 | data[1]);
qCDebug(dcWebasto()) << " - Active power:" << power;
thing->setStateValue(liveWallboxPowerConsumptionStateTypeId, power);
} break;
case Webasto::TqEnergyMeter: {
if (data.count() < 2)
return;
int energy = (static_cast<quint32>(data[0])<<16 | data[1]);
qCDebug(dcWebasto()) << " - Energy meter:" << energy << "Wh";
thing->setStateValue(liveWallboxTotalEnergyConsumedStateTypeId, energy);
} break;
case Webasto::TqMaxCurrent:
qCDebug(dcWebasto()) << " - Max. Current" << data[0];
thing->setStateValue(liveWallboxMaxPossibleChargingCurrentStateTypeId, data[0]);
break;
case Webasto::TqMinimumCurrentLimit:
qCDebug(dcWebasto()) << " - Min. Current" << data[0];
break;
case Webasto::TqMaxCurrentFromEVSE:
qCDebug(dcWebasto()) << " - Max. Current EVSE" << data[0];
break;
case Webasto::TqMaxCurrentFromCable:
qCDebug(dcWebasto()) << " - Max. Current Cable" << data[0];
break;
case Webasto::TqMaxCurrentFromEV:
qCDebug(dcWebasto()) << " - Max. Current EV" << data[0];
break;
case Webasto::TqUserPriority:
qCDebug(dcWebasto()) << " - User priority" << data[0];
break;
case Webasto::TqEVBatteryState:
qCDebug(dcWebasto()) << " - Battery state" << data[0];
break;
case Webasto::TqEVBatteryCapacity: {
if (data.count() < 2)
return;
uint batteryCapacity = (static_cast<quint32>(data[0])<<16 | data[1]);
qCDebug(dcWebasto()) << " - Battery capacity" << batteryCapacity << "Wh";
} break;
case Webasto::TqScheduleType:
qCDebug(dcWebasto()) << " - Schedule type" << data[0];
break;
case Webasto::TqRequiredEnergy: {
if (data.count() < 2)
return;
uint requiredEnergy = (static_cast<quint32>(data[0])<<16 | data[1]);
qCDebug(dcWebasto()) << " - Required energy" << requiredEnergy;
} break;
case Webasto::TqRequiredBatteryState:
qCDebug(dcWebasto()) << " - Required battery state" << data[0];
break;
case Webasto::TqScheduledTime:
qCDebug(dcWebasto()) << " - Scheduled time" << data[0];
break;
case Webasto::TqScheduledDate:
qCDebug(dcWebasto()) << " - Scheduled date" << data[0];
break;
case Webasto::TqChargedEnergy:
qCDebug(dcWebasto()) << " - Charged energy" << data[0];
thing->setStateValue(liveWallboxSessionEnergyStateTypeId, data[0]/1000.00); // Charged energy in kWh
break;
case Webasto::TqStartTime:
qCDebug(dcWebasto()) << " - Start time" << (static_cast<quint32>(data[0])<<16 | data[1]);
break;
case Webasto::TqChargingTime: {
if (data.count() < 2)
return;
uint seconds = (static_cast<quint32>(data[0])<<16 | data[1]);
qCDebug(dcWebasto()) << " - Charging time" << seconds << "s";
thing->setStateValue(liveWallboxSessionTimeStateTypeId, seconds/60.00); // Charging time in minutes
} break;
case Webasto::TqEndTime: {
if (data.count() < 2)
return;
uint hour = ((static_cast<quint32>(data[0])<<16 | data[1])&0xff0000)>>16;
uint minutes = ((static_cast<quint32>(data[0])<<16 | data[1])&0x00ff00)>>8;
uint seconds= (static_cast<quint32>(data[0])<<16 | data[1])&0x0000ff;
qCDebug(dcWebasto()) << " - End time" << hour << "h" << minutes << "m" << seconds << "s";
} break;
case Webasto::TqUserId: {
if (data.count() < 10)
return;
QByteArray userID;
Q_FOREACH(quint16 i, data) {
userID.append(i>>16);
userID.append(i&0xff);
}
qCDebug(dcWebasto()) << " - User ID:" << userID;
} break;
case Webasto::TqSmartVehicleDetected:
qCDebug(dcWebasto()) << " - Smart vehicle detected:" << data[0];
break;
case Webasto::TqSafeCurrent:
qCDebug(dcWebasto()) << " - Safe current:" << data[0];
break;
case Webasto::TqComTimeout:
qCDebug(dcWebasto()) << " - Com timeout:" << data[0];
break;
default:
break;
}
}
}

View File

@ -0,0 +1,77 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef INTEGRATIONPLUGINWEBASTO_H
#define INTEGRATIONPLUGINWEBASTO_H
#include "integrations/integrationplugin.h"
#include "plugintimer.h"
#include "webasto.h"
#include "../discovery/discovery.h"
#include "../discovery/host.h"
#include "../modbus/modbustcpmaster.h"
#include <QObject>
#include <QHostAddress>
#include <QUuid>
class IntegrationPluginWebasto : public IntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginwebasto.json")
Q_INTERFACES(IntegrationPlugin)
public:
explicit IntegrationPluginWebasto();
void init() override;
void discoverThings(ThingDiscoveryInfo *info) override;
void setupThing(ThingSetupInfo *info) override;
void postSetupThing(Thing *thing) override;
void executeAction(ThingActionInfo *info) override;
void thingRemoved(Thing *thing) override;
private:
Discovery *m_discovery = nullptr;
PluginTimer *m_pluginTimer = nullptr;
QHash<Thing *, Webasto *> m_webastoConnections;
QHash<QUuid, ThingActionInfo *> m_asyncActions;
void update(Webasto *webasto);
private slots:
void onConnectionChanged(bool connected);
void onWriteRequestExecuted(const QUuid &requestId, bool success);
void onWriteRequestError(const QUuid &requestId, const QString &error);
void onReceivedRegister(Webasto::TqModbusRegister registerAddress, const QVector<quint16> &data);
};
#endif // INTEGRATIONPLUGINWEBASTO_H

View File

@ -0,0 +1,195 @@
{
"id": "9fa369ab-c225-4447-9a23-f4911d9b056c",
"name": "Webasto",
"displayName": "webasto",
"vendors": [
{
"id": "274f4453-6acf-4204-be21-379abbe3b5a7",
"name": "webasto",
"displayName": "Webasto",
"thingClasses": [
{
"id": "48472124-3199-4827-990a-b72069bd5658",
"displayName": "Live Wallbox",
"name": "liveWallbox",
"createMethods": ["discovery"],
"interfaces": ["evcharger", "connectable"],
"paramTypes": [
{
"id": "51fa3ea8-e819-46ca-b975-1bee6285441c",
"name": "ipAddress",
"displayName": "IP address",
"type": "QString",
"defaultValue": "0.0.0.0"
},
{
"id": "4aa97965-fc1c-488a-92a6-848c214564bc",
"name": "macAddress",
"displayName": "MAC address",
"type": "QString",
"defaultValue": "",
"readOnly": true
}
],
"stateTypes":[
{
"id": "7e6ed2b4-aa8a-4bf6-b20b-84ecc6cc1508",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"name": "connected",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "b076353b-e911-444f-80ad-3f78c4075d1a",
"name": "chargePointState",
"displayName": "Charge point state",
"displayNameEvent": "Charge point state changed",
"type": "QString",
"possibleValues": [
"No vehicle attached",
"Vehicle attached, no permission",
"Charging authorized",
"Charging",
"Charging paused",
"Charge successful (car still attached)",
"Charging stopped by user (car still attached)",
"Charging error (car still attached)",
"Charging station reserved (No car attached)",
"User not authorized (car attached)"
],
"defaultValue": "No vehicle attached"
},
{
"id": "a1a452f9-de93-4c31-b71b-c74264f85a3e",
"name": "cableState",
"displayName": "Cable state",
"displayNameEvent": "Cable state changed",
"type": "QString",
"possibleValues": [
"No cable attached",
"Cable attached but no car attached)",
"Cable attached and car attached",
"Cable attached, car attached and lock active"
],
"defaultValue": "No cable attached"
},
{
"id": "3c054603-d933-4e30-a2cc-2177beaaffdb",
"name": "power",
"displayName": "Charging",
"type": "bool",
"defaultValue": false,
"displayNameAction": "Start charging",
"displayNameEvent": "Charging status changed",
"writable": true
},
{
"id": "96ed77ce-c5cf-4981-8a72-b619f5702724",
"name": "maxChargingCurrent",
"displayName": "Charging current",
"displayNameAction": "Set charging current",
"displayNameEvent": "Charging current changed",
"type": "double",
"unit": "Ampere",
"minValue": 6.00,
"maxValue": 80.00,
"defaultValue": 6.00,
"writable": true
},
{
"id": "2027fbb6-c9d2-4a75-bdd0-a3ad3785cdc6",
"name": "currentPhase1",
"displayName": "Current phase 1",
"displayNameEvent": "Current phase 1 changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 0.00
},
{
"id": "1793f645-d7db-4e99-af92-3587aa3069f3",
"name": "currentPhase2",
"displayName": "Current phase 2",
"displayNameEvent": "Current phase 2 changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 0.00
},
{
"id": "feb8c5da-91a7-45f9-acc3-c1b61478c3d2",
"name": "currentPhase3",
"displayName": "Current phase 3",
"displayNameEvent": "Current phase 3 changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 0.00
},
{
"id": "b20a46ee-0f22-4096-a348-34e68e99e0be",
"name": "powerConsumption",
"displayName": "Power consumption",
"displayNameEvent": "Power consumtion changed",
"type": "double",
"unit": "KiloWatt",
"defaultValue": 0.00
},
{
"id": "80568c51-054c-4351-b9d2-e875fee4cc1f",
"name": "totalEnergyConsumed",
"displayName": "Total energy consumed",
"displayNameEvent": "Total energy consumption changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0
},
{
"id": "87c70567-794e-4af2-916c-b34cf864afcf",
"name": "sessionTime",
"displayName": "Session time",
"displayNameEvent": "Session time changed",
"type": "int",
"unit": "Minutes",
"defaultValue": 0
},
{
"id": "b9b46920-55c1-4bfa-9200-acdc9c0a2471",
"name": "sessionEnergy",
"displayName": "Session energy",
"displayNameEvent": "Session energy changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0
},
{
"id": "56d31fd1-5cfb-42dd-8181-e6b0d0ca9c8a",
"name": "error",
"displayName": "Error ",
"displayNameEvent": "Error changed",
"type": "int",
"defaultValue": 0
},
{
"id": "0e60b15d-2b0c-4672-960e-7c6ea67bf7ea",
"name": "maxPossibleChargingCurrent",
"displayName": "Maximum possible charging current",
"displayNameEvent": "Maximum possible charging current changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 6.00
},
{
"id": "48b62082-f286-433e-9cf8-2dcf6c0ea248",
"name": "userId",
"displayName": "User ID",
"displayNameEvent": "User ID changed",
"type": "QString",
"defaultValue": ""
}
]
}
]
}
]
}

13
webasto/meta.json Normal file
View File

@ -0,0 +1,13 @@
{
"title": "webasto",
"tagline": "Integrates Webasto Live DC wallbox into nymea.",
"icon": "webasto.png",
"stability": "consumer",
"offline": true,
"technologies": [
"network"
],
"categories": [
"tool"
]
}

View File

@ -0,0 +1,280 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>Webasto</name>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="79"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="82"/>
<source>Cable state</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: cableState, ID: {a1a452f9-de93-4c31-b71b-c74264f85a3e})
----------
The name of the StateType ({a1a452f9-de93-4c31-b71b-c74264f85a3e}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="85"/>
<source>Cable state changed</source>
<extracomment>The name of the EventType ({a1a452f9-de93-4c31-b71b-c74264f85a3e}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="88"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="91"/>
<source>Charge point state</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: chargePointState, ID: {b076353b-e911-444f-80ad-3f78c4075d1a})
----------
The name of the StateType ({b076353b-e911-444f-80ad-3f78c4075d1a}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="94"/>
<source>Charge point state changed</source>
<extracomment>The name of the EventType ({b076353b-e911-444f-80ad-3f78c4075d1a}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="97"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="100"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="103"/>
<source>Charging</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, ActionType: power, ID: {3c054603-d933-4e30-a2cc-2177beaaffdb})
----------
The name of the ParamType (ThingClass: liveWallbox, EventType: power, ID: {3c054603-d933-4e30-a2cc-2177beaaffdb})
----------
The name of the StateType ({3c054603-d933-4e30-a2cc-2177beaaffdb}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="106"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="109"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="112"/>
<source>Charging current</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, ActionType: chargeCurrent, ID: {96ed77ce-c5cf-4981-8a72-b619f5702724})
----------
The name of the ParamType (ThingClass: liveWallbox, EventType: chargeCurrent, ID: {96ed77ce-c5cf-4981-8a72-b619f5702724})
----------
The name of the StateType ({96ed77ce-c5cf-4981-8a72-b619f5702724}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="115"/>
<source>Charging current changed</source>
<extracomment>The name of the EventType ({96ed77ce-c5cf-4981-8a72-b619f5702724}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="118"/>
<source>Charging status changed</source>
<extracomment>The name of the EventType ({3c054603-d933-4e30-a2cc-2177beaaffdb}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="121"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="124"/>
<source>Connected</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: connected, ID: {7e6ed2b4-aa8a-4bf6-b20b-84ecc6cc1508})
----------
The name of the StateType ({7e6ed2b4-aa8a-4bf6-b20b-84ecc6cc1508}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="127"/>
<source>Connected changed</source>
<extracomment>The name of the EventType ({7e6ed2b4-aa8a-4bf6-b20b-84ecc6cc1508}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="130"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="133"/>
<source>Current phase 1</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: currentPhase1, ID: {2027fbb6-c9d2-4a75-bdd0-a3ad3785cdc6})
----------
The name of the StateType ({2027fbb6-c9d2-4a75-bdd0-a3ad3785cdc6}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="136"/>
<source>Current phase 1 changed</source>
<extracomment>The name of the EventType ({2027fbb6-c9d2-4a75-bdd0-a3ad3785cdc6}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="139"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="142"/>
<source>Current phase 2</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: currentPhase2, ID: {1793f645-d7db-4e99-af92-3587aa3069f3})
----------
The name of the StateType ({1793f645-d7db-4e99-af92-3587aa3069f3}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="145"/>
<source>Current phase 2 changed</source>
<extracomment>The name of the EventType ({1793f645-d7db-4e99-af92-3587aa3069f3}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="148"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="151"/>
<source>Current phase 3</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: currentPhase3, ID: {feb8c5da-91a7-45f9-acc3-c1b61478c3d2})
----------
The name of the StateType ({feb8c5da-91a7-45f9-acc3-c1b61478c3d2}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="154"/>
<source>Current phase 3 changed</source>
<extracomment>The name of the EventType ({feb8c5da-91a7-45f9-acc3-c1b61478c3d2}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="157"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="160"/>
<source>Error </source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: error, ID: {56d31fd1-5cfb-42dd-8181-e6b0d0ca9c8a})
----------
The name of the StateType ({56d31fd1-5cfb-42dd-8181-e6b0d0ca9c8a}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="163"/>
<source>Error changed</source>
<extracomment>The name of the EventType ({56d31fd1-5cfb-42dd-8181-e6b0d0ca9c8a}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="166"/>
<source>IP address</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, Type: thing, ID: {51fa3ea8-e819-46ca-b975-1bee6285441c})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="169"/>
<source>Live Wallbox</source>
<extracomment>The name of the ThingClass ({48472124-3199-4827-990a-b72069bd5658})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="172"/>
<source>MAC address</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, Type: thing, ID: {4aa97965-fc1c-488a-92a6-848c214564bc})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="175"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="178"/>
<source>Maximum possible charging current</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: maxPossibleChargingCurrent, ID: {0e60b15d-2b0c-4672-960e-7c6ea67bf7ea})
----------
The name of the StateType ({0e60b15d-2b0c-4672-960e-7c6ea67bf7ea}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="181"/>
<source>Maximum possible charging current changed</source>
<extracomment>The name of the EventType ({0e60b15d-2b0c-4672-960e-7c6ea67bf7ea}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="184"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="187"/>
<source>Power consumption</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: powerConsumption, ID: {b20a46ee-0f22-4096-a348-34e68e99e0be})
----------
The name of the StateType ({b20a46ee-0f22-4096-a348-34e68e99e0be}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="190"/>
<source>Power consumtion changed</source>
<extracomment>The name of the EventType ({b20a46ee-0f22-4096-a348-34e68e99e0be}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="193"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="196"/>
<source>Session energy</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: sessionEnergy, ID: {b9b46920-55c1-4bfa-9200-acdc9c0a2471})
----------
The name of the StateType ({b9b46920-55c1-4bfa-9200-acdc9c0a2471}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="199"/>
<source>Session energy changed</source>
<extracomment>The name of the EventType ({b9b46920-55c1-4bfa-9200-acdc9c0a2471}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="202"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="205"/>
<source>Session time</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: sessionTime, ID: {87c70567-794e-4af2-916c-b34cf864afcf})
----------
The name of the StateType ({87c70567-794e-4af2-916c-b34cf864afcf}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="208"/>
<source>Session time changed</source>
<extracomment>The name of the EventType ({87c70567-794e-4af2-916c-b34cf864afcf}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="211"/>
<source>Set charging current</source>
<extracomment>The name of the ActionType ({96ed77ce-c5cf-4981-8a72-b619f5702724}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="214"/>
<source>Start charging</source>
<extracomment>The name of the ActionType ({3c054603-d933-4e30-a2cc-2177beaaffdb}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="217"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="220"/>
<source>Total energy consumed</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: totalEnergyConsumed, ID: {80568c51-054c-4351-b9d2-e875fee4cc1f})
----------
The name of the StateType ({80568c51-054c-4351-b9d2-e875fee4cc1f}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="223"/>
<source>Total energy consumption changed</source>
<extracomment>The name of the EventType ({80568c51-054c-4351-b9d2-e875fee4cc1f}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="226"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="229"/>
<source>User ID</source>
<extracomment>The name of the ParamType (ThingClass: liveWallbox, EventType: userId, ID: {48b62082-f286-433e-9cf8-2dcf6c0ea248})
----------
The name of the StateType ({48b62082-f286-433e-9cf8-2dcf6c0ea248}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="232"/>
<source>User ID changed</source>
<extracomment>The name of the EventType ({48b62082-f286-433e-9cf8-2dcf6c0ea248}) of ThingClass liveWallbox</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="235"/>
<source>Webasto</source>
<extracomment>The name of the vendor ({274f4453-6acf-4204-be21-379abbe3b5a7})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/webasto/plugininfo.h" line="238"/>
<source>webasto</source>
<extracomment>The name of the plugin Webasto ({9fa369ab-c225-4447-9a23-f4911d9b056c})</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

141
webasto/webasto.cpp Normal file
View File

@ -0,0 +1,141 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 "webasto.h"
#include "extern-plugininfo.h"
Webasto::Webasto(const QHostAddress &address, uint port, QObject *parent) :
QObject(parent)
{
qCDebug(dcWebasto()) << "Webasto: Webasto connection created" << address.toString() << port;
m_modbusConnection = new ModbusTCPMaster(address, port, this);
m_modbusConnection->setNumberOfRetries(3);
m_modbusConnection->setTimeout(1000);
connect(m_modbusConnection, &ModbusTCPMaster::receivedHoldingRegister, this, &Webasto::onReceivedHoldingRegister);
connect(m_modbusConnection, &ModbusTCPMaster::writeRequestExecuted, this, &Webasto::writeRequestExecuted);
connect(m_modbusConnection, &ModbusTCPMaster::writeRequestError, this, &Webasto::writeRequestError);
m_lifeBitTimer = new QTimer(this);
m_lifeBitTimer->start(10000);
connect(m_lifeBitTimer, &QTimer::timeout, this, [this] {
setLiveBit();
});
}
void Webasto::setAddress(const QHostAddress &address)
{
qCDebug(dcWebasto()) << "Webasto: set address" << address;
m_modbusConnection->setHostAddress(address);
}
QHostAddress Webasto::address() const
{
return m_modbusConnection->hostAddress();
}
bool Webasto::connected()
{
return m_modbusConnection->connected();
}
bool Webasto::connectDevice()
{
return m_modbusConnection->connectDevice();
}
void Webasto::setLivebitInterval(uint seconds)
{
qCDebug(dcWebasto()) << "Webasto: Live bit interval set to" << seconds << "[s]";
m_lifeBitTimer->setInterval(seconds*1000);
}
void Webasto::getRegister(Webasto::TqModbusRegister modbusRegister, uint length)
{
qCDebug(dcWebasto()) << "Webasto: Get register" << modbusRegister << length;
if (length < 1 && length > 10) {
qCWarning(dcWebasto()) << "Invalide register length, allowed values [1,10]";
return;
}
m_modbusConnection->readHoldingRegister(m_unitId, modbusRegister, length);
}
QUuid Webasto::setSafeCurrent(quint16 ampere) const
{
return m_modbusConnection->writeHoldingRegister(m_unitId, TqSafeCurrent, ampere);
}
QUuid Webasto::seComTimeout(quint16 seconds) const
{
return m_modbusConnection->writeHoldingRegister(m_unitId, TqComTimeout, seconds);
}
QUuid Webasto::setChargePower(quint32 watt) const
{
QVector<quint16> data;
data.append(watt>>16);
data.append(watt&0xff);
return m_modbusConnection->writeHoldingRegisters(m_unitId, TqChargePower, data);
}
QUuid Webasto::setChargeCurrent(quint16 ampere) const
{
return m_modbusConnection->writeHoldingRegister(m_unitId, TqChargeCurrent, ampere);
}
void Webasto::setLiveBit()
{
qCDebug(dcWebasto()) << "Webasto: Set live bit";
m_modbusConnection->writeHoldingRegister(m_unitId, TqLifeBit, 0x0001);
if (m_awaitingLiveBitResponse) {
// Live bit response has not been received, setting connection as disconnected
// The live bit acts as heartbeat for both sides, client and server
if (m_connected) {
m_connected = false;
emit connectionStateChanged(false);
}
} else {
m_awaitingLiveBitResponse = true;
}
}
void Webasto::onReceivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values)
{
Q_UNUSED(slaveAddress)
if (modbusRegister == TqLifeBit) {
m_awaitingLiveBitResponse = false;
if (!m_connected) {
m_connected = true;
emit connectionStateChanged(true);
}
}
emit receivedRegister(TqModbusRegister(modbusRegister), values);
}

152
webasto/webasto.h Normal file
View File

@ -0,0 +1,152 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef WEBASTO_H
#define WEBASTO_H
#include <QObject>
#include <QHostAddress>
#include <QTimer>
#include <QUuid>
#include "../modbus/modbustcpmaster.h"
class Webasto : public QObject
{
Q_OBJECT
public:
enum ChargePointState {
ChargePointStateNoVehicleAttached = 0,
ChargePointStateVehicleAttachedNoPermission,
ChargePointStateChargingAuthorized,
ChargePointStateCharging,
ChargePointStateChargingPaused,
ChargePointStateChargeSuccessfulCarStillAttached,
ChargePointStateChargingStoppedByUserCarStillAttached,
ChargePointStateChargingErrorCarStillAttached,
ChargePointStateChargingStationReservedNorCarAttached,
ChargePointStateUserNotAuthorizedCarAttached
};
Q_ENUM(ChargePointState)
enum CableState {
CableStateNoCableAttached = 0,
CableStateCableAttachedNoCarAttached,
CableStateCableAttachedCarAttached,
CableStateCableAttachedCarAttachedLockActive
};
Q_ENUM(CableState)
enum EvseState {
EvseSateStarting = 0,
EvseSateRunning,
EvseSateError
};
Q_ENUM(EvseState)
enum TqModbusRegister {
TqChargePointState = 1000, // State of the charging device
TqChargeState = 1001, // Charging
TqEVSEState = 1002, // State of the charging station
TqCableState = 1004, // State of the charging cable
TqEVSEError = 1006, // Error code of the charging station
TqCurrentL1 = 1008, // Charging current L1
TqCurrentL2 = 1010, // Charging current L2
TqCurrentL3 = 1012, // Charging current L3
TqActivePower = 1020, // Electric Power that can be changed to f.e. mechanical, chemical, thermic power
TqActivePowerL1 = 1024, // Active power L1
TqActivePowerL2 = 1028, // Active power L2
TqActivePowerL3 = 1032, // Active power L3
TqEnergyMeter = 1036, // Meter reading of the charging station
TqMaxCurrent = 1100, // Maximal charging current UINT of the hardware (EVSE, cable, EV)
TqMinimumCurrentLimit = 1102, // Minimal charging current of the hardware (EVSE, cable, EV)
TqMaxCurrentFromEVSE = 1104, // Maximal charging current of the charging station
TqMaxCurrentFromCable = 1106, // Maximal charging current of the cable
TqMaxCurrentFromEV = 1108, // Maximal charging current of the EV
TqUserPriority = 1200, // Priorities of the user 0: not defined 1: high priority - 10: low priority
TqEVBatteryState = 1300, // Returns an estimate of the SoC
TqEVBatteryCapacity = 1302, // Returns an estimate of the EV Battery Capacity
TqScheduleType = 1400, // Type/information of traveling 0: energy that has to be charged, 1: Specification of the desired battery charge (Needs: state of the battery)
TqRequiredEnergy = 1402, // Desired energy
TqRequiredBatteryState = 1404, // Desired state of the battery
TqScheduledTime = 1408, // Departure time
TqScheduledDate = 1412, // Departure date
TqChargedEnergy = 1502, // Sum of charged energy for the current session
TqStartTime = 1504, // Start time of charging process
TqChargingTime = 1508, // Duration since beginning of charge
TqEndTime = 1512, // End time of charging process
TqUserId = 1600, // 24 Bytes long User ID (OCPP IdTag) from the current session
TqSmartVehicleDetected = 1620, //Returns 1 if an EV currently connected is a smart vehicle, or 0 if no EV connected or it is not a smart vehicle,
TqSafeCurrent = 2000, // Max. charge current under communication failure
TqComTimeout = 2002, // Communication timeout
TqChargePower = 5000, // Charge power
TqChargeCurrent = 5001, // Charge current
TqLifeBit = 6000 // Communication monitoring 0/1 Toggle-Bit EM writes 1, Live deletes it and puts it on 0.
};
Q_ENUM(TqModbusRegister)
explicit Webasto(const QHostAddress &address, uint port = 502, QObject *parent = nullptr);
void setAddress(const QHostAddress &address);
QHostAddress address() const;
bool connected();
bool connectDevice();
void setLivebitInterval(uint seconds);
void getRegister(TqModbusRegister modbusRegister, uint length = 1);
QUuid setSafeCurrent(quint16 ampere) const;
QUuid seComTimeout(quint16 seconds) const;
QUuid setChargePower(quint32 watt) const;
QUuid setChargeCurrent(quint16 ampere) const;
void setLiveBit();
private:
ModbusTCPMaster *m_modbusConnection = nullptr;
QHostAddress m_address;
uint m_unitId = 255;
private:
QTimer *m_lifeBitTimer = nullptr;
bool m_connected = false;
bool m_awaitingLiveBitResponse = false;
signals:
void connectionStateChanged(bool state);
void writeRequestExecuted(const QUuid &requestId, bool success);
void writeRequestError(const QUuid &requestId, const QString &error);
void receivedRegister(TqModbusRegister registerAddress, const QVector<quint16> &data);
private slots:
void onReceivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
};
#endif // WEBASTO_H

BIN
webasto/webasto.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

19
webasto/webasto.pro Normal file
View File

@ -0,0 +1,19 @@
include(../plugins.pri)
QT += \
serialbus \
network
SOURCES += \
integrationpluginwebasto.cpp \
webasto.cpp \
../modbus/modbustcpmaster.cpp \
../discovery/discovery.cpp \
../discovery/host.cpp
HEADERS += \
integrationpluginwebasto.h \
webasto.h \
../modbus/modbustcpmaster.h \
../discovery/discovery.h \
../discovery/host.h