Add evdash settings and enable / disable API methods

This commit is contained in:
Simon Stürz 2025-11-12 11:43:15 +01:00
parent b7e8925236
commit 0ad69ed5eb
8 changed files with 205 additions and 13 deletions

View File

@ -457,7 +457,7 @@
<section id="loginOverlay" class="login-view" aria-labelledby="loginTitle"> <section id="loginOverlay" class="login-view" aria-labelledby="loginTitle">
<div class="login-panel"> <div class="login-panel">
<h2 id="loginTitle">Sign in</h2> <h2 id="loginTitle">Sign in</h2>
<p>Please enter your credentials.</p> <p>Authorization required.</p>
<div id="loginError" class="error-message hidden" role="alert"></div> <div id="loginError" class="error-message hidden" role="alert"></div>
<form id="loginForm" autocomplete="on"> <form id="loginForm" autocomplete="on">
<label for="username">Username <label for="username">Username

View File

@ -29,6 +29,7 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "evdashengine.h" #include "evdashengine.h"
#include "evdashsettings.h"
#include "evdashwebserverresource.h" #include "evdashwebserverresource.h"
#include <integrations/thingmanager.h> #include <integrations/thingmanager.h>
@ -94,23 +95,48 @@ EvDashEngine::EvDashEngine(ThingManager *thingManager, EvDashWebServerResource *
qCWarning(dcEvDashExperience()) << "WebSocket accept error" << error << m_webSocketServer->errorString(); qCWarning(dcEvDashExperience()) << "WebSocket accept error" << error << m_webSocketServer->errorString();
}); });
startWebSocket(4449); EvDashSettings settings;
settings.beginGroup("General");
m_webSocketPort = settings.value("webSocketServerPort", 4449).toUInt();
bool enabled = settings.value("enabled", false).toBool();
settings.endGroup();
// Start the service if enabled
setEnabled(enabled);
} }
EvDashEngine::~EvDashEngine() EvDashEngine::~EvDashEngine()
{ {
if (m_webSocketServer->isListening()) stopWebSocketServer();
m_webSocketServer->close(); }
for (QWebSocket *client : qAsConst(m_clients)) { bool EvDashEngine::enabled() const
if (client->state() == QAbstractSocket::ConnectedState) {
client->close(QWebSocketProtocol::CloseCodeGoingAway, QStringLiteral("Server shutting down")); return m_enabled;
}
client->deleteLater(); bool EvDashEngine::setEnabled(bool enabled)
{
m_enabled = enabled;
if (m_enabled) {
if (!startWebSocketServer(m_webSocketPort)) {
return false;
}
} else {
stopWebSocketServer();
} }
m_clients.clear(); qCDebug(dcEvDashExperience()) << "The EV Dash service is now" << (enabled ? "enabled" : "disabled");
m_authenticatedClients.clear(); m_webServerResource->setEnabled(m_enabled);
EvDashSettings settings;
settings.beginGroup("General");
settings.setValue("enabled", enabled);
settings.endGroup();
emit enabledChanged(m_enabled);
return true;
} }
void EvDashEngine::onThingAdded(Thing *thing) void EvDashEngine::onThingAdded(Thing *thing)
@ -151,7 +177,7 @@ void EvDashEngine::monitorChargerThing(Thing *thing)
}); });
} }
bool EvDashEngine::startWebSocket(quint16 port) bool EvDashEngine::startWebSocketServer(quint16 port)
{ {
if (m_webSocketServer->isListening()) { if (m_webSocketServer->isListening()) {
if (m_webSocketServer->serverPort() == port && port != 0) if (m_webSocketServer->serverPort() == port && port != 0)
@ -171,6 +197,22 @@ bool EvDashEngine::startWebSocket(quint16 port)
return listening; return listening;
} }
void EvDashEngine::stopWebSocketServer()
{
if (m_webSocketServer->isListening())
m_webSocketServer->close();
for (QWebSocket *client : qAsConst(m_clients)) {
if (client->state() == QAbstractSocket::ConnectedState)
client->close(QWebSocketProtocol::CloseCodeGoingAway, QStringLiteral("Server shutting down"));
client->deleteLater();
}
m_clients.clear();
m_authenticatedClients.clear();
}
void EvDashEngine::processTextMessage(QWebSocket *socket, const QString &message) void EvDashEngine::processTextMessage(QWebSocket *socket, const QString &message)
{ {
if (!socket) if (!socket)

View File

@ -48,10 +48,22 @@ class EvDashEngine : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
enum EvDashError {
EvDashErrorNoError = 0,
EvDashErrorBackendError,
EvDashErrorDuplicateUser,
EvDashErrorBadPassword
};
Q_ENUM(EvDashError)
explicit EvDashEngine(ThingManager *thingManager, EvDashWebServerResource *webServerResource, QObject *parent = nullptr); explicit EvDashEngine(ThingManager *thingManager, EvDashWebServerResource *webServerResource, QObject *parent = nullptr);
~EvDashEngine() override; ~EvDashEngine() override;
bool enabled() const;
bool setEnabled(bool enabled);
signals: signals:
void enabledChanged(bool enabled);
void webSocketListeningChanged(bool listening); void webSocketListeningChanged(bool listening);
private slots: private slots:
@ -62,7 +74,11 @@ private slots:
private: private:
ThingManager *m_thingManager = nullptr; ThingManager *m_thingManager = nullptr;
EvDashWebServerResource *m_webServerResource = nullptr; EvDashWebServerResource *m_webServerResource = nullptr;
bool m_enabled = false;
QWebSocketServer *m_webSocketServer = nullptr; QWebSocketServer *m_webSocketServer = nullptr;
quint16 m_webSocketPort = 4449;
QList<QWebSocket *> m_clients; QList<QWebSocket *> m_clients;
QHash<QWebSocket *, QString> m_authenticatedClients; QHash<QWebSocket *, QString> m_authenticatedClients;
@ -71,7 +87,8 @@ private:
void monitorChargerThing(Thing *thing); void monitorChargerThing(Thing *thing);
// Websocket server // Websocket server
bool startWebSocket(quint16 port = 0); bool startWebSocketServer(quint16 port = 0);
void stopWebSocketServer();
void processTextMessage(QWebSocket *socket, const QString &message); void processTextMessage(QWebSocket *socket, const QString &message);
// Websocket API // Websocket API

View File

@ -38,6 +38,31 @@ EvDashJsonHandler::EvDashJsonHandler(EvDashEngine *engine, QObject *parent):
JsonHandler{parent}, JsonHandler{parent},
m_engine{engine} m_engine{engine}
{ {
registerEnum<EvDashEngine::EvDashError>();
QVariantMap params, returns;
QString description;
params.clear(); returns.clear();
description = "Get the enabled status of EV Dash service.";
returns.insert("enabled", enumValueName(Bool));
registerMethod("GetEnabled", description, params, returns);
params.clear(); returns.clear();
description = "Enable/Disable the EV Dash service.";
params.insert("enabled", enumValueName(Bool));
returns.insert("evDashError", enumRef<EvDashEngine::EvDashError>());
registerMethod("SetEnabled", description, params, returns);
// Notifications
params.clear();
description = "Emitted whenever the EV Dash service has been enabled or disabled.";
params.insert("enabled", enumValueName(Bool));
registerNotification("EnabledChanged", description, params);
connect(m_engine, &EvDashEngine::enabledChanged, this, [=](bool enabled){
emit EnabledChanged({{"enabled", enabled}});
});
} }
@ -46,3 +71,25 @@ QString EvDashJsonHandler::name() const
return "EvDash"; return "EvDash";
} }
JsonReply *EvDashJsonHandler::GetEnabled(const QVariantMap &params)
{
Q_UNUSED(params)
QVariantMap returns;
returns.insert("enabled", m_engine->enabled());
return createReply(returns);
}
JsonReply *EvDashJsonHandler::SetEnabled(const QVariantMap &params)
{
bool enabled = params.value("enabled").toBool();
EvDashEngine::EvDashError error = EvDashEngine::EvDashErrorNoError;
if (!m_engine->setEnabled(enabled))
error = EvDashEngine::EvDashErrorBackendError;
QVariantMap returns;
returns.insert("evDashError", enumValueName(error));
return createReply(returns);
}

View File

@ -45,7 +45,8 @@ public:
QString name() const override; QString name() const override;
// Q_INVOKABLE JsonReply *SetEnabled(const QVariantMap &params); Q_INVOKABLE JsonReply *GetEnabled(const QVariantMap &params);
Q_INVOKABLE JsonReply *SetEnabled(const QVariantMap &params);
signals: signals:
void EnabledChanged(const QVariantMap &params); void EnabledChanged(const QVariantMap &params);

39
plugin/evdashsettings.cpp Normal file
View File

@ -0,0 +1,39 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU 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 General
* Public License for more details.
*
* You should have received a copy of the GNU 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 "evdashsettings.h"
#include <nymeasettings.h>
EvDashSettings::EvDashSettings()
: QSettings(NymeaSettings::settingsPath() + "/evdash.conf", QSettings::IniFormat)
{
}

44
plugin/evdashsettings.h Normal file
View File

@ -0,0 +1,44 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU 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 General
* Public License for more details.
*
* You should have received a copy of the GNU 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 EVDASHSETTINGS_H
#define EVDASHSETTINGS_H
#include <QObject>
#include <QSettings>
class EvDashSettings : public QSettings
{
public:
explicit EvDashSettings();
};
#endif // EVDASHSETTINGS_H

View File

@ -14,11 +14,13 @@ QT += network sql websockets
HEADERS += experiencepluginevdash.h \ HEADERS += experiencepluginevdash.h \
evdashengine.h \ evdashengine.h \
evdashjsonhandler.h \ evdashjsonhandler.h \
evdashsettings.h \
evdashwebserverresource.h evdashwebserverresource.h
SOURCES += experiencepluginevdash.cpp \ SOURCES += experiencepluginevdash.cpp \
evdashengine.cpp \ evdashengine.cpp \
evdashjsonhandler.cpp \ evdashjsonhandler.cpp \
evdashsettings.cpp \
evdashwebserverresource.cpp evdashwebserverresource.cpp
target.path = $$[QT_INSTALL_LIBS]/nymea/experiences/ target.path = $$[QT_INSTALL_LIBS]/nymea/experiences/