added session finished event

This commit is contained in:
Boernsman 2021-01-13 14:32:41 +01:00
parent 0803221e68
commit 5b38c6c9bc
5 changed files with 209 additions and 71 deletions

View File

@ -44,27 +44,27 @@ IntegrationPluginKeba::IntegrationPluginKeba()
void IntegrationPluginKeba::init()
{
m_discovery = new Discovery(this);
connect(m_discovery, &Discovery::finished, this, [this](const QList<Host> &hosts) {
m_discovery = new Discovery(this);
connect(m_discovery, &Discovery::finished, this, [this](const QList<Host> &hosts) {
foreach (const Host &host, hosts) {
if (!host.hostName().contains("keba", Qt::CaseSensitivity::CaseInsensitive))
continue;
foreach (const Host &host, hosts) {
if (!host.hostName().contains("keba", Qt::CaseSensitivity::CaseInsensitive))
continue;
foreach (Thing *existingThing, myThings()) {
if (existingThing->paramValue(wallboxThingMacAddressParamTypeId).toString() == host.macAddress()) {
if (existingThing->paramValue(wallboxThingIpAddressParamTypeId).toString() != host.address()) {
qCDebug(dcKebaKeContact()) << "Keba Wallbox IP Address has changed, from" << existingThing->paramValue(wallboxThingIpAddressParamTypeId).toString() << "to" << host.address();
existingThing->setParamValue(wallboxThingIpAddressParamTypeId, host.address());
foreach (Thing *existingThing, myThings()) {
if (existingThing->paramValue(wallboxThingMacAddressParamTypeId).toString() == host.macAddress()) {
if (existingThing->paramValue(wallboxThingIpAddressParamTypeId).toString() != host.address()) {
qCDebug(dcKebaKeContact()) << "Keba Wallbox IP Address has changed, from" << existingThing->paramValue(wallboxThingIpAddressParamTypeId).toString() << "to" << host.address();
existingThing->setParamValue(wallboxThingIpAddressParamTypeId, host.address());
} else {
qCDebug(dcKebaKeContact()) << "Keba Wallbox" << existingThing->name() << "IP address has not changed" << host.address();
}
break;
}
}
}
});
} else {
qCDebug(dcKebaKeContact()) << "Keba Wallbox" << existingThing->name() << "IP address has not changed" << host.address();
}
break;
}
}
}
});
}
void IntegrationPluginKeba::discoverThings(ThingDiscoveryInfo *info)
@ -113,9 +113,9 @@ void IntegrationPluginKeba::setupThing(ThingSetupInfo *info)
KeContact *keba = new KeContact(address, this);
connect(keba, &KeContact::reachableChanged, this, &IntegrationPluginKeba::onConnectionChanged);
connect(keba, &KeContact::commandExecuted, this, &IntegrationPluginKeba::onCommandExecuted);
connect(keba, &KeContact::reportOneReceived, this, &IntegrationPluginKeba::onReportOneReceived);
connect(keba, &KeContact::reportTwoReceived, this, &IntegrationPluginKeba::onReportTwoReceived);
connect(keba, &KeContact::reportThreeReceived, this, &IntegrationPluginKeba::onReportThreeReceived);
connect(keba, &KeContact::report1XXReceived, this, &IntegrationPluginKeba::onReport1XXReceived);
connect(keba, &KeContact::broadcastReceived, this, &IntegrationPluginKeba::onBroadcastReceived);
if (!keba->init()){
qCWarning(dcKebaKeContact()) << "Cannot bind to port" << 7090;
@ -316,12 +316,7 @@ void IntegrationPluginKeba::onReportTwoReceived(const KeContact::ReportTwo &repo
if (!thing)
return;
thing->setStateValue()
thing->setStateValue(wallboxPowerStateTypeId, reportTwo.enableUser);
thing->setStateValue(wallboxError1StateTypeId, reportTwo.error1);
thing->setStateValue(wallboxError2StateTypeId, reportTwo.error2);
qCDebug(dcKebaKeContact()) << "Report 2 recieved for" << thing->name();
qCDebug(dcKebaKeContact()) << "Report 2 received for" << thing->name() << "Serial number:" << thing->stateValue(wallboxSerialnumberStateTypeId).toString();
qCDebug(dcKebaKeContact()) << " - State:" << reportTwo.state;
qCDebug(dcKebaKeContact()) << " - Error 1:" << reportTwo.error1;
qCDebug(dcKebaKeContact()) << " - Error 2:" << reportTwo.error2;
@ -338,17 +333,27 @@ void IntegrationPluginKeba::onReportTwoReceived(const KeContact::ReportTwo &repo
qCDebug(dcKebaKeContact()) << " - Timeout CT:" << reportTwo.timeoutCt;
qCDebug(dcKebaKeContact()) << " - Output:" << reportTwo.output;
qCDebug(dcKebaKeContact()) << " - Input:" << reportTwo.input;
qCDebug(dcKebaKeContact()) << " - Serialnumber:" << reportTwo.serialNumber;
qCDebug(dcKebaKeContact()) << " - Serial number:" << reportTwo.serialNumber;
qCDebug(dcKebaKeContact()) << " - Uptime:" << reportTwo.seconds;
if (reportTwo.serialNumber == thing->stateValue(wallboxSerialnumberStateTypeId).toString()) {
setDeviceState(thing, reportTwo.state);
setDevicePlugState(thing, reportTwo.plugState);
//thing->setStateValue(wallboxMaxChargingCurrentAmpereStateTypeId, reportTwo.maxCurrent);
thing->setStateValue(wallboxMaxChargingCurrentPercentStateTypeId, reportTwo.maxCurrentPercentage);
//thing->setStateValue(wallboxCurrentHardwareLimitationStateTypeId, reportTwo.currentHardwareLimitation);
thing->setStateValue(wallboxPowerStateTypeId, reportTwo.enableUser);
thing->setStateValue(wallboxError1StateTypeId, reportTwo.error1);
thing->setStateValue(wallboxError2StateTypeId, reportTwo.error2);
//thing->setStateValue(wallboxMaxChargingCurrentAmpereStateTypeId, reportTwo.maxCurrent);
thing->setStateValue(wallboxMaxChargingCurrentPercentStateTypeId, reportTwo.maxCurrentPercentage);
//thing->setStateValue(wallboxCurrentHardwareLimitationStateTypeId, reportTwo.currentHardwareLimitation);
thing->setStateValue(wallboxOutputX2StateTypeId, reportTwo.output);
thing->setStateValue(wallboxInputStateTypeId, reportTwo.input);
setDeviceState(thing, reportTwo.state);
setDevicePlugState(thing, reportTwo.plugState);
thing->setStateValue(wallboxUptimeStateTypeId, reportTwo.seconds);
} else {
qCWarning(dcKebaKeContact()) << "Received report but the serial number didn't match";
}
}
void IntegrationPluginKeba::onReportThreeReceived(const KeContact::ReportThree &reportThree)
@ -358,16 +363,77 @@ void IntegrationPluginKeba::onReportThreeReceived(const KeContact::ReportThree &
if (!thing)
return;
thing->setStateValue(wallboxCurrentPhase1EventTypeId, reportThree.CurrentPhase1);
thing->setStateValue(wallboxCurrentPhase2EventTypeId, reportThree.CurrentPhase2);
thing->setStateValue(wallboxCurrentPhase3EventTypeId, reportThree.CurrentPhase3);
thing->setStateValue(wallboxVoltagePhase1EventTypeId, reportThree.VoltagePhase1);
thing->setStateValue(wallboxVoltagePhase2EventTypeId, reportThree.VoltagePhase2);
thing->setStateValue(wallboxVoltagePhase3EventTypeId, reportThree.VoltagePhase3);
thing->setStateValue(wallboxPowerConsumptionStateTypeId, reportThree.Power);
thing->setStateValue(wallboxSessionEnergyStateTypeId, reportThree.EnergySession); //TODO check state name
thing->setStateValue(wallboxPowerFactorStateTypeId, reportThree.PowerFactor);
thing->setStateValue(wallboxTotalEnergyConsumedStateTypeId, reportThree.EnergyTotal);
qCDebug(dcKebaKeContact()) << "Report 3 received for" << thing->name() << "Serial number:" << thing->stateValue(wallboxSerialnumberStateTypeId).toString();
qCDebug(dcKebaKeContact()) << " - Current phase 1:" << reportThree.currentPhase1 << "[mA]";
qCDebug(dcKebaKeContact()) << " - Current phase 2:" << reportThree.currentPhase2 << "[mA]";
qCDebug(dcKebaKeContact()) << " - Current phase 3:" << reportThree.currentPhase3 << "[mA]";
qCDebug(dcKebaKeContact()) << " - Voltage phase 1:" << reportThree.voltagePhase1 << "[V]";
qCDebug(dcKebaKeContact()) << " - Voltage phase 2:" << reportThree.voltagePhase2 << "[V]";
qCDebug(dcKebaKeContact()) << " - Voltage phase 3:" << reportThree.voltagePhase3 << "[V]";
qCDebug(dcKebaKeContact()) << " - Power consumption:" << reportThree.power << "[W]";
qCDebug(dcKebaKeContact()) << " - Energy session" << reportThree.energySession << "[Wh]";
qCDebug(dcKebaKeContact()) << " - Energy total" << reportThree.energyTotal << "[Wh]";
qCDebug(dcKebaKeContact()) << " - Serial number" << reportThree.serialNumber;
qCDebug(dcKebaKeContact()) << " - Uptime" << reportThree.seconds;
if (reportThree.serialNumber == thing->stateValue(wallboxSerialnumberStateTypeId).toString()) {
thing->setStateValue(wallboxCurrentPhase1EventTypeId, reportThree.currentPhase1);
thing->setStateValue(wallboxCurrentPhase2EventTypeId, reportThree.currentPhase2);
thing->setStateValue(wallboxCurrentPhase3EventTypeId, reportThree.currentPhase3);
thing->setStateValue(wallboxVoltagePhase1EventTypeId, reportThree.voltagePhase1);
thing->setStateValue(wallboxVoltagePhase2EventTypeId, reportThree.voltagePhase2);
thing->setStateValue(wallboxVoltagePhase3EventTypeId, reportThree.voltagePhase3);
thing->setStateValue(wallboxPowerConsumptionStateTypeId, reportThree.power);
thing->setStateValue(wallboxSessionEnergyStateTypeId, reportThree.energySession);
thing->setStateValue(wallboxPowerFactorStateTypeId, reportThree.powerFactor);
thing->setStateValue(wallboxTotalEnergyConsumedStateTypeId, reportThree.energyTotal);
} else {
qCWarning(dcKebaKeContact()) << "Received report but the serial number didn't match";
}
}
void IntegrationPluginKeba::onReport1XXReceived(int reportNumber, const KeContact::Report1XX &report)
{
KeContact *keba = static_cast<KeContact *>(sender());
Thing *thing = myThings().findById(m_kebaDevices.key(keba));
if (!thing)
return;
qCDebug(dcKebaKeContact()) << "Report" << reportNumber << "received for" << thing->name() << "Serial number:" << thing->stateValue(wallboxSerialnumberStateTypeId).toString();
qCDebug(dcKebaKeContact()) << " - Session Id" << report.sessionId;
qCDebug(dcKebaKeContact()) << " - Curr HW" << report.currHW;
qCDebug(dcKebaKeContact()) << " - Energy start" << report.startEnergy;
qCDebug(dcKebaKeContact()) << " - Energy present" << report.ePres;
qCDebug(dcKebaKeContact()) << " - Start time" << report.startTime;
qCDebug(dcKebaKeContact()) << " - End time" << report.endTime;
qCDebug(dcKebaKeContact()) << " - Stop reason" << report.stopReason;
qCDebug(dcKebaKeContact()) << " - RFID Tag" << report.rfidTag;
qCDebug(dcKebaKeContact()) << " - RFID Class" << report.rfidClass;
qCDebug(dcKebaKeContact()) << " - Serial number" << report.serialNumber;
qCDebug(dcKebaKeContact()) << " - Uptime" << report.seconds;
// Report 101 is the lastest finished session
if (reportNumber == 101) {
if (report.serialNumber == thing->stateValue(wallboxSerialnumberStateTypeId).toString()) {
if (!m_lastSessionId.contains(thing->id())) {
m_lastSessionId.insert(thing->id(), report.sessionId);
} else {
if (m_lastSessionId.value(thing->id()) != report.sessionId) {
qCDebug(dcKebaKeContact()) << "New session id receivd";
Event event;
event.setThingId(thing->id());
ParamList params;
//params << Param(wallboxSessio);
event.setParams(params);
emitEvent(event);
}
}
} else {
qCWarning(dcKebaKeContact()) << "Received report but the serial number didn't match";
}
} else {
qCWarning(dcKebaKeContact()) << "Received unhandled report" << reportNumber;
}
}
void IntegrationPluginKeba::onBroadcastReceived(KeContact::BroadcastType type, const QVariant &content)

View File

@ -67,6 +67,8 @@ private:
Discovery *m_discovery = nullptr;
QHash<ThingId, KeContact *> m_kebaDevices;
QHash<ThingId, int> m_lastSessionId;
QHash<KeContact *, ThingSetupInfo *> m_asyncSetup;
QHash<QUuid, ThingActionInfo *> m_asyncActions;
QHash<ThingId, QDateTime> m_chargingSessionStartTime;
@ -77,9 +79,9 @@ private:
private slots:
void onConnectionChanged(bool status);
void onCommandExecuted(QUuid requestId, bool success);
void onReportOneReceived(const KeContact::ReportOne &reportOne);
void onReportTwoReceived(const KeContact::ReportTwo &reportTwo);
void onReportThreeReceived(const KeContact::ReportThree &reportThree);
void onReport1XXReceived(int reportNumber, const KeContact::Report1XX &report);
void onBroadcastReceived(KeContact::BroadcastType type, const QVariant &content);
};

View File

@ -298,6 +298,38 @@
}
]
}
],
"eventTypes": [
{
"id": "dac02c37-f051-481a-ae99-1de0885ef37a",
"name": "chargingSessionFinished",
"displayName": "Charging session finished",
"paramTypes": [
{
"id": "33446eae-f2cc-4cf2-af29-b3a45e4b91c0",
"name": "id",
"displayName": "ID",
"type": "int",
"defaultValue": "0"
},
{
"id": "60494d6f-853b-42b8-894e-108a52ed6feb",
"name": "duration",
"displayName": "Duration",
"type": "int",
"unit": "Seconds",
"defaultValue": 0
},
{
"id": "c8de58b6-b671-4fee-b552-d2c14a37a769",
"name": "energy",
"displayName": "Energy",
"type": "double",
"defaultValue": 0.00,
"unit": "KiloWattHour"
}
]
}
]
}
]

View File

@ -92,7 +92,7 @@ QUuid KeContact::stop(const QByteArray &rfidToken)
return requestId;
}
void KeContact::setAddress(QHostAddress address)
void KeContact::setAddress(const QHostAddress &address)
{
m_address = address;
}
@ -339,19 +339,29 @@ void KeContact::readPendingDatagrams()
QVariantMap data = jsonDoc.toVariant().toMap();
if(data.contains("ID")) {
if (data.value("ID").toString() == "1") {
int id = data.value("ID").toInt();
if (id == 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();;
reportOne.serialNumber = data.value("Serial").toString();
if (data.contains("COM-module")) {
reportOne.comModule = (data.value("COM-module").toInt() == 1);
} else {
reportOne.comModule = false;
}
if (data.contains("Sec")) {
reportOne.comModule = data.value("Sec").toInt();
} else {
reportOne.comModule = 0;
}
emit reportOneReceived(reportOne);
} else if(data.value("ID").toString() == "2"){
} else if (id == 2) {
ReportTwo reportTwo;
qCDebug(dcKebaKeContact()) << "Report 2 reveiced";
qCDebug(dcKebaKeContact()) << "Report 2 received";
int state = data.value("State").toInt();
reportTwo.state = State(state);
reportTwo.error1 = data.value("Error1").toInt();
@ -371,22 +381,33 @@ void KeContact::readPendingDatagrams()
reportTwo.seconds = data.value("Sec").toInt();
emit reportTwoReceived(reportTwo);
} else if(data.value("ID").toString() == "3"){
} else if (id == 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();
reportThree.currentPhase1 = data.value("I1").toInt()/1000.00;
reportThree.currentPhase2 = data.value("I2").toInt()/1000.00;
reportThree.currentPhase3 = data.value("I3").toInt()/1000.00;
reportThree.voltagePhase1 = data.value("U1").toInt();
reportThree.voltagePhase2 = data.value("U2").toInt();
reportThree.voltagePhase3 = data.value("U3").toInt();
reportThree.power = data.value("P").toInt()/1000.00;
reportThree.powerFactor = data.value("PF").toInt()/10.00;
reportThree.energySession = data.value("E pres").toInt()/10000.00;
reportThree.energyTotal = data.value("E total").toInt()/10000.00;
reportThree.serialNumber = data.value("Serial").toString();
reportThree.seconds = data.value("Sec").toInt();
emit reportThreeReceived(reportThree);
} else if (id >= 100) {
Report1XX report;
report.sessionId = data.value("Session ID").toInt();
report.currHW = data.value("Curr HW").toInt();
//report. = data.value("Curr HW").toInt(); TODO
report.currHW = data.value("Curr HW").toInt();
report.currHW = data.value("Curr HW").toInt();
report.currHW = data.value("Curr HW").toInt();
report.currHW = data.value("Curr HW").toInt();
emit report1XXReceived(id, report);
}
} else {
if (data.contains("State")) {

View File

@ -113,17 +113,32 @@ public:
};
struct ReportThree {
int VoltagePhase1; //voltage in V
int VoltagePhase2; //voltage in V
int VoltagePhase3; //voltage in V
int CurrentPhase1; //current in mA
int CurrentPhase2; //current in mA
int CurrentPhase3; //current in mA
int Power; //Current power in mW (Real Power).
int PowerFactor; //Power factor in 0,1% (cosphi)
int EnergySession; //Power consumption of the current loading session in 0,1Wh; Reset with new loading session (state = 2).
int EnergyTotal; //Total power consumption (persistent) without current loading session 0,1Wh; Is summed up after each completed charging session (state = 0).
QString SerialNumber;
int voltagePhase1; //voltage in V
int voltagePhase2; //voltage in V
int voltagePhase3; //voltage in V
double currentPhase1; //current in A
double currentPhase2; //current in A
double currentPhase3; //current in A
double power; //Current power in W (Real Power).
double powerFactor; //Power factor in 0,1% (cosphi)
double energySession; //Power consumption of the current loading session in 0,1Wh; Reset with new loading session (state = 2).
double energyTotal; //Total power consumption (persistent) without current loading session 0,1Wh; Is summed up after each completed charging session (state = 0).
QString serialNumber;
int seconds; //Current system clock since restart of the charging station.
};
struct Report1XX {
int sessionId; // running session counter; not resettable"
int currHW; // maximum charging current of the cable and the charging station setting (equal to report 2)"E
double startEnergy; // total energy value at the beginning of the session"
double ePres; // delivered energy until now (equal to E pres in report 3)"
int startTime; // system time when the session was started (seconds from reboot; NTP implementation is still under progress)"
int endTime; // system time when the session has ended"
int stopReason; // reason for stopping the session (1 = vehicle unplug; 10 = Rfid token)"
QByteArray rfidTag; // RFID Token ID if session started with rfid; hexadecimal; first character is the lowest nibble"
QByteArray rfidClass; // RFID classifier shows the defined color code if the used card is a BMW card (for example “010104” means the white card)"
QString serialNumber; // serial number of the charging station"
int seconds; // current time when the report was generated
};
QHostAddress address();
@ -145,6 +160,7 @@ public:
void getReport1(); // Command “report”
void getReport2();
void getReport3();
void getReport1XX(int reportNumber = 100);
// Command “report 1xx”
@ -176,6 +192,7 @@ signals:
void reportOneReceived(const ReportOne &reportOne);
void reportTwoReceived(const ReportTwo &reportTwo);
void reportThreeReceived(const ReportThree &reportThree);
void report1XXReceived(int reportNumber, const Report1XX &report);
void broadcastReceived(BroadcastType type, const QVariant &content);
private slots: