Add keba series check and fetch product information during setup
parent
7bf00706ef
commit
195d4ea2e6
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue