From b58652366ae67a9c914236af50858785b170bbd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 11 Oct 2023 10:41:19 +0200 Subject: [PATCH] Keba: Fix parsing product information for BMW --- keba/integrationpluginkeba.cpp | 7 ++-- keba/kebaproductinfo.cpp | 66 +++++++++++++++++++++++++++------- keba/kebaproductinfo.h | 5 ++- 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/keba/integrationpluginkeba.cpp b/keba/integrationpluginkeba.cpp index 52b2922b..2af19966 100644 --- a/keba/integrationpluginkeba.cpp +++ b/keba/integrationpluginkeba.cpp @@ -38,7 +38,10 @@ IntegrationPluginKeba::IntegrationPluginKeba() { - + // KebaProductInfo bmw("BMW-10-EC240522-E1R"); + // KebaProductInfo ke("KC-P30-EC240122-E0R"); + // KebaProductInfo ge("KC-P30-EC220112-000-DE"); + // KebaProductInfo n("KC-P30-EC2404B2-M0A-GE"); } void IntegrationPluginKeba::init() @@ -96,7 +99,7 @@ void IntegrationPluginKeba::discoverThings(ThingDiscoveryInfo *info) if (discoveredThingClassId != info->thingClassId()) continue; - ThingDescriptor descriptor(discoveredThingClassId, "Keba " + result.product, "Serial: " + result.serialNumber + " - " + result.networkDeviceInfo.address().toString()); + ThingDescriptor descriptor(discoveredThingClassId, productInformation.manufacturer() + " " + result.product, "Serial: " + result.serialNumber + " - " + result.networkDeviceInfo.address().toString()); qCDebug(dcKeba()) << "Discovered:" << descriptor.title() << descriptor.description(); // Check if we already have set up this device diff --git a/keba/kebaproductinfo.cpp b/keba/kebaproductinfo.cpp index a850afec..774f3faa 100644 --- a/keba/kebaproductinfo.cpp +++ b/keba/kebaproductinfo.cpp @@ -34,6 +34,13 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : m_productString(productString) { + // Examples + + // BMW-10-EC240522-E1R + // KC-P30-EC240122-E0R + // KC-P30-EC220112-000-DE + // KC-P30-EC2404B2-M0A-GE + qCDebug(dcKeba()) << "Parsing product information from" << productString.count() << productString; if (m_productString.count() < 19) { qCWarning(dcKeba()) << "Invalid product information string size for" << productString << ". Cannot parse."; @@ -41,13 +48,33 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : return; } + QStringList subStrings = productString.split('-'); + if (subStrings.count() < 4) { + qCWarning(dcKeba()) << "Invalid product information format" << subStrings << ". Cannot parse" << productString; + m_isValid = false; + return; + } + + // 1. Manufacturer + // 2. Model + // 3. Desciptor + // 4. Meter infos + // Parse the product string according to Keba Product code definitions - m_model = m_productString.mid(3, 3); + m_manufacturer = subStrings.at(0); + if (m_manufacturer == "KC") { + m_manufacturer = "KeConnect"; + } + qCDebug(dcKeba()) << "Manufacturer:" << m_manufacturer; + m_model = subStrings.at(1); qCDebug(dcKeba()) << "Model:" << m_model; - m_countryCode = m_productString.at(7); + + + QString descriptor = subStrings.at(2); // EC240522 + m_countryCode = descriptor.at(0); // E qCDebug(dcKeba()) << "Country:" << m_countryCode; - QChar connectorValue = m_productString.at(8); + QChar connectorValue = descriptor.at(1); if (connectorValue.toLower() == QChar('s')) { m_connector = ConnectorSocket; qCDebug(dcKeba()) << "Connector: Socket"; @@ -59,7 +86,7 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : return; } - QChar connectorTypeValue = m_productString.at(9); + QChar connectorTypeValue = descriptor.at(2); if (connectorTypeValue.isDigit() && connectorTypeValue == QChar('1')) { m_connectorType = Type1; } else if (connectorTypeValue.isDigit() && connectorTypeValue == QChar('2')) { @@ -73,7 +100,7 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : qCDebug(dcKeba()) << "Connector type:" << m_connectorType; - QChar connectorCurrentValue = m_productString.at(10); + QChar connectorCurrentValue = descriptor.at(3); if (connectorCurrentValue.isDigit() && connectorTypeValue == QChar('1')) { m_current = Current13A; } else if (connectorCurrentValue.isDigit() && connectorTypeValue == QChar('2')) { @@ -89,13 +116,18 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : qCDebug(dcKeba()) << "Current:" << m_current; - QString cableValue = m_productString.mid(11, 2); + // KC-P30-EC24 01 22-E0R + + QString cableValue = descriptor.mid(4, 2)/*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 == "05") { + m_cable = Cable5m; + qCDebug(dcKeba()) << "Cable: 5 meter"; } else if (cableValue == "04") { m_cable = Cable6m; qCDebug(dcKeba()) << "Cable: 6 meter"; @@ -107,7 +139,8 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : return; } - QChar seriesValue = m_productString.at(13); + // KC-P30-EC2401 2 2-E0R + QChar seriesValue = descriptor.at(6); if (seriesValue == QChar('0')) { m_series = SeriesE; qCDebug(dcKeba()) << "Series: E"; @@ -140,7 +173,8 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : return; } - QChar phaseCountValue = m_productString.at(14); + + QChar phaseCountValue = descriptor.at(7); if (phaseCountValue == QChar('1')) { m_phaseCount = 1; } else if (phaseCountValue == QChar('2')) { @@ -152,7 +186,10 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : qCDebug(dcKeba()) << "Phases:" << m_phaseCount; - QChar meterValue = m_productString.at(16); + // Meter infos + QString meterInfos = subStrings.at(3); + + QChar meterValue = meterInfos.at(0); if (meterValue == QChar('0')) { m_meter = NoMeter; qCDebug(dcKeba()) << "Meter: No meter"; @@ -171,7 +208,7 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : } - QChar authValue = m_productString.at(18); + QChar authValue = meterInfos.at(2); if (authValue == QChar('0')) { m_authorization = NoAuthorization; qCDebug(dcKeba()) << "Authorization: No authorization"; @@ -182,8 +219,8 @@ KebaProductInfo::KebaProductInfo(const QString &productString) : m_authorization = Key; qCDebug(dcKeba()) << "Authorization: Key"; } else { - m_isValid = false; - return; + // Note: we don't require this info, so we don't mark it as invalid. + qCDebug(dcKeba()) << "Authorization: Unknown" << authValue; } m_germanEdition = m_productString.toUpper().endsWith("DE"); @@ -200,6 +237,11 @@ QString KebaProductInfo::productString() const return m_productString; } +QString KebaProductInfo::manufacturer() const +{ + return m_manufacturer; +} + QString KebaProductInfo::model() const { return m_model; diff --git a/keba/kebaproductinfo.h b/keba/kebaproductinfo.h index 4363d08a..8c7053f5 100644 --- a/keba/kebaproductinfo.h +++ b/keba/kebaproductinfo.h @@ -63,6 +63,7 @@ public: NoCable = 0, Cable4m = 1, Cable6m = 4, + Cable5m = 5, Cable5p5m = 7 }; Q_ENUM(Cable) @@ -102,7 +103,8 @@ public: QString productString() const; // Porperties in the string - QString model() const; // KC-P30 + QString manufacturer() const; // KC (KeConnect), BMW... + QString model() const; // P30 QString countryCode() const; // E Connector connector() const; // Socket / Cable ConnectorType connectorType() const; // Type 1 / Type 2 @@ -118,6 +120,7 @@ private: bool m_isValid = true; QString m_productString; + QString m_manufacturer; QString m_model; QString m_countryCode; Connector m_connector;