improved async action handling

This commit is contained in:
Boernsman 2020-02-18 18:56:18 +05:00 committed by bernhard.trinnes
parent 4b0b83d941
commit 1cbbeb2045
5 changed files with 200 additions and 92 deletions

View File

@ -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<KeContact *>(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);});

View File

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

View File

@ -39,7 +39,8 @@
"displayName": "Connected",
"displayNameEvent": "Connection changed",
"type": "bool",
"defaultValue": false
"defaultValue": false,
"cached": false
},
{
"id": "83ed0774-2a91-434d-b03c-d920d02f2981",

View File

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

View File

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