From 195d4ea2e6be0e959d76b071134c12edc71856e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 17 Feb 2022 17:34:40 +0100 Subject: [PATCH 01/10] Add keba series check and fetch product information during setup --- keba/README.md | 15 +- keba/integrationpluginkeba.cpp | 32 ++++- keba/keba.pro | 2 + keba/kebaproductinfo.cpp | 249 +++++++++++++++++++++++++++++++++ keba/kebaproductinfo.h | 132 +++++++++++++++++ 5 files changed, 421 insertions(+), 9 deletions(-) create mode 100644 keba/kebaproductinfo.cpp create mode 100644 keba/kebaproductinfo.h diff --git a/keba/README.md b/keba/README.md index 435e2b49..3ec0b30c 100644 --- a/keba/README.md +++ b/keba/README.md @@ -10,19 +10,18 @@ This plugin allows to control Keba KeContact EV-Charging stations. * BMW (certain models) Please make sure that your model supports communication through the UDP protocol. -Only c-series and x-series have this ability (by Feb 2022). Check the product overview on KEBA home page to verify. -https://www.keba.com/download/x/21634787f7/kecontact-p30_productoverview_en.pdf +Only `c-series` and `x-series` have this ability (by Feb 2022). You can check the [product overview](https://www.keba.com/download/x/21634787f7/kecontact-p30_productoverview_en.pdf) +on KEBA home page to verify your models capabilities. - -## Requirements +## Requirments * nymea and the wallbox are required to be in the same network. * UDP Port 7090 must not be blocked by a firewall or router. * The package "nymea-plugin-keba" must be installed. -* KeContact P20 Charging station with network connection (LSA+ socket): Firmware version: 2.5 or higher. -* KeContact P30 Charging station or BMW wallbox: Firmware version 3.05 of higher. -* **Enabled UDP function with DIP-switch DWS1.3 = ON.** +* KeContact P20 Charging station with network connection (LSA+ socket). Firmware version: `2.5` or higher. +* KeContact P30 Charging station or BMW wallbox. Firmware version `3.05` of higher. +* **Enabled UDP function with DIP-switch `DWS1.3 = ON`.** -## More +## More information https://www.keba.com/en/emobility/products/product-overview/product_overview diff --git a/keba/integrationpluginkeba.cpp b/keba/integrationpluginkeba.cpp index e9cdcff4..52478b38 100644 --- a/keba/integrationpluginkeba.cpp +++ b/keba/integrationpluginkeba.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2020, nymea GmbH +* Copyright 2013 - 2022, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -29,6 +29,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "plugininfo.h" +#include "kebaproductinfo.h" #include "integrationpluginkeba.h" #include @@ -162,6 +163,8 @@ void IntegrationPluginKeba::setupThing(ThingSetupInfo *info) qCDebug(dcKeba()) << " - DIP switch 1" << report.dipSw1; qCDebug(dcKeba()) << " - DIP switch 2" << report.dipSw2; + KebaProductInfo productInformation(report.product); + if (thing->paramValue(wallboxThingSerialNumberParamTypeId).toString().isEmpty()) { qCDebug(dcKeba()) << "Update serial number parameter for" << thing << "to" << report.serialNumber; thing->setParamValue(wallboxThingSerialNumberParamTypeId, report.serialNumber); @@ -182,6 +185,33 @@ void IntegrationPluginKeba::setupThing(ThingSetupInfo *info) return; } + // Parse the product code and check if the model actually supports the communication + // Only series X and C support UDP/Modbus + if (productInformation.isValid()) { + bool supported = false; + // This model does not support communication with smart devices. + switch (productInformation.series()) { + case KebaProductInfo::SeriesC: + case KebaProductInfo::SeriesXWlan: + case KebaProductInfo::SeriesXWlan3G: + case KebaProductInfo::SeriesXWlan4G: + case KebaProductInfo::SeriesX3G: + case KebaProductInfo::SeriesX4G: + qCDebug(dcKeba()) << "The keba" << productInformation.series() << "is capable of communicating using UDP"; + supported = true; + break; + default: + break; + } + + if (!supported) { + qCWarning(dcKeba()) << "Connected successfully to Keba but this" << productInformation.series() << "has no communication module."; + info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("This model does not support communication with smart devices.")); + return; + } + } + + m_kebaDevices.insert(thing->id(), keba); info->finish(Thing::ThingErrorNoError); qCDebug(dcKeba()) << "Setup finsihed successfully for" << thing << thing->params(); diff --git a/keba/keba.pro b/keba/keba.pro index e8bc1164..d28edbd8 100644 --- a/keba/keba.pro +++ b/keba/keba.pro @@ -7,11 +7,13 @@ TARGET = $$qtLibraryTarget(nymea_integrationpluginkeba) SOURCES += \ integrationpluginkeba.cpp \ kebadiscovery.cpp \ + kebaproductinfo.cpp \ kecontact.cpp \ kecontactdatalayer.cpp HEADERS += \ integrationpluginkeba.h \ kebadiscovery.h \ + kebaproductinfo.h \ kecontact.h \ kecontactdatalayer.h diff --git a/keba/kebaproductinfo.cpp b/keba/kebaproductinfo.cpp new file mode 100644 index 00000000..aa885d7e --- /dev/null +++ b/keba/kebaproductinfo.cpp @@ -0,0 +1,249 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2022, 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 "kebaproductinfo.h" +#include "extern-plugininfo.h" + +KebaProductInfo::KebaProductInfo(const QString &productString) : + m_productString(productString) +{ + qCDebug(dcKeba()) << "Parsing product information from" << productString.count() << productString; + if (m_productString.count() != 22) { + qCWarning(dcKeba()) << "Invalid product information string size for" << productString << ". Cannot parse."; + m_isValid = false; + return; + } + + // Parse the product string according to Keba Product code definitions + m_model = m_productString.mid(3, 3); + qCDebug(dcKeba()) << "Model:" << m_model; + m_countryCode = m_productString.at(7); + qCDebug(dcKeba()) << "Country:" << m_countryCode; + + QChar connectorValue = m_productString.at(8); + if (connectorValue.toLower() == QChar('s')) { + m_connector = ConnectorSocket; + qCDebug(dcKeba()) << "Connector: Socket"; + } else if (connectorValue.toLower() == QChar('c')) { + m_connector = ConnectorCabel; + qCDebug(dcKeba()) << "Connector: Cabel"; + } else { + m_isValid = false; + return; + } + + QChar connectorTypeValue = m_productString.at(9); + if (connectorTypeValue.isDigit() && connectorTypeValue == QChar('1')) { + m_connectorType = Type1; + } else if (connectorTypeValue.isDigit() && connectorTypeValue == QChar('2')) { + m_connectorType = Type2; + } else if (connectorTypeValue.toLower() == QChar('s')) { + m_connectorType = Shutter; + } else { + m_isValid = false; + return; + } + + qCDebug(dcKeba()) << "Connector type:" << m_connectorType; + + QChar connectorCurrentValue = m_productString.at(10); + if (connectorCurrentValue.isDigit() && connectorTypeValue == QChar('1')) { + m_current = Current13A; + } else if (connectorCurrentValue.isDigit() && connectorTypeValue == QChar('2')) { + m_current = Current16A; + } else if (connectorCurrentValue.isDigit() && connectorTypeValue == QChar('3')) { + m_current = Current20A; + } else if (connectorCurrentValue.isDigit() && connectorTypeValue == QChar('4')) { + m_current = Current32A; + } else { + m_isValid = false; + return; + } + + qCDebug(dcKeba()) << "Current:" << m_current; + + QString cabelValue = m_productString.mid(11, 2); + if (cabelValue == "00") { + m_cabel = NoCabel; + qCDebug(dcKeba()) << "Cabel: No cabel"; + } else if (cabelValue == "01") { + m_cabel = Cabel4m; + qCDebug(dcKeba()) << "Cabel: 4 meter"; + } else if (cabelValue == "04") { + m_cabel = Cabel6m; + qCDebug(dcKeba()) << "Cabel: 6 meter"; + } else if (cabelValue == "07") { + m_cabel = Cabel5p5m; + qCDebug(dcKeba()) << "Cabel: 5.5 meter"; + } else { + m_isValid = false; + return; + } + + QChar seriesValue = m_productString.at(13); + if (seriesValue == QChar('0')) { + m_series = SeriesE; + qCDebug(dcKeba()) << "Series: E"; + } else if (seriesValue == QChar('1')) { + m_series = SeriesB; + qCDebug(dcKeba()) << "Series: B"; + } else if (seriesValue == QChar('2')) { + m_series = SeriesC; + qCDebug(dcKeba()) << "Series: C"; + } else if (seriesValue == QChar('3')) { + m_series = SeriesA; + qCDebug(dcKeba()) << "Series: A"; + } else if (seriesValue.toLower() == QChar('b')) { + m_series = SeriesXWlan; + qCDebug(dcKeba()) << "Series: X (Wlan)"; + } else if (seriesValue.toLower() == QChar('c')) { + m_series = SeriesXWlan3G; + qCDebug(dcKeba()) << "Series: X (Wlan + 3G)"; + } else if (seriesValue.toLower() == QChar('e')) { + m_series = SeriesXWlan4G; + qCDebug(dcKeba()) << "Series: X (Wlan + 4G)"; + } else if (seriesValue.toLower() == QChar('g')) { + m_series = SeriesX3G; + qCDebug(dcKeba()) << "Series: X (3G)"; + } else if (seriesValue.toLower() == QChar('h')) { + m_series = SeriesX4G; + qCDebug(dcKeba()) << "Series: X (4G)"; + } else { + m_isValid = false; + return; + } + + QChar phaseCountValue = m_productString.at(14); + if (phaseCountValue == QChar('1')) { + m_phaseCount = 1; + } else if (phaseCountValue == QChar('2')) { + m_phaseCount = 3; + } else { + m_isValid = false; + return; + } + + qCDebug(dcKeba()) << "Phases:" << m_phaseCount; + + QChar meterValue = m_productString.at(16); + if (meterValue == QChar('0')) { + m_meter = NoMeter; + qCDebug(dcKeba()) << "Meter: No meter"; + } else if (meterValue.toLower() == QChar('e')) { + m_meter = MeterNotCalibrated; + qCDebug(dcKeba()) << "Meter: Not calibrated meter"; + } else if (meterValue.toLower() == QChar('m')) { + m_meter = MeterCalibrated; + qCDebug(dcKeba()) << "Meter: Calibrated meter"; + } else if (meterValue.toLower() == QChar('l')) { + m_meter = MeterCalibratedNationalCertified; + qCDebug(dcKeba()) << "Meter: Calibrated meter (national certified)"; + } else { + m_isValid = false; + return; + } + + + QChar authValue = m_productString.at(18); + if (authValue == QChar('0')) { + m_authorization = NoAuthorization; + qCDebug(dcKeba()) << "Authorization: No authorization"; + } else if (authValue.toLower() == QChar('r')) { + m_authorization = Rfid; + qCDebug(dcKeba()) << "Authorization: RFID"; + } else if (authValue.toLower() == QChar('k')) { + m_authorization = Key; + qCDebug(dcKeba()) << "Authorization: Key"; + } else { + m_isValid = false; + return; + } + +} + +bool KebaProductInfo::isValid() const +{ + return m_isValid; +} + +QString KebaProductInfo::productString() const +{ + return m_productString; +} + +QString KebaProductInfo::model() const +{ + return m_model; +} + +QString KebaProductInfo::countryCode() const +{ + return m_countryCode; +} + +KebaProductInfo::Connector KebaProductInfo::connector() const +{ + return m_connector; +} + +KebaProductInfo::ConnectorType KebaProductInfo::connectorType() const +{ + return m_connectorType; +} + +KebaProductInfo::ConnectorCurrent KebaProductInfo::current() const +{ + return m_current; +} + +KebaProductInfo::Cabel KebaProductInfo::cabel() const +{ + return m_cabel; +} + +KebaProductInfo::Series KebaProductInfo::series() const +{ + return m_series; +} + +int KebaProductInfo::phaseCount() const +{ + return m_phaseCount; +} + +KebaProductInfo::Meter KebaProductInfo::meter() const +{ + return m_meter; +} + +KebaProductInfo::Authorization KebaProductInfo::authorization() const +{ + return m_authorization; +} diff --git a/keba/kebaproductinfo.h b/keba/kebaproductinfo.h new file mode 100644 index 00000000..77dd7bdd --- /dev/null +++ b/keba/kebaproductinfo.h @@ -0,0 +1,132 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2022, 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 KEBAPRODUCTINFO_H +#define KEBAPRODUCTINFO_H + +#include +#include + +class KebaProductInfo +{ + Q_GADGET +public: + enum Connector { + ConnectorSocket, + ConnectorCabel + }; + Q_ENUM(Connector) + + enum ConnectorType { + Type1, + Type2, + Shutter + }; + Q_ENUM(ConnectorType) + + enum ConnectorCurrent { + Current13A = 1, + Current16A = 2, + Current20A = 3, + Current32A = 4 + }; + Q_ENUM(ConnectorCurrent) + + enum Cabel { + NoCabel = 0, + Cabel4m = 1, + Cabel6m = 4, + Cabel5p5m = 7 + }; + Q_ENUM(Cabel) + + enum Series { + SeriesE, + SeriesB, + SeriesC, + SeriesA, + SeriesXWlan, + SeriesXWlan3G, + SeriesXWlan4G, + SeriesX3G, + SeriesX4G + }; + Q_ENUM(Series) + + enum Meter { + NoMeter, + MeterNotCalibrated, + MeterCalibrated, + MeterCalibratedNationalCertified + }; + Q_ENUM(Meter) + + enum Authorization { + NoAuthorization, + Rfid, + Key + }; + Q_ENUM(Authorization) + + KebaProductInfo(const QString &productString); + + bool isValid() const; + + QString productString() const; + + // Porperties in the string + QString model() const; // KC-P30 + QString countryCode() const; // E + Connector connector() const; // Socket / Cabel + ConnectorType connectorType() const; // Type 1 / Type 2 + ConnectorCurrent current() const; // 13A, 16A ... + Cabel cabel() const; // 4m, 6m... + Series series() const; // x, c, a... + int phaseCount() const; // 1 or 3 + Meter meter() const; // No meter, Calibrated, ... + Authorization authorization() const; + +private: + bool m_isValid = true; + + QString m_productString; + QString m_model; + QString m_countryCode; + Connector m_connector; + ConnectorType m_connectorType; + ConnectorCurrent m_current; + Cabel m_cabel; + Series m_series; + int m_phaseCount; + Meter m_meter; + Authorization m_authorization; +}; + +#endif // KEBAPRODUCTINFO_H From 56b0036cca8a9ffc5d41a79160e146180cefc616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 17 Feb 2022 17:37:20 +0100 Subject: [PATCH 02/10] Add new translation strings --- .../9142b09f-30a9-43d0-9ede-2f8debe075ac-de.ts | 15 ++++++++++----- .../9142b09f-30a9-43d0-9ede-2f8debe075ac-en_US.ts | 15 ++++++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-de.ts b/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-de.ts index 4f7f0726..dfda9e10 100644 --- a/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-de.ts +++ b/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-de.ts @@ -4,30 +4,35 @@ IntegrationPluginKeba - + The communication could not be established. - + The network discovery is not available. Please enter the IP address manually. - + Error opening network port. Fehler beim Öffnen des Netzwerkports. - + Already configured for this IP address. - + The required communication interface is not enabled on this wallbox. Please make sure the DIP switch 1.3 is switched on and try again. + + + This model does not support communication with smart devices. + + Keba diff --git a/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-en_US.ts b/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-en_US.ts index 3e9da0f0..4c5407cc 100644 --- a/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-en_US.ts +++ b/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-en_US.ts @@ -4,30 +4,35 @@ IntegrationPluginKeba - + The communication could not be established. - + The network discovery is not available. Please enter the IP address manually. - + Error opening network port. - + Already configured for this IP address. - + The required communication interface is not enabled on this wallbox. Please make sure the DIP switch 1.3 is switched on and try again. + + + This model does not support communication with smart devices. + + Keba From bcd243d83e61f42284c6a8593cc73ddf6156f294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 17 Feb 2022 17:52:51 +0100 Subject: [PATCH 03/10] Fix product length verification since it may vary in the end --- keba/kebaproductinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keba/kebaproductinfo.cpp b/keba/kebaproductinfo.cpp index aa885d7e..c70dad40 100644 --- a/keba/kebaproductinfo.cpp +++ b/keba/kebaproductinfo.cpp @@ -35,7 +35,7 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : m_productString(productString) { qCDebug(dcKeba()) << "Parsing product information from" << productString.count() << productString; - if (m_productString.count() != 22) { + if (m_productString.count() < 19) { qCWarning(dcKeba()) << "Invalid product information string size for" << productString << ". Cannot parse."; m_isValid = false; return; From 39d55877d96684c3da011343724f3b7440313bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 18 Feb 2022 06:22:28 +0100 Subject: [PATCH 04/10] Fix typos --- keba/integrationpluginkeba.cpp | 1 - keba/kebaproductinfo.cpp | 34 +++++++++++++++++----------------- keba/kebaproductinfo.h | 20 ++++++++++---------- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/keba/integrationpluginkeba.cpp b/keba/integrationpluginkeba.cpp index 52478b38..07ff9096 100644 --- a/keba/integrationpluginkeba.cpp +++ b/keba/integrationpluginkeba.cpp @@ -211,7 +211,6 @@ void IntegrationPluginKeba::setupThing(ThingSetupInfo *info) } } - m_kebaDevices.insert(thing->id(), keba); info->finish(Thing::ThingErrorNoError); qCDebug(dcKeba()) << "Setup finsihed successfully for" << thing << thing->params(); diff --git a/keba/kebaproductinfo.cpp b/keba/kebaproductinfo.cpp index c70dad40..2a5daf26 100644 --- a/keba/kebaproductinfo.cpp +++ b/keba/kebaproductinfo.cpp @@ -52,8 +52,8 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : m_connector = ConnectorSocket; qCDebug(dcKeba()) << "Connector: Socket"; } else if (connectorValue.toLower() == QChar('c')) { - m_connector = ConnectorCabel; - qCDebug(dcKeba()) << "Connector: Cabel"; + m_connector = ConnectorCable; + qCDebug(dcKeba()) << "Connector: Cable"; } else { m_isValid = false; return; @@ -89,19 +89,19 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : qCDebug(dcKeba()) << "Current:" << m_current; - QString cabelValue = m_productString.mid(11, 2); - if (cabelValue == "00") { - m_cabel = NoCabel; - qCDebug(dcKeba()) << "Cabel: No cabel"; - } else if (cabelValue == "01") { - m_cabel = Cabel4m; - qCDebug(dcKeba()) << "Cabel: 4 meter"; - } else if (cabelValue == "04") { - m_cabel = Cabel6m; - qCDebug(dcKeba()) << "Cabel: 6 meter"; - } else if (cabelValue == "07") { - m_cabel = Cabel5p5m; - qCDebug(dcKeba()) << "Cabel: 5.5 meter"; + QString cableValue = m_productString.mid(11, 2); + if (cableValue == "00") { + m_cable = NoCable; + qCDebug(dcKeba()) << "Cable: No cable"; + } else if (cableValue == "01") { + m_cable = Cable4m; + qCDebug(dcKeba()) << "Cable: 4 meter"; + } else if (cableValue == "04") { + m_cable = Cable6m; + qCDebug(dcKeba()) << "Cable: 6 meter"; + } else if (cableValue == "07") { + m_cable = Cable5p5m; + qCDebug(dcKeba()) << "Cable: 5.5 meter"; } else { m_isValid = false; return; @@ -223,9 +223,9 @@ KebaProductInfo::ConnectorCurrent KebaProductInfo::current() const return m_current; } -KebaProductInfo::Cabel KebaProductInfo::cabel() const +KebaProductInfo::Cable KebaProductInfo::cable() const { - return m_cabel; + return m_cable; } KebaProductInfo::Series KebaProductInfo::series() const diff --git a/keba/kebaproductinfo.h b/keba/kebaproductinfo.h index 77dd7bdd..fd40eb0c 100644 --- a/keba/kebaproductinfo.h +++ b/keba/kebaproductinfo.h @@ -40,7 +40,7 @@ class KebaProductInfo public: enum Connector { ConnectorSocket, - ConnectorCabel + ConnectorCable }; Q_ENUM(Connector) @@ -59,13 +59,13 @@ public: }; Q_ENUM(ConnectorCurrent) - enum Cabel { - NoCabel = 0, - Cabel4m = 1, - Cabel6m = 4, - Cabel5p5m = 7 + enum Cable { + NoCable = 0, + Cable4m = 1, + Cable6m = 4, + Cable5p5m = 7 }; - Q_ENUM(Cabel) + Q_ENUM(Cable) enum Series { SeriesE, @@ -104,10 +104,10 @@ public: // Porperties in the string QString model() const; // KC-P30 QString countryCode() const; // E - Connector connector() const; // Socket / Cabel + Connector connector() const; // Socket / Cable ConnectorType connectorType() const; // Type 1 / Type 2 ConnectorCurrent current() const; // 13A, 16A ... - Cabel cabel() const; // 4m, 6m... + Cable cable() const; // 4m, 6m... Series series() const; // x, c, a... int phaseCount() const; // 1 or 3 Meter meter() const; // No meter, Calibrated, ... @@ -122,7 +122,7 @@ private: Connector m_connector; ConnectorType m_connectorType; ConnectorCurrent m_current; - Cabel m_cabel; + Cable m_cable; Series m_series; int m_phaseCount; Meter m_meter; From b8db29c0ef2221c89932ab1a34d2450e0edf9f0f Mon Sep 17 00:00:00 2001 From: simonseres Date: Mon, 28 Feb 2022 08:51:00 +0100 Subject: [PATCH 05/10] updated README for Model Deutschland Edition --- keba/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/keba/README.md b/keba/README.md index 3ec0b30c..b1d576c6 100644 --- a/keba/README.md +++ b/keba/README.md @@ -8,12 +8,13 @@ This plugin allows to control Keba KeContact EV-Charging stations. * P20 (certain models) * P30 (certain models) * BMW (certain models) + * Keba Deutschland Edition Please make sure that your model supports communication through the UDP protocol. Only `c-series` and `x-series` have this ability (by Feb 2022). You can check the [product overview](https://www.keba.com/download/x/21634787f7/kecontact-p30_productoverview_en.pdf) on KEBA home page to verify your models capabilities. -## Requirments +## Requirements * nymea and the wallbox are required to be in the same network. * UDP Port 7090 must not be blocked by a firewall or router. From 4b52ed8084fc72905197cfe8d457ba0603a07e38 Mon Sep 17 00:00:00 2001 From: simonseres Date: Tue, 1 Mar 2022 17:50:24 +0100 Subject: [PATCH 06/10] correct typos --- keba/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keba/README.md b/keba/README.md index b1d576c6..50c222f1 100644 --- a/keba/README.md +++ b/keba/README.md @@ -21,7 +21,7 @@ on KEBA home page to verify your models capabilities. * The package "nymea-plugin-keba" must be installed. * KeContact P20 Charging station with network connection (LSA+ socket). Firmware version: `2.5` or higher. * KeContact P30 Charging station or BMW wallbox. Firmware version `3.05` of higher. -* **Enabled UDP function with DIP-switch `DWS1.3 = ON`.** +* **Enabled UDP function with DIP-switch `DSW1.3 = ON`.** ## More information From 5be4be9e0bf20ad862fc7f7b81c9b004cda29983 Mon Sep 17 00:00:00 2001 From: simonseres Date: Thu, 10 Mar 2022 12:49:27 +0100 Subject: [PATCH 07/10] more excemptions on keba types and models --- keba/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/keba/README.md b/keba/README.md index 50c222f1..bd922cb2 100644 --- a/keba/README.md +++ b/keba/README.md @@ -8,11 +8,12 @@ This plugin allows to control Keba KeContact EV-Charging stations. * P20 (certain models) * P30 (certain models) * BMW (certain models) - * Keba Deutschland Edition + * [Keba Deutschland Edition](https://a.storyblok.com/f/40131/x/fc59dc7bf7/datenblatt_deutschland_edition.pdf) + * [Keba Green Edition](https://keba.com/download/x/7ec5b6e96f/121218_dbde.pdf) Please make sure that your model supports communication through the UDP protocol. -Only `c-series` and `x-series` have this ability (by Feb 2022). You can check the [product overview](https://www.keba.com/download/x/21634787f7/kecontact-p30_productoverview_en.pdf) -on KEBA home page to verify your models capabilities. +Only `c-series` and `x-series` have this ability (by March 2022) with the excemption of `Deutschland Edition` and `Green Edition`. +You can check the [product overview](https://www.keba.com/download/x/21634787f7/kecontact-p30_productoverview_en.pdf) on KEBA home page to verify your models capabilities. ## Requirements From 2a2d9dcdff9146241a08cb8592af0e7fc937af25 Mon Sep 17 00:00:00 2001 From: simonseres Date: Thu, 10 Mar 2022 16:17:47 +0100 Subject: [PATCH 08/10] change of wording --- keba/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keba/README.md b/keba/README.md index bd922cb2..44e67dbf 100644 --- a/keba/README.md +++ b/keba/README.md @@ -13,7 +13,7 @@ This plugin allows to control Keba KeContact EV-Charging stations. Please make sure that your model supports communication through the UDP protocol. Only `c-series` and `x-series` have this ability (by March 2022) with the excemption of `Deutschland Edition` and `Green Edition`. -You can check the [product overview](https://www.keba.com/download/x/21634787f7/kecontact-p30_productoverview_en.pdf) on KEBA home page to verify your models capabilities. +The [product overview](https://www.keba.com/download/x/21634787f7/kecontact-p30_productoverview_en.pdf) helps to verify about your models capabilities. ## Requirements From 8baf921119c7bf124e95f539c75b01d01c08ccbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 16 Mar 2022 08:13:04 +0100 Subject: [PATCH 09/10] Allow supported A and B series editions --- keba/integrationpluginkeba.cpp | 30 ++++++++++++++++++++++++++---- keba/kebaproductinfo.cpp | 7 +++++++ keba/kebaproductinfo.h | 2 ++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/keba/integrationpluginkeba.cpp b/keba/integrationpluginkeba.cpp index 07ff9096..bfd28382 100644 --- a/keba/integrationpluginkeba.cpp +++ b/keba/integrationpluginkeba.cpp @@ -185,12 +185,32 @@ void IntegrationPluginKeba::setupThing(ThingSetupInfo *info) return; } - // Parse the product code and check if the model actually supports the communication - // Only series X and C support UDP/Modbus + // Parse the product code and check if the model actually supports the UDP/Modbus communication + // Supported are: + // - The A series (german edition), no meter DE440 (green edition) + // - The B series (german edition), no meter DE440 + // - All C series + // - All X series + if (productInformation.isValid()) { + bool supported = false; - // This model does not support communication with smart devices. + + qCDebug(dcKeba()) << "Product information are valid. Evaluating if model supports UDP/Modbus communication..."; + switch (productInformation.series()) { + case KebaProductInfo::SeriesA: + if (productInformation.model() == "P30" && productInformation.germanEdition()) { + qCDebug(dcKeba()) << "The P30 A series german edition is supported (DE440 GREEN EDITION)"; + supported = true; + } + break; + case KebaProductInfo::SeriesB: + if (productInformation.model() == "P30" && productInformation.germanEdition()) { + qCDebug(dcKeba()) << "The P30 B series german edition is supported (DE440)"; + supported = true; + } + break; case KebaProductInfo::SeriesC: case KebaProductInfo::SeriesXWlan: case KebaProductInfo::SeriesXWlan3G: @@ -205,10 +225,12 @@ void IntegrationPluginKeba::setupThing(ThingSetupInfo *info) } if (!supported) { - qCWarning(dcKeba()) << "Connected successfully to Keba but this" << productInformation.series() << "has no communication module."; + qCWarning(dcKeba()) << "Connected successfully to Keba but this model" << productInformation.series() << "has no communication module."; info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("This model does not support communication with smart devices.")); return; } + } else { + qCWarning(dcKeba()) << "Product information are not valid. Cannot determin if this model supports UDP/Modbus communication, assuming yes so let's try to init..."; } m_kebaDevices.insert(thing->id(), keba); diff --git a/keba/kebaproductinfo.cpp b/keba/kebaproductinfo.cpp index 2a5daf26..a850afec 100644 --- a/keba/kebaproductinfo.cpp +++ b/keba/kebaproductinfo.cpp @@ -186,6 +186,8 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : return; } + m_germanEdition = m_productString.toUpper().endsWith("DE"); + qCDebug(dcKeba()) << "German Edition:" << m_germanEdition; } bool KebaProductInfo::isValid() const @@ -247,3 +249,8 @@ KebaProductInfo::Authorization KebaProductInfo::authorization() const { return m_authorization; } + +bool KebaProductInfo::germanEdition() const +{ + return m_germanEdition; +} diff --git a/keba/kebaproductinfo.h b/keba/kebaproductinfo.h index fd40eb0c..4363d08a 100644 --- a/keba/kebaproductinfo.h +++ b/keba/kebaproductinfo.h @@ -112,6 +112,7 @@ public: int phaseCount() const; // 1 or 3 Meter meter() const; // No meter, Calibrated, ... Authorization authorization() const; + bool germanEdition() const; private: bool m_isValid = true; @@ -127,6 +128,7 @@ private: int m_phaseCount; Meter m_meter; Authorization m_authorization; + bool m_germanEdition = false; }; #endif // KEBAPRODUCTINFO_H From 6af3cf907e3150464317c99cbc54018c10f43231 Mon Sep 17 00:00:00 2001 From: simonseres Date: Fri, 25 Mar 2022 16:44:24 +0100 Subject: [PATCH 10/10] corrected some statements --- keba/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/keba/README.md b/keba/README.md index 44e67dbf..509c39b7 100644 --- a/keba/README.md +++ b/keba/README.md @@ -6,13 +6,14 @@ This plugin allows to control Keba KeContact EV-Charging stations. * KeContact Wallbox * P20 (certain models) - * P30 (certain models) + * P30 + * c-series + * x-series * BMW (certain models) - * [Keba Deutschland Edition](https://a.storyblok.com/f/40131/x/fc59dc7bf7/datenblatt_deutschland_edition.pdf) - * [Keba Green Edition](https://keba.com/download/x/7ec5b6e96f/121218_dbde.pdf) + * [Keba Deutschland Edition](https://a.storyblok.com/f/40131/x/fc59dc7bf7/datenblatt_deutschland_edition.pdf) (DE440) +(by March 2022) Please make sure that your model supports communication through the UDP protocol. -Only `c-series` and `x-series` have this ability (by March 2022) with the excemption of `Deutschland Edition` and `Green Edition`. The [product overview](https://www.keba.com/download/x/21634787f7/kecontact-p30_productoverview_en.pdf) helps to verify about your models capabilities. ## Requirements