Import existing sources
This commit is contained in:
@@ -0,0 +1,331 @@
|
||||
#include "espremoteagent.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include "webservercontainer.h"
|
||||
#include "webserverclientconnection.h"
|
||||
#include "espremoteagentcontainers.h"
|
||||
#include "espremoteport.h"
|
||||
|
||||
EspRemoteAgent::EspRemoteAgent(std::vector<SerialPortConfig> &&serialPortConfigs, QObject *parent) :
|
||||
AbstractWebserver{parent}
|
||||
{
|
||||
m_ports.reserve(serialPortConfigs.size());
|
||||
|
||||
for (auto &config : serialPortConfigs)
|
||||
m_ports.emplace_back(std::make_unique<EspRemotePort>(std::move(config), this));
|
||||
}
|
||||
|
||||
EspRemoteAgent::~EspRemoteAgent() = default;
|
||||
|
||||
void EspRemoteAgent::requestReceived(WebserverClientConnection &client, const Request &request)
|
||||
{
|
||||
const QUrl url{request.path};
|
||||
const QUrlQuery query{url};
|
||||
|
||||
if (url.path() == "/")
|
||||
{
|
||||
sendRootResponse(client, url, query);
|
||||
}
|
||||
else if (url.path() == "/open")
|
||||
{
|
||||
sendOpenResponse(client, url, query);
|
||||
}
|
||||
else if (url.path() == "/close")
|
||||
{
|
||||
sendCloseResponse(client, url, query);
|
||||
}
|
||||
else if (url.path() == "/reboot")
|
||||
{
|
||||
sendRebootResponse(client, url, query);
|
||||
}
|
||||
else if (url.path() == "/setDTR")
|
||||
{
|
||||
sendSetDTRResponse(client, url, query);
|
||||
}
|
||||
else if (url.path() == "/setRTS")
|
||||
{
|
||||
sendSetRTSResponse(client, url, query);
|
||||
}
|
||||
else
|
||||
if (!client.sendFullResponse(404, "Not Found", {{"Content-Type", "text/plain"}}, "The requested path \"" + request.path + "\" was not found."))
|
||||
qWarning() << "sending response failed";
|
||||
}
|
||||
|
||||
void EspRemoteAgent::sendRootResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query)
|
||||
{
|
||||
QString content =
|
||||
"<html>"
|
||||
"<head>"
|
||||
"<title>ESP Remote Agent</title>"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<table border=\"1\">"
|
||||
"<thead>"
|
||||
"<tr>"
|
||||
"<th>ID</th>"
|
||||
"<th>Port</th>"
|
||||
"<th>Status</th>"
|
||||
"<th>Message</th>"
|
||||
"<th>Actions</th>"
|
||||
"<th>Log output</th>"
|
||||
"</tr>"
|
||||
"</thead>"
|
||||
"<tbody>";
|
||||
|
||||
std::size_t i{};
|
||||
for (const auto &port : m_ports)
|
||||
{
|
||||
const auto currentId = i++;
|
||||
content += QStringLiteral("<tr>"
|
||||
"<td>%0</td>"
|
||||
"<td>%1</td>"
|
||||
"<td>%2</td>"
|
||||
"<td>%3</td>"
|
||||
"<td>"
|
||||
"<a href=\"open?id=%0\">Open</a> "
|
||||
"<a href=\"close?id=%0\">Close</a><br />"
|
||||
"<a href=\"reboot?id=%0\">Reboot</a><br />"
|
||||
"DTR %4 <a href=\"setDTR?id=%0&set=%5\">Toggle</a><br />"
|
||||
"RTS %6 <a href=\"setRTS?id=%0&set=%7\">Toggle</a>"
|
||||
"</td>"
|
||||
"<td><pre>%8</pre></td>"
|
||||
"</tr>")
|
||||
.arg(currentId)
|
||||
.arg(port->port())
|
||||
.arg(port->status())
|
||||
.arg(port->message())
|
||||
.arg(port->isDataTerminalReady() ? "On" : "Off")
|
||||
.arg(port->isDataTerminalReady() ? "false" : "true")
|
||||
.arg(port->isRequestToSend() ? "On" : "Off")
|
||||
.arg(port->isRequestToSend() ? "false" : "true")
|
||||
.arg(port->logOutput());
|
||||
}
|
||||
|
||||
content += "</tbody>"
|
||||
"</table>"
|
||||
"</body>"
|
||||
"</html>";
|
||||
|
||||
if (!client.sendFullResponse(200, "Ok", {{"Content-Type", "text/html"}}, content.toUtf8()))
|
||||
qWarning() << "sending response failed";
|
||||
}
|
||||
|
||||
void EspRemoteAgent::sendOpenResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query)
|
||||
{
|
||||
if (!query.hasQueryItem("id"))
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "id missing"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
const auto idStr = query.queryItemValue("id");
|
||||
bool ok{};
|
||||
const auto id = idStr.toInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "could not parse id"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
if (id < 0 || id >= m_ports.size())
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "id out of range"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*std::next(std::begin(m_ports), id))->tryOpen())
|
||||
{
|
||||
if (!client.sendFullResponse(200, "Ok", {{"Content-Type", "text/plain"}}, "Port opened successfully!"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!client.sendFullResponse(500, "Internal Server Error", {{"Content-Type", "text/plain"}}, "Opening port failed!"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void EspRemoteAgent::sendCloseResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query)
|
||||
{
|
||||
if (!query.hasQueryItem("id"))
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "id missing"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
const auto idStr = query.queryItemValue("id");
|
||||
bool ok{};
|
||||
const auto id = idStr.toInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "could not parse id"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
if (id < 0 || id >= m_ports.size())
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "id out of range"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
|
||||
(*std::next(std::begin(m_ports), id))->close();
|
||||
if (!client.sendFullResponse(200, "Ok", {{"Content-Type", "text/plain"}}, "Port closed successfully!"))
|
||||
qWarning() << "sending response failed";
|
||||
}
|
||||
|
||||
void EspRemoteAgent::sendRebootResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query)
|
||||
{
|
||||
if (!query.hasQueryItem("id"))
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "id missing"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
const auto idStr = query.queryItemValue("id");
|
||||
bool ok{};
|
||||
const auto id = idStr.toInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "could not parse id"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
if (id < 0 || id >= m_ports.size())
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "id out of range"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*std::next(std::begin(m_ports), id))->reboot())
|
||||
{
|
||||
if (!client.sendFullResponse(200, "Ok", {{"Content-Type", "text/plain"}}, "Reboot successfully!"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!client.sendFullResponse(500, "Internal Server Error", {{"Content-Type", "text/plain"}}, "Reboot failed!"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void EspRemoteAgent::sendSetDTRResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query)
|
||||
{
|
||||
if (!query.hasQueryItem("id"))
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "id missing"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
const auto idStr = query.queryItemValue("id");
|
||||
bool ok{};
|
||||
const auto id = idStr.toInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "could not parse id"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
if (id < 0 || id >= m_ports.size())
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "id out of range"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!query.hasQueryItem("set"))
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "set missing"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
bool set;
|
||||
if (const auto setStr = query.queryItemValue("set"); setStr == "true")
|
||||
set = true;
|
||||
else if (setStr == "false")
|
||||
set = false;
|
||||
else
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "could not parse set"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*std::next(std::begin(m_ports), id))->setDataTerminalReady(set))
|
||||
{
|
||||
if (!client.sendFullResponse(200, "Ok", {{"Content-Type", "text/plain"}}, "Port set DTR successfully!"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!client.sendFullResponse(500, "Internal Server Error", {{"Content-Type", "text/plain"}}, "Set port DTR failed!"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void EspRemoteAgent::sendSetRTSResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query)
|
||||
{
|
||||
if (!query.hasQueryItem("id"))
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "id missing"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
const auto idStr = query.queryItemValue("id");
|
||||
bool ok{};
|
||||
const auto id = idStr.toInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "could not parse id"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
if (id < 0 || id >= m_ports.size())
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "id out of range"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!query.hasQueryItem("set"))
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "set missing"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
bool set;
|
||||
if (const auto setStr = query.queryItemValue("set"); setStr == "true")
|
||||
set = true;
|
||||
else if (setStr == "false")
|
||||
set = false;
|
||||
else
|
||||
{
|
||||
if (!client.sendFullResponse(400, "Bad Request", {{"Content-Type", "text/plain"}}, "could not parse set"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*std::next(std::begin(m_ports), id))->setRequestToSend(set))
|
||||
{
|
||||
if (!client.sendFullResponse(200, "Ok", {{"Content-Type", "text/plain"}}, "Port set RTS successfully!"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!client.sendFullResponse(500, "Internal Server Error", {{"Content-Type", "text/plain"}}, "Set port RTS failed!"))
|
||||
qWarning() << "sending response failed";
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "abstractwebserver.h"
|
||||
|
||||
class SerialPortConfig;
|
||||
class WebserverClientConnection;
|
||||
class Request;
|
||||
class EspRemotePort;
|
||||
class QUrl;
|
||||
class QUrlQuery;
|
||||
|
||||
class EspRemoteAgent : public AbstractWebserver
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EspRemoteAgent(std::vector<SerialPortConfig> &&serialPortConfigs, QObject *parent = nullptr);
|
||||
~EspRemoteAgent() override;
|
||||
|
||||
protected:
|
||||
void requestReceived(WebserverClientConnection &client, const Request &request) override;
|
||||
|
||||
private:
|
||||
void sendRootResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query);
|
||||
void sendOpenResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query);
|
||||
void sendCloseResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query);
|
||||
void sendRebootResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query);
|
||||
void sendSetDTRResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query);
|
||||
void sendSetRTSResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query);
|
||||
|
||||
std::vector<std::unique_ptr<EspRemotePort>> m_ports;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
[Webserver]
|
||||
listen=Any
|
||||
port=80
|
||||
|
||||
[PortA]
|
||||
port=/dev/ttyUSB0
|
||||
baudrate=115200
|
||||
url=ws://office-pi:1235/charger0
|
||||
|
||||
[PortB]
|
||||
port=/dev/ttyUSB1
|
||||
baudrate=115200
|
||||
url=ws://office-pi:1235/charger1
|
||||
@@ -0,0 +1,31 @@
|
||||
QT = core network serialport websockets
|
||||
|
||||
TARGET = espremoteagent
|
||||
|
||||
TEMPLATE = app
|
||||
|
||||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
|
||||
PROJECT_ROOT = ..
|
||||
|
||||
DESTDIR = $${OUT_PWD}/$${PROJECT_ROOT}/bin
|
||||
|
||||
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
DBLIBS += webserver
|
||||
|
||||
HEADERS += \
|
||||
espremoteagent.h \
|
||||
espremoteagentcontainers.h \
|
||||
espremoteport.h
|
||||
|
||||
SOURCES += \
|
||||
espremoteport.cpp \
|
||||
main.cpp \
|
||||
espremoteagent.cpp
|
||||
|
||||
OTHER_FILES += \
|
||||
espremoteagent.ini
|
||||
|
||||
include($${PROJECT_ROOT}/project.pri)
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
struct SerialPortConfig
|
||||
{
|
||||
QString port;
|
||||
int baudrate;
|
||||
QUrl url;
|
||||
};
|
||||
@@ -0,0 +1,225 @@
|
||||
#include "espremoteport.h"
|
||||
|
||||
#include <QSerialPort>
|
||||
#include <QWebSocket>
|
||||
#include <QTimerEvent>
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QTimer>
|
||||
|
||||
EspRemotePort::EspRemotePort(SerialPortConfig &&config, QObject *parent) :
|
||||
QObject{parent},
|
||||
m_config{std::move(config)},
|
||||
m_port{std::make_unique<QSerialPort>(m_config.port)},
|
||||
m_websocket{m_config.url.isEmpty() ? nullptr : std::make_unique<QWebSocket>(QString{}, QWebSocketProtocol::VersionLatest, this)}
|
||||
{
|
||||
connect(m_port.get(), &QSerialPort::readyRead, this, &EspRemotePort::serialReadyRead);
|
||||
|
||||
if (m_websocket)
|
||||
{
|
||||
connect(m_websocket.get(), &QWebSocket::connected, this, &EspRemotePort::websocketConnected);
|
||||
connect(m_websocket.get(), &QWebSocket::disconnected, this, &EspRemotePort::websocketDisconnected);
|
||||
connect(m_websocket.get(), qOverload<QAbstractSocket::SocketError>(&QWebSocket::error), this, &EspRemotePort::websocketError);
|
||||
connect(m_websocket.get(), &QWebSocket::textMessageReceived, this, &EspRemotePort::websocketTextMessageReceived);
|
||||
qDebug() << "connecting to" << m_config.url;
|
||||
m_websocket->open(m_config.url);
|
||||
}
|
||||
|
||||
tryOpen();
|
||||
}
|
||||
|
||||
EspRemotePort::~EspRemotePort() = default;
|
||||
|
||||
QString EspRemotePort::status() const
|
||||
{
|
||||
if (m_port->isOpen())
|
||||
return tr("Open");
|
||||
else
|
||||
return tr("Not open");
|
||||
}
|
||||
|
||||
QString EspRemotePort::logOutput() const
|
||||
{
|
||||
QString str;
|
||||
for (const auto &line : m_logOutput)
|
||||
{
|
||||
if (!str.isEmpty())
|
||||
str += "\n";
|
||||
str += line.toHtmlEscaped();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
bool EspRemotePort::reboot()
|
||||
{
|
||||
bool set = m_port->isDataTerminalReady();
|
||||
|
||||
Q_ASSERT(m_port);
|
||||
|
||||
if (!m_port->setDataTerminalReady(!set))
|
||||
return false;
|
||||
|
||||
QTimer::singleShot(100, m_port.get(), [set,port=m_port.get()](){
|
||||
if (!port->setDataTerminalReady(set))
|
||||
qWarning() << "reboot failed";
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EspRemotePort::setDataTerminalReady(bool set)
|
||||
{
|
||||
return m_port->setDataTerminalReady(set);
|
||||
}
|
||||
|
||||
bool EspRemotePort::isDataTerminalReady()
|
||||
{
|
||||
return m_port->isDataTerminalReady();
|
||||
}
|
||||
|
||||
bool EspRemotePort::setRequestToSend(bool set)
|
||||
{
|
||||
return m_port->setRequestToSend(set);
|
||||
}
|
||||
|
||||
bool EspRemotePort::isRequestToSend()
|
||||
{
|
||||
return m_port->isRequestToSend();
|
||||
}
|
||||
|
||||
bool EspRemotePort::tryOpen()
|
||||
{
|
||||
m_port->close();
|
||||
|
||||
if (!m_port->setBaudRate(m_config.baudrate))
|
||||
qWarning() << "could not set baud rate" << m_config.baudrate;
|
||||
|
||||
if (!m_port->open(QIODevice::ReadWrite))
|
||||
{
|
||||
m_message = tr("Could not open port because %0").arg(m_port->errorString());
|
||||
qWarning() << m_message;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EspRemotePort::close()
|
||||
{
|
||||
m_port->close();
|
||||
}
|
||||
|
||||
void EspRemotePort::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (event->timerId() == m_reconnectTimerId)
|
||||
{
|
||||
m_reconnectTimerId = -1;
|
||||
|
||||
if (!m_config.url.isEmpty())
|
||||
{
|
||||
Q_ASSERT(m_websocket);
|
||||
qDebug() << "reconnecting to" << m_config.url;
|
||||
m_websocket->open(m_config.url);
|
||||
}
|
||||
}
|
||||
else
|
||||
QObject::timerEvent(event);
|
||||
}
|
||||
|
||||
void EspRemotePort::serialReadyRead()
|
||||
{
|
||||
while (m_port->canReadLine())
|
||||
{
|
||||
auto line = m_port->readLine();
|
||||
|
||||
if (line.endsWith('\n'))
|
||||
{
|
||||
line.chop(1);
|
||||
if (line.endsWith('\r'))
|
||||
line.chop(1);
|
||||
}
|
||||
|
||||
// qDebug() << line;
|
||||
|
||||
if (m_websocket)
|
||||
{
|
||||
m_websocket->sendTextMessage(QJsonDocument{QJsonObject{
|
||||
{"type", "log"},
|
||||
{"line", QString{line}},
|
||||
}}.toJson());
|
||||
}
|
||||
|
||||
m_logOutput.push(std::move(line));
|
||||
|
||||
while (m_logOutput.size() > 10)
|
||||
m_logOutput.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void EspRemotePort::websocketConnected()
|
||||
{
|
||||
qDebug() << "called";
|
||||
|
||||
if (m_reconnectTimerId != -1)
|
||||
killTimer(m_reconnectTimerId);
|
||||
}
|
||||
|
||||
void EspRemotePort::websocketDisconnected()
|
||||
{
|
||||
qDebug() << "called";
|
||||
}
|
||||
|
||||
void EspRemotePort::websocketError(QAbstractSocket::SocketError error)
|
||||
{
|
||||
qDebug() << "called" << error;
|
||||
|
||||
if (m_reconnectTimerId != -1)
|
||||
killTimer(m_reconnectTimerId);
|
||||
|
||||
m_reconnectTimerId = startTimer(5000);
|
||||
}
|
||||
|
||||
void EspRemotePort::websocketTextMessageReceived(const QString &message)
|
||||
{
|
||||
// qDebug() << message;
|
||||
|
||||
QJsonParseError error;
|
||||
const auto doc = QJsonDocument::fromJson(message.toUtf8(), &error);
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
{
|
||||
qWarning() << "could not parse json command:" << error.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!doc.isObject())
|
||||
{
|
||||
qWarning() << "json command is not an object";
|
||||
return;
|
||||
}
|
||||
|
||||
const auto obj = doc.object();
|
||||
|
||||
if (!obj.contains("type"))
|
||||
{
|
||||
qWarning() << "json command does not contain a type";
|
||||
return;
|
||||
}
|
||||
|
||||
const auto typeVal = obj.value("type");
|
||||
|
||||
if (!typeVal.isString())
|
||||
{
|
||||
qWarning() << "json command type is not a string";
|
||||
return;
|
||||
}
|
||||
|
||||
const auto type = typeVal.toString();
|
||||
|
||||
if (type == "reboot")
|
||||
{
|
||||
reboot();
|
||||
}
|
||||
else
|
||||
qWarning() << "unknown command type" << type;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractSocket>
|
||||
|
||||
#include "espremoteagentcontainers.h"
|
||||
#include "webserverutils.h"
|
||||
|
||||
class QSerialPort;
|
||||
class QWebSocket;
|
||||
|
||||
class EspRemotePort : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EspRemotePort(SerialPortConfig &&config, QObject *parent = nullptr);
|
||||
~EspRemotePort() override;
|
||||
|
||||
QString port() const { return m_config.port; }
|
||||
QString status() const;
|
||||
QString message() const { return m_message; }
|
||||
QString logOutput() const;
|
||||
|
||||
bool reboot();
|
||||
|
||||
bool setDataTerminalReady(bool set);
|
||||
bool isDataTerminalReady();
|
||||
|
||||
bool setRequestToSend(bool set);
|
||||
bool isRequestToSend();
|
||||
|
||||
bool tryOpen();
|
||||
void close();
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void serialReadyRead();
|
||||
void websocketConnected();
|
||||
void websocketDisconnected();
|
||||
void websocketError(QAbstractSocket::SocketError error);
|
||||
void websocketTextMessageReceived(const QString &message);
|
||||
|
||||
private:
|
||||
SerialPortConfig m_config;
|
||||
const std::unique_ptr<QSerialPort> m_port;
|
||||
const std::unique_ptr<QWebSocket> m_websocket;
|
||||
QString m_message;
|
||||
iterable_queue<QString> m_logOutput;
|
||||
|
||||
int m_reconnectTimerId{-1};
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QSettings>
|
||||
#include <QUrl>
|
||||
|
||||
#include "espremoteagent.h"
|
||||
#include "espremoteagentcontainers.h"
|
||||
#include "webserverutils.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
qSetMessagePattern(QStringLiteral("%{time dd.MM.yyyy HH:mm:ss.zzz} "
|
||||
"["
|
||||
"%{if-debug}D%{endif}"
|
||||
"%{if-info}I%{endif}"
|
||||
"%{if-warning}W%{endif}"
|
||||
"%{if-critical}C%{endif}"
|
||||
"%{if-fatal}F%{endif}"
|
||||
"] "
|
||||
"%{function}(): "
|
||||
"%{message}"));
|
||||
|
||||
QCoreApplication app{argc, argv};
|
||||
|
||||
QSettings settings{"espremoteagent.ini", QSettings::IniFormat};
|
||||
|
||||
std::vector<SerialPortConfig> serialPortConfigs;
|
||||
|
||||
const auto probePort = [&](auto group){
|
||||
auto port = settings.value(QStringLiteral("%0/port").arg(group)).toString();
|
||||
if (port.isEmpty())
|
||||
return;
|
||||
|
||||
QUrl url;
|
||||
if (auto urlStr = settings.value(QStringLiteral("%0/url").arg(group)).toString(); !urlStr.isEmpty())
|
||||
url = QUrl{std::move(urlStr)};
|
||||
|
||||
int baudrate{};
|
||||
bool ok{};
|
||||
baudrate = settings.value(QStringLiteral("%0/baudrate").arg(group)).toInt(&ok);
|
||||
if (!ok)
|
||||
qFatal("could not parse baudrate for %s", qPrintable(group));
|
||||
|
||||
serialPortConfigs.emplace_back(SerialPortConfig{
|
||||
.port=std::move(port),
|
||||
.baudrate=baudrate,
|
||||
.url=std::move(url)
|
||||
});
|
||||
};
|
||||
|
||||
probePort("PortA");
|
||||
probePort("PortB");
|
||||
|
||||
QHostAddress webserverListen = parseHostAddress(settings.value("Webserver/listen").toString());
|
||||
int webserverPort;
|
||||
{
|
||||
bool ok{};
|
||||
webserverPort = settings.value("Webserver/port", 1234).toInt(&ok);
|
||||
if (!ok)
|
||||
qFatal("could not parse webserver port");
|
||||
}
|
||||
|
||||
EspRemoteAgent agent{std::move(serialPortConfigs)};
|
||||
if (!agent.listen(webserverListen, webserverPort))
|
||||
qFatal("could not start listening %s", qPrintable(agent.errorString()));
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
Reference in New Issue
Block a user