added wall-be plug-in

pull/1/head
Boernsman 2020-01-22 16:25:24 +01:00
parent 28542347a2
commit 59a9927f2c
16 changed files with 1178 additions and 2 deletions

18
debian/control vendored
View File

@ -33,11 +33,26 @@ Description: nymea.io plugin for Drexel & Weiss heat pumps
This package will install the nymea.io plugin for Drexel & Weiss heat pumps
Package: nymea-plugin-wallbe
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
nymea-plugins-translations,
libmodbus,
Description: nymea.io plugin for wallbe 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 wallbe
Package: nymea-plugins-translations
Section: misc
Architecture: all
Depends: ${misc:Depends}
Replaces: guh-plugins-translations
Description: Translation files for nymea plugins - translations
The nymea daemon is a plugin based IoT (Internet of Things) server. The
server works like a translator for devices, things and services and
@ -52,6 +67,7 @@ Package: nymea-plugins-modbus
Section: libs
Architecture: all
Depends: nymea-plugin-drexelundweiss,
nymea-plugin-wallbe,
Description: Plugins for nymea IoT server - the modbus plugin collection
The nymea daemon is a plugin based IoT (Internet of Things) server. The
server works like a translator for devices, things and services and

1
debian/nymea-plugin-wallbe.install.in vendored Normal file
View File

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

View File

@ -1,5 +1,7 @@
include(../plugins.pri)
TARGET = $$qtLibraryTarget(nymea_deviceplugindrexelundweiss)
QT += \
serialport \
serialbus \

View File

@ -2,7 +2,7 @@ TEMPLATE = subdirs
PLUGIN_DIRS = \
drexelundweiss \
wallbe \
message(============================================)
message("Qt version:" $$[QT_VERSION])

14
wallbe/README.md Normal file
View File

@ -0,0 +1,14 @@
# Wallbe
Plug-in for the EV-charger wall-be,
with network device discovery.
Make sure to enable the Network interface in your Wallbe device,
have a look in the Wallbe manual or call the Wallbe support.
## Technical Specification
* Default IP Adress 192.168.0.8
* Default Name EVCC_1
* Port 502
* Modbus-Slave Address 180

View File

@ -0,0 +1,207 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 "devicepluginwallbe.h"
#include "plugininfo.h"
#include "devices/devicemanager.h"
#include "devices/device.h"
#include "types/param.h"
#include <QDebug>
#include <QStringList>
#include <QJsonDocument>
#include <QNetworkInterface>
DevicePluginWallbe::DevicePluginWallbe()
{
}
void DevicePluginWallbe::setupDevice(DeviceSetupInfo *info)
{
Device *device = info->device();
qCDebug(dcWallbe) << "Setting up a new device:" << device->params();
QHostAddress address(device->paramValue(wallbeEcoDeviceIpParamTypeId).toString());
if (address.isNull()){
qCWarning(dcWallbe) << "IP address is null";
info->finish(Device::DeviceErrorSetupFailed, tr("IP address parameter not valid"));
return;
}
WallBe *wallbe = new WallBe(address, 502, this);
m_connections.insert(device, wallbe);
info->finish(Device::DeviceErrorNoError);
}
void DevicePluginWallbe::discoverDevices(DeviceDiscoveryInfo *info)
{
if (info->deviceClassId() == wallbeEcoDeviceClassId){
Discover *discover = new Discover(QStringList("-xO" "-p 502"));
connect(discover, &Discover::devicesDiscovered, this, [info, this](QList<Host> hosts){
foreach (Host host, hosts) {
DeviceDescriptor descriptor;
foreach(Device *device, myDevices().filterByParam(wallbeEcoDeviceMacParamTypeId, host.macAddress())) {
descriptor.setDeviceId(device->id());
break;
}
descriptor.setTitle(host.hostName());
ParamList params;
params.append(Param(wallbeEcoDeviceIpParamTypeId, host.address()));
params.append(Param(wallbeEcoDeviceMacParamTypeId, host.macAddress()));
descriptor.setParams(params);
info->addDeviceDescriptor(descriptor);
}
info->finish(Device::DeviceErrorNoError);
});
return;
}
Q_ASSERT_X(false, "discoverDevices", QString("Unhandled deviceClassId: %1").arg(info->deviceClassId().toString()).toUtf8());
}
void DevicePluginWallbe::postSetupDevice(Device *device)
{
if (!m_pluginTimer) {
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(120);
connect(m_pluginTimer, &PluginTimer::timeout, this, [this] {
foreach(Device *device, m_connections.keys()) {
update(device);
}
});
}
if (device->deviceClassId() == wallbeEcoDeviceClassId){
update(device);
return;
}
Q_ASSERT_X(false, "postSetupDevice", QString("Unhandled deviceClassId: %1").arg(device->deviceClassId().toString()).toUtf8());
}
void DevicePluginWallbe::executeAction(DeviceActionInfo *info)
{
Device *device = info->device();
Action action = info->action();
WallBe *wallbe = m_connections.value(device);
if (!wallbe) {
qCWarning(dcWallbe()) << "Wallbe object not available";
info->finish(Device::DeviceErrorHardwareFailure);
return;
}
if (device->deviceClassId() == wallbeEcoDeviceClassId){
// check if this is the "set power" action
if (action.actionTypeId() == wallbeEcoPowerActionTypeId) {
// get the param value of the charging action
bool charging = action.param(wallbeEcoPowerActionPowerParamTypeId).value().toBool();
qCDebug(dcWallbe) << "start Charging button" << device->name() << "set power to" << charging;
wallbe->setChargingStatus(charging);
// Set the "power" state
device->setStateValue(wallbeEcoPowerStateTypeId, charging);
info->finish(Device::DeviceErrorNoError);
return;
} else if(action.actionTypeId() == wallbeEcoChargeCurrentActionTypeId){
uint16_t current = action.param(wallbeEcoChargeCurrentEventChargeCurrentParamTypeId).value().toUInt();
qCDebug(dcWallbe) << "Charging power set to" << current;
wallbe->setChargingCurrent(current);
device->setStateValue(wallbeEcoChargeCurrentStateTypeId, current);
info->finish(Device::DeviceErrorNoError);
return;
}
Q_ASSERT_X(false, "executeAction", QString("Unhandled action: %1").arg(action.actionTypeId().toString()).toUtf8());
}
Q_ASSERT_X(false, "executeAction", QString("Unhandled deviceClassId: %1").arg(device->deviceClassId().toString()).toUtf8());
}
void DevicePluginWallbe::deviceRemoved(Device *device)
{
m_address.removeOne(QHostAddress(device->paramValue(wallbeEcoDeviceIpParamTypeId).toString()));
WallBe *wallbe = m_connections.take(device);
if (wallbe) {
qCDebug(dcWallbe) << "Remove device" << device->name();
wallbe->deleteLater();
}
if (myDevices().isEmpty()) {
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
m_pluginTimer = nullptr;
}
}
void DevicePluginWallbe::update(Device *device)
{
WallBe * wallbe = m_connections.value(device);
if(!wallbe->isAvailable())
return;
device->setStateValue(wallbeEcoConnectedStateTypeId, true);
//EV state - 16 bit ASCII (8bit)
switch (wallbe->getEvStatus()) {
case 65:
device->setStateValue(wallbeEcoEvStatusStateTypeId, "A - No car plugged in");
break;
case 66:
device->setStateValue(wallbeEcoEvStatusStateTypeId, "B - Supply equipment not yet ready");
break;
case 67:
device->setStateValue(wallbeEcoEvStatusStateTypeId, "C - Ready to charge");
break;
case 68:
device->setStateValue(wallbeEcoEvStatusStateTypeId, "D - Ready to charge, ventilation needed");
break;
case 69:
device->setStateValue(wallbeEcoEvStatusStateTypeId, "E - Short circuit detected");
break;
case 70:
device->setStateValue(wallbeEcoEvStatusStateTypeId, "F - Supply equipment not available");
break;
default:
device->setStateValue(wallbeEcoEvStatusStateTypeId, "F - Supply equipment not available");
}
qCDebug(dcWallbe) << "EV State:" << device->stateValue(wallbeEcoEvStatusStateTypeId).toString();
// Extract Input Register 102 - load time - 32bit integer
device->setStateValue(wallbeEcoChargeTimeStateTypeId, wallbe->getChargingTime());
// Read the charge current state
device->setStateValue(wallbeEcoChargeCurrentStateTypeId, wallbe->getChargingCurrent());
device->setStateValue(wallbeEcoPowerStateTypeId, wallbe->getChargingStatus());
}

View File

@ -0,0 +1,64 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 DEVICEPLUGINWALLBE_H
#define DEVICEPLUGINWALLBE_H
#include "devices/deviceplugin.h"
#include "wallbe.h"
#include "host.h"
#include "discover.h"
#include "plugintimer.h"
#include <QObject>
#include <QHostAddress>
class DevicePluginWallbe : public DevicePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "devicepluginwallbe.json")
Q_INTERFACES(DevicePlugin)
public:
explicit DevicePluginWallbe();
void discoverDevices(DeviceDiscoveryInfo *info) override;
void setupDevice(DeviceSetupInfo *info) override;
void postSetupDevice(Device *device) override;
void executeAction(DeviceActionInfo *info) override;
void deviceRemoved(Device *device) override;
private:
QHash<Device *, WallBe *> m_connections;
QList<QHostAddress> m_address;
PluginTimer *m_pluginTimer = nullptr;
void update(Device *device);
};
#endif // DEVICEPLUGINWALLBE_H

View File

@ -0,0 +1,99 @@
{
"displayName": "wallbe plugin",
"name": "Wallbe",
"id": "0de5bbd2-0dad-4727-9a17-3ee149106048",
"vendors": [
{
"displayName": "Petring",
"name": "petring",
"id": "831b4b87-0a6c-4d51-b055-967bb6e5fab5",
"deviceClasses": [
{
"id": "e66c84f6-b398-47e9-8aeb-33840e7b4492",
"displayName": "Wallbe eco 2.0",
"name": "wallbeEco",
"createMethods": ["discovery"],
"interfaces": ["evcharger", "connectable"],
"paramTypes": [
{
"id": "95f297a7-56a5-4789-9b14-6735717344b5",
"displayName": "IP address",
"name": "ip",
"type": "QString",
"inputType": "IPv4Address",
"defaultValue": "192.168.0.8"
},
{
"id": "551b03f0-dd70-4463-929b-3668dbd3290f",
"displayName": "MAC address",
"name": "mac",
"type": "QString",
"defaultValue": ""
}
],
"stateTypes":[
{
"id": "39a8e92b-40e5-4648-b5a8-2ffcb5598081",
"displayName": "Connected",
"name": "connected",
"type": "bool",
"defaultValue": false,
"displayNameEvent": "Connected changed"
},
{
"id": "8dc2fef8-d16e-422a-8498-456b818f5752",
"name": "chargeTime",
"displayName": "Charging Time",
"unit": "Minutes",
"type": "int",
"defaultValue": 0,
"displayNameEvent": "Charging time changed"
},
{
"id": "2a95c4fb-9a15-4788-ae09-d34e71314da6",
"name": "evStatus",
"displayName": "EV Status",
"type": "QString",
"possibleValues": [
"A - No car plugged in",
"B - Supply equipment not yet ready",
"C - Ready to charge",
"D - Ready to charge, ventilation needed",
"E - Short circuit detected",
"F - Supply equipment not available"
],
"defaultValue": "F - Supply equipment not available",
"displayNameEvent": "EV status changed"
},
{
"id": "26793adc-de10-426f-bb17-170c227891b2",
"name": "power",
"displayName": "Charging",
"type": "bool",
"defaultValue": false,
"displayNameAction": "Start charging",
"displayNameEvent": "Charging status changed",
"writable": true
},
{
"id": "60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1",
"name": "chargeCurrent",
"displayName": "Charging current",
"displayNameAction": "Set charging current",
"displayNameEvent": "Charging current changed",
"unit": "Ampere",
"type": "int",
"defaultValue": 0,
"type": "int",
"unit": "Ampere",
"minValue": 6,
"maxValue": 80,
"defaultValue": 6,
"writable": true
}
]
}
]
}
]
}

162
wallbe/discover.cpp Normal file
View File

@ -0,0 +1,162 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <QHostAddress>
#include <QNetworkInterface>
#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<QHostAddress, int> pair = QHostAddress::parseSubnet(interface.toString() + "/24");
targets << QString("%1/%2").arg(pair.first.toString()).arg(pair.second);
}
}
return targets;
}
QList<Host> Discover::parseProcessOutput(const QByteArray &processData)
{
m_reader.clear();
m_reader.addData(processData);
QList<Host> 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<QProcess*>(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()
{
}

73
wallbe/discover.h Normal file
View File

@ -0,0 +1,73 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 DISCOVER_H
#define DISCOVER_H
#include <QObject>
#include <QProcess>
#include <QXmlStreamReader>
#include <QTimer>
#include <QHostAddress>
#include "host.h"
class Discover : public QObject
{
Q_OBJECT
public:
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<Host> parseProcessOutput(const QByteArray &processData);
Host parseHost();
signals:
void devicesDiscovered(QList<Host>);
private slots:
void onTimeout();
};
#endif // DISCOVER_H

73
wallbe/host.cpp Normal file
View File

@ -0,0 +1,73 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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()
{
}
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;
}
QString Host::macAddress() const
{
return m_macAddress;
}
bool Host::reachable() const
{
return m_reachable;
}
bool Host::isValid() const
{
return !m_hostName.isEmpty() && !m_address.isEmpty();
}
QDebug operator<<(QDebug dbg, const Host &host)
{
dbg.nospace() << "Host(" << host.hostName() << ", " << host.address() << ", " << (host.reachable() ? "up" : "down") << ")";
return dbg.space();
}

56
wallbe/host.h Normal file
View File

@ -0,0 +1,56 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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>
class Host
{
public:
Host();
Host(const QString &hostName, const QString &address, const QString &macAddress, const bool &reachable);
QString hostName() const;
QString address() const;
QString macAddress() const;
bool reachable() const;
bool isValid() const;
private:
QString m_hostName;
QString m_address;
QString m_macAddress;
bool m_reachable;
};
QDebug operator<<(QDebug dbg, const Host &host);
#endif // HOST_H

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>DevicePluginWallbe</name>
<message>
<location filename="../devicepluginwallbe.cpp" line="50"/>
<source>IP address parameter not valid</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Wallbe</name>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="44"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="47"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="50"/>
<source>Charging</source>
<extracomment>The name of the ParamType (DeviceClass: wallbeEco, ActionType: power, ID: {26793adc-de10-426f-bb17-170c227891b2})
----------
The name of the ParamType (DeviceClass: wallbeEco, EventType: power, ID: {26793adc-de10-426f-bb17-170c227891b2})
----------
The name of the StateType ({26793adc-de10-426f-bb17-170c227891b2}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="53"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="56"/>
<source>Charging Time</source>
<extracomment>The name of the ParamType (DeviceClass: wallbeEco, EventType: chargeTime, ID: {8dc2fef8-d16e-422a-8498-456b818f5752})
----------
The name of the StateType ({8dc2fef8-d16e-422a-8498-456b818f5752}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="59"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="62"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="65"/>
<source>Charging current</source>
<extracomment>The name of the ParamType (DeviceClass: wallbeEco, ActionType: chargeCurrent, ID: {60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1})
----------
The name of the ParamType (DeviceClass: wallbeEco, EventType: chargeCurrent, ID: {60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1})
----------
The name of the StateType ({60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="68"/>
<source>Charging current changed</source>
<extracomment>The name of the EventType ({60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="71"/>
<source>Charging status changed</source>
<extracomment>The name of the EventType ({26793adc-de10-426f-bb17-170c227891b2}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="74"/>
<source>Charging time changed</source>
<extracomment>The name of the EventType ({8dc2fef8-d16e-422a-8498-456b818f5752}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="77"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="80"/>
<source>Connected</source>
<extracomment>The name of the ParamType (DeviceClass: wallbeEco, EventType: connected, ID: {39a8e92b-40e5-4648-b5a8-2ffcb5598081})
----------
The name of the StateType ({39a8e92b-40e5-4648-b5a8-2ffcb5598081}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="83"/>
<source>Connected changed</source>
<extracomment>The name of the EventType ({39a8e92b-40e5-4648-b5a8-2ffcb5598081}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="86"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="89"/>
<source>EV Status</source>
<extracomment>The name of the ParamType (DeviceClass: wallbeEco, EventType: evStatus, ID: {2a95c4fb-9a15-4788-ae09-d34e71314da6})
----------
The name of the StateType ({2a95c4fb-9a15-4788-ae09-d34e71314da6}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="92"/>
<source>EV status changed</source>
<extracomment>The name of the EventType ({2a95c4fb-9a15-4788-ae09-d34e71314da6}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="95"/>
<source>IP address</source>
<extracomment>The name of the ParamType (DeviceClass: wallbeEco, Type: device, ID: {95f297a7-56a5-4789-9b14-6735717344b5})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="98"/>
<source>MAC address</source>
<extracomment>The name of the ParamType (DeviceClass: wallbeEco, Type: device, ID: {551b03f0-dd70-4463-929b-3668dbd3290f})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="101"/>
<source>Petring</source>
<extracomment>The name of the vendor ({831b4b87-0a6c-4d51-b055-967bb6e5fab5})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="104"/>
<source>Set charging current</source>
<extracomment>The name of the ActionType ({60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="107"/>
<source>Start charging</source>
<extracomment>The name of the ActionType ({26793adc-de10-426f-bb17-170c227891b2}) of DeviceClass wallbeEco</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="110"/>
<source>Wallbe eco 2.0</source>
<extracomment>The name of the DeviceClass ({e66c84f6-b398-47e9-8aeb-33840e7b4492})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/wallbe/plugininfo.h" line="113"/>
<source>wallbe plugin</source>
<extracomment>The name of the plugin Wallbe ({0de5bbd2-0dad-4727-9a17-3ee149106048})</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

190
wallbe/wallbe.cpp Normal file
View File

@ -0,0 +1,190 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 "wallbe.h"
#include "extern-plugininfo.h"
WallBe::WallBe(QHostAddress address, int port, QObject *parent) : QObject(parent)
{
// TCP connction to target device
m_device = modbus_new_tcp(QVariant(address.toIPv4Address()).toByteArray(), port);
if(m_device == nullptr){
qCWarning(dcWallbe) << "Error Modbus TCP";
free((void*)(m_device));
return;
}
if(modbus_connect(m_device) == -1){
qCWarning(dcWallbe) << "Error Connecting Modbus";
free((void*)(m_device));
return;
}
if(modbus_set_slave(m_device, 180) == -1){
qCWarning(dcWallbe) << "Error Setting Slave ID";
free((void*)(m_device));
return;
}
m_macAddress = getMacAddress();
}
/*
// Extract Input Register 104 - DIP - 16bit integer
if(!(tab_reg[4] && 0x0200)){
// DIP Switch 10 has to be "ON" to enable remote charge control.
// DIP Switch 1 = LSB
qCWarning(dcWallbe) << "DIP switch 10 not on:" << tab_reg[4];
}
*/
WallBe::~WallBe()
{
if (m_device){
modbus_close(m_device);
modbus_free(m_device);
}
}
bool WallBe::isAvailable()
{
uint16_t reg;
if(!m_device)
return false;
// Read random Register to check if the device is reachable
if (modbus_read_input_registers(m_device, 100, 1, &reg) == -1){
qDebug(dcWallbe) << "Connection Failed:" << modbus_strerror(errno) ;
return false;
}
return true;
}
bool WallBe::connect()
{
if(!m_device)
return false;
// Conenct ot the device
if (modbus_connect(m_device) == -1) {
qCDebug(dcWallbe) << "Connection failed: " << modbus_strerror(errno);
return false;
}
return true;
}
QString WallBe::getMacAddress()
{
QString mac;
uint16_t reg[3];
if(!isAvailable()){
if(!connect()){
return "";
}
}
int ret = modbus_read_registers(m_device, 301, 3, reg);
if (ret == -1){
qDebug(dcWallbe) << "Connection Failed:" << modbus_strerror(errno) ;
return "";
}
// for(){
mac = (reg[0] && 0x00ff) + (reg[0] >> 8);// + ":" + (reg[1] && 0x00ff) + (reg[1] >> 8) + ":" + (reg[2] && 0x00ff) + (reg[2] >> 8));
//}
qDebug(dcWallbe) << "Device Mac Address:" << mac ;
return mac;
}
int WallBe::getEvStatus()
{
uint16_t reg;
if(modbus_read_input_registers(m_device, 100, 1, &reg) == -1)
return 0;
return (int)reg;
}
int WallBe::getErrorCode()
{
uint16_t reg;
if(modbus_read_input_registers(m_device, 107, 1, &reg) == -1)
return 0;
return (int)reg;
}
int WallBe::getChargingCurrent()
{
uint16_t reg;
if(modbus_read_input_registers(m_device, 300, 1, &reg) == -1)
return 0;
return (int)reg;
}
bool WallBe::getChargingStatus()
{
uint8_t reg;
// Read if the charging is enabled
if(modbus_read_bits(m_device, 400, 1, &reg) == -1)
return false;
return (int)reg;
}
int WallBe::getChargingTime()
{
uint16_t reg[2];
if(modbus_read_registers(m_device, 102, 2, reg) == -1)
return 0;
return (((uint32_t)(reg[2]<<16)|(uint32_t)(reg[3]))/60); //Converts to minutes
}
void WallBe::setChargingCurrent(int current)
{
if(modbus_write_register(m_device, 300, current) == -1){ //TODO
qDebug(dcWallbe) << "Could not set Current" ;
return;
}
}
void WallBe::setChargingStatus(bool enable)
{
if(modbus_write_bit(m_device, 400, enable) == -1){ //TODO
return;
}
}

62
wallbe/wallbe.h Normal file
View File

@ -0,0 +1,62 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 WALLBE_H
#define WALLBE_H
#include <QObject>
#include <QHostAddress>
#include <QProcess>
#include <modbus/modbus.h>
class WallBe : public QObject
{
Q_OBJECT
public:
WallBe(QHostAddress address, int port, QObject *parent = nullptr);
~WallBe();
bool isAvailable();
bool connect();
int getEvStatus();
int getChargingCurrent();
bool getChargingStatus();
int getChargingTime();
int getErrorCode();
void setChargingCurrent(int current);
void setChargingStatus(bool enable);
private:
modbus_t *m_device;
QString m_macAddress;
QString getMacAddress();
};
#endif // WALLBE_H

19
wallbe/wallbe.pro Normal file
View File

@ -0,0 +1,19 @@
include(../plugins.pri)
TARGET = $$qtLibraryTarget(nymea_devicepluginwallbe)
QT += \
network \
serialbus \
SOURCES += \
devicepluginwallbe.cpp \
wallbe.cpp \
host.cpp \
discover.cpp
HEADERS += \
devicepluginwallbe.h \
wallbe.h \
host.h \
discover.h