diff --git a/keba/integrationpluginkeba.cpp b/keba/integrationpluginkeba.cpp index d502b14d..fa733892 100644 --- a/keba/integrationpluginkeba.cpp +++ b/keba/integrationpluginkeba.cpp @@ -214,42 +214,43 @@ void DevicePluginKeba::onReportTwoReceived(const KeContact::ReportTwo &reportTwo return; device->setStateValue(wallboxPowerStateTypeId, reportTwo.enableUser); + device->setStateValue(wallboxMaxChargingCurrentPercentStateTypeId, reportTwo.MaxCurrentPercentage); switch (reportTwo.state) { - case KeContact::State::Starting: + case KeContact::StateStarting: device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Starting")); break; - case KeContact::State::NotReady: + case KeContact::StateNotReady: device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Not ready for charging")); break; - case KeContact::State::Ready: + case KeContact::StateReady: device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Ready for charging")); break; - case KeContact::State::Charging: + case KeContact::StateCharging: device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Charging")); break; - case KeContact::State::Error: + case KeContact::StateError: device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Erro")); break; - case KeContact::State::AuthorizationRejected: + case KeContact::StateAuthorizationRejected: device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Authorization rejected")); break; } switch (reportTwo.plugState) { - case KeContact::PlugState::Unplugged: + case KeContact::PlugStateUnplugged: device->setStateValue(wallboxPlugStateStateTypeId, QT_TR_NOOP("Unplugged")); break; - case KeContact::PlugState::PluggedOnChargingStation: + case KeContact::PlugStatePluggedOnChargingStation: device->setStateValue(wallboxPlugStateStateTypeId, QT_TR_NOOP("Plugged in charging station")); break; - case KeContact::PlugState::PluggedOnChargingStationAndPluggedOnEV: + case KeContact::PlugStatePluggedOnChargingStationAndPluggedOnEV: device->setStateValue(wallboxPlugStateStateTypeId, QT_TR_NOOP("Plugged in on EV")); break; - case KeContact::PlugState::PluggedOnChargingStationAndPlugLocked: + case KeContact::PlugStatePluggedOnChargingStationAndPlugLocked: device->setStateValue(wallboxPlugStateStateTypeId, QT_TR_NOOP("Plugged in and locked")); break; - case KeContact::PlugState::PluggedOnChargingStationAndPlugLockedAndPluggedOnEV: + case KeContact::PlugStatePluggedOnChargingStationAndPlugLockedAndPluggedOnEV: device->setStateValue(wallboxPlugStateStateTypeId, QT_TR_NOOP("Plugged in on EV and locked")); break; } @@ -273,17 +274,74 @@ void DevicePluginKeba::onReportThreeReceived(const KeContact::ReportThree &repor device->setStateValue(wallboxTotalEnergyConsumedStateTypeId, reportThree.EnergyTotal); } +void DevicePluginKeba::onBroadcastReceived(KeContact::BroadcastType type, const QVariant &content) +{ + KeContact *keba = static_cast(sender()); + Device *device = myDevices().findById(m_kebaDevices.key(keba)); + if (!device) + return; + + switch (type) { + case KeContact::BroadcastTypePlug: + switch (KeContact::PlugState(content.toInt())) { + case KeContact::PlugStateUnplugged: + device->setStateValue(wallboxPlugStateStateTypeId, QT_TR_NOOP("Unplugged")); + break; + case KeContact::PlugStatePluggedOnChargingStation: + device->setStateValue(wallboxPlugStateStateTypeId, QT_TR_NOOP("Plugged in charging station")); + break; + case KeContact::PlugStatePluggedOnChargingStationAndPluggedOnEV: + device->setStateValue(wallboxPlugStateStateTypeId, QT_TR_NOOP("Plugged in on EV")); + break; + case KeContact::PlugStatePluggedOnChargingStationAndPlugLocked: + device->setStateValue(wallboxPlugStateStateTypeId, QT_TR_NOOP("Plugged in and locked")); + break; + case KeContact::PlugStatePluggedOnChargingStationAndPlugLockedAndPluggedOnEV: + device->setStateValue(wallboxPlugStateStateTypeId, QT_TR_NOOP("Plugged in on EV and locked")); + break; + } + break; + case KeContact::BroadcastTypeInput: + break; + case KeContact::BroadcastTypeEPres: + device->setStateValue(wallboxEPStateTypeId, content.toInt()); + break; + case KeContact::BroadcastTypeState: + switch (KeContact::State(content.toInt())) { + case KeContact::StateStarting: + device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Starting")); + break; + case KeContact::StateNotReady: + device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Not ready for charging")); + break; + case KeContact::StateReady: + device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Ready for charging")); + break; + case KeContact::StateCharging: + device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Charging")); + break; + case KeContact::StateError: + device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Erro")); + break; + case KeContact::StateAuthorizationRejected: + device->setStateValue(wallboxActivityStateTypeId, QT_TR_NOOP("Authorization rejected")); + break; + } + break; + case KeContact::BroadcastTypeMaxCurr: + device->setStateValue(wallboxMaxChargingCurrentStateTypeId, content.toInt()); + break; + case KeContact::BroadcastTypeEnableSys: + break; + } +} + void DevicePluginKeba::executeAction(DeviceActionInfo *info) { Device *device = info->device(); Action action = info->action(); - qCDebug(dcKebaKeContact()) << "Execute action" << device->name() << action.actionTypeId().toString(); - if (device->deviceClassId() == wallboxDeviceClassId) { - - // Print information that we are executing now the update action - qCDebug(dcKebaKeContact()) << "Execute update action" << action.id(); KeContact *keba = m_kebaDevices.value(device->id()); if (!keba) { qCWarning(dcKebaKeContact()) << "Device not properly initialized, Keba object missing"; @@ -291,8 +349,8 @@ void DevicePluginKeba::executeAction(DeviceActionInfo *info) } if(action.actionTypeId() == wallboxMaxChargingCurrentActionTypeId){ - int ampere = action.param(wallboxMaxChargingCurrentActionMaxChargingCurrentParamTypeId).value().toInt()*1000; - QUuid requestId = keba->setMaxAmpere(ampere); + int milliAmpere = action.param(wallboxMaxChargingCurrentActionMaxChargingCurrentParamTypeId).value().toInt(); + QUuid requestId = keba->setMaxAmpere(milliAmpere); m_asyncActions.insert(requestId, info); connect(info, &DeviceActionInfo::aborted, this, [requestId, this]{m_asyncActions.remove(requestId);}); diff --git a/keba/integrationpluginkeba.h b/keba/integrationpluginkeba.h index 2ecf7da8..a6907e6c 100644 --- a/keba/integrationpluginkeba.h +++ b/keba/integrationpluginkeba.h @@ -75,6 +75,7 @@ private slots: void onReportOneReceived(const KeContact::ReportOne &reportOne); void onReportTwoReceived(const KeContact::ReportTwo &reportTwo); void onReportThreeReceived(const KeContact::ReportThree &reportThree); + void onBroadcastReceived(KeContact::BroadcastType type, const QVariant &content); }; #endif // INTEGRATIONPLUGINKEBA_H diff --git a/keba/integrationpluginkeba.json b/keba/integrationpluginkeba.json index 6a5f4d73..8be24382 100644 --- a/keba/integrationpluginkeba.json +++ b/keba/integrationpluginkeba.json @@ -39,7 +39,8 @@ "displayName": "Connected", "displayNameEvent": "Connection changed", "type": "bool", - "defaultValue": false + "defaultValue": false, + "cached": false }, { "id": "83ed0774-2a91-434d-b03c-d920d02f2981", diff --git a/keba/kecontact.cpp b/keba/kecontact.cpp index e7a981ec..f7d369c8 100644 --- a/keba/kecontact.cpp +++ b/keba/kecontact.cpp @@ -45,6 +45,7 @@ KeContact::KeContact(QHostAddress address, QObject *parent) : emit connectionChanged(false); //Try to send the next command handleNextCommandInQueue(); + m_deviceBlocked = false; }); } @@ -88,13 +89,14 @@ void KeContact::sendCommand(const QByteArray &command) emit connectionChanged(false); return; } - if(!m_commandList.isEmpty()) { + if(m_deviceBlocked) { //add command to queue m_commandList.append(command); } else { //send command m_udpSocket->writeDatagram(command, m_address, 7090); m_requestTimeoutTimer->start(5000); + m_deviceBlocked = true; } } @@ -107,7 +109,7 @@ void KeContact::handleNextCommandInQueue() } qCDebug(dcKebaKeContact()) << "Handle Command Queue- Pending commands" << m_commandList.length() << "Pending requestIds" << m_pendingRequests.length(); if (!m_commandList.isEmpty()) { - QByteArray command = m_commandList.first(); + QByteArray command = m_commandList.takeFirst(); m_udpSocket->writeDatagram(command, m_address, 7090); m_requestTimeoutTimer->start(5000); } else { @@ -244,83 +246,119 @@ void KeContact::readPendingDatagrams() qCDebug(dcKebaKeContact()) << "Data received" << datagram; if(datagram.contains("TCH-OK")){ - if (datagram.contains("done")) { - emit commandExecuted(m_pendingRequests.takeFirst(), true); + + //Command response has been received, now send the next command + m_deviceBlocked = false; + m_requestTimeoutTimer->stop(); + handleNextCommandInQueue(); + + if (!m_pendingRequests.isEmpty()) { + QUuid requestId = m_pendingRequests.takeFirst(); + if (datagram.contains("done")) { + emit commandExecuted(requestId, true); + } else { + emit commandExecuted(requestId, false); + } } else { - emit commandExecuted(m_pendingRequests.takeFirst(), false); + //Probably the response has taken too long and the requestId has been already removed } - } + } else if(datagram.left(8).contains("Firmware")){ - //Command response has been received, now send the next command - m_requestTimeoutTimer->stop(); - handleNextCommandInQueue(); + //Command response has been received, now send the next command + m_deviceBlocked = false; + m_requestTimeoutTimer->stop(); + handleNextCommandInQueue(); - if(datagram.left(8).contains("Firmware")){ qCDebug(dcKebaKeContact()) << "Firmware information reveiced"; QByteArrayList firmware = datagram.split(':'); if (firmware.length() >= 2) { emit deviceInformationReceived(firmware[1]); } - } + } else { - // Convert the rawdata to a json document - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(datagram, &error); - if (error.error != QJsonParseError::NoError) { - qCWarning(dcKebaKeContact()) << "Failed to parse JSON data" << datagram << ":" << error.errorString(); - } + //Command response has been received, now send the next command + m_deviceBlocked = false; + m_requestTimeoutTimer->stop(); + handleNextCommandInQueue(); - QVariantMap data = jsonDoc.toVariant().toMap(); + // Convert the rawdata to a json document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(datagram, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcKebaKeContact()) << "Failed to parse JSON data" << datagram << ":" << error.errorString(); + } - if(data.contains("ID")){ + QVariantMap data = jsonDoc.toVariant().toMap(); - if (data.value("ID").toString() == "1") { - ReportOne reportOne; - qCDebug(dcKebaKeContact()) << "Report 1 received"; - reportOne.product = data.value("Product").toString(); - reportOne.firmware = data.value("Firmware").toString(); - reportOne.serialNumber = data.value("Serial").toString();; - emit reportOneReceived(reportOne); + if(data.contains("ID")) { - } else if(data.value("ID").toString() == "2"){ + if (data.value("ID").toString() == "1") { + ReportOne reportOne; + qCDebug(dcKebaKeContact()) << "Report 1 received"; + reportOne.product = data.value("Product").toString(); + reportOne.firmware = data.value("Firmware").toString(); + reportOne.serialNumber = data.value("Serial").toString();; + emit reportOneReceived(reportOne); - ReportTwo reportTwo; - qCDebug(dcKebaKeContact()) << "Report 2 reveiced"; - int state = data.value("State").toInt(); - reportTwo.state = State(state); - reportTwo.error1 = data.value("Error1").toInt(); - reportTwo.error2 = data.value("Error2").toInt(); - reportTwo.plugState = PlugState(data.value("Plug").toInt()); - reportTwo.enableUser = data.value("Enable user").toBool(); - reportTwo.enableSys = data.value("Enable sys").toBool(); - reportTwo.MaxCurrent = data.value("Max curr").toInt()/1000; - reportTwo.MaxCurrentPercentage = data.value("Max curr %").toInt()/10; - reportTwo.CurrentHardwareLimitation = data.value("Curr HW").toInt()/1000; - reportTwo.CurrentUser = data.value("Curr user").toInt(); - reportTwo.CurrFS = data.value("Curr FS").toInt(); - reportTwo.TmoFS = data.value("Tmo FS").toInt(); - reportTwo.output = data.value("Output").toInt(); - reportTwo.input= data.value("Input").toInt(); - reportTwo.serialNumber = data.value("Serial").toString(); - reportTwo.seconds = data.value("Sec").toInt(); - emit reportTwoReceived(reportTwo); + } else if(data.value("ID").toString() == "2"){ - } else if(data.value("ID").toString() == "3"){ + ReportTwo reportTwo; + qCDebug(dcKebaKeContact()) << "Report 2 reveiced"; + int state = data.value("State").toInt(); + reportTwo.state = State(state); + reportTwo.error1 = data.value("Error1").toInt(); + reportTwo.error2 = data.value("Error2").toInt(); + reportTwo.plugState = PlugState(data.value("Plug").toInt()); + reportTwo.enableUser = data.value("Enable user").toBool(); + reportTwo.enableSys = data.value("Enable sys").toBool(); + reportTwo.MaxCurrent = data.value("Max curr").toInt()/1000; + reportTwo.MaxCurrentPercentage = data.value("Max curr %").toInt()/10; + reportTwo.CurrentHardwareLimitation = data.value("Curr HW").toInt()/1000; + reportTwo.CurrentUser = data.value("Curr user").toInt(); + reportTwo.CurrFS = data.value("Curr FS").toInt(); + reportTwo.TmoFS = data.value("Tmo FS").toInt(); + reportTwo.output = data.value("Output").toInt(); + reportTwo.input= data.value("Input").toInt(); + reportTwo.serialNumber = data.value("Serial").toString(); + reportTwo.seconds = data.value("Sec").toInt(); + emit reportTwoReceived(reportTwo); - ReportThree reportThree; - qCDebug(dcKebaKeContact()) << "Report 3 reveiced"; - reportThree.CurrentPhase1 = data.value("I1").toInt(); - reportThree.CurrentPhase2 = data.value("I2").toInt(); - reportThree.CurrentPhase3 = data.value("I3").toInt(); - reportThree.VoltagePhase1 = data.value("U1").toInt(); - reportThree.VoltagePhase2 = data.value("U2").toInt(); - reportThree.VoltagePhase3 = data.value("U3").toInt(); - reportThree.Power = data.value("P").toInt(); - reportThree.PowerFactor = data.value("PF").toInt()/10; - reportThree.EnergySession = data.value("E pres").toInt()/10000.00; - reportThree.EnergyTotal = data.value("E total").toInt()/10000.00; - reportThree.SerialNumber = data.value("Serial").toString(); - emit reportThreeReceived(reportThree); + } else if(data.value("ID").toString() == "3"){ + + ReportThree reportThree; + qCDebug(dcKebaKeContact()) << "Report 3 reveiced"; + reportThree.CurrentPhase1 = data.value("I1").toInt(); + reportThree.CurrentPhase2 = data.value("I2").toInt(); + reportThree.CurrentPhase3 = data.value("I3").toInt(); + reportThree.VoltagePhase1 = data.value("U1").toInt(); + reportThree.VoltagePhase2 = data.value("U2").toInt(); + reportThree.VoltagePhase3 = data.value("U3").toInt(); + reportThree.Power = data.value("P").toInt(); + reportThree.PowerFactor = data.value("PF").toInt()/10; + reportThree.EnergySession = data.value("E pres").toInt()/10000.00; + reportThree.EnergyTotal = data.value("E total").toInt()/10000.00; + reportThree.SerialNumber = data.value("Serial").toString(); + emit reportThreeReceived(reportThree); + } + } else { + if (data.contains("State")) { + emit broadcastReceived(BroadcastType::BroadcastTypeState, data.value("State")); + } + if (data.contains("Plug")) { + emit broadcastReceived(BroadcastType::BroadcastTypePlug, data.value("Plug")); + } + if (data.contains("Input")) { + emit broadcastReceived(BroadcastType::BroadcastTypeInput, data.value("Input")); + } + if (data.contains("Enable sys")) { + emit broadcastReceived(BroadcastType::BroadcastTypeEnableSys, data.value("Enable sys")); + } + if (data.contains("Max curr")) { + emit broadcastReceived(BroadcastType::BroadcastTypeMaxCurr, data.value("Max curr")); + } + if (data.contains("E pres")) { + emit broadcastReceived(BroadcastType::BroadcastTypeEPres, data.value("E pres")); + } } } } diff --git a/keba/kecontact.h b/keba/kecontact.h index 8455619a..06e1da02 100644 --- a/keba/kecontact.h +++ b/keba/kecontact.h @@ -47,20 +47,29 @@ public: bool init(); enum State { - Starting = 0, - NotReady, - Ready, - Charging, - Error, - AuthorizationRejected + StateStarting = 0, + StateNotReady, + StateReady, + StateCharging, + StateError, + StateAuthorizationRejected }; enum PlugState { - Unplugged = 0, - PluggedOnChargingStation = 1, - PluggedOnChargingStationAndPlugLocked = 3, - PluggedOnChargingStationAndPluggedOnEV = 5, - PluggedOnChargingStationAndPlugLockedAndPluggedOnEV = 7 + PlugStateUnplugged = 0, + PlugStatePluggedOnChargingStation = 1, + PlugStatePluggedOnChargingStationAndPlugLocked = 3, + PlugStatePluggedOnChargingStationAndPluggedOnEV = 5, + PlugStatePluggedOnChargingStationAndPlugLockedAndPluggedOnEV = 7 + }; + + enum BroadcastType { + BroadcastTypeState = 0, + BroadcastTypePlug, + BroadcastTypeInput, + BroadcastTypeEnableSys, + BroadcastTypeMaxCurr, + BroadcastTypeEPres }; struct ReportOne { @@ -139,6 +148,7 @@ signals: void reportOneReceived(const ReportOne &reportOne); void reportTwoReceived(const ReportTwo &reportTwo); void reportThreeReceived(const ReportThree &reportThree); + void broadcastReceived(BroadcastType type, const QVariant &content); private slots: void readPendingDatagrams();