Implement thing evse mapping and add init mechanism for charger things
parent
c4b8a9a77e
commit
09200b2da1
|
|
@ -5,6 +5,7 @@ PKGCONFIG += nymea-mqtt
|
|||
|
||||
SOURCES += \
|
||||
jsonrpc/everestconnection.cpp \
|
||||
jsonrpc/everestevse.cpp \
|
||||
jsonrpc/everestjsonrpcclient.cpp \
|
||||
jsonrpc/everestjsonrpcdiscovery.cpp \
|
||||
jsonrpc/everestjsonrpcinterface.cpp \
|
||||
|
|
@ -16,6 +17,7 @@ SOURCES += \
|
|||
|
||||
HEADERS += \
|
||||
jsonrpc/everestconnection.h \
|
||||
jsonrpc/everestevse.h \
|
||||
jsonrpc/everestjsonrpcclient.h \
|
||||
jsonrpc/everestjsonrpcdiscovery.h \
|
||||
jsonrpc/everestjsonrpcinterface.h \
|
||||
|
|
|
|||
|
|
@ -346,6 +346,7 @@ void IntegrationPluginEverest::setupThing(ThingSetupInfo *info)
|
|||
ThingDescriptors descriptors;
|
||||
qCDebug(dcEverest()) << "The client is now available, synching things...";
|
||||
foreach (const EverestJsonRpcClient::EVSEInfo &evseInfo, connection->client()->evseInfos()) {
|
||||
|
||||
// FIXME: somehow we need to now if this evse is AC or DC in order to spawn the right child thingclass.
|
||||
|
||||
// Check if we already have a child device for this index
|
||||
|
|
@ -391,14 +392,9 @@ void IntegrationPluginEverest::setupThing(ThingSetupInfo *info)
|
|||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
|
||||
thing->setStateValue(everestChargerAcConnectedStateTypeId, connection->available());
|
||||
connection->addThing(thing);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void IntegrationPluginEverest::postSetupThing(Thing *thing)
|
||||
{
|
||||
Q_UNUSED(thing)
|
||||
}
|
||||
|
||||
void IntegrationPluginEverest::executeAction(ThingActionInfo *info)
|
||||
|
|
@ -454,8 +450,32 @@ void IntegrationPluginEverest::executeAction(ThingActionInfo *info)
|
|||
}
|
||||
|
||||
return;
|
||||
} else if (info->thing()->thingClassId() == everestChargerAcThingClassId) {
|
||||
Thing *thing = info->thing();
|
||||
Thing *parentThing = myThings().findById(thing->parentId());
|
||||
EverestConnection *connection = m_everstConnections.value(parentThing);
|
||||
if (!connection) {
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!thing->stateValue(everestChargerAcConnectedStateTypeId).toBool()) {
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
|
||||
EverestEvse *evse = connection->getEvse(thing);
|
||||
if (!evse) {
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ public:
|
|||
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||
|
||||
void setupThing(ThingSetupInfo *info) override;
|
||||
void postSetupThing(Thing *thing) override;
|
||||
void thingRemoved(Thing *thing) override;
|
||||
|
||||
void executeAction(ThingActionInfo *info) override;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@
|
|||
|
||||
#include "everestconnection.h"
|
||||
#include "extern-plugininfo.h"
|
||||
#include "jsonrpc/everestjsonrpcclient.h"
|
||||
#include "everestevse.h"
|
||||
#include "everestjsonrpcclient.h"
|
||||
|
||||
EverestConnection::EverestConnection(quint16 port, QObject *parent)
|
||||
: QObject{parent},
|
||||
|
|
@ -53,10 +54,9 @@ EverestConnection::EverestConnection(quint16 port, QObject *parent)
|
|||
}
|
||||
});
|
||||
|
||||
// Reconnect timer is only required for IP based connections, otherwise we have the NetworkDeviceMonitor
|
||||
// Reconnect timer in case the network device is reachable but the websocketserver not yet
|
||||
m_reconnectTimer.setInterval(5000);
|
||||
m_reconnectTimer.setSingleShot(false);
|
||||
|
||||
connect(&m_reconnectTimer, &QTimer::timeout, this, [this](){
|
||||
if (m_client->available())
|
||||
return;
|
||||
|
|
@ -80,19 +80,22 @@ EverestJsonRpcClient *EverestConnection::client() const
|
|||
return m_client;
|
||||
}
|
||||
|
||||
Things EverestConnection::things() const
|
||||
EverestEvse *EverestConnection::getEvse(Thing *thing)
|
||||
{
|
||||
return Things();
|
||||
return m_everestEvses.value(thing);
|
||||
}
|
||||
|
||||
void EverestConnection::addThing(Thing *thing)
|
||||
{
|
||||
Q_UNUSED(thing)
|
||||
qCDebug(dcEverest()) << "Adding thing" << thing->name() << "to connection" << m_client->serverUrl().toString();
|
||||
EverestEvse *evse = new EverestEvse(m_client, thing);
|
||||
m_everestEvses.insert(thing, evse);
|
||||
}
|
||||
|
||||
void EverestConnection::removeThing(Thing *thing)
|
||||
{
|
||||
Q_UNUSED(thing)
|
||||
qCDebug(dcEverest()) << "Remove thing" << thing->name() << "from connection" << m_client->serverUrl().toString();
|
||||
m_everestEvses.take(thing)->deleteLater();
|
||||
}
|
||||
|
||||
NetworkDeviceMonitor *EverestConnection::monitor() const
|
||||
|
|
@ -119,14 +122,14 @@ void EverestConnection::start()
|
|||
if (m_monitor) {
|
||||
if (m_monitor->reachable()) {
|
||||
QUrl url = buildUrl();
|
||||
qCDebug(dcEverest()) << "Connecting JsonRpc client to" << url.toString();
|
||||
qCDebug(dcEverest()) << "Connecting" << this;
|
||||
if (m_client->available())
|
||||
m_client->disconnectFromServer();
|
||||
|
||||
m_client->connectToServer(url);
|
||||
}
|
||||
} else {
|
||||
qCDebug(dcEverest()) << "Connecting MQTT client to" << m_monitor->networkDeviceInfo().address().toString();
|
||||
qCDebug(dcEverest()) << "Connecting" << this;
|
||||
m_client->connectToServer(buildUrl());
|
||||
|
||||
// Note: on connected this will be stopped, otherwise we want the timer running
|
||||
|
|
@ -172,3 +175,10 @@ QUrl EverestConnection::buildUrl() const
|
|||
url.setPort(m_port);
|
||||
return url;
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, EverestConnection *connection)
|
||||
{
|
||||
QDebugStateSaver saver(debug);
|
||||
debug.noquote().nospace() << "EverestConnection(" << connection->client()->serverUrl().toString() << ")";
|
||||
return debug;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <network/macaddress.h>
|
||||
#include <network/networkdevicemonitor.h>
|
||||
|
||||
class EverestEvse;
|
||||
class EverestJsonRpcClient;
|
||||
|
||||
class EverestConnection : public QObject
|
||||
|
|
@ -50,7 +51,7 @@ public:
|
|||
|
||||
EverestJsonRpcClient *client() const;
|
||||
|
||||
Things things() const;
|
||||
EverestEvse *getEvse(Thing *thing);
|
||||
|
||||
void addThing(Thing *thing);
|
||||
void removeThing(Thing *thing);
|
||||
|
|
@ -76,7 +77,10 @@ private:
|
|||
EverestJsonRpcClient *m_client = nullptr;
|
||||
bool m_running = false;
|
||||
|
||||
QHash<Thing *, EverestEvse *> m_everestEvses;
|
||||
QUrl buildUrl() const;
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, EverestConnection *connection);
|
||||
|
||||
#endif // EVERESTCONNECTION_H
|
||||
|
|
|
|||
|
|
@ -0,0 +1,189 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2025, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by
|
||||
* copyright law, and remains the property of nymea GmbH. All rights, including
|
||||
* reproduction, publication, editing and translation, are reserved. The use of
|
||||
* this project is subject to the terms of a license agreement to be concluded
|
||||
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
||||
* under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; version 3. This project is distributed in the hope that
|
||||
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this project. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under
|
||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
||||
* https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "everestevse.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
EverestEvse::EverestEvse(EverestJsonRpcClient *client, Thing *thing, QObject *parent)
|
||||
: QObject{parent},
|
||||
m_client{client},
|
||||
m_thing{thing}
|
||||
{
|
||||
m_index = thing->paramValue("index").toInt();
|
||||
|
||||
connect(m_client, &EverestJsonRpcClient::availableChanged, this, [this](bool available){
|
||||
if (available) {
|
||||
qCDebug(dcEverest()) << "Evse: The connection is now available";
|
||||
initialize();
|
||||
} else {
|
||||
qCDebug(dcEverest()) << "Evse: The connection is not available any more.";
|
||||
m_initialized = false;
|
||||
m_thing->setStateValue("connected", false);
|
||||
}
|
||||
});
|
||||
|
||||
if (m_client->available()) {
|
||||
qCDebug(dcEverest()) << "Evse: The connection is already available. Initializing the instance...";
|
||||
}
|
||||
}
|
||||
|
||||
int EverestEvse::index() const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
|
||||
void EverestEvse::initialize()
|
||||
{
|
||||
qCDebug(dcEverest()) << "Evse: Initializing data for" << m_thing->name();
|
||||
|
||||
// Fetch all initial data for this device, once done we get notifications on data changes
|
||||
|
||||
EverestJsonRpcReply *reply = nullptr;
|
||||
|
||||
reply = m_client->evseGetInfo(m_index);
|
||||
m_pendingInitReplies.append(reply);
|
||||
connect(reply, &EverestJsonRpcReply::finished, reply, &EverestJsonRpcReply::deleteLater);
|
||||
connect(reply, &EverestJsonRpcReply::finished, this, [this, reply](){
|
||||
qCDebug(dcEverest()) << "Evse: Reply finished" << m_client->serverUrl().toString() << reply->method();
|
||||
if (reply->error()) {
|
||||
qCWarning(dcEverest()) << "Evse: JsonRpc reply finished with error" << reply->method() << reply->method() << reply->error();
|
||||
// FIXME: check what we do if an init call failes. Do we stay disconnected and show an error or do we ignore it...
|
||||
} else {
|
||||
QVariantMap result = reply->response().value("result").toMap();
|
||||
EverestJsonRpcClient::ResponseError error = EverestJsonRpcClient::parseResponseError(result.value("error").toString());
|
||||
if (error) {
|
||||
qCWarning(dcEverest()) << "Evse: Reply finished with an error" << reply->method() << error;
|
||||
// FIXME: check what we do if an init call failes. Do we stay disconnected and show an error or do we ignore it...
|
||||
} else {
|
||||
// No error, store the data
|
||||
m_evseInfo = EverestJsonRpcClient::parseEvseInfo(result.value("info").toMap());
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are done with the init process of this EVSE
|
||||
evaluateInitFinished(reply);
|
||||
});
|
||||
|
||||
reply = m_client->evseGetHardwareCapabilities(m_index);
|
||||
m_pendingInitReplies.append(reply);
|
||||
connect(reply, &EverestJsonRpcReply::finished, reply, &EverestJsonRpcReply::deleteLater);
|
||||
connect(reply, &EverestJsonRpcReply::finished, this, [this, reply](){
|
||||
qCDebug(dcEverest()) << "Evse: Reply finished" << m_client->serverUrl().toString() << reply->method();
|
||||
if (reply->error()) {
|
||||
qCWarning(dcEverest()) << "Evse: JsonRpc reply finished with error" << reply->method() << reply->method() << reply->error();
|
||||
// FIXME: check what we do if an init call failes. Do we stay disconnected and show an error or do we ignore it...
|
||||
} else {
|
||||
QVariantMap result = reply->response().value("result").toMap();
|
||||
EverestJsonRpcClient::ResponseError error = EverestJsonRpcClient::parseResponseError(result.value("error").toString());
|
||||
if (error) {
|
||||
qCWarning(dcEverest()) << "Evse: Reply finished with an error" << reply->method() << error;
|
||||
// FIXME: check what we do if an init call failes. Do we stay disconnected and show an error or do we ignore it...
|
||||
} else {
|
||||
// No error, store the data
|
||||
m_hardwareCapabilities = EverestJsonRpcClient::parseHardwareCapabilities(result.value("hardware_capabilities").toMap());
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are done with the init process of this EVSE
|
||||
evaluateInitFinished(reply);
|
||||
});
|
||||
|
||||
reply = m_client->evseGetStatus(m_index);
|
||||
m_pendingInitReplies.append(reply);
|
||||
connect(reply, &EverestJsonRpcReply::finished, reply, &EverestJsonRpcReply::deleteLater);
|
||||
connect(reply, &EverestJsonRpcReply::finished, this, [this, reply](){
|
||||
qCDebug(dcEverest()) << "Evse: Reply finished" << m_client->serverUrl().toString() << reply->method();
|
||||
if (reply->error()) {
|
||||
qCWarning(dcEverest()) << "Evse: JsonRpc reply finished with error" << reply->method() << reply->method() << reply->error();
|
||||
// FIXME: check what we do if an init call failes. Do we stay disconnected and show an error or do we ignore it...
|
||||
} else {
|
||||
QVariantMap result = reply->response().value("result").toMap();
|
||||
EverestJsonRpcClient::ResponseError error = EverestJsonRpcClient::parseResponseError(result.value("error").toString());
|
||||
if (error) {
|
||||
qCWarning(dcEverest()) << "Evse: Reply finished with an error" << reply->method() << error;
|
||||
// FIXME: check what we do if an init call failes. Do we stay disconnected and show an error or do we ignore it...
|
||||
} else {
|
||||
// No error, store the data
|
||||
m_evseStatus = EverestJsonRpcClient::parseEvseStatus(result.value("status").toMap());
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are done with the init process of this EVSE
|
||||
evaluateInitFinished(reply);
|
||||
});
|
||||
}
|
||||
|
||||
void EverestEvse::evaluateInitFinished(EverestJsonRpcReply *reply)
|
||||
{
|
||||
if (m_initialized)
|
||||
return;
|
||||
|
||||
m_pendingInitReplies.removeAll(reply);
|
||||
|
||||
if (m_pendingInitReplies.isEmpty()) {
|
||||
qCDebug(dcEverest()) << "Evse: The initialization of" << m_thing->name() << "has finished, the charger is now connected.";
|
||||
m_initialized = true;
|
||||
|
||||
// Set all initial states
|
||||
m_thing->setStateValue("connected", true);
|
||||
|
||||
processEvseStatus();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EverestEvse::processEvseStatus()
|
||||
{
|
||||
if (m_thing->thingClassId() == everestChargerAcThingClassId) {
|
||||
m_thing->setStateValue(everestChargerAcStateStateTypeId, m_evseStatus.evseStateString);
|
||||
m_thing->setStateValue(everestChargerAcChargingStateTypeId, m_evseStatus.evseState == EverestJsonRpcClient::EvseStateCharging);
|
||||
m_thing->setStateValue(everestChargerAcPluggedInStateTypeId, m_evseStatus.evseState != EverestJsonRpcClient::EvseStateUnplugged);
|
||||
// TODO: check what we do it available is false, shall we disconnect the thing or introduce a new state
|
||||
}
|
||||
}
|
||||
|
||||
void EverestEvse::processHardwareCapabilities()
|
||||
{
|
||||
if (m_thing->thingClassId() == everestChargerAcThingClassId) {
|
||||
if (!m_hardwareCapabilities.phaseSwitchDuringCharging) {
|
||||
// Only option left is set the desired phase count to 3, force that value
|
||||
m_thing->setStatePossibleValues(everestChargerAcDesiredPhaseCountStateTypeId, { 3 });
|
||||
m_thing->setStateValue(everestChargerAcDesiredPhaseCountStateTypeId, 3);
|
||||
m_thing->setStateValue(everestChargerAcPhaseCountStateTypeId, 3);
|
||||
} else {
|
||||
m_thing->setStatePossibleValues(everestChargerAcDesiredPhaseCountStateTypeId, { 1, 3 });
|
||||
m_thing->setStateValue(everestChargerAcPhaseCountStateTypeId, m_thing->stateValue(everestChargerAcDesiredPhaseCountStateTypeId));
|
||||
}
|
||||
|
||||
m_thing->setStateMaxValue(everestChargerAcMaxChargingCurrentStateTypeId, m_hardwareCapabilities.maxCurrentImport);
|
||||
m_thing->setStateMinValue(everestChargerAcMaxChargingCurrentStateTypeId, m_hardwareCapabilities.minCurrentImport == 0 ? 6 : m_hardwareCapabilities.minCurrentImport);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2025, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by
|
||||
* copyright law, and remains the property of nymea GmbH. All rights, including
|
||||
* reproduction, publication, editing and translation, are reserved. The use of
|
||||
* this project is subject to the terms of a license agreement to be concluded
|
||||
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
||||
* under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; version 3. This project is distributed in the hope that
|
||||
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this project. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under
|
||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
||||
* https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef EVERESTEVSE_H
|
||||
#define EVERESTEVSE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "jsonrpc/everestjsonrpcclient.h"
|
||||
|
||||
class EverestEvse : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit EverestEvse(EverestJsonRpcClient *client, Thing *thing, QObject *parent = nullptr);
|
||||
|
||||
int index() const;
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
EverestJsonRpcClient *m_client = nullptr;
|
||||
Thing *m_thing = nullptr;
|
||||
|
||||
int m_index = -1;
|
||||
bool m_initialized = false;
|
||||
|
||||
EverestJsonRpcClient::EVSEInfo m_evseInfo;
|
||||
EverestJsonRpcClient::EVSEStatus m_evseStatus;
|
||||
EverestJsonRpcClient::HardwareCapabilities m_hardwareCapabilities;
|
||||
|
||||
QVector<EverestJsonRpcReply *> m_pendingInitReplies;
|
||||
|
||||
void initialize();
|
||||
void evaluateInitFinished(EverestJsonRpcReply *reply);
|
||||
|
||||
void processEvseStatus();
|
||||
void processHardwareCapabilities();
|
||||
};
|
||||
|
||||
#endif // EVERESTEVSE_H
|
||||
|
|
@ -107,12 +107,16 @@ EverestJsonRpcClient::EverestJsonRpcClient(QObject *parent)
|
|||
m_evseInfos.append(parseEvseInfo(evseInfoVariant.toMap()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// We are done with the init and the client is now available
|
||||
if (!m_available) {
|
||||
m_available = true;
|
||||
emit availableChanged(m_available);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
} else {
|
||||
|
|
@ -161,26 +165,13 @@ EverestJsonRpcClient::ChargerInfo EverestJsonRpcClient::chargerInfo() const
|
|||
return m_chargerInfo;
|
||||
}
|
||||
|
||||
EverestJsonRpcReply *EverestJsonRpcClient::apiHello()
|
||||
EverestJsonRpcReply *EverestJsonRpcClient::evseGetInfo(int evseIndex)
|
||||
{
|
||||
EverestJsonRpcReply *reply = new EverestJsonRpcReply(m_commandId, "API.Hello", QVariantMap(), this);
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method();
|
||||
sendRequest(reply);
|
||||
return reply;
|
||||
}
|
||||
QVariantMap params;
|
||||
params.insert("evse_index", evseIndex);
|
||||
|
||||
EverestJsonRpcReply *EverestJsonRpcClient::chargePointGetEVSEInfos()
|
||||
{
|
||||
EverestJsonRpcReply *reply = new EverestJsonRpcReply(m_commandId, "ChargePoint.GetEVSEInfos", QVariantMap(), this);
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method();
|
||||
sendRequest(reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
EverestJsonRpcReply *EverestJsonRpcClient::evseGetInfo()
|
||||
{
|
||||
EverestJsonRpcReply *reply = new EverestJsonRpcReply(m_commandId, "EVSE.GetInfo", QVariantMap(), this);
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method();
|
||||
EverestJsonRpcReply *reply = new EverestJsonRpcReply(m_commandId, "EVSE.GetInfo", params, this);
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method() << params;
|
||||
sendRequest(reply);
|
||||
return reply;
|
||||
}
|
||||
|
|
@ -191,7 +182,7 @@ EverestJsonRpcReply *EverestJsonRpcClient::evseGetStatus(int evseIndex)
|
|||
params.insert("evse_index", evseIndex);
|
||||
|
||||
EverestJsonRpcReply *reply = new EverestJsonRpcReply(m_commandId, "EVSE.GetStatus", params, this);
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method();
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method() << params;
|
||||
sendRequest(reply);
|
||||
return reply;
|
||||
}
|
||||
|
|
@ -201,12 +192,112 @@ EverestJsonRpcReply *EverestJsonRpcClient::evseGetHardwareCapabilities(int evseI
|
|||
QVariantMap params;
|
||||
params.insert("evse_index", evseIndex);
|
||||
|
||||
EverestJsonRpcReply *reply = new EverestJsonRpcReply(m_commandId, "EVSE.GetStatus", params, this);
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method();
|
||||
EverestJsonRpcReply *reply = new EverestJsonRpcReply(m_commandId, "EVSE.GetHardwareCapabilities", params, this);
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method() << params;
|
||||
sendRequest(reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
EverestJsonRpcReply *EverestJsonRpcClient::evseGetMeterData(int evseIndex)
|
||||
{
|
||||
QVariantMap params;
|
||||
params.insert("evse_index", evseIndex);
|
||||
|
||||
EverestJsonRpcReply *reply = new EverestJsonRpcReply(m_commandId, "EVSE.GetMeterData", params, this);
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method() << params;
|
||||
sendRequest(reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
EverestJsonRpcReply *EverestJsonRpcClient::evseSetChargingAllowed(int evseIndex, bool allowed)
|
||||
{
|
||||
QVariantMap params;
|
||||
params.insert("evse_index", evseIndex);
|
||||
params.insert("charging_allowed", allowed);
|
||||
|
||||
EverestJsonRpcReply *reply = new EverestJsonRpcReply(m_commandId, "EVSE.SetChargingAllowed", params, this);
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method() << params;
|
||||
sendRequest(reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
EverestJsonRpcClient::ResponseError EverestJsonRpcClient::parseResponseError(const QString &responseErrorString)
|
||||
{
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<ResponseError>();
|
||||
return static_cast<ResponseError>(metaEnum.keyToValue(QString("ResponseError").append(responseErrorString).toUtf8()));
|
||||
}
|
||||
|
||||
EverestJsonRpcClient::ConnectorType EverestJsonRpcClient::parseConnectorType(const QString &connectorTypeString)
|
||||
{
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<ConnectorType>();
|
||||
return static_cast<ConnectorType>(metaEnum.keyToValue(QString("ConnectorType").append(connectorTypeString).toUtf8()));
|
||||
}
|
||||
|
||||
EverestJsonRpcClient::ChargeProtocol EverestJsonRpcClient::parseChargeProtocol(const QString &chargeProtocolString)
|
||||
{
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<ChargeProtocol>();
|
||||
return static_cast<ChargeProtocol>(metaEnum.keyToValue(QString("ChargeProtocol").append(chargeProtocolString).toUtf8()));
|
||||
}
|
||||
|
||||
EverestJsonRpcClient::EvseState EverestJsonRpcClient::parseEvseState(const QString &evseStateString)
|
||||
{
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<EvseState>();
|
||||
return static_cast<EvseState>(metaEnum.keyToValue(QString("EvseState").append(evseStateString).toUtf8()));
|
||||
}
|
||||
|
||||
EverestJsonRpcClient::EVSEInfo EverestJsonRpcClient::parseEvseInfo(const QVariantMap &evseInfoMap)
|
||||
{
|
||||
EVSEInfo evseInfo;
|
||||
evseInfo.index = evseInfoMap.value("index").toInt();
|
||||
evseInfo.id = evseInfoMap.value("id").toString();
|
||||
evseInfo.bidirectionalCharging = evseInfoMap.value("bidi_charging").toBool();
|
||||
foreach (const QVariant &connectorInfoVariant, evseInfoMap.value("available_connectors").toList()) {
|
||||
evseInfo.availableConnectors.append(parseConnectorInfo(connectorInfoVariant.toMap()));
|
||||
}
|
||||
return evseInfo;
|
||||
}
|
||||
|
||||
EverestJsonRpcClient::ConnectorInfo EverestJsonRpcClient::parseConnectorInfo(const QVariantMap &connectorInfoMap)
|
||||
{
|
||||
ConnectorInfo connectorInfo;
|
||||
connectorInfo.connectorId = connectorInfoMap.value("id").toInt();
|
||||
connectorInfo.type = parseConnectorType(connectorInfoMap.value("type").toString());
|
||||
connectorInfo.description = connectorInfoMap.value("description").toString();
|
||||
return connectorInfo;
|
||||
}
|
||||
|
||||
EverestJsonRpcClient::EVSEStatus EverestJsonRpcClient::parseEvseStatus(const QVariantMap &evseStatusMap)
|
||||
{
|
||||
EVSEStatus evseStatus;
|
||||
evseStatus.chargedEnergyWh = evseStatusMap.value("charged_energy_wh").toDouble();
|
||||
evseStatus.dischargedEnergyWh = evseStatusMap.value("discharged_energy_wh").toDouble();
|
||||
evseStatus.chargingDuration = evseStatusMap.value("charging_duration_s").toInt();
|
||||
evseStatus.chargingAllowed = evseStatusMap.value("charging_allowed").toBool();
|
||||
evseStatus.available = evseStatusMap.value("available").toBool();
|
||||
evseStatus.activeConnectorId = evseStatusMap.value("active_connector_id").toInt();
|
||||
evseStatus.evseError = evseStatusMap.value("evse_error").toString();
|
||||
evseStatus.chargeProtocol = parseChargeProtocol(evseStatusMap.value("charge_protocol").toString());
|
||||
evseStatus.evseState = parseEvseState(evseStatusMap.value("state").toString());
|
||||
evseStatus.evseStateString = evseStatusMap.value("state").toString();
|
||||
return evseStatus;
|
||||
}
|
||||
|
||||
EverestJsonRpcClient::HardwareCapabilities EverestJsonRpcClient::parseHardwareCapabilities(const QVariantMap &hardwareCapabilitiesMap)
|
||||
{
|
||||
HardwareCapabilities hardwareCapabilities;
|
||||
hardwareCapabilities.maxCurrentExport = hardwareCapabilitiesMap.value("max_current_A_export").toDouble();
|
||||
hardwareCapabilities.maxCurrentImport = hardwareCapabilitiesMap.value("max_current_A_import").toDouble();
|
||||
hardwareCapabilities.maxPhaseCountExport = hardwareCapabilitiesMap.value("max_phase_count_export").toInt();
|
||||
hardwareCapabilities.maxPhaseCountImport = hardwareCapabilitiesMap.value("max_phase_count_import").toInt();
|
||||
hardwareCapabilities.minCurrentExport = hardwareCapabilitiesMap.value("min_current_A_export").toDouble();
|
||||
hardwareCapabilities.minCurrentImport = hardwareCapabilitiesMap.value("min_current_A_import").toDouble();
|
||||
hardwareCapabilities.minPhaseCountExport = hardwareCapabilitiesMap.value("min_phase_count_export").toInt();
|
||||
hardwareCapabilities.minPhaseCountImport = hardwareCapabilitiesMap.value("min_phase_count_import").toInt();
|
||||
hardwareCapabilities.phaseSwitchDuringCharging = hardwareCapabilitiesMap.value("phase_switch_during_charging").toBool();
|
||||
return hardwareCapabilities;
|
||||
}
|
||||
|
||||
|
||||
void EverestJsonRpcClient::connectToServer(const QUrl &serverUrl)
|
||||
{
|
||||
m_interface->connectServer(serverUrl);
|
||||
|
|
@ -267,30 +358,18 @@ void EverestJsonRpcClient::processDataPacket(const QByteArray &data)
|
|||
}
|
||||
}
|
||||
|
||||
EverestJsonRpcClient::EVSEInfo EverestJsonRpcClient::parseEvseInfo(const QVariantMap &evseInfoMap)
|
||||
EverestJsonRpcReply *EverestJsonRpcClient::apiHello()
|
||||
{
|
||||
EVSEInfo evseInfo;
|
||||
evseInfo.index = evseInfoMap.value("index").toInt();
|
||||
evseInfo.id = evseInfoMap.value("id").toString();
|
||||
evseInfo.bidirectionalCharging = evseInfoMap.value("bidi_charging").toBool();
|
||||
foreach (const QVariant &connectorInfoVariant, evseInfoMap.value("available_connectors").toList()) {
|
||||
evseInfo.availableConnectors.append(parseConnectorInfo(connectorInfoVariant.toMap()));
|
||||
}
|
||||
return evseInfo;
|
||||
EverestJsonRpcReply *reply = new EverestJsonRpcReply(m_commandId, "API.Hello", QVariantMap(), this);
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method();
|
||||
sendRequest(reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
EverestJsonRpcClient::ConnectorInfo EverestJsonRpcClient::parseConnectorInfo(const QVariantMap &connectorInfoMap)
|
||||
EverestJsonRpcReply *EverestJsonRpcClient::chargePointGetEVSEInfos()
|
||||
{
|
||||
ConnectorInfo connectorInfo;
|
||||
connectorInfo.connectorId = connectorInfoMap.value("id").toInt();
|
||||
connectorInfo.type = parseConnectorType(connectorInfoMap.value("type").toString());
|
||||
connectorInfo.description = connectorInfoMap.value("description").toString();
|
||||
return connectorInfo;
|
||||
EverestJsonRpcReply *reply = new EverestJsonRpcReply(m_commandId, "ChargePoint.GetEVSEInfos", QVariantMap(), this);
|
||||
qCDebug(dcEverest()) << "Calling" << reply->method();
|
||||
sendRequest(reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
EverestJsonRpcClient::ConnectorType EverestJsonRpcClient::parseConnectorType(const QString &connectorTypeString)
|
||||
{
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<ConnectorType>();
|
||||
return static_cast<ConnectorType>(metaEnum.keyToValue(QString("ConnectorType").append(connectorTypeString).toUtf8()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,18 @@ class EverestJsonRpcClient : public QObject
|
|||
public:
|
||||
// API Enums
|
||||
|
||||
enum ResponseError {
|
||||
ResponseErrorNoError = 0,
|
||||
ResponseErrorErrorInvalidParameter,
|
||||
ResponseErrorErrorOutOfRange,
|
||||
ResponseErrorErrorValuesNotApplied,
|
||||
ResponseErrorErrorInvalidEVSEIndex,
|
||||
ResponseErrorErrorInvalidConnectorID,
|
||||
ResponseErrorErrorNoDataAvailable,
|
||||
ResponseErrorErrorUnknownError
|
||||
};
|
||||
Q_ENUM(ResponseError)
|
||||
|
||||
enum ConnectorType {
|
||||
ConnectorTypecCCS1,
|
||||
ConnectorTypecCCS2,
|
||||
|
|
@ -71,6 +83,29 @@ public:
|
|||
};
|
||||
Q_ENUM(ConnectorType)
|
||||
|
||||
enum ChargeProtocol {
|
||||
ChargeProtocolUnknown,
|
||||
ChargeProtocolIEC61851,
|
||||
ChargeProtocolDIN70121,
|
||||
ChargeProtocolISO15118,
|
||||
ChargeProtocolISO15118_20
|
||||
};
|
||||
Q_ENUM(ChargeProtocol)
|
||||
|
||||
enum EvseState {
|
||||
EvseStateUnplugged,
|
||||
EvseStateDisabled,
|
||||
EvseStatePreparing,
|
||||
EvseStateReserved,
|
||||
EvseStateAuthRequired,
|
||||
EvseStateWaitingForEnergy,
|
||||
EvseStateCharging,
|
||||
EvseStateChargingPausedEV,
|
||||
EvseStateChargingPausedEVSE,
|
||||
EvseStateFinished
|
||||
};
|
||||
Q_ENUM(EvseState)
|
||||
|
||||
// API Objects
|
||||
|
||||
typedef struct ChargerInfo {
|
||||
|
|
@ -94,6 +129,38 @@ public:
|
|||
QList<ConnectorInfo> availableConnectors;
|
||||
} EVSEInfo;
|
||||
|
||||
typedef struct EVSEStatus {
|
||||
double chargedEnergyWh = 0;
|
||||
double dischargedEnergyWh = 0;
|
||||
int chargingDuration = 0; // seconds
|
||||
bool chargingAllowed = false;
|
||||
bool available = false;
|
||||
int activeConnectorId = -1;
|
||||
QString evseError; // FIXME: maybe convert to internal enum
|
||||
ChargeProtocol chargeProtocol = ChargeProtocolUnknown;
|
||||
EvseState evseState = EvseStateUnplugged;
|
||||
QString evseStateString;
|
||||
// TODO:
|
||||
// o: "ac_charge_param": "$ACChargeParametersObj",
|
||||
// o: "dc_charge_param": "$DCChargeParametersObj",
|
||||
// o: "ac_charge_loop": "$ACChargeLoopObj",
|
||||
// o: "dc_charge_loop": "$DCChargeLoopObj",
|
||||
// o: display_parameters: "$DisplayParametersObj",
|
||||
|
||||
} EVSEStatus;
|
||||
|
||||
typedef struct HardwareCapabilities {
|
||||
double maxCurrentExport = 0;
|
||||
double maxCurrentImport = 0;
|
||||
int maxPhaseCountExport = 0;
|
||||
int maxPhaseCountImport = 0;
|
||||
double minCurrentExport = 0;
|
||||
double minCurrentImport = 0;
|
||||
int minPhaseCountExport = 0;
|
||||
int minPhaseCountImport = 0;
|
||||
bool phaseSwitchDuringCharging = false;
|
||||
} HardwareCapabilities;
|
||||
|
||||
|
||||
explicit EverestJsonRpcClient(QObject *parent = nullptr);
|
||||
|
||||
|
|
@ -109,12 +176,26 @@ public:
|
|||
QList<EVSEInfo> evseInfos() const;
|
||||
|
||||
// API calls
|
||||
EverestJsonRpcReply *apiHello();
|
||||
EverestJsonRpcReply *chargePointGetEVSEInfos();
|
||||
|
||||
EverestJsonRpcReply *evseGetInfo();
|
||||
EverestJsonRpcReply *evseGetInfo(int evseIndex);
|
||||
EverestJsonRpcReply *evseGetStatus(int evseIndex);
|
||||
EverestJsonRpcReply *evseGetHardwareCapabilities(int evseIndex);
|
||||
EverestJsonRpcReply *evseGetMeterData(int evseIndex);
|
||||
|
||||
EverestJsonRpcReply *evseSetChargingAllowed(int evseIndex, bool allowed);
|
||||
|
||||
// API parser methods
|
||||
|
||||
// Enums
|
||||
static ResponseError parseResponseError(const QString &responseErrorString);
|
||||
static ConnectorType parseConnectorType(const QString &connectorTypeString);
|
||||
static ChargeProtocol parseChargeProtocol(const QString &chargeProtocolString);
|
||||
static EvseState parseEvseState(const QString &evseStateString);
|
||||
|
||||
// Objects
|
||||
static EVSEInfo parseEvseInfo(const QVariantMap &evseInfoMap);
|
||||
static ConnectorInfo parseConnectorInfo(const QVariantMap &connectorInfoMap);
|
||||
static EVSEStatus parseEvseStatus(const QVariantMap &evseStatusMap);
|
||||
static HardwareCapabilities parseHardwareCapabilities(const QVariantMap &hardwareCapabilitiesMap);
|
||||
|
||||
public slots:
|
||||
void connectToServer(const QUrl &serverUrl);
|
||||
|
|
@ -141,10 +222,11 @@ private:
|
|||
bool m_authenticationRequired = false;
|
||||
QList<EVSEInfo> m_evseInfos;
|
||||
|
||||
// API parser methods
|
||||
EVSEInfo parseEvseInfo(const QVariantMap &evseInfoMap);
|
||||
ConnectorInfo parseConnectorInfo(const QVariantMap &connectorInfoMap);
|
||||
ConnectorType parseConnectorType(const QString &connectorTypeString);
|
||||
|
||||
// API calls
|
||||
EverestJsonRpcReply *apiHello();
|
||||
EverestJsonRpcReply *chargePointGetEVSEInfos();
|
||||
|
||||
};
|
||||
|
||||
#endif // EVERESTJSONRPCCLIENT_H
|
||||
|
|
|
|||
Loading…
Reference in New Issue