diff --git a/webasto/integrationpluginwebasto.cpp b/webasto/integrationpluginwebasto.cpp index e8029b1..79a1d83 100644 --- a/webasto/integrationpluginwebasto.cpp +++ b/webasto/integrationpluginwebasto.cpp @@ -125,9 +125,15 @@ void IntegrationPluginWebasto::setupThing(ThingSetupInfo *info) Webasto *webasto = new Webasto(address, 502, thing); m_webastoConnections.insert(thing, webasto); connect(webasto, &Webasto::destroyed, this, [thing, this] {m_webastoConnections.remove(thing);}); - //TODO signal socket - //TODO emit setup finished - connect(webasto, &Webasto::connectionChanged, info, [info] (bool connected) { + connect(webasto, &Webasto::connectionStateChanged, this, &IntegrationPluginWebasto::onConnectionChanged); + connect(webasto, &Webasto::receivedRegister, this, &IntegrationPluginWebasto::onReceivedRegister); + connect(webasto, &Webasto::writeRequestError, this, &IntegrationPluginWebasto::onWriteRequestError); + connect(webasto, &Webasto::writeRequestExecuted, this, &IntegrationPluginWebasto::onWriteRequestExecuted); + if (!webasto->connectDevice()) { + qCWarning(dcWebasto()) << "Could not connect to device"; + info->finish(Thing::ThingErrorSetupFailed); + } + connect(webasto, &Webasto::connectionStateChanged, info, [info] (bool connected) { if (connected) info->finish(Thing::ThingErrorNoError); }); @@ -139,6 +145,14 @@ void IntegrationPluginWebasto::setupThing(ThingSetupInfo *info) void IntegrationPluginWebasto::postSetupThing(Thing *thing) { qCDebug(dcWebasto()) << "Post setup thing" << thing->name(); + if (!m_pluginTimer) { + m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(1); + connect(m_pluginTimer, &PluginTimer::timeout, this, [this] { + Q_FOREACH(Webasto *connection, m_webastoConnections) { + update(connection); + } + }); + } if (thing->thingClassId() == liveWallboxThingClassId) { Webasto *connection = m_webastoConnections.value(thing); @@ -165,9 +179,27 @@ void IntegrationPluginWebasto::executeAction(ThingActionInfo *info) } if (action.actionTypeId() == liveWallboxPowerActionTypeId) { - // Enable/Disable the charging process + bool enabled = action.paramValue(liveWallboxPowerActionPowerParamTypeId).toBool(); + thing->setStateValue(liveWallboxPowerActionTypeId, enabled); + int ampere = 0; + if (enabled) { + ampere = thing->stateValue(liveWallboxChargeCurrentStateTypeId).toInt(); + } + QUuid requestId = connection->setChargeCurrent(ampere); + if (requestId.isNull()) { + info->finish(Thing::ThingErrorHardwareFailure); + } else { + m_asyncActions.insert(requestId, info); + } } else if (action.actionTypeId() == liveWallboxChargeCurrentActionTypeId) { - + int ampere = action.paramValue(liveWallboxChargeCurrentActionChargeCurrentParamTypeId).toInt(); + thing->setStateValue(liveWallboxChargeCurrentStateTypeId, ampere); + QUuid requestId = connection->setChargeCurrent(ampere); + if (requestId.isNull()) { + info->finish(Thing::ThingErrorHardwareFailure); + } else { + m_asyncActions.insert(requestId, info); + } } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); } @@ -187,6 +219,27 @@ void IntegrationPluginWebasto::thingRemoved(Thing *thing) } } +void IntegrationPluginWebasto::update(Webasto *webasto) +{ + webasto->getRegister(Webasto::TqChargePointState); + webasto->getRegister(Webasto::TqCableState); + webasto->getRegister(Webasto::TqEVSEError); + + webasto->getRegister(Webasto::TqCurrentL1); + webasto->getRegister(Webasto::TqCurrentL2); + webasto->getRegister(Webasto::TqCurrentL3); + + webasto->getRegister(Webasto::TqActivePower, 2); + webasto->getRegister(Webasto::TqEnergyMeter, 2); + + webasto->getRegister(Webasto::TqMaxCurrent); + + webasto->getRegister(Webasto::TqChargedEnergy); + webasto->getRegister(Webasto::TqChargingTime, 2); + + webasto->getRegister(Webasto::TqUserId, 10); +} + void IntegrationPluginWebasto::onConnectionChanged(bool connected) { Webasto *connection = static_cast(sender()); @@ -198,3 +251,191 @@ void IntegrationPluginWebasto::onConnectionChanged(bool connected) thing->setStateValue(liveWallboxConnectedStateTypeId, connected); } +void IntegrationPluginWebasto::onWriteRequestExecuted(const QUuid &requestId, bool success) +{ + if (m_asyncActions.contains(requestId)) { + ThingActionInfo *info = m_asyncActions.take(requestId); + if (success) { + info->finish(Thing::ThingErrorNoError); + } else { + info->finish(Thing::ThingErrorHardwareFailure); + } + } +} + +void IntegrationPluginWebasto::onWriteRequestError(const QUuid &requestId, const QString &error) +{ + Q_UNUSED(requestId); + qCWarning(dcWebasto()) << "Write request error" << error; +} + +void IntegrationPluginWebasto::onReceivedRegister(Webasto::TqModbusRegister modbusRegister, const QVector &data) +{ + Webasto *connection = static_cast(sender()); + Thing *thing = m_webastoConnections.key(connection); + if (!thing) { + qCWarning(dcWebasto()) << "On basic information received, thing not found for connection"; + return; + } + if (thing->thingClassId() == liveWallboxThingClassId) { + switch (modbusRegister) { + case Webasto::TqChargePointState: + qCDebug(dcWebasto()) << " - Charge point state:" << Webasto::ChargePointState(data[0]); + switch (Webasto::ChargePointState(data[0])) { + case Webasto::ChargePointStateNoVehicleAttached: + thing->setStateValue(liveWallboxChargePointStateStateTypeId, "No vehicle attached"); + break; + case Webasto::ChargePointStateVehicleAttachedNoPermission: + thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Vehicle attached, no permission"); + break; + case Webasto::ChargePointStateChargingAuthorized: + thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging authorized"); + break; + case Webasto::ChargePointStateCharging: + thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging"); + break; + case Webasto::ChargePointStateChargingPaused: + thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging paused"); + break; + case Webasto::ChargePointStateChargeSuccessfulCarStillAttached: + thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charge successful (car still attached)"); + break; + case Webasto::ChargePointStateChargingStoppedByUserCarStillAttached: + thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging stopped by user (car still attached)"); + break; + case Webasto::ChargePointStateChargingErrorCarStillAttached: + thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging error (car still attached)"); + break; + case Webasto::ChargePointStateChargingStationReservedNorCarAttached: + thing->setStateValue(liveWallboxChargePointStateStateTypeId, "Charging station reserved (No car attached)"); + break; + case Webasto::ChargePointStateUserNotAuthorizedCarAttached: + thing->setStateValue(liveWallboxChargePointStateStateTypeId, "User not authorized (car attached)"); + break; + } + break; + case Webasto::TqChargeState: + qCDebug(dcWebasto()) << " - Charge state:" << data[0]; + break; + case Webasto::TqEVSEState: + qCDebug(dcWebasto()) << " - EVSE state:" << data[0]; + break; + case Webasto::TqCableState: + qCDebug(dcWebasto()) << " - Cable state:" << Webasto::CableState(data[0]); + switch (Webasto::CableState(data[0])) { + case Webasto::CableStateNoCableAttached: + thing->setStateValue(liveWallboxCableStateStateTypeId, "No cable attached"); + break; + case Webasto::CableStateCableAttachedNoCarAttached: + thing->setStateValue(liveWallboxCableStateStateTypeId, "Cable attached but no car attached)"); + break; + case Webasto::CableStateCableAttachedCarAttached: + thing->setStateValue(liveWallboxCableStateStateTypeId, "Cable attached and car attached"); + break; + case Webasto::CableStateCableAttachedCarAttachedLockActive: + thing->setStateValue(liveWallboxCableStateStateTypeId, "Cable attached, car attached and lock active"); + break; + } + break; + case Webasto::TqEVSEError: + qCDebug(dcWebasto()) << " - EVSE error:" << data[0]; + thing->setStateValue(liveWallboxErrorStateTypeId, data[0]); + break; + case Webasto::TqCurrentL1: + qCDebug(dcWebasto()) << " - Current L1:" << data[0]; + thing->setStateValue(liveWallboxCurrentPhase1StateTypeId, data[0]); + break; + case Webasto::TqCurrentL2: + qCDebug(dcWebasto()) << " - Current L2:" << data[0]; + thing->setStateValue(liveWallboxCurrentPhase2StateTypeId, data[0]); + break; + case Webasto::TqCurrentL3: + qCDebug(dcWebasto()) << " - Current L3:" << data[0]; + thing->setStateValue(liveWallboxCurrentPhase3StateTypeId, data[0]); + break; + case Webasto::TqActivePower: { + int power = (static_cast(data[0])<<16 | data[1]); + qCDebug(dcWebasto()) << " - Active power:" << power; + thing->setStateValue(liveWallboxPowerConsumptionStateTypeId, power); + } break; + case Webasto::TqEnergyMeter: { + int energy = (static_cast(data[0])<<16 | data[1]); + qCDebug(dcWebasto()) << " - Energy meter:" << energy << "Wh"; + thing->setStateValue(liveWallboxTotalEnergyConsumedStateTypeId, energy); + } break; + case Webasto::TqMaxCurrent: + qCDebug(dcWebasto()) << " - Max. Current" << data[0]; + thing->setStateValue(liveWallboxMaxPossibleChargingCurrentStateTypeId, data[0]); + break; + case Webasto::TqMinimumCurrentLimit: + qCDebug(dcWebasto()) << " - Min. Current" << data[0]; + break; + case Webasto::TqMaxCurrentFromEVSE: + qCDebug(dcWebasto()) << " - Max. Current EVSE" << data[0]; + break; + case Webasto::TqMaxCurrentFromCable: + qCDebug(dcWebasto()) << " - Max. Current Cable" << data[0]; + break; + case Webasto::TqMaxCurrentFromEV: + qCDebug(dcWebasto()) << " - Max. Current EV" << data[0]; + break; + case Webasto::TqUserPriority: + qCDebug(dcWebasto()) << " - User priority" << data[0]; + break; + case Webasto::TqEVBatteryState: + qCDebug(dcWebasto()) << " - Battery state" << data[0]; + break; + case Webasto::TqEVBatteryCapacity: + qCDebug(dcWebasto()) << " - Battery capacity" << data[0]; + break; + case Webasto::TqScheduleType: + qCDebug(dcWebasto()) << " - Schedule type" << data[0]; + break; + case Webasto::TqRequiredEnergy: + qCDebug(dcWebasto()) << " - Required energy" << data[0]; + break; + case Webasto::TqRequiredBatteryState: + qCDebug(dcWebasto()) << " - Required battery state" << data[0]; + break; + case Webasto::TqScheduledTime: + qCDebug(dcWebasto()) << " - Scheduled time" << data[0]; + break; + case Webasto::TqScheduledDate: + qCDebug(dcWebasto()) << " - Scheduled date" << data[0]; + break; + case Webasto::TqChargedEnergy: + qCDebug(dcWebasto()) << " - Charged energy" << data[0]; + thing->setStateValue(liveWallboxSessionEnergyStateTypeId, data[0]/1000.00); // Charged energy in kWh + break; + case Webasto::TqStartTime: + qCDebug(dcWebasto()) << " - Start time" << data[0]; + break; + case Webasto::TqChargingTime: + qCDebug(dcWebasto()) << " - Charging time" << data[0]; + thing->setStateValue(liveWallboxSessionTimeStateTypeId, data[0]/60.00); // Charging time in minutes + break; + case Webasto::TqEndTime: + qCDebug(dcWebasto()) << " - End time" << data[0]; + break; + case Webasto::TqUserId: { + QByteArray userID; + Q_FOREACH(quint16 i, data) { + userID.append(i>>16); + userID.append(i&0xff); + } + qCDebug(dcWebasto()) << " - User ID:" << userID; + } break; + case Webasto::TqSmartVehicleDetected: + qCDebug(dcWebasto()) << " - Smart vehicle detected:" << data[0]; + break; + case Webasto::TqSafeCurrent: + qCDebug(dcWebasto()) << " - Safe current:" << data[0]; + break; + case Webasto::TqComTimeout: + qCDebug(dcWebasto()) << " - Com timeout:" << data[0]; + break; + default: + break; + } + } +} diff --git a/webasto/integrationpluginwebasto.h b/webasto/integrationpluginwebasto.h index 6224c8d..b1d765b 100644 --- a/webasto/integrationpluginwebasto.h +++ b/webasto/integrationpluginwebasto.h @@ -36,6 +36,7 @@ #include "webasto.h" #include "../discovery/discovery.h" #include "../discovery/host.h" +#include "../modbus/modbustcpmaster.h" #include #include @@ -59,11 +60,18 @@ public: private: Discovery *m_discovery = nullptr; + PluginTimer *m_pluginTimer = nullptr; QHash m_webastoConnections; QHash m_asyncActions; + void update(Webasto *webasto); + private slots: void onConnectionChanged(bool connected); + void onWriteRequestExecuted(const QUuid &requestId, bool success); + void onWriteRequestError(const QUuid &requestId, const QString &error); + + void onReceivedRegister(Webasto::TqModbusRegister registerAddress, const QVector &data); }; #endif // INTEGRATIONPLUGINWEBASTO_H diff --git a/webasto/integrationpluginwebasto.json b/webasto/integrationpluginwebasto.json index 3f964a5..e344844 100644 --- a/webasto/integrationpluginwebasto.json +++ b/webasto/integrationpluginwebasto.json @@ -41,15 +41,6 @@ "defaultValue": false, "cached": false }, - { - "id": "537e01ac-9290-421d-a5cb-987d9e088941", - "name": "chargeTime", - "displayName": "Charging Time", - "unit": "Minutes", - "type": "int", - "defaultValue": 0, - "displayNameEvent": "Charging time changed" - }, { "id": "b076353b-e911-444f-80ad-3f78c4075d1a", "name": "chargePointState", @@ -80,7 +71,7 @@ "No cable attached", "Cable attached but no car attached)", "Cable attached and car attached", - "Cable attached,car attached and lock active" + "Cable attached, car attached and lock active" ], "defaultValue": "No cable attached" }, @@ -106,6 +97,94 @@ "maxValue": 80.00, "defaultValue": 6.00, "writable": true + }, + { + "id": "2027fbb6-c9d2-4a75-bdd0-a3ad3785cdc6", + "name": "currentPhase1", + "displayName": "Current phase 1", + "displayNameEvent": "Current phase 1 changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0.00 + }, + { + "id": "1793f645-d7db-4e99-af92-3587aa3069f3", + "name": "currentPhase2", + "displayName": "Current phase 2", + "displayNameEvent": "Current phase 2 changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0.00 + }, + { + "id": "feb8c5da-91a7-45f9-acc3-c1b61478c3d2", + "name": "currentPhase3", + "displayName": "Current phase 3", + "displayNameEvent": "Current phase 3 changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0.00 + }, + { + "id": "b20a46ee-0f22-4096-a348-34e68e99e0be", + "name": "powerConsumption", + "displayName": "Power consumption", + "displayNameEvent": "Power consumtion changed", + "type": "double", + "unit": "KiloWatt", + "defaultValue": 0.00 + }, + { + "id": "80568c51-054c-4351-b9d2-e875fee4cc1f", + "name": "totalEnergyConsumed", + "displayName": "Total energy consumed", + "displayNameEvent": "Total energy consumption changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, + { + "id": "87c70567-794e-4af2-916c-b34cf864afcf", + "name": "sessionTime", + "displayName": "Session time", + "displayNameEvent": "Session time changed", + "type": "int", + "unit": "Minutes", + "defaultValue": 0 + }, + { + "id": "b9b46920-55c1-4bfa-9200-acdc9c0a2471", + "name": "sessionEnergy", + "displayName": "Session energy", + "displayNameEvent": "Session energy changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, + { + "id": "56d31fd1-5cfb-42dd-8181-e6b0d0ca9c8a", + "name": "error", + "displayName": "Error ", + "displayNameEvent": "Error changed", + "type": "int", + "defaultValue": 0 + }, + { + "id": "0e60b15d-2b0c-4672-960e-7c6ea67bf7ea", + "name": "maxPossibleChargingCurrent", + "displayName": "Maximum possible charging current", + "displayNameEvent": "Maximum possible charging current changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 6.00 + }, + { + "id": "48b62082-f286-433e-9cf8-2dcf6c0ea248", + "name": "userId", + "displayName": "User ID", + "displayNameEvent": "User ID changed", + "type": "QString", + "defaultValue": "" } ] } diff --git a/webasto/translations/9fa369ab-c225-4447-9a23-f4911d9b056c-en_US.ts b/webasto/translations/9fa369ab-c225-4447-9a23-f4911d9b056c-en_US.ts new file mode 100644 index 0000000..d8b5db2 --- /dev/null +++ b/webasto/translations/9fa369ab-c225-4447-9a23-f4911d9b056c-en_US.ts @@ -0,0 +1,280 @@ + + + + + Webasto + + + + Cable state + The name of the ParamType (ThingClass: liveWallbox, EventType: cableState, ID: {a1a452f9-de93-4c31-b71b-c74264f85a3e}) +---------- +The name of the StateType ({a1a452f9-de93-4c31-b71b-c74264f85a3e}) of ThingClass liveWallbox + + + + + Cable state changed + The name of the EventType ({a1a452f9-de93-4c31-b71b-c74264f85a3e}) of ThingClass liveWallbox + + + + + + Charge point state + The name of the ParamType (ThingClass: liveWallbox, EventType: chargePointState, ID: {b076353b-e911-444f-80ad-3f78c4075d1a}) +---------- +The name of the StateType ({b076353b-e911-444f-80ad-3f78c4075d1a}) of ThingClass liveWallbox + + + + + Charge point state changed + The name of the EventType ({b076353b-e911-444f-80ad-3f78c4075d1a}) of ThingClass liveWallbox + + + + + + + Charging + The name of the ParamType (ThingClass: liveWallbox, ActionType: power, ID: {3c054603-d933-4e30-a2cc-2177beaaffdb}) +---------- +The name of the ParamType (ThingClass: liveWallbox, EventType: power, ID: {3c054603-d933-4e30-a2cc-2177beaaffdb}) +---------- +The name of the StateType ({3c054603-d933-4e30-a2cc-2177beaaffdb}) of ThingClass liveWallbox + + + + + + + Charging current + The name of the ParamType (ThingClass: liveWallbox, ActionType: chargeCurrent, ID: {96ed77ce-c5cf-4981-8a72-b619f5702724}) +---------- +The name of the ParamType (ThingClass: liveWallbox, EventType: chargeCurrent, ID: {96ed77ce-c5cf-4981-8a72-b619f5702724}) +---------- +The name of the StateType ({96ed77ce-c5cf-4981-8a72-b619f5702724}) of ThingClass liveWallbox + + + + + Charging current changed + The name of the EventType ({96ed77ce-c5cf-4981-8a72-b619f5702724}) of ThingClass liveWallbox + + + + + Charging status changed + The name of the EventType ({3c054603-d933-4e30-a2cc-2177beaaffdb}) of ThingClass liveWallbox + + + + + + Connected + The name of the ParamType (ThingClass: liveWallbox, EventType: connected, ID: {7e6ed2b4-aa8a-4bf6-b20b-84ecc6cc1508}) +---------- +The name of the StateType ({7e6ed2b4-aa8a-4bf6-b20b-84ecc6cc1508}) of ThingClass liveWallbox + + + + + Connected changed + The name of the EventType ({7e6ed2b4-aa8a-4bf6-b20b-84ecc6cc1508}) of ThingClass liveWallbox + + + + + + Current phase 1 + The name of the ParamType (ThingClass: liveWallbox, EventType: currentPhase1, ID: {2027fbb6-c9d2-4a75-bdd0-a3ad3785cdc6}) +---------- +The name of the StateType ({2027fbb6-c9d2-4a75-bdd0-a3ad3785cdc6}) of ThingClass liveWallbox + + + + + Current phase 1 changed + The name of the EventType ({2027fbb6-c9d2-4a75-bdd0-a3ad3785cdc6}) of ThingClass liveWallbox + + + + + + Current phase 2 + The name of the ParamType (ThingClass: liveWallbox, EventType: currentPhase2, ID: {1793f645-d7db-4e99-af92-3587aa3069f3}) +---------- +The name of the StateType ({1793f645-d7db-4e99-af92-3587aa3069f3}) of ThingClass liveWallbox + + + + + Current phase 2 changed + The name of the EventType ({1793f645-d7db-4e99-af92-3587aa3069f3}) of ThingClass liveWallbox + + + + + + Current phase 3 + The name of the ParamType (ThingClass: liveWallbox, EventType: currentPhase3, ID: {feb8c5da-91a7-45f9-acc3-c1b61478c3d2}) +---------- +The name of the StateType ({feb8c5da-91a7-45f9-acc3-c1b61478c3d2}) of ThingClass liveWallbox + + + + + Current phase 3 changed + The name of the EventType ({feb8c5da-91a7-45f9-acc3-c1b61478c3d2}) of ThingClass liveWallbox + + + + + + Error + The name of the ParamType (ThingClass: liveWallbox, EventType: error, ID: {56d31fd1-5cfb-42dd-8181-e6b0d0ca9c8a}) +---------- +The name of the StateType ({56d31fd1-5cfb-42dd-8181-e6b0d0ca9c8a}) of ThingClass liveWallbox + + + + + Error changed + The name of the EventType ({56d31fd1-5cfb-42dd-8181-e6b0d0ca9c8a}) of ThingClass liveWallbox + + + + + IP address + The name of the ParamType (ThingClass: liveWallbox, Type: thing, ID: {51fa3ea8-e819-46ca-b975-1bee6285441c}) + + + + + Live Wallbox + The name of the ThingClass ({48472124-3199-4827-990a-b72069bd5658}) + + + + + MAC address + The name of the ParamType (ThingClass: liveWallbox, Type: thing, ID: {4aa97965-fc1c-488a-92a6-848c214564bc}) + + + + + + Maximum possible charging current + The name of the ParamType (ThingClass: liveWallbox, EventType: maxPossibleChargingCurrent, ID: {0e60b15d-2b0c-4672-960e-7c6ea67bf7ea}) +---------- +The name of the StateType ({0e60b15d-2b0c-4672-960e-7c6ea67bf7ea}) of ThingClass liveWallbox + + + + + Maximum possible charging current changed + The name of the EventType ({0e60b15d-2b0c-4672-960e-7c6ea67bf7ea}) of ThingClass liveWallbox + + + + + + Power consumption + The name of the ParamType (ThingClass: liveWallbox, EventType: powerConsumption, ID: {b20a46ee-0f22-4096-a348-34e68e99e0be}) +---------- +The name of the StateType ({b20a46ee-0f22-4096-a348-34e68e99e0be}) of ThingClass liveWallbox + + + + + Power consumtion changed + The name of the EventType ({b20a46ee-0f22-4096-a348-34e68e99e0be}) of ThingClass liveWallbox + + + + + + Session energy + The name of the ParamType (ThingClass: liveWallbox, EventType: sessionEnergy, ID: {b9b46920-55c1-4bfa-9200-acdc9c0a2471}) +---------- +The name of the StateType ({b9b46920-55c1-4bfa-9200-acdc9c0a2471}) of ThingClass liveWallbox + + + + + Session energy changed + The name of the EventType ({b9b46920-55c1-4bfa-9200-acdc9c0a2471}) of ThingClass liveWallbox + + + + + + Session time + The name of the ParamType (ThingClass: liveWallbox, EventType: sessionTime, ID: {87c70567-794e-4af2-916c-b34cf864afcf}) +---------- +The name of the StateType ({87c70567-794e-4af2-916c-b34cf864afcf}) of ThingClass liveWallbox + + + + + Session time changed + The name of the EventType ({87c70567-794e-4af2-916c-b34cf864afcf}) of ThingClass liveWallbox + + + + + Set charging current + The name of the ActionType ({96ed77ce-c5cf-4981-8a72-b619f5702724}) of ThingClass liveWallbox + + + + + Start charging + The name of the ActionType ({3c054603-d933-4e30-a2cc-2177beaaffdb}) of ThingClass liveWallbox + + + + + + Total energy consumed + The name of the ParamType (ThingClass: liveWallbox, EventType: totalEnergyConsumed, ID: {80568c51-054c-4351-b9d2-e875fee4cc1f}) +---------- +The name of the StateType ({80568c51-054c-4351-b9d2-e875fee4cc1f}) of ThingClass liveWallbox + + + + + Total energy consumption changed + The name of the EventType ({80568c51-054c-4351-b9d2-e875fee4cc1f}) of ThingClass liveWallbox + + + + + + User ID + The name of the ParamType (ThingClass: liveWallbox, EventType: userId, ID: {48b62082-f286-433e-9cf8-2dcf6c0ea248}) +---------- +The name of the StateType ({48b62082-f286-433e-9cf8-2dcf6c0ea248}) of ThingClass liveWallbox + + + + + User ID changed + The name of the EventType ({48b62082-f286-433e-9cf8-2dcf6c0ea248}) of ThingClass liveWallbox + + + + + Webasto + The name of the vendor ({274f4453-6acf-4204-be21-379abbe3b5a7}) + + + + + webasto + The name of the plugin Webasto ({9fa369ab-c225-4447-9a23-f4911d9b056c}) + + + + diff --git a/webasto/webasto.cpp b/webasto/webasto.cpp index 339e73f..b4709f6 100644 --- a/webasto/webasto.cpp +++ b/webasto/webasto.cpp @@ -34,53 +34,91 @@ Webasto::Webasto(const QHostAddress &address, uint port, QObject *parent) : QObject(parent) { - m_modbusConnection = new QModbusTcpClient(this); - m_modbusConnection->setConnectionParameter(QModbusDevice::NetworkPortParameter, port); - m_modbusConnection->setConnectionParameter(QModbusDevice::NetworkAddressParameter, address.toString()); + qCDebug(dcWebasto()) << "Webasto: Webasto connection created" << address.toString() << port; + m_modbusConnection = new ModbusTCPMaster(address, port, this); m_modbusConnection->setNumberOfRetries(3); m_modbusConnection->setTimeout(1000); + connect(m_modbusConnection, &ModbusTCPMaster::connectionStateChanged, this, &Webasto::connectionStateChanged); + connect(m_modbusConnection, &ModbusTCPMaster::receivedHoldingRegister, this, &Webasto::onReceivedHoldingRegister); + connect(m_modbusConnection, &ModbusTCPMaster::writeRequestExecuted, this, &Webasto::writeRequestExecuted); + connect(m_modbusConnection, &ModbusTCPMaster::writeRequestError, this, &Webasto::writeRequestError); + + m_lifeBitTimer = new QTimer(this); + m_lifeBitTimer->start(10000); + connect(m_lifeBitTimer, &QTimer::timeout, this, [this] { + setLiveBit(); + }); } void Webasto::setAddress(const QHostAddress &address) { qCDebug(dcWebasto()) << "Webasto: set address" << address; - m_modbusConnection->setConnectionParameter(QModbusDevice::NetworkAddressParameter, address.toString()); + m_modbusConnection->setHostAddress(address); } QHostAddress Webasto::address() const { - return QHostAddress(m_modbusConnection->connectionParameter(QModbusDevice::NetworkAddressParameter).toString()); + return m_modbusConnection->hostAddress(); } bool Webasto::connected() { - return (m_modbusConnection->state() == QModbusTcpClient::State::ConnectedState); + return m_modbusConnection->connected(); } -void Webasto::getBasicInformation() +bool Webasto::connectDevice() { - + return m_modbusConnection->connectDevice(); } -void Webasto::getUserId() +void Webasto::setLivebitInterval(uint seconds) { - + qCDebug(dcWebasto()) << "Webasto: Live bit interval set to" << seconds << "[s]"; + m_lifeBitTimer->setInterval(seconds*1000); } -void Webasto::getSessionInformation() +void Webasto::getRegister(Webasto::TqModbusRegister modbusRegister, uint length) { + qCDebug(dcWebasto()) << "Webasto: Get register" << modbusRegister << length; + if (length < 1 && length > 10) { + qCWarning(dcWebasto()) << "Invalide register length, allowed values [1,10]"; + return; + } + m_modbusConnection->readHoldingRegister(m_unitId, modbusRegister, length); +} + +QUuid Webasto::setSafeCurrent(quint16 ampere) const +{ + return m_modbusConnection->writeHoldingRegister(m_unitId, TqSafeCurrent, ampere); +} + +QUuid Webasto::seComTimeout(quint16 seconds) const +{ + return m_modbusConnection->writeHoldingRegister(m_unitId, TqComTimeout, seconds); +} + +QUuid Webasto::setChargePower(quint32 watt) const +{ + QVector data; + data.append(watt>>16); + data.append(watt&0xff); + return m_modbusConnection->writeHoldingRegisters(m_unitId, TqChargePower, data); +} + +QUuid Webasto::setChargeCurrent(quint16 ampere) const +{ + return m_modbusConnection->writeHoldingRegister(m_unitId, TqChargeCurrent, ampere); } void Webasto::setLiveBit() { - + qCDebug(dcWebasto()) << "Webasto: Set live bit"; + m_modbusConnection->writeHoldingRegister(m_unitId, TqLifeBit, 0x0001); } -QUuid Webasto::writeHoldingRegister() +void Webasto::onReceivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector &values) { - QUuid request = QUuid::createUuid(); - - - return request; + Q_UNUSED(slaveAddress) + emit receivedRegister(TqModbusRegister(modbusRegister), values); } diff --git a/webasto/webasto.h b/webasto/webasto.h index c64f8eb..16a852a 100644 --- a/webasto/webasto.h +++ b/webasto/webasto.h @@ -34,9 +34,10 @@ #include #include #include -#include #include +#include "../modbus/modbustcpmaster.h" + class Webasto : public QObject { Q_OBJECT @@ -63,41 +64,14 @@ public: }; Q_ENUM(CableState) - enum EvseSate { + enum EvseState { EvseSateStarting = 0, EvseSateRunning, EvseSateError }; - Q_ENUM(EvseSate) + Q_ENUM(EvseState) - struct BasicInformation { - double currentL1; // [A] - double currentL2; // [A] - double currentL3; // [A] - double activePower; // [W] - uint activePowerL1; - uint activePowerL2; - uint activePowerL3; - double energyMeter; // [kWh] - }; - - struct CurrentLimitations { - double maxCurrent; - double minimumCurrentLimit; - double maxCurrentFromEvse; - double maxCurrentFromCable; - double maxCurrentFromEV; - }; - - explicit Webasto(const QHostAddress &address, uint port = 502, QObject *parent = nullptr); - - void setAddress(const QHostAddress &address); - QHostAddress address() const; - bool connected(); - -private: enum TqModbusRegister { - // Get Basic Information polls Register 1000 to 1037 TqChargePointState = 1000, // State of the charging device TqChargeState = 1001, // Charging TqEVSEState = 1002, // State of the charging station @@ -111,63 +85,67 @@ private: TqActivePowerL2 = 1028, // Active power L2 TqActivePowerL3 = 1032, // Active power L3 TqEnergyMeter = 1036, // Meter reading of the charging station - // Get Current Limitatoins polls register 1100 to 1110 TqMaxCurrent = 1100, // Maximal charging current UINT of the hardware (EVSE, cable, EV) TqMinimumCurrentLimit = 1102, // Minimal charging current of the hardware (EVSE, cable, EV) TqMaxCurrentFromEVSE = 1104, // Maximal charging current of the charging station TqMaxCurrentFromCable = 1106, // Maximal charging current of the cable TqMaxCurrentFromEV = 1108, // Maximal charging current of the EV - // Get User Priority TqUserPriority = 1200, // Priorities of the user 0: not defined 1: high priority - 10: low priority - // Get Battery state TqEVBatteryState = 1300, // Returns an estimate of the SoC TqEVBatteryCapacity = 1302, // Returns an estimate of the EV Battery Capacity - // Get Schedule polls register 1400 to 1414 TqScheduleType = 1400, // Type/information of traveling 0: energy that has to be charged, 1: Specification of the desired battery charge (Needs: state of the battery) TqRequiredEnergy = 1402, // Desired energy TqRequiredBatteryState = 1404, // Desired state of the battery TqScheduledTime = 1408, // Departure time TqScheduledDate = 1412, // Departure date - // Set session polls register 1500 to 15014 TqChargedEnergy = 1502, // Sum of charged energy for the current session TqStartTime = 1504, // Start time of charging process TqChargingTime = 1508, // Duration since beginning of charge TqEndTime = 1512, // End time of charging process - // Get user id polls register 1600 to 1620 TqUserId = 1600, // 24 Bytes long User ID (OCPP IdTag) from the current session TqSmartVehicleDetected = 1620, //Returns 1 if an EV currently connected is a smart vehicle, or 0 if no EV connected or it is not a smart vehicle, - // Get failsafe polls register 2000 to 2004 TqSafeCurrent = 2000, // Max. charge current under communication failure TqComTimeout = 2002, // Communication timeout - // Get Charge power polls register 5000 to 5002 TqChargePower = 5000, // Charge power TqChargeCurrent = 5001, // Charge current TqLifeBit = 6000 // Communication monitoring 0/1 Toggle-Bit EM writes 1, Live deletes it and puts it on 0. }; + Q_ENUM(TqModbusRegister) - QModbusTcpClient *m_modbusConnection = nullptr; - QHostAddress m_address; - uint m_unitId = 255; + explicit Webasto(const QHostAddress &address, uint port = 502, QObject *parent = nullptr); - void getBasicInformation(); - void getUserId(); - void getCurrentLimitations(); - void getSessionInformation(); - void getFailsafeSpecs(); - void getChargeCurrentAndPower(); - void getUserPriority(); - void getBatteryState(); + void setAddress(const QHostAddress &address); + QHostAddress address() const; + bool connected(); + bool connectDevice(); + + void setLivebitInterval(uint seconds); + + void getRegister(TqModbusRegister modbusRegister, uint length = 1); + + QUuid setSafeCurrent(quint16 ampere) const; + QUuid seComTimeout(quint16 seconds) const; + QUuid setChargePower(quint32 watt) const; + QUuid setChargeCurrent(quint16 ampere) const; void setLiveBit(); +private: + + ModbusTCPMaster *m_modbusConnection = nullptr; + QHostAddress m_address; + uint m_unitId = 255; + private: QTimer *m_lifeBitTimer = nullptr; - QUuid writeHoldingRegister(); signals: - void connectionChanged(bool connected); - void userIdReceived(const QByteArray &userId); - void currentLimitationsReceived(const CurrentLimitations &limitations); - void userPriorityReceived(uint userPriority); // 0 lowest - 10 highest + void connectionStateChanged(bool state); + void writeRequestExecuted(const QUuid &requestId, bool success); + void writeRequestError(const QUuid &requestId, const QString &error); + void receivedRegister(TqModbusRegister registerAddress, const QVector &data); + +private slots: + void onReceivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector &values); }; #endif // WEBASTO_H diff --git a/webasto/webasto.pro b/webasto/webasto.pro index a9abc65..3d94e5f 100644 --- a/webasto/webasto.pro +++ b/webasto/webasto.pro @@ -7,11 +7,13 @@ QT += \ SOURCES += \ integrationpluginwebasto.cpp \ webasto.cpp \ + ../modbus/modbustcpmaster.cpp \ ../discovery/discovery.cpp \ ../discovery/host.cpp HEADERS += \ integrationpluginwebasto.h \ webasto.h \ + ../modbus/modbustcpmaster.h \ ../discovery/discovery.h \ ../discovery/host.h