diff --git a/debian/control b/debian/control
index 3ba6372..1ad4456 100644
--- a/debian/control
+++ b/debian/control
@@ -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
diff --git a/debian/nymea-plugin-wallbe.install.in b/debian/nymea-plugin-wallbe.install.in
new file mode 100644
index 0000000..c6bd4a3
--- /dev/null
+++ b/debian/nymea-plugin-wallbe.install.in
@@ -0,0 +1 @@
+usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_devicepluginwallbe.so
diff --git a/drexelundweiss/drexelundweiss.pro b/drexelundweiss/drexelundweiss.pro
index b68e01e..f8fe629 100644
--- a/drexelundweiss/drexelundweiss.pro
+++ b/drexelundweiss/drexelundweiss.pro
@@ -1,5 +1,7 @@
include(../plugins.pri)
+TARGET = $$qtLibraryTarget(nymea_deviceplugindrexelundweiss)
+
QT += \
serialport \
serialbus \
diff --git a/nymea-plugins-modbus.pro b/nymea-plugins-modbus.pro
index 8f5a1f0..0a6f508 100644
--- a/nymea-plugins-modbus.pro
+++ b/nymea-plugins-modbus.pro
@@ -2,7 +2,7 @@ TEMPLATE = subdirs
PLUGIN_DIRS = \
drexelundweiss \
-
+ wallbe \
message(============================================)
message("Qt version:" $$[QT_VERSION])
diff --git a/wallbe/README.md b/wallbe/README.md
new file mode 100644
index 0000000..00c5df2
--- /dev/null
+++ b/wallbe/README.md
@@ -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
diff --git a/wallbe/devicepluginwallbe.cpp b/wallbe/devicepluginwallbe.cpp
new file mode 100644
index 0000000..361e7de
--- /dev/null
+++ b/wallbe/devicepluginwallbe.cpp
@@ -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 .
+*
+* 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
+#include
+#include
+#include
+
+
+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 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());
+}
diff --git a/wallbe/devicepluginwallbe.h b/wallbe/devicepluginwallbe.h
new file mode 100644
index 0000000..051cd3a
--- /dev/null
+++ b/wallbe/devicepluginwallbe.h
@@ -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 .
+*
+* 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
+#include
+
+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 m_connections;
+ QList m_address;
+ PluginTimer *m_pluginTimer = nullptr;
+
+ void update(Device *device);
+};
+
+#endif // DEVICEPLUGINWALLBE_H
diff --git a/wallbe/devicepluginwallbe.json b/wallbe/devicepluginwallbe.json
new file mode 100644
index 0000000..0e6aca3
--- /dev/null
+++ b/wallbe/devicepluginwallbe.json
@@ -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
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/wallbe/discover.cpp b/wallbe/discover.cpp
new file mode 100644
index 0000000..5af54e4
--- /dev/null
+++ b/wallbe/discover.cpp
@@ -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 .
+*
+* For any further details and any questions please contact us under contact@nymea.io
+* or see our FAQ/Licensing Information on https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include
+#include
+#include "discover.h"
+#include "extern-plugininfo.h"
+
+Discover::Discover(QStringList arguments, QObject *parent) :
+ QObject(parent),
+ m_arguments(arguments),
+ m_discoveryProcess(nullptr),
+ m_aboutToQuit(false)
+{
+}
+
+Discover::~Discover()
+{
+ // Stop running processes
+ m_aboutToQuit = true;
+
+ if (m_discoveryProcess && m_discoveryProcess->state() == QProcess::Running) {
+ qCDebug(dcWallbe()) << "Kill running discovery process";
+ m_discoveryProcess->terminate();
+ m_discoveryProcess->waitForFinished(5000);
+ }
+}
+
+QStringList Discover::getDefaultTargets()
+{
+ QStringList targets;
+ foreach (const QHostAddress &interface, QNetworkInterface::allAddresses()) {
+ if (!interface.isLoopback() && interface.scopeId().isEmpty()) {
+ QPair pair = QHostAddress::parseSubnet(interface.toString() + "/24");
+ targets << QString("%1/%2").arg(pair.first.toString()).arg(pair.second);
+ }
+ }
+ return targets;
+}
+
+QList Discover::parseProcessOutput(const QByteArray &processData)
+{
+ m_reader.clear();
+ m_reader.addData(processData);
+
+ QList hosts;
+
+ while (!m_reader.atEnd() && !m_reader.hasError()) {
+
+ QXmlStreamReader::TokenType token = m_reader.readNext();
+ if(token == QXmlStreamReader::StartDocument)
+ continue;
+
+ if(token == QXmlStreamReader::StartElement && m_reader.name() == "host") {
+ Host host = parseHost();
+ if (host.isValid()) {
+ hosts.append(host);
+ }
+ }
+ }
+ return hosts;
+}
+
+Host Discover::parseHost()
+{
+ if (!m_reader.isStartElement() || m_reader.name() != "host")
+ return Host();
+
+ QString address; QString hostName; QString status; QString mac;
+ while(!(m_reader.tokenType() == QXmlStreamReader::EndElement && m_reader.name() == "host")){
+
+ m_reader.readNext();
+
+ if (m_reader.isStartElement() && m_reader.name() == "hostname") {
+ QString name = m_reader.attributes().value("name").toString();
+ if (!name.isEmpty())
+ hostName = name;
+
+ m_reader.readNext();
+ }
+
+ if (m_reader.name() == "address") {
+ QString addr = m_reader.attributes().value("addr").toString();
+ if (!addr.isEmpty())
+ address = addr;
+ }
+
+ if (m_reader.name() == "state") {
+ QString state = m_reader.attributes().value("state").toString();
+ if (!state.isEmpty())
+ status = state;
+ }
+
+ if (m_reader.name() == "mac") { //TODO CHeck Keyword
+ QString macAddress = m_reader.attributes().value("state").toString();
+ if (!macAddress.isEmpty())
+ mac = macAddress;
+ }
+ }
+ return Host(hostName, address, mac, (status == "open" ? true : false));
+}
+
+void Discover::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ QProcess *process = static_cast(sender());
+
+ // If the process was killed because nymead is shutting down...we dont't care any more about the result
+ if (m_aboutToQuit)
+ return;
+
+ // Discovery
+ if (process == m_discoveryProcess) {
+
+ qCDebug(dcWallbe()) << "Discovery process finished";
+
+ process->deleteLater();
+ m_discoveryProcess = nullptr;
+
+ if (exitCode != 0 || exitStatus != QProcess::NormalExit) {
+ qCWarning(dcWallbe()) << "Network scan error:" << process->readAllStandardError();
+ return;
+ }
+
+ QByteArray outputData = process->readAllStandardOutput();
+ emit devicesDiscovered(parseProcessOutput(outputData));
+
+ }
+}
+
+bool Discover::getProcessStatus()
+{
+ return m_discoveryProcess;
+}
+
+void Discover::onTimeout()
+{
+
+}
diff --git a/wallbe/discover.h b/wallbe/discover.h
new file mode 100644
index 0000000..4c75916
--- /dev/null
+++ b/wallbe/discover.h
@@ -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 .
+*
+* 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
+#include
+#include
+#include
+#include
+
+#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 parseProcessOutput(const QByteArray &processData);
+ Host parseHost();
+
+signals:
+ void devicesDiscovered(QList);
+
+private slots:
+ void onTimeout();
+};
+
+#endif // DISCOVER_H
diff --git a/wallbe/host.cpp b/wallbe/host.cpp
new file mode 100644
index 0000000..bf6c388
--- /dev/null
+++ b/wallbe/host.cpp
@@ -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 .
+*
+* 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();
+}
diff --git a/wallbe/host.h b/wallbe/host.h
new file mode 100644
index 0000000..71463c4
--- /dev/null
+++ b/wallbe/host.h
@@ -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 .
+*
+* 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
+#include
+
+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
diff --git a/wallbe/translations/0de5bbd2-0dad-4727-9a17-3ee149106048-en_US.ts b/wallbe/translations/0de5bbd2-0dad-4727-9a17-3ee149106048-en_US.ts
new file mode 100644
index 0000000..f153da9
--- /dev/null
+++ b/wallbe/translations/0de5bbd2-0dad-4727-9a17-3ee149106048-en_US.ts
@@ -0,0 +1,138 @@
+
+
+
+
+ DevicePluginWallbe
+
+
+ IP address parameter not valid
+
+
+
+
+ Wallbe
+
+
+
+
+ Charging
+ 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
+
+
+
+
+
+ Charging Time
+ 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
+
+
+
+
+
+
+ Charging current
+ 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
+
+
+
+
+ Charging current changed
+ The name of the EventType ({60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) of DeviceClass wallbeEco
+
+
+
+
+ Charging status changed
+ The name of the EventType ({26793adc-de10-426f-bb17-170c227891b2}) of DeviceClass wallbeEco
+
+
+
+
+ Charging time changed
+ The name of the EventType ({8dc2fef8-d16e-422a-8498-456b818f5752}) of DeviceClass wallbeEco
+
+
+
+
+
+ Connected
+ 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
+
+
+
+
+ Connected changed
+ The name of the EventType ({39a8e92b-40e5-4648-b5a8-2ffcb5598081}) of DeviceClass wallbeEco
+
+
+
+
+
+ EV Status
+ 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
+
+
+
+
+ EV status changed
+ The name of the EventType ({2a95c4fb-9a15-4788-ae09-d34e71314da6}) of DeviceClass wallbeEco
+
+
+
+
+ IP address
+ The name of the ParamType (DeviceClass: wallbeEco, Type: device, ID: {95f297a7-56a5-4789-9b14-6735717344b5})
+
+
+
+
+ MAC address
+ The name of the ParamType (DeviceClass: wallbeEco, Type: device, ID: {551b03f0-dd70-4463-929b-3668dbd3290f})
+
+
+
+
+ Petring
+ The name of the vendor ({831b4b87-0a6c-4d51-b055-967bb6e5fab5})
+
+
+
+
+ Set charging current
+ The name of the ActionType ({60b5b6b8-bcd3-4c3f-8501-f15af94bc8c1}) of DeviceClass wallbeEco
+
+
+
+
+ Start charging
+ The name of the ActionType ({26793adc-de10-426f-bb17-170c227891b2}) of DeviceClass wallbeEco
+
+
+
+
+ Wallbe eco 2.0
+ The name of the DeviceClass ({e66c84f6-b398-47e9-8aeb-33840e7b4492})
+
+
+
+
+ wallbe plugin
+ The name of the plugin Wallbe ({0de5bbd2-0dad-4727-9a17-3ee149106048})
+
+
+
+
diff --git a/wallbe/wallbe.cpp b/wallbe/wallbe.cpp
new file mode 100644
index 0000000..652eaec
--- /dev/null
+++ b/wallbe/wallbe.cpp
@@ -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 .
+*
+* 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, ®) == -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, ®) == -1)
+ return 0;
+
+ return (int)reg;
+}
+
+int WallBe::getErrorCode()
+{
+ uint16_t reg;
+
+ if(modbus_read_input_registers(m_device, 107, 1, ®) == -1)
+ return 0;
+
+ return (int)reg;
+}
+
+int WallBe::getChargingCurrent()
+{
+ uint16_t reg;
+
+ if(modbus_read_input_registers(m_device, 300, 1, ®) == -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, ®) == -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;
+ }
+}
diff --git a/wallbe/wallbe.h b/wallbe/wallbe.h
new file mode 100644
index 0000000..3bb8d7f
--- /dev/null
+++ b/wallbe/wallbe.h
@@ -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 .
+*
+* 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
+#include
+#include
+
+#include
+
+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
diff --git a/wallbe/wallbe.pro b/wallbe/wallbe.pro
new file mode 100644
index 0000000..7af11bf
--- /dev/null
+++ b/wallbe/wallbe.pro
@@ -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