added auto rediscovery
This commit is contained in:
parent
cdff51655f
commit
0803221e68
@ -4,17 +4,19 @@ This plugin allows to control Keba KeContact EV-Charging stations.
|
|||||||
|
|
||||||
## Supported Things
|
## Supported Things
|
||||||
|
|
||||||
* KeContact
|
* KeContact Wallbox
|
||||||
* Enable/disable the charging stations
|
* P20
|
||||||
* Set maximum charging current
|
* P30
|
||||||
* Get all informations e.g. voltage, current ...
|
* BMW
|
||||||
* Print messages on the display
|
|
||||||
|
|
||||||
## Requirments
|
## Requirments
|
||||||
|
|
||||||
* nymea and the wallbox are required to be in the same network.
|
* nymea and the wallbox are required to be in the same network.
|
||||||
* Port 7090 must not be blocked by a firewall or router.
|
* UDP Port 7090 must not be blocked by a firewall or router.
|
||||||
* The package "nymea-plugin-keba" must be installed.
|
* The package "nymea-plugin-keba" must be installed.
|
||||||
|
* KeContact P20 Charging station with network connection (LSA+ socket). Firmware version: 2.5 or higher.
|
||||||
|
* KeContact P30 Charging station or BMW wallbox. Firmware version 3.05 of higher.
|
||||||
|
* Enabled UDP function with DIP-switch DWS1.3 = ON.
|
||||||
|
|
||||||
## More
|
## More
|
||||||
|
|
||||||
|
|||||||
@ -42,20 +42,45 @@ IntegrationPluginKeba::IntegrationPluginKeba()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IntegrationPluginKeba::init()
|
||||||
|
{
|
||||||
|
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 (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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void IntegrationPluginKeba::discoverThings(ThingDiscoveryInfo *info)
|
void IntegrationPluginKeba::discoverThings(ThingDiscoveryInfo *info)
|
||||||
{
|
{
|
||||||
if (info->thingClassId() == wallboxThingClassId) {
|
if (info->thingClassId() == wallboxThingClassId) {
|
||||||
Discovery *discovery = new Discovery(info);
|
qCDebug(dcKebaKeContact()) << "Discovering Keba Wallbox";
|
||||||
discovery->discoverHosts(25);
|
m_discovery->discoverHosts(25);
|
||||||
|
connect(m_discovery, &Discovery::finished, info, [this, info] (const QList<Host> &hosts) {
|
||||||
|
|
||||||
connect(discovery, &Discovery::finished, info, [this, info](const QList<Host> &hosts) {
|
|
||||||
qCDebug(dcKebaKeContact()) << "Discovery finished. Found" << hosts.count() << "devices";
|
|
||||||
foreach (const Host &host, hosts) {
|
foreach (const Host &host, hosts) {
|
||||||
if (!host.hostName().contains("keba", Qt::CaseSensitivity::CaseInsensitive))
|
if (!host.hostName().contains("keba", Qt::CaseSensitivity::CaseInsensitive))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ThingDescriptor descriptor(wallboxThingClassId, "Wallbox", host.address() + " (" + host.macAddress() + ")");
|
ThingDescriptor descriptor(wallboxThingClassId, "Wallbox", host.address() + " (" + host.macAddress() + ")");
|
||||||
|
|
||||||
|
// Rediscovery
|
||||||
foreach (Thing *existingThing, myThings()) {
|
foreach (Thing *existingThing, myThings()) {
|
||||||
if (existingThing->paramValue(wallboxThingMacAddressParamTypeId).toString() == host.macAddress()) {
|
if (existingThing->paramValue(wallboxThingMacAddressParamTypeId).toString() == host.macAddress()) {
|
||||||
descriptor.setThingId(existingThing->id());
|
descriptor.setThingId(existingThing->id());
|
||||||
@ -86,7 +111,7 @@ void IntegrationPluginKeba::setupThing(ThingSetupInfo *info)
|
|||||||
|
|
||||||
QHostAddress address = QHostAddress(thing->paramValue(wallboxThingIpAddressParamTypeId).toString());
|
QHostAddress address = QHostAddress(thing->paramValue(wallboxThingIpAddressParamTypeId).toString());
|
||||||
KeContact *keba = new KeContact(address, this);
|
KeContact *keba = new KeContact(address, this);
|
||||||
connect(keba, &KeContact::connectionChanged, this, &IntegrationPluginKeba::onConnectionChanged);
|
connect(keba, &KeContact::reachableChanged, this, &IntegrationPluginKeba::onConnectionChanged);
|
||||||
connect(keba, &KeContact::commandExecuted, this, &IntegrationPluginKeba::onCommandExecuted);
|
connect(keba, &KeContact::commandExecuted, this, &IntegrationPluginKeba::onCommandExecuted);
|
||||||
connect(keba, &KeContact::reportOneReceived, this, &IntegrationPluginKeba::onReportOneReceived);
|
connect(keba, &KeContact::reportOneReceived, this, &IntegrationPluginKeba::onReportOneReceived);
|
||||||
connect(keba, &KeContact::reportTwoReceived, this, &IntegrationPluginKeba::onReportTwoReceived);
|
connect(keba, &KeContact::reportTwoReceived, this, &IntegrationPluginKeba::onReportTwoReceived);
|
||||||
@ -98,13 +123,26 @@ void IntegrationPluginKeba::setupThing(ThingSetupInfo *info)
|
|||||||
return info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("Error opening network port."));
|
return info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("Error opening network port."));
|
||||||
}
|
}
|
||||||
|
|
||||||
ThingId id = thing->id();
|
m_kebaDevices.insert(thing->id(), keba);
|
||||||
m_kebaDevices.insert(id, keba);
|
|
||||||
m_asyncSetup.insert(keba, info);
|
|
||||||
keba->getReport1();
|
keba->getReport1();
|
||||||
connect(info, &ThingSetupInfo::aborted, this, [id, keba, this]{
|
connect(keba, &KeContact::reportOneReceived, info, [info] (const KeContact::ReportOne &report) {
|
||||||
m_asyncSetup.remove(keba);
|
Thing *thing = info->thing();
|
||||||
m_kebaDevices.remove(id);
|
|
||||||
|
qCDebug(dcKebaKeContact()) << "Report one received for" << thing->name();
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Firmware" << report.firmware;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Product" << report.product;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Uptime" << report.seconds;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Com Module" << report.comModule;
|
||||||
|
|
||||||
|
thing->setStateValue(wallboxConnectedStateTypeId, true);
|
||||||
|
thing->setStateValue(wallboxFirmwareStateTypeId, report.firmware);
|
||||||
|
thing->setStateValue(wallboxModelStateTypeId, report.product);
|
||||||
|
thing->setStateValue(wallboxUptimeStateTypeId, report.seconds);
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
});
|
||||||
|
connect(info, &ThingSetupInfo::aborted, keba, &KeContact::deleteLater);
|
||||||
|
connect(keba, &KeContact::destroyed, this, [thing, keba, this]{
|
||||||
|
m_kebaDevices.remove(thing->id());
|
||||||
keba->deleteLater();
|
keba->deleteLater();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -118,39 +156,24 @@ void IntegrationPluginKeba::postSetupThing(Thing *thing)
|
|||||||
qCDebug(dcKebaKeContact()) << "Post setup" << thing->name();
|
qCDebug(dcKebaKeContact()) << "Post setup" << thing->name();
|
||||||
KeContact *keba = m_kebaDevices.value(thing->id());
|
KeContact *keba = m_kebaDevices.value(thing->id());
|
||||||
if (!keba) {
|
if (!keba) {
|
||||||
return;
|
qCWarning(dcKebaKeContact()) << "No Keba connection found for this thing";
|
||||||
}
|
} else {
|
||||||
keba->getReport2();
|
|
||||||
keba->getReport3();
|
|
||||||
|
|
||||||
if (!m_pluginTimer) {
|
|
||||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60);
|
|
||||||
connect(m_pluginTimer, &PluginTimer::timeout, this, &IntegrationPluginKeba::updateData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntegrationPluginKeba::thingRemoved(Thing *thing)
|
|
||||||
{
|
|
||||||
if (thing->thingClassId() == wallboxThingClassId) {
|
|
||||||
KeContact *keba = m_kebaDevices.take(thing->id());
|
|
||||||
keba->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myThings().empty()) {
|
|
||||||
// last device has been removed the plug in timer can be stopped again
|
|
||||||
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
|
|
||||||
m_pluginTimer = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntegrationPluginKeba::updateData()
|
|
||||||
{
|
|
||||||
foreach (KeContact *keba, m_kebaDevices) {
|
|
||||||
keba->getReport2();
|
keba->getReport2();
|
||||||
keba->getReport3();
|
keba->getReport3();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_updateTimer) {
|
||||||
|
m_updateTimer = hardwareManager()->pluginTimerManager()->registerTimer(60);
|
||||||
|
connect(m_updateTimer, &PluginTimer::timeout, this, [this] {
|
||||||
|
|
||||||
foreach (Thing *thing, myThings().filterByThingClassId(wallboxThingClassId)) {
|
foreach (Thing *thing, myThings().filterByThingClassId(wallboxThingClassId)) {
|
||||||
|
KeContact *keba = m_kebaDevices.value(thing->id());
|
||||||
|
if (!keba) {
|
||||||
|
qCWarning(dcKebaKeContact()) << "No Keba connection found for" << thing->name();
|
||||||
|
}
|
||||||
|
keba->getReport2();
|
||||||
|
keba->getReport3();
|
||||||
|
|
||||||
if (m_chargingSessionStartTime.contains(thing->id())) {
|
if (m_chargingSessionStartTime.contains(thing->id())) {
|
||||||
QDateTime startTime = m_chargingSessionStartTime.value(thing->id());
|
QDateTime startTime = m_chargingSessionStartTime.value(thing->id());
|
||||||
|
|
||||||
@ -163,6 +186,37 @@ void IntegrationPluginKeba::updateData()
|
|||||||
thing->setStateValue(wallboxSessionTimeStateTypeId, 0);
|
thing->setStateValue(wallboxSessionTimeStateTypeId, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_reconnectTimer) {
|
||||||
|
m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(60*5);
|
||||||
|
connect(m_reconnectTimer, &PluginTimer::timeout, this, [this] {
|
||||||
|
Q_FOREACH(Thing *thing, myThings().filterByThingClassId(wallboxThingClassId)) {
|
||||||
|
if (thing->stateValue(wallboxConnectedStateTypeId) == false) {
|
||||||
|
m_discovery->discoverHosts(25);
|
||||||
|
break; // start discovery once for every device as soon as one device is disconnected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntegrationPluginKeba::thingRemoved(Thing *thing)
|
||||||
|
{
|
||||||
|
qCDebug(dcKebaKeContact()) << "Deleting" << thing->name();
|
||||||
|
if (thing->thingClassId() == wallboxThingClassId) {
|
||||||
|
KeContact *keba = m_kebaDevices.take(thing->id());
|
||||||
|
keba->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myThings().empty()) {
|
||||||
|
qCDebug(dcKebaKeContact()) << "Stopping plugin timers";
|
||||||
|
hardwareManager()->pluginTimerManager()->unregisterTimer(m_reconnectTimer);
|
||||||
|
m_reconnectTimer = nullptr;
|
||||||
|
hardwareManager()->pluginTimerManager()->unregisterTimer(m_updateTimer);
|
||||||
|
m_updateTimer = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginKeba::setDeviceState(Thing *thing, KeContact::State state)
|
void IntegrationPluginKeba::setDeviceState(Thing *thing, KeContact::State state)
|
||||||
@ -230,15 +284,17 @@ void IntegrationPluginKeba::onConnectionChanged(bool status)
|
|||||||
}
|
}
|
||||||
thing->setStateValue(wallboxConnectedStateTypeId, status);
|
thing->setStateValue(wallboxConnectedStateTypeId, status);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
//TODO start rediscovery
|
m_discovery->discoverHosts(25);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginKeba::onCommandExecuted(QUuid requestId, bool success)
|
void IntegrationPluginKeba::onCommandExecuted(QUuid requestId, bool success)
|
||||||
{
|
{
|
||||||
updateData();
|
|
||||||
if (m_asyncActions.contains(requestId)) {
|
if (m_asyncActions.contains(requestId)) {
|
||||||
KeContact *keba = static_cast<KeContact *>(sender());
|
KeContact *keba = static_cast<KeContact *>(sender());
|
||||||
|
|
||||||
|
keba->getReport2(); //Check if the state was actually set
|
||||||
|
|
||||||
Thing *thing = myThings().findById(m_kebaDevices.key(keba));
|
Thing *thing = myThings().findById(m_kebaDevices.key(keba));
|
||||||
if (!thing) {
|
if (!thing) {
|
||||||
qCWarning(dcKebaKeContact()) << "On command executed: missing device object";
|
qCWarning(dcKebaKeContact()) << "On command executed: missing device object";
|
||||||
@ -253,18 +309,6 @@ void IntegrationPluginKeba::onCommandExecuted(QUuid requestId, bool success)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginKeba::onReportOneReceived(const KeContact::ReportOne &reportOne)
|
|
||||||
{
|
|
||||||
Q_UNUSED(reportOne);
|
|
||||||
KeContact *keba = static_cast<KeContact *>(sender());
|
|
||||||
if (m_asyncSetup.contains(keba)) {
|
|
||||||
ThingSetupInfo *info = m_asyncSetup.value(keba);
|
|
||||||
info->finish(Thing::ThingErrorNoError);
|
|
||||||
} else {
|
|
||||||
qCDebug(dcKebaKeContact()) << "Report one received without an associated async setup";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntegrationPluginKeba::onReportTwoReceived(const KeContact::ReportTwo &reportTwo)
|
void IntegrationPluginKeba::onReportTwoReceived(const KeContact::ReportTwo &reportTwo)
|
||||||
{
|
{
|
||||||
KeContact *keba = static_cast<KeContact *>(sender());
|
KeContact *keba = static_cast<KeContact *>(sender());
|
||||||
@ -272,8 +316,36 @@ void IntegrationPluginKeba::onReportTwoReceived(const KeContact::ReportTwo &repo
|
|||||||
if (!thing)
|
if (!thing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
thing->setStateValue()
|
||||||
thing->setStateValue(wallboxPowerStateTypeId, reportTwo.enableUser);
|
thing->setStateValue(wallboxPowerStateTypeId, reportTwo.enableUser);
|
||||||
thing->setStateValue(wallboxMaxChargingCurrentPercentStateTypeId, reportTwo.MaxCurrentPercentage);
|
thing->setStateValue(wallboxError1StateTypeId, reportTwo.error1);
|
||||||
|
thing->setStateValue(wallboxError2StateTypeId, reportTwo.error2);
|
||||||
|
|
||||||
|
qCDebug(dcKebaKeContact()) << "Report 2 recieved for" << thing->name();
|
||||||
|
qCDebug(dcKebaKeContact()) << " - State:" << reportTwo.state;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Error 1:" << reportTwo.error1;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Error 2:" << reportTwo.error2;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Plug:" << reportTwo.plugState;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Enable sys:" << reportTwo.enableSys;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Enable user:" << reportTwo.enableUser;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Max curr:" << reportTwo.maxCurrent;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Max curr %:" << reportTwo.maxCurrentPercentage;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Curr HW:" << reportTwo.currentHardwareLimitation;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Curr User:" << reportTwo.currentUser;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Curr FS:" << reportTwo.currentFailsafe;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Tmo FS:" << reportTwo.timeoutFailsafe;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Curr timer:" << reportTwo.currTimer;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Timeout CT:" << reportTwo.timeoutCt;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Output:" << reportTwo.output;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Input:" << reportTwo.input;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Serialnumber:" << reportTwo.serialNumber;
|
||||||
|
qCDebug(dcKebaKeContact()) << " - Uptime:" << reportTwo.seconds;
|
||||||
|
|
||||||
|
|
||||||
|
//thing->setStateValue(wallboxMaxChargingCurrentAmpereStateTypeId, reportTwo.maxCurrent);
|
||||||
|
thing->setStateValue(wallboxMaxChargingCurrentPercentStateTypeId, reportTwo.maxCurrentPercentage);
|
||||||
|
//thing->setStateValue(wallboxCurrentHardwareLimitationStateTypeId, reportTwo.currentHardwareLimitation);
|
||||||
|
|
||||||
|
|
||||||
setDeviceState(thing, reportTwo.state);
|
setDeviceState(thing, reportTwo.state);
|
||||||
setDevicePlugState(thing, reportTwo.plugState);
|
setDevicePlugState(thing, reportTwo.plugState);
|
||||||
@ -286,14 +358,15 @@ void IntegrationPluginKeba::onReportThreeReceived(const KeContact::ReportThree &
|
|||||||
if (!thing)
|
if (!thing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
thing->setStateValue(wallboxI1EventTypeId, reportThree.CurrentPhase1);
|
thing->setStateValue(wallboxCurrentPhase1EventTypeId, reportThree.CurrentPhase1);
|
||||||
thing->setStateValue(wallboxI2EventTypeId, reportThree.CurrentPhase2);
|
thing->setStateValue(wallboxCurrentPhase2EventTypeId, reportThree.CurrentPhase2);
|
||||||
thing->setStateValue(wallboxI3EventTypeId, reportThree.CurrentPhase3);
|
thing->setStateValue(wallboxCurrentPhase3EventTypeId, reportThree.CurrentPhase3);
|
||||||
thing->setStateValue(wallboxU1EventTypeId, reportThree.VoltagePhase1);
|
thing->setStateValue(wallboxVoltagePhase1EventTypeId, reportThree.VoltagePhase1);
|
||||||
thing->setStateValue(wallboxU2EventTypeId, reportThree.VoltagePhase2);
|
thing->setStateValue(wallboxVoltagePhase2EventTypeId, reportThree.VoltagePhase2);
|
||||||
thing->setStateValue(wallboxU3EventTypeId, reportThree.VoltagePhase3);
|
thing->setStateValue(wallboxVoltagePhase3EventTypeId, reportThree.VoltagePhase3);
|
||||||
thing->setStateValue(wallboxPStateTypeId, reportThree.Power);
|
thing->setStateValue(wallboxPowerConsumptionStateTypeId, reportThree.Power);
|
||||||
thing->setStateValue(wallboxEPStateTypeId, reportThree.EnergySession);
|
thing->setStateValue(wallboxSessionEnergyStateTypeId, reportThree.EnergySession); //TODO check state name
|
||||||
|
thing->setStateValue(wallboxPowerFactorStateTypeId, reportThree.PowerFactor);
|
||||||
thing->setStateValue(wallboxTotalEnergyConsumedStateTypeId, reportThree.EnergyTotal);
|
thing->setStateValue(wallboxTotalEnergyConsumedStateTypeId, reportThree.EnergyTotal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +384,7 @@ void IntegrationPluginKeba::onBroadcastReceived(KeContact::BroadcastType type, c
|
|||||||
case KeContact::BroadcastTypeInput:
|
case KeContact::BroadcastTypeInput:
|
||||||
break;
|
break;
|
||||||
case KeContact::BroadcastTypeEPres:
|
case KeContact::BroadcastTypeEPres:
|
||||||
thing->setStateValue(wallboxEPStateTypeId, content.toInt());
|
thing->setStateValue(wallboxSessionEnergyStateTypeId, content.toInt());
|
||||||
break;
|
break;
|
||||||
case KeContact::BroadcastTypeState:
|
case KeContact::BroadcastTypeState:
|
||||||
setDeviceState(thing, KeContact::State(content.toInt()));
|
setDeviceState(thing, KeContact::State(content.toInt()));
|
||||||
|
|||||||
@ -52,6 +52,7 @@ class IntegrationPluginKeba : public IntegrationPlugin
|
|||||||
public:
|
public:
|
||||||
explicit IntegrationPluginKeba();
|
explicit IntegrationPluginKeba();
|
||||||
|
|
||||||
|
void init() override;
|
||||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||||
void setupThing(ThingSetupInfo *info) override;
|
void setupThing(ThingSetupInfo *info) override;
|
||||||
|
|
||||||
@ -59,10 +60,12 @@ public:
|
|||||||
void thingRemoved(Thing* thing) override;
|
void thingRemoved(Thing* thing) override;
|
||||||
|
|
||||||
void executeAction(ThingActionInfo *info) override;
|
void executeAction(ThingActionInfo *info) override;
|
||||||
void updateData();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PluginTimer *m_pluginTimer = nullptr;
|
PluginTimer *m_updateTimer = nullptr;
|
||||||
|
PluginTimer *m_reconnectTimer = nullptr;
|
||||||
|
|
||||||
|
Discovery *m_discovery = nullptr;
|
||||||
QHash<ThingId, KeContact *> m_kebaDevices;
|
QHash<ThingId, KeContact *> m_kebaDevices;
|
||||||
QHash<KeContact *, ThingSetupInfo *> m_asyncSetup;
|
QHash<KeContact *, ThingSetupInfo *> m_asyncSetup;
|
||||||
QHash<QUuid, ThingActionInfo *> m_asyncActions;
|
QHash<QUuid, ThingActionInfo *> m_asyncActions;
|
||||||
|
|||||||
@ -29,7 +29,8 @@
|
|||||||
"displayName": "MAC Address",
|
"displayName": "MAC Address",
|
||||||
"type": "QString",
|
"type": "QString",
|
||||||
"inputType": "TextLine",
|
"inputType": "TextLine",
|
||||||
"defaultValue":""
|
"defaultValue":"",
|
||||||
|
"readOnly": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"stateTypes": [
|
"stateTypes": [
|
||||||
@ -42,6 +43,60 @@
|
|||||||
"defaultValue": false,
|
"defaultValue": false,
|
||||||
"cached": false
|
"cached": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "b44bc948-1234-4f87-9a22-bfb6de09df4d",
|
||||||
|
"name": "error1",
|
||||||
|
"displayName": "Error 1",
|
||||||
|
"displayNameEvent": "Error 1 changed",
|
||||||
|
"type": "int",
|
||||||
|
"defaultValue": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "afca201a-5213-43fe-bfec-cae6ce7509d2",
|
||||||
|
"name": "error2",
|
||||||
|
"displayName": "Error 2",
|
||||||
|
"displayNameEvent": "Error 2 changed",
|
||||||
|
"type": "int",
|
||||||
|
"defaultValue": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c3fca233-95b9-4948-88c6-4c0f13cf53b1",
|
||||||
|
"name": "model",
|
||||||
|
"displayName": "Model",
|
||||||
|
"displayNameEvent": "Model changed",
|
||||||
|
"type": "QString",
|
||||||
|
"defaultValue": "Unknown",
|
||||||
|
"possibleValues": [
|
||||||
|
"Unknown",
|
||||||
|
"Keba P20",
|
||||||
|
"Keba P30",
|
||||||
|
"BMW"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e941ace5-fb7f-4dc2-b3f2-188233f4e934",
|
||||||
|
"name": "firmware",
|
||||||
|
"displayName": "Firmware",
|
||||||
|
"displayNameEvent": "Firmware changed",
|
||||||
|
"type": "QString",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9a1b4316-ce01-4cd3-890f-a8c94b8b5029",
|
||||||
|
"name": "serialnumber",
|
||||||
|
"displayName": "Serial number",
|
||||||
|
"displayNameEvent": "Serial number changed",
|
||||||
|
"type": "QString",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1d30ce60-2ea0-450f-817e-5c88f59ebfbf",
|
||||||
|
"name": "sessionId",
|
||||||
|
"displayName": "Session ID",
|
||||||
|
"displayNameEvent": "Session ID changed",
|
||||||
|
"type": "uint",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "83ed0774-2a91-434d-b03c-d920d02f2981",
|
"id": "83ed0774-2a91-434d-b03c-d920d02f2981",
|
||||||
"name": "power",
|
"name": "power",
|
||||||
@ -103,7 +158,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "4a2d75d8-a3a0-4b40-9ca7-e8b6f11d0ef9",
|
"id": "4a2d75d8-a3a0-4b40-9ca7-e8b6f11d0ef9",
|
||||||
"name": "U1",
|
"name": "voltagePhase1",
|
||||||
"displayName": "Voltage phase 1",
|
"displayName": "Voltage phase 1",
|
||||||
"displayNameEvent": "Voltage phase 1 changed",
|
"displayNameEvent": "Voltage phase 1 changed",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
@ -112,7 +167,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "c8344ca5-21ac-4cd1-8f4b-e5ed202c5862",
|
"id": "c8344ca5-21ac-4cd1-8f4b-e5ed202c5862",
|
||||||
"name": "U2",
|
"name": "voltagePhase2",
|
||||||
"displayName": "Voltage Phase 2",
|
"displayName": "Voltage Phase 2",
|
||||||
"displayNameEvent": "Voltage phase 2 changed",
|
"displayNameEvent": "Voltage phase 2 changed",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
@ -121,7 +176,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "5f01e86c-0943-4849-a01a-db441916ebd5",
|
"id": "5f01e86c-0943-4849-a01a-db441916ebd5",
|
||||||
"name": "U3",
|
"name": "voltagePhase3",
|
||||||
"displayName": "Voltage Phase 3",
|
"displayName": "Voltage Phase 3",
|
||||||
"displayNameEvent": "Voltage phase 3 changed",
|
"displayNameEvent": "Voltage phase 3 changed",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
@ -130,40 +185,49 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "31ec17b0-11e3-4332-92b0-fea821cf024f",
|
"id": "31ec17b0-11e3-4332-92b0-fea821cf024f",
|
||||||
"name": "I1",
|
"name": "currentPhase1",
|
||||||
"displayName": "Current Phase 1",
|
"displayName": "Current Phase 1",
|
||||||
"displayNameEvent": "Current phase 1 changed",
|
"displayNameEvent": "Current phase 1 changed",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"unit": "MilliAmpere",
|
"unit": "Ampere",
|
||||||
"defaultValue": 0
|
"defaultValue": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cdc7e10a-0d0a-4e93-ad2c-d34ffca45c97",
|
"id": "cdc7e10a-0d0a-4e93-ad2c-d34ffca45c97",
|
||||||
"name": "I2",
|
"name": "currentPhase2",
|
||||||
"displayName": "Current Phase 2",
|
"displayName": "Current Phase 2",
|
||||||
"displayNameEvent": "Current phase 2 changed",
|
"displayNameEvent": "Current phase 2 changed",
|
||||||
"type": "int",
|
"type": "double",
|
||||||
"unit": "MilliAmpere",
|
"unit": "Ampere",
|
||||||
"defaultValue": 0
|
"defaultValue": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "da838dc8-85f0-4e55-b4b5-cb93a43b373d",
|
"id": "da838dc8-85f0-4e55-b4b5-cb93a43b373d",
|
||||||
"name": "I3",
|
"name": "currentPhase3",
|
||||||
"displayName": "Current Phase 3",
|
"displayName": "Current Phase 3",
|
||||||
"displayNameEvent": "Current phase 3 changed",
|
"displayNameEvent": "Current phase 3 changed",
|
||||||
"type": "int",
|
"type": "double",
|
||||||
"unit": "MilliAmpere",
|
"unit": "Ampere",
|
||||||
"defaultValue": 0
|
"defaultValue": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "7af9e93b-099d-4d9d-a480-9c0f66aecd8b",
|
"id": "7af9e93b-099d-4d9d-a480-9c0f66aecd8b",
|
||||||
"name": "P",
|
"name": "powerConsumption",
|
||||||
"displayName": "Power consumption",
|
"displayName": "Power consumption",
|
||||||
"displayNameEvent": "Power consumtion changed",
|
"displayNameEvent": "Power consumtion changed",
|
||||||
"type": "int",
|
"type": "double",
|
||||||
"unit": "MilliWatt",
|
"unit": "Watt",
|
||||||
"defaultValue": 0
|
"defaultValue": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "889c3c9a-96b4-4408-bd9a-d79e36ed9296",
|
||||||
|
"name": "powerFactor",
|
||||||
|
"displayName": "Power factor",
|
||||||
|
"displayNameEvent": "Power factor changed",
|
||||||
|
"type": "double",
|
||||||
|
"unit": "Percentage",
|
||||||
|
"defaultValue": 0.00
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "a6f35ea0-aaea-438b-b818-6d161762611e",
|
"id": "a6f35ea0-aaea-438b-b818-6d161762611e",
|
||||||
"name": "sessionTime",
|
"name": "sessionTime",
|
||||||
@ -175,9 +239,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "8e277efe-21ef-4536-bfc0-901b32d44d7c",
|
"id": "8e277efe-21ef-4536-bfc0-901b32d44d7c",
|
||||||
"name": "EP",
|
"name": "sessionEnergy",
|
||||||
"displayName": "Present energy",
|
"displayName": "Session energy",
|
||||||
"displayNameEvent": "Present energy changed",
|
"displayNameEvent": "Session energy changed",
|
||||||
"type": "double",
|
"type": "double",
|
||||||
"unit": "KiloWattHour",
|
"unit": "KiloWattHour",
|
||||||
"defaultValue": 0
|
"defaultValue": 0
|
||||||
@ -190,6 +254,33 @@
|
|||||||
"type": "double",
|
"type": "double",
|
||||||
"unit": "KiloWattHour",
|
"unit": "KiloWattHour",
|
||||||
"defaultValue": 0
|
"defaultValue": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "96b2d176-6460-4109-8824-3af4679c6573",
|
||||||
|
"name": "outputX2",
|
||||||
|
"displayName": "Output X2",
|
||||||
|
"displayNameEvent": "Output X2 changed",
|
||||||
|
"displayNameAction": "Set output X2",
|
||||||
|
"type": "bool",
|
||||||
|
"writable": true,
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ba600276-8b36-4404-b8ec-415245e5bc15",
|
||||||
|
"name": "input",
|
||||||
|
"displayName": "Input",
|
||||||
|
"displayNameEvent": "Input changed",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3421ecf9-c95f-4dc1-ad0c-144e9b6ae056",
|
||||||
|
"name": "uptime",
|
||||||
|
"displayName": "Uptime",
|
||||||
|
"displayNameEvent": "Uptime changed",
|
||||||
|
"type": "int",
|
||||||
|
"unit": "Seconds",
|
||||||
|
"defaultValue": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"actionTypes": [
|
"actionTypes": [
|
||||||
|
|||||||
@ -42,7 +42,7 @@ KeContact::KeContact(QHostAddress address, QObject *parent) :
|
|||||||
m_requestTimeoutTimer->setSingleShot(true);
|
m_requestTimeoutTimer->setSingleShot(true);
|
||||||
connect(m_requestTimeoutTimer, &QTimer::timeout, this, [this] {
|
connect(m_requestTimeoutTimer, &QTimer::timeout, this, [this] {
|
||||||
//This timer will be started when a request is sent and stopped or resetted when a response has been received
|
//This timer will be started when a request is sent and stopped or resetted when a response has been received
|
||||||
emit connectionChanged(false);
|
emit reachableChanged(false);
|
||||||
//Try to send the next command
|
//Try to send the next command
|
||||||
handleNextCommandInQueue();
|
handleNextCommandInQueue();
|
||||||
m_deviceBlocked = false;
|
m_deviceBlocked = false;
|
||||||
@ -72,18 +72,52 @@ QHostAddress KeContact::address()
|
|||||||
return m_address;
|
return m_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUuid KeContact::start(const QByteArray &rfidToken, const QByteArray &rfidClassifier)
|
||||||
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
|
m_pendingRequests.append(requestId);
|
||||||
|
QByteArray datagram = "start "+rfidToken + " " + rfidClassifier;
|
||||||
|
qCDebug(dcKebaKeContact()) << "Datagram : " << datagram;
|
||||||
|
sendCommand(datagram, requestId);;
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid KeContact::stop(const QByteArray &rfidToken)
|
||||||
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
|
m_pendingRequests.append(requestId);
|
||||||
|
QByteArray datagram = "stop "+rfidToken;
|
||||||
|
qCDebug(dcKebaKeContact()) << "Datagram : " << datagram;
|
||||||
|
sendCommand(datagram, requestId);
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
void KeContact::setAddress(QHostAddress address)
|
void KeContact::setAddress(QHostAddress address)
|
||||||
{
|
{
|
||||||
m_address = address;
|
m_address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KeContact::sendCommand(const QByteArray &command, const QUuid &requestId)
|
||||||
|
{
|
||||||
|
QTimer::singleShot(5000, this, [requestId, this] {
|
||||||
|
if (m_pendingRequests.contains(requestId)) {
|
||||||
|
m_pendingRequests.removeOne(requestId);
|
||||||
|
emit commandExecuted(requestId, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sendCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
void KeContact::sendCommand(const QByteArray &command)
|
void KeContact::sendCommand(const QByteArray &command)
|
||||||
{
|
{
|
||||||
if (!m_udpSocket) {
|
if (!m_udpSocket) {
|
||||||
qCWarning(dcKebaKeContact()) << "UDP socket not initialized";
|
qCWarning(dcKebaKeContact()) << "UDP socket not initialized";
|
||||||
emit connectionChanged(false);
|
emit reachableChanged(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_deviceBlocked) {
|
if(m_deviceBlocked) {
|
||||||
//add command to queue
|
//add command to queue
|
||||||
m_commandList.append(command);
|
m_commandList.append(command);
|
||||||
@ -99,7 +133,10 @@ void KeContact::handleNextCommandInQueue()
|
|||||||
{
|
{
|
||||||
if (!m_udpSocket) {
|
if (!m_udpSocket) {
|
||||||
qCWarning(dcKebaKeContact()) << "UDP socket not initialized";
|
qCWarning(dcKebaKeContact()) << "UDP socket not initialized";
|
||||||
emit connectionChanged(false);
|
if (m_reachable == true) {
|
||||||
|
m_reachable = false;
|
||||||
|
emit reachableChanged(false);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qCDebug(dcKebaKeContact()) << "Handle Command Queue- Pending commands" << m_commandList.length() << "Pending requestIds" << m_pendingRequests.length();
|
qCDebug(dcKebaKeContact()) << "Handle Command Queue- Pending commands" << m_commandList.length() << "Pending requestIds" << m_pendingRequests.length();
|
||||||
@ -125,13 +162,7 @@ QUuid KeContact::enableOutput(bool state)
|
|||||||
datagram.append("ena 0");
|
datagram.append("ena 0");
|
||||||
}
|
}
|
||||||
qCDebug(dcKebaKeContact()) << "Datagram : " << datagram;
|
qCDebug(dcKebaKeContact()) << "Datagram : " << datagram;
|
||||||
sendCommand(datagram);
|
sendCommand(datagram, requestId);
|
||||||
QTimer::singleShot(5000, this, [requestId, this] {
|
|
||||||
if (m_pendingRequests.contains(requestId)) {
|
|
||||||
m_pendingRequests.removeOne(requestId);
|
|
||||||
emit commandExecuted(requestId, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return requestId;
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,12 +174,8 @@ QUuid KeContact::setMaxAmpere(int milliAmpere)
|
|||||||
qCDebug(dcKebaKeContact()) << "Update max current to : " << milliAmpere;
|
qCDebug(dcKebaKeContact()) << "Update max current to : " << milliAmpere;
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
data.append("curr " + QVariant(milliAmpere).toByteArray());
|
data.append("curr " + QVariant(milliAmpere).toByteArray());
|
||||||
qCDebug(dcKebaKeContact()) << "send command: " << data;
|
qCDebug(dcKebaKeContact()) << "sSnd command: " << data;
|
||||||
sendCommand(data);
|
sendCommand(data, requestId);
|
||||||
if (m_pendingRequests.contains(requestId)) {
|
|
||||||
m_pendingRequests.removeOne(requestId);
|
|
||||||
emit commandExecuted(requestId, false);
|
|
||||||
}
|
|
||||||
return requestId;
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,12 +196,35 @@ QUuid KeContact::displayMessage(const QByteArray &message)
|
|||||||
modifiedMessage.resize(23);
|
modifiedMessage.resize(23);
|
||||||
}
|
}
|
||||||
data.append("display 0 0 0 0 " + modifiedMessage);
|
data.append("display 0 0 0 0 " + modifiedMessage);
|
||||||
qCDebug(dcKebaKeContact()) << "send command: " << data;
|
qCDebug(dcKebaKeContact()) << "Send command: " << data;
|
||||||
sendCommand(data);
|
sendCommand(data, requestId);
|
||||||
if (m_pendingRequests.contains(requestId)) {
|
return requestId;
|
||||||
m_pendingRequests.removeOne(requestId);
|
|
||||||
emit commandExecuted(requestId, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUuid KeContact::chargeWithEnergyLimit(double energy)
|
||||||
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
|
m_pendingRequests.append(requestId);
|
||||||
|
|
||||||
|
QByteArray data;
|
||||||
|
data.append("setenergy " + QVariant(static_cast<int>(energy*10000)).toByteArray());
|
||||||
|
qCDebug(dcKebaKeContact()) << "Send command: " << data;
|
||||||
|
sendCommand(data, requestId);
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid KeContact::setFailsafe(int timeout, int current, bool save)
|
||||||
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
|
m_pendingRequests.append(requestId);
|
||||||
|
|
||||||
|
QByteArray data;
|
||||||
|
data.append("failsave");
|
||||||
|
data.append(" "+QVariant(timeout).toByteArray());
|
||||||
|
data.append(" "+QVariant(current).toByteArray());
|
||||||
|
data.append((save ? " 1":" 0"));
|
||||||
|
qCDebug(dcKebaKeContact()) << "Send command: " << data;
|
||||||
|
sendCommand(data, requestId);
|
||||||
return requestId;
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +287,10 @@ void KeContact::readPendingDatagrams()
|
|||||||
//Only process data from the target device
|
//Only process data from the target device
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
emit connectionChanged(true);
|
if (m_reachable != true) {
|
||||||
|
m_reachable = true;
|
||||||
|
emit reachableChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
qCDebug(dcKebaKeContact()) << "Data received" << datagram;
|
qCDebug(dcKebaKeContact()) << "Data received" << datagram;
|
||||||
if(datagram.contains("TCH-OK")){
|
if(datagram.contains("TCH-OK")){
|
||||||
@ -306,12 +359,12 @@ void KeContact::readPendingDatagrams()
|
|||||||
reportTwo.plugState = PlugState(data.value("Plug").toInt());
|
reportTwo.plugState = PlugState(data.value("Plug").toInt());
|
||||||
reportTwo.enableUser = data.value("Enable user").toBool();
|
reportTwo.enableUser = data.value("Enable user").toBool();
|
||||||
reportTwo.enableSys = data.value("Enable sys").toBool();
|
reportTwo.enableSys = data.value("Enable sys").toBool();
|
||||||
reportTwo.MaxCurrent = data.value("Max curr").toInt()/1000;
|
reportTwo.maxCurrent = data.value("Max curr").toInt()/1000;
|
||||||
reportTwo.MaxCurrentPercentage = data.value("Max curr %").toInt()/10;
|
reportTwo.maxCurrentPercentage = data.value("Max curr %").toInt()/10;
|
||||||
reportTwo.CurrentHardwareLimitation = data.value("Curr HW").toInt()/1000;
|
reportTwo.currentHardwareLimitation = data.value("Curr HW").toInt()/1000;
|
||||||
reportTwo.CurrentUser = data.value("Curr user").toInt();
|
reportTwo.currentUser = data.value("Curr user").toInt();
|
||||||
reportTwo.CurrFS = data.value("Curr FS").toInt();
|
reportTwo.currentFailsafe = data.value("Curr FS").toInt();
|
||||||
reportTwo.TmoFS = data.value("Tmo FS").toInt();
|
reportTwo.timeoutFailsafe = data.value("Tmo FS").toInt();
|
||||||
reportTwo.output = data.value("Output").toInt();
|
reportTwo.output = data.value("Output").toInt();
|
||||||
reportTwo.input= data.value("Input").toInt();
|
reportTwo.input= data.value("Input").toInt();
|
||||||
reportTwo.serialNumber = data.value("Serial").toString();
|
reportTwo.serialNumber = data.value("Serial").toString();
|
||||||
|
|||||||
@ -46,6 +46,14 @@ public:
|
|||||||
~KeContact();
|
~KeContact();
|
||||||
bool init();
|
bool init();
|
||||||
|
|
||||||
|
enum Model {
|
||||||
|
ModelUnkown,
|
||||||
|
ModelP20,
|
||||||
|
ModelP30,
|
||||||
|
ModelBMW
|
||||||
|
};
|
||||||
|
Q_ENUM(Model)
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
StateStarting = 0,
|
StateStarting = 0,
|
||||||
StateNotReady,
|
StateNotReady,
|
||||||
@ -54,6 +62,7 @@ public:
|
|||||||
StateError,
|
StateError,
|
||||||
StateAuthorizationRejected
|
StateAuthorizationRejected
|
||||||
};
|
};
|
||||||
|
Q_ENUM(State)
|
||||||
|
|
||||||
enum PlugState {
|
enum PlugState {
|
||||||
PlugStateUnplugged = 0,
|
PlugStateUnplugged = 0,
|
||||||
@ -62,6 +71,7 @@ public:
|
|||||||
PlugStatePluggedOnChargingStationAndPluggedOnEV = 5,
|
PlugStatePluggedOnChargingStationAndPluggedOnEV = 5,
|
||||||
PlugStatePluggedOnChargingStationAndPlugLockedAndPluggedOnEV = 7
|
PlugStatePluggedOnChargingStationAndPlugLockedAndPluggedOnEV = 7
|
||||||
};
|
};
|
||||||
|
Q_ENUM(PlugState)
|
||||||
|
|
||||||
enum BroadcastType {
|
enum BroadcastType {
|
||||||
BroadcastTypeState = 0,
|
BroadcastTypeState = 0,
|
||||||
@ -73,9 +83,11 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ReportOne {
|
struct ReportOne {
|
||||||
QString product;
|
QString product; // Model name (variant
|
||||||
QString serialNumber;
|
QString serialNumber; // Serial number
|
||||||
QString firmware;
|
QString firmware; // Firmware version
|
||||||
|
bool comModule; // Communication module is installed (only P30)
|
||||||
|
int seconds; // Current system clock since restart of the charging station.(only P30)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ReportTwo {
|
struct ReportTwo {
|
||||||
@ -85,15 +97,18 @@ public:
|
|||||||
PlugState plugState; //Current condition of the loading connection
|
PlugState plugState; //Current condition of the loading connection
|
||||||
bool enableSys; //Enable state for charging (contains Enable input, RFID, UDP,..).
|
bool enableSys; //Enable state for charging (contains Enable input, RFID, UDP,..).
|
||||||
bool enableUser; //Enable condition via UDP.
|
bool enableUser; //Enable condition via UDP.
|
||||||
int MaxCurrent; //Current preset value via Control pilot in milliampere.
|
int maxCurrent; //Current preset value via Control pilot in milliampere.
|
||||||
int MaxCurrentPercentage; //Current preset value via Control pilot in 0,1% of the PWM value
|
int maxCurrentPercentage; //Current preset value via Control pilot in 0,1% of the PWM value
|
||||||
int CurrentHardwareLimitation; //Highest possible charging current of the charging connection. Contains device maximum, DIP-switch setting, cable coding and temperature reduction.
|
int currentHardwareLimitation; //Highest possible charging current of the charging connection. Contains device maximum, DIP-switch setting, cable coding and temperature reduction.
|
||||||
int CurrentUser; //Current preset value of the user via UDP; Default = 63000mA.
|
int currentUser; //Current preset value of the user via UDP; Default = 63000mA.
|
||||||
int CurrFS; //Current preset value for the Failsafe function.
|
int currentFailsafe; //Current preset value for the Failsafe function.
|
||||||
int TmoFS; //Communication timeout before triggering the Failsafe function.
|
int timeoutFailsafe; //Communication timeout before triggering the Failsafe function.
|
||||||
|
int currTimer; //Shows the current preset value of currtime.
|
||||||
|
int timeoutCt; //Shows the remaining time until the current value is accepted.
|
||||||
|
int setEnergy; //Shows the set energy limit
|
||||||
bool output; //State of the output X2.
|
bool output; //State of the output X2.
|
||||||
bool input; //State of the potential free Enable input X1. When using the input, please pay attention to the information in the installation manual.
|
bool input; //State of the potential free Enable input X1. When using the input, please pay attention to the information in the installation manual.
|
||||||
QString serialNumber; //
|
QString serialNumber; //Serial number
|
||||||
int seconds; //Current system clock since restart of the charging station.
|
int seconds; //Current system clock since restart of the charging station.
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -112,21 +127,34 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
QHostAddress address();
|
QHostAddress address();
|
||||||
int serialNumber();
|
void setAddress(const QHostAddress &address);
|
||||||
|
|
||||||
void setAddress(QHostAddress address);
|
bool reachable();
|
||||||
|
|
||||||
QUuid enableOutput(bool state);
|
QUuid start(const QByteArray &rfidToken, const QByteArray &rfidClassifier); // Command “start”
|
||||||
QUuid setMaxAmpere(int milliAmpere);
|
QUuid stop(const QByteArray &rfidToken); // Command “stop”
|
||||||
QUuid unlockCharger();
|
|
||||||
QUuid displayMessage(const QByteArray &message);
|
|
||||||
|
|
||||||
void getDeviceInformation();
|
QUuid enableOutput(bool state); // Command “ena”
|
||||||
void getReport1();
|
QUuid setMaxAmpere(int milliAmpere); // Command “curr”
|
||||||
|
QUuid unlockCharger(); // Command “unlock"
|
||||||
|
QUuid displayMessage(const QByteArray &message); // Command “display”
|
||||||
|
QUuid chargeWithEnergyLimit(double energy); // Command “setenergy”
|
||||||
|
QUuid setFailsafe(int timeout, int current, bool save); // Command “failsafe”
|
||||||
|
|
||||||
|
void getDeviceInformation(); // Command “i”
|
||||||
|
void getReport1(); // Command “report”
|
||||||
void getReport2();
|
void getReport2();
|
||||||
void getReport3();
|
void getReport3();
|
||||||
|
|
||||||
|
// Command “report 1xx”
|
||||||
|
|
||||||
|
// Command “currtime”
|
||||||
|
// Command “output”
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool m_reachable = false;
|
||||||
QUdpSocket *m_udpSocket = nullptr;
|
QUdpSocket *m_udpSocket = nullptr;
|
||||||
QHostAddress m_address;
|
QHostAddress m_address;
|
||||||
QByteArrayList m_commandList;
|
QByteArrayList m_commandList;
|
||||||
@ -136,11 +164,13 @@ private:
|
|||||||
int m_serialNumber;
|
int m_serialNumber;
|
||||||
QList<QUuid> m_pendingRequests;
|
QList<QUuid> m_pendingRequests;
|
||||||
|
|
||||||
|
|
||||||
|
void sendCommand(const QByteArray &data, const QUuid &requestId);
|
||||||
void sendCommand(const QByteArray &data);
|
void sendCommand(const QByteArray &data);
|
||||||
void handleNextCommandInQueue();
|
void handleNextCommandInQueue();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void connectionChanged(bool status);
|
void reachableChanged(bool status);
|
||||||
void commandExecuted(QUuid requestId, bool success);
|
void commandExecuted(QUuid requestId, bool success);
|
||||||
void deviceInformationReceived(const QString &firmware);
|
void deviceInformationReceived(const QString &firmware);
|
||||||
void reportOneReceived(const ReportOne &reportOne);
|
void reportOneReceived(const ReportOne &reportOne);
|
||||||
@ -151,7 +181,5 @@ signals:
|
|||||||
private slots:
|
private slots:
|
||||||
void readPendingDatagrams();
|
void readPendingDatagrams();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // KECONTACT_H
|
#endif // KECONTACT_H
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user