Major wip refactor

Allow running without gui
Remove serialPortMultiplexer broadcast use
Add TcpServer and TcpClient
Introduce the concept of an item source
This commit is contained in:
Carl Philipp Klemm 2026-03-01 14:39:27 +01:00
parent cbeb8d49a7
commit 6d742e60db
38 changed files with 928 additions and 825 deletions

View file

@ -1,26 +1,64 @@
#include <QtWidgets/QApplication>
#include <stdio.h>
#include <QDebug>
#include <QTcpSocket>
#include <QMessageBox>
//Currently pipewire support is disabled
//#include <pipewire/pipewire.h>
#ifndef Q_OS_ANDROID
#include <QSettings>
#include <QtSerialPort/QtSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QCommandLineParser>
#endif
#include "microcontroller.h"
#include "ui/mainwindow.h"
#include "items/itemstore.h"
#include "mainobject.h"
#include "programmode.h"
#define BAUD QSerialPort::Baud38400
QJsonObject getJsonObjectFromDisk(const QString& filePath, bool* error = nullptr)
{
QFile file;
file.setFileName(filePath);
bool ret = file.open(QIODevice::ReadOnly);
if(!file.isOpen() || !ret)
{
std::cerr<<"Can not open config file: "<<filePath.toLatin1().data()<<std::endl;
}
else
{
QJsonParseError qerror;
QJsonDocument document(QJsonDocument::fromJson(file.readAll(), &qerror));
file.close();
if(qerror.error != QJsonParseError::NoError)
{
qDebug()<<filePath<<" "<<qerror.errorString();
if(error) (*error) = true;
}
return document.object();
}
return QJsonObject();
}
bool storeJsonObjectToDisk(const QJsonObject& json, QString filePath)
{
QFile file(filePath + ".out");
qDebug()<<"config file: "<<filePath;
bool ret = file.open(QIODevice::WriteOnly);
if(!file.isOpen() || !ret)
{
std::cerr<<"Can not open config file: "<<filePath.toLatin1().data()<<std::endl;
return false;
}
else
{
QJsonDocument document(json);
file.write(document.toJson());
file.close();
QFile::remove(filePath);
file.rename(filePath);
return true;
}
}
int main(int argc, char *argv[])
{
@ -37,102 +75,111 @@ int main(int argc, char *argv[])
QDir::setCurrent(a.applicationDirPath());
//parse comand line
#ifndef Q_OS_ANDROID
QCommandLineParser parser;
parser.setApplicationDescription("Smart Home Interface");
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption tcpOption(QStringList() << "t" << "tcp", QCoreApplication::translate("main", "Use Tcp connection"));
parser.addOption(tcpOption);
QCommandLineOption hostOption(QStringList() << "H" << "host", QCoreApplication::translate("main",
"Set server host ip addres"), "adress");
QCommandLineOption masterOption(QStringList() << "m" << "master", QCoreApplication::translate("main", "Use in master mode"));
parser.addOption(masterOption);
QCommandLineOption hostOption(QStringList() << "H" << "host", QCoreApplication::translate("main", "Set server host ip addres"), "address", "0.0.0.0");
parser.addOption(hostOption);
QCommandLineOption portOption(QStringList() << "p" << "port", QCoreApplication::translate("main",
"Set server Port in TCP mode or Serial port in serial mode"), "port");
QCommandLineOption portOption(QStringList() << "p" << "port", QCoreApplication::translate("main", "Set server Port"), "port", "104476");
parser.addOption(portOption);
QCommandLineOption serialOption(QStringList() << "s" << "serial", QCoreApplication::translate("main",
"Use serial connection"));
parser.addOption(serialOption);
QCommandLineOption baudOption(QStringList() << "b" << "baud", QCoreApplication::translate("main", "Set Baud Rate"));
parser.addOption(baudOption);
QCommandLineOption settingsPathOption(QStringList() << "c" << "config", QCoreApplication::translate("main",
"Set config file"), "configFilePath");
QCommandLineOption settingsPathOption(QStringList()<<"c"<<"config", QCoreApplication::translate("main", "Set config file"), "configFilePath",
QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/shinterface.json");
parser.addOption(settingsPathOption);
QCommandLineOption secondaryOption(QStringList() << "e" << "secondary", QCoreApplication::translate("main",
"Set if instance is not main instance"));
parser.addOption(secondaryOption);
QCommandLineOption headlessOption(QStringList()<<"e"<<"headless", QCoreApplication::translate("main", "Dont start the gui"));
parser.addOption(headlessOption);
parser.process(a);
#endif
QIODevice* masterIODevice = nullptr;
int retVal;
#ifndef Q_OS_ANDROID
if(parser.isSet(tcpOption))
programMode = PROGRAM_MODE_UI_ONLY;
if(parser.isSet(masterOption))
{
QTcpSocket* microSocket = new QTcpSocket;
programMode = PROGRAM_MODE_PRIMARY;
if(parser.isSet(headlessOption))
programMode = PROGRAM_MODE_HEADLESS_PRIMARY;
}
if(programMode == PROGRAM_MODE_PRIMARY || programMode == PROGRAM_MODE_HEADLESS_PRIMARY)
{
QJsonObject json = getJsonObjectFromDisk(parser.value(settingsPathOption));
bool tcpMicro = json["MicroTcp"].toBool(true);
json["MicroTcp"] = tcpMicro;
int port = 6856;
if(parser.isSet(portOption)) port = parser.value(portOption).toInt();
QString host("127.0.0.1");
if(parser.isSet(hostOption)) host = parser.value(hostOption);
std::cout<<"connecting to "<<host.toStdString()<<':'<<port<<'\n';
microSocket->connectToHost(host, port, QIODevice::ReadWrite);
if(!microSocket->waitForConnected(1000))
QIODevice* microDevice = nullptr;
if(tcpMicro)
{
std::cout<<"Can not connect to to Server.\n";
QMessageBox::critical(nullptr, "Error", "Can not connect to to Server");
return 1;
int port = json["MicroTcpPort"].toInt(6856);
json["MicroTcpPort"] = port;
QString host = json["MicroTcpHost"].toString("127.0.0.1");
json["MicroTcpHost"] = host;
QTcpSocket* microSocket = new QTcpSocket;
qInfo()<<"connecting to "<<host.toStdString()<<':'<<port<<" for tcp micro";
microSocket->connectToHost(host, port, QIODevice::ReadWrite);
if(!microSocket->waitForConnected(1000))
{
qCritical()<<"Can not connect to tcp micro";
storeJsonObjectToDisk(json, parser.value(settingsPathOption));
if(programMode == PROGRAM_MODE_PRIMARY)
QMessageBox::critical(nullptr, "Error", "Can not connect to tcp micro");
return 1;
}
microDevice = microSocket;
}
masterIODevice = microSocket;
else
{
QString port = json["MicroSerialPort"].toString("ttyUSB0");
json["MicroSerialPort"] = port;
int baud = json["MicroSerialBaud"].toInt(38400);
json["MicroSerialBaud"] = baud;
QSerialPort *microPort = new QSerialPort;
microPort->setPortName(port);
microPort->setBaudRate(baud);
microPort->open(QIODevice::ReadWrite);
if(!microPort->isOpen())
{
qCritical()<<"Can not open serial port"<<port;
storeJsonObjectToDisk(json, parser.value(settingsPathOption));
if(programMode == PROGRAM_MODE_PRIMARY)
QMessageBox::critical(nullptr, "Error", "Can not open serial port " + port);
return 1;
}
microDevice = microPort;
}
PrimaryMainObject mainObject(microDevice, &json, parser.value(hostOption), parser.value(portOption).toInt());
MainWindow* w = nullptr;
if(programMode != PROGRAM_MODE_HEADLESS_PRIMARY)
{
w = new MainWindow(&mainObject);
QObject::connect(&mainObject.micro, SIGNAL(textRecived(QString)), w, SLOT(changeHeaderLableText(QString)));
QObject::connect(&mainObject.micro, SIGNAL(textRecived(QString)), w, SLOT(changeHeaderLableText(QString)));
//QObject::connect(&w, &MainWindow::sigSave, &mainObject, &MainObject::storeToDisk);
QObject::connect(w, &MainWindow::createdItem, &globalItems, [](std::shared_ptr<Item> item){globalItems.addItem(item, false);});
w->show();
}
retVal = a.exec();
delete w;
delete microDevice;
mainObject.store(json);
storeJsonObjectToDisk(json, parser.value(settingsPathOption));
}
else
{
QSerialPort* microPort = new QSerialPort;
if(parser.isSet(portOption)) microPort->setPortName(parser.value(portOption));
else microPort->setPortName("ttyUSB0");
SecondaryMainObject mainObject(parser.value(hostOption), parser.value(portOption).toInt());
MainWindow w(&mainObject);
//QObject::connect(&w, &MainWindow::sigSave, &mainObject, &MainObject::sendJson);
w.show();
if(parser.isSet(portOption)) microPort->setBaudRate(parser.value(baudOption).toInt());
else microPort->setBaudRate(BAUD);
if(!microPort->open(QIODevice::ReadWrite)) std::cout<<"Can not open serial port "<<microPort->portName().toStdString()
<<". Continueing in demo mode"<<'\n';
masterIODevice = microPort;
retVal = a.exec();
}
MainObject mainObject(masterIODevice, parser.isSet(settingsPathOption) ? parser.value(settingsPathOption) : "",
!parser.isSet(secondaryOption));
#else
QTcpSocket* microSocket = new QTcpSocket;
microSocket->connectToHost("10.0.0.1", 6856, QIODevice::ReadWrite);
if(!microSocket->waitForConnected(1000))
{
std::cout<<"Can not connect to to Server.\n";
return 1;
}
masterIODevice = microSocket;
MainObject mainObject(masterIODevice, parser.isSet(settingsPathOption) ? parser.value(settingsPathOption) : "",
!parser.isSet(secondaryOption));
#endif
//mainwindow
MainWindow w(&mainObject);
QObject::connect(&mainObject.micro, SIGNAL(textRecived(QString)), &w, SLOT(changeHeaderLableText(QString)));
QObject::connect(&w, &MainWindow::sigBrodcast, &mainObject, &MainObject::sendJson);
QObject::connect(&w, &MainWindow::sigSave, &mainObject, &MainObject::storeToDisk);
QObject::connect(&w, &MainWindow::createdItem, &mainObject.items, &ItemStore::addItem);
if(!mainObject.micro.connected())
w.changeHeaderLableText("No io debug only!");
w.show();
int retVal = a.exec();
if(masterIODevice)
delete masterIODevice;
return retVal;
}