Add keba series check and fetch product information during setup

master
Simon Stürz 2022-02-17 17:34:40 +01:00
parent 7bf00706ef
commit 195d4ea2e6
5 changed files with 421 additions and 9 deletions

View File

@ -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

View File

@ -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 <QJsonDocument>
@ -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();

View File

@ -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

249
keba/kebaproductinfo.cpp Normal file
View File

@ -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 <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 "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;
}

132
keba/kebaproductinfo.h Normal file
View File

@ -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 <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 KEBAPRODUCTINFO_H
#define KEBAPRODUCTINFO_H
#include <QObject>
#include <QString>
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