Newer
Older
/*
* Konstruktor
*/
Server::Server(QString TCPhostName, QObject *parent) :
QObject(parent),
m_gatewayHostName(TCPhostName),
m_gatewayTCPsocket(this)
{
// Verbindung zum MySensors Controller:
m_gatewayTCPsocket.connectToHost(QHostAddress(m_gatewayHostName), 5003);
connect(&m_gatewayTCPsocket, &QTcpSocket::readyRead,
this, &Server::onReadyReadSensorValueTCP);
qDebug() << "TCPsocket" << m_gatewayHostName << "Port 5003" ;
SHactuator::setSocket(&m_gatewayTCPsocket);
// HTTP Requests für Tasmota:
m_tasmota = new QNetworkAccessManager();
// m_tasmota->setTransferTimeout(1500); // ms -- ab Qt 5.15
connect(m_tasmota, &QNetworkAccessManager::finished,
this, &Server::tasmotaReply);
SHsensor::initStatics(m_tasmota); // Map für alle Namen und Tasmota Manager
// serielle Schnittstelle ansehen und starten:
// startSerial();
SHsensor *t_wrom = new SHsensor(NodeIDBadObenT, SHsensor::tempSensor, "http://192.168.178.72");
SHsensor *t_lrom = new SHsensor(NodeIDLivingroom, SHsensor::tempSensor, "http://192.168.178.102");
SHsensor *t_bath = new SHsensor(NodeIDBadUntenT, SHsensor::tempSensor, "http://192.168.178.100");
// SHsensor *t_dummy = new SHsensor(NodeIdDummy, SHsensor::tempSensor, "http://192.168.178.72");
// SHsensor *solar = new SHsensor(NodeIdLightSensor, SHsensor::lightSensor);
SHsensor *central = new SHsensor(NodeIDCentral, SHsensor::lightSensor, "http://192.168.178.142");
// SHsensor *wash = new SHsensor(NodeIDWashMachine, SHsensor::powerSensor, "http://192.168.178.105");
// SHsensor *ecar = new SHsensor(NodeIDeCar, SHsensor::powerSensor);
// SHsensor *airc = new SHsensor(NodeIdAirconditioner, SHsensor::powerSensor, "http://192.168.178.49");
// Repeater:
// SHsensor *dummy = new SHsensor("Dummy", NodeIdDummy, SHsensor::none); addAllSensors einbeziehen
// SHsensor *repeat2 = new SHsensor(NodeIDRepeater2, SHsensor::none);
//
// Bad;8;1; Off;22.5;18.5;07:15;21:00
// Arbeit;7;1;Off;22.5;18.5;07:15;21:00
// Wohn;5;1; Off;22.5;18.5;07:15;23:00
// Kamin;2;1; Off;22.5;18.5;07:15;23:00
SHactuator *sBath300 = new SHactuator(NodeIDBadUnten, 320, SHactuator::SensorType::Switch, "http://192.168.178.93");
HeatControl *controlBath300 = new HeatControl(t_bath, sBath300, 22.5, 18.5, QTime(7,10), QTime(21,0));
// Bad oben:
SHactuator *sBathUp400 = new SHactuator(NodeIDBadOben, 400, SHactuator::SensorType::Switch, "http://192.168.178.24");
HeatControl * controlBathUp400 = new HeatControl(t_wrom, sBathUp400, 22.5, 18.5, QTime(7,10), QTime(21,0));
SHactuator *sLRom1000 = new SHactuator(NodeIdSolarheat, 1115, SHactuator::SensorType::Switch, "http://192.168.178.68");
HeatControl *controlKamn1000 = new HeatControl(t_lrom, sLRom1000, 22.5, 18.5, QTime(7,12), QTime(23,0));
SHactuator *sWall900 = new SHactuator(NodeIDWallLR, 910, SHactuator::SensorType::Switch, "http://192.168.178.30");
HeatControl *controlWall900 = new HeatControl(t_lrom, sWall900, 22.5, 18.5, QTime(7,14), QTime(23,0));
SHactuator *sWall450 = new SHactuator(NodeIDWallM, 455, SHactuator::SensorType::Switch, "http://192.168.178.96");
HeatControl *controlWall450 = new HeatControl(t_lrom, sWall450, 22.5, 18.5, QTime(7,16), QTime(23,0));
SHactuator *sFlor150 = new SHactuator(NodeIdSolarheatFloor, 155, SHactuator::SensorType::Switch, "http://192.168.178.63");
HeatControl *controlFlor150 = new HeatControl(t_lrom, sFlor150, 22.5, 18.5, QTime(7,16), QTime(23,0));
SHactuator *sHW_60_2500 = new SHactuator(NodeIdHW_60, 2550, SHactuator::SensorType::Switch, "http://192.168.178.122");
SHactuator *sHW_40_2500 = new SHactuator(NodeIdHW_40, 2550, SHactuator::SensorType::Switch, "http://192.168.178.74");
HotwaterControl *controlHW_60_2500 = new HotwaterControl(sHW_60_2500);
HotwaterControl *controlHW_40_2500 = new HotwaterControl(sHW_40_2500);
// solar controllers
m_solarControl =
new SolarControl(
central, /* solar, */
/* {wash, ecar, airc}, */
{controlHW_40_2500, controlHW_60_2500, controlKamn1000, controlWall900, controlWall450, controlBathUp400, controlBath300, controlFlor150} // absteigende Sortierung bzw. Priorisierung
);
// Ping: TODO
// einlesen:
HeatControl::readCSV();
// Timer starten:
startTimers();
// WebSocketServer
startWebSocketServer();
// SHsensor::displayMem("Server::Server ENDE");
/*
*
*/
Server::Server() // private: nur zum Testen
{
SHsensor::initStatics(nullptr);
}
// Timer zum regelmäßigen Abfragen der Werte von den Clients inkl. Status-Anzeige:
QTimer *submitTimer = new QTimer;
connect(submitTimer, &QTimer::timeout, this, &Server::showSensorValues);
submitTimer->start(SHsensor::POLLING_INTERVALL * 1000); // ms
// Kontrolle der Zeitstempel: wenn man länger nichts hört wird auf NOVALUE gesetz
QTimer *timeStampTimer = new QTimer(this);
connect(timeStampTimer, &QTimer::timeout, this, &SHsensor::checkTimeStampALL);
timeStampTimer->start(SHsensor::CONTROL_INTERVALL * 1000); // ms
// heatControl Timer: für Geräte, die ON/OFF (oder veraltet im Timer-Modus) gesteuert werden
// TODO: unklar, ob das noch gebraucht wird
QTimer *heatControlTimer = new QTimer(this);
connect(heatControlTimer, &QTimer::timeout, this, &HeatControl::processALL);
heatControlTimer->start(23 * 1000); // ms
// SolarControl Timer: Energie-Management
QTimer *SolarControlTimer = new QTimer(this);
connect(SolarControlTimer, &QTimer::timeout, m_solarControl, &SolarControl::process);
SolarControlTimer->start(23 * 1000); // ms
// SHsensor::displayMem("Server::startTimers ENDE");
for (int i=10; i>=0; i--) { // wait some time for previous TCP connection to get started
qDebug() << "Count down" << i;
sleep(1);
}
m_webSocketServer = new QWebSocketServer(QStringLiteral("SH Server"), QWebSocketServer::NonSecureMode, this);
qDebug() << "webSocketServer Interface started";
const quint16 port = 1235;
if (m_webSocketServer->listen(QHostAddress::Any, port)) {
qDebug() << "webSocketServer listening on port " + QString::number(port);
connect(m_webSocketServer, &QWebSocketServer::newConnection,
this, &Server::onNewClientConnection);
// connect(m_webSocketServer, &QWebSocketServer::closed,
// this, &Server::closed);
// mutex.unlock();
} else {
qDebug() << "ERROR: m_pWebSocketServer->listen " + QString::number(port);
}
// SHsensor::displayMem("Server::startWebSocketServer ENDE");
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
}
/*
*
*/
void Server::sendToClient(const QJsonObject & jsonObj)
{
mutex.lock();
QWebSocket *pClient = nullptr;
if (m_webSocketClients.size() > 0)
pClient = qobject_cast<QWebSocket *>(sender());
// find matching client
for (int i=0; i < m_webSocketClients.size(); i++)
if (m_webSocketClients[i] == pClient) {
// send the json message
QString message = QJsonDocument(jsonObj).toJson(QJsonDocument::Compact);
if (m_webSocketClients[i]) {
// qDebug() << "Sending to " + QString::number(application->getClientID());
m_webSocketClients[i]->sendTextMessage(message);
} else
qDebug() << "Sending ERROR message '" + message + "' to " << i;
break;
}
mutex.unlock();
}
#ifdef OLD
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/*
*
*/
void Server::startSerial() {
m_serial = nullptr; // weil im Fehlerfall diese Methode erneut aufgerufen wird (siehe connect unten)
const char blankString[] = QT_TRANSLATE_NOOP("SettingsDialog", "N/A");
const auto infos = QSerialPortInfo::availablePorts();
QString port;
// Infos einsammeln:
for (const QSerialPortInfo &info : infos) {
QStringList list;
QString description = info.description();
QString manufacturer = info.manufacturer();
QString serialNumber = info.serialNumber();
list << info.portName()
<< (!description.isEmpty() ? description : blankString)
<< (!manufacturer.isEmpty() ? manufacturer : blankString)
<< (!serialNumber.isEmpty() ? serialNumber : blankString)
<< info.systemLocation()
<< (info.vendorIdentifier() ? QString::number(info.vendorIdentifier(), 16) : blankString)
<< (info.productIdentifier() ? QString::number(info.productIdentifier(), 16) : blankString);
qDebug() << list;
if (not manufacturer.isEmpty())
port = info.systemLocation();
}
if (not port.isEmpty()) {
// Öffnen:
m_serial = new QSerialPort(this);
connect(m_serial, &QSerialPort::readyRead, this, &Server::onReadyReadSensorValueSerial);
// connect(m_serial, &QSerialPort::errorOccurred, this, &Server::startSerial);// d.h. reconnect serial
m_serial->setPortName(port);
m_serial->setBaudRate(115200);
m_serial->setDataBits(QSerialPort::DataBits::Data8);
m_serial->setParity(QSerialPort::Parity::NoParity);
m_serial->setStopBits(QSerialPort::StopBits::OneStop);
m_serial->setFlowControl(QSerialPort::FlowControl::NoFlowControl);
qDebug() << "open" << port << "...";
if (m_serial->open(QIODevice::ReadWrite))
qDebug() << "Serielle Schnittstelle zu" << port;
else
qDebug() << "Keine serielle Schnittstelle";
} else {
qDebug() << "Keine serielle Schnittstelle";
}
SHactuator::setSerial(m_serial);
// SHsensor::displayMem("Server::startSerial ENDE");
#endif // OLD
/*
*
*/
void Server::showSensorValues()
{
SHsensor::printALL();
// SHsensor::displayMem("Server::showSensorValues ENDE");
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/*
*
*/
static bool getValueFromJSON(const QJsonObject & jsonInput, const QVector<QString> &P, QString & retValue) {
QJsonObject jsonObj = jsonInput;
for (int i = 0; i<P.size()-1; i++) {
QString p = P[i];
QJsonValue value = jsonObj.value(p);
// qDebug() << value;
jsonObj = value.toObject();
// qDebug() << "jsonObj" << jsonObj;
}
// last:
/* in case of string value get value and convert into string*/
QString last = P[P.size()-1];
// qDebug() << "last: " << jsonObj[last];
QJsonValue value = jsonObj[last];
// qDebug() << "value:" << value.toString();
/* in case of array get array and convert into string*/
// qWarning() << tr("QJsonObject[appName] of value: ") << item["imp"];
// QJsonArray test = item["imp"].toArray();
// qWarning() << test[1].toString();
if (value.isDouble())
retValue = QString::number(value.toDouble());
else if (value.isArray()) {
QJsonArray qja = value.toArray();
QJsonValue v0 = qja[0];
QJsonValue v1 = qja[1];
QJsonValue v2 = qja[2];
if (v0.isDouble() and v1.isDouble() and v2.isDouble()) // solar power
retValue = QString::number(-(v0.toDouble() + v1.toDouble() + v2.toDouble()));
else
retValue = "";
} else
retValue = value.toString();
if (retValue == "")
return false;
return true;
}
/*
*
*/
void Server::processTasmotaMsg(QString jsonMSG)
{
// parse the json message:
QJsonParseError err;
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonMSG.toUtf8(), &err);
if (err.error != QJsonParseError::NoError) {
qDebug() << "# ERROR Server::tasmotaReply(): wrong JSON format";
return;
}
QJsonObject jsonObj = jsonDoc.object();
QString devName, state, value;
bool isError = true;
if (getValueFromJSON(jsonObj, {"POWER"}, state)) {
// qDebug() << "# ACK message" << state;
isError = false;
} else if (getValueFromJSON(jsonObj, {"Status","DeviceName"}, devName) and
getValueFromJSON(jsonObj, {"StatusSTS", "POWER"}, state) and
getValueFromJSON(jsonObj, {"StatusSNS", "ENERGY", "Power"}, value)) {
// neuer Wert für NOUS:
// qDebug() << "# message received for " << devName << "NID" << nid;
if (nid != -1) {
SHsensor::setValue(nid, SID_RELAY, state);
SHsensor::setValue(nid, SID_POWER, value);
// qDebug() << "# message values" << devName << state << value;
} else if (getValueFromJSON(jsonObj, {"Status","DeviceName"}, devName) and
getValueFromJSON(jsonObj, {"StatusSNS", "DS18B20", "Temperature"}, value)) {
// neuer Temperatur Wert:
int nid = SHsensor::nid(devName);
// qDebug() << "# message received for " << devName << "NID" << nid;
if (nid != -1) {
SHsensor::setValue(nid, SID_TEMP, value);
// qDebug() << "# message values" << devName << value;
isError = false;
}
}
if (isError)
qDebug() << "# invalid HTTP reply message: ignored";
}
/*
*
*/
void Server::tasmotaReply(QNetworkReply *reply)
{
// SHsensor::displayMem("Server::tasmotaReply");
if (reply->error()) {
qDebug() << reply->errorString();
return;
}
QString jsonMSG = reply->readAll();
reply->deleteLater(); // sonst Memory Leak
// SHsensor::displayMem("Server::tasmotaReply ENDE");
// SHsensor::displayMem("Server::onReadyReadSensorValueTCP");
SHmessage msg(data);
if (msg.command() == C_SET)
SHsensor::setValue(msg.nodeId(), msg.sensorId(), msg.payload());
// SHsensor::displayMem("Server::onReadyReadSensorValueTCP ENDE");
#ifdef OLD
/*
*
*/
void Server::onReadyReadSensorValueSerial()
{
// SHsensor::displayMem("Server::onReadyReadSensorValueSerial");
QByteArray collected;
const QByteArray data = m_serial->readAll();
m_serial->clear();
// qDebug() << "SerialMsg=" << data;
for (auto i : data) {
collected = collected + i;
if (i == '\n') {
// QString qs = QString(collected);
// qDebug() << qs;
SHmessage * msg = new SHmessage(collected);
if (not msg->error() and msg->command() == C_SET)
SHsensor::setValue(msg->nodeId(), msg->sensorId(), msg->payload());
delete msg;
// SHsensor::displayMem("Server::onReadyReadSensorValueSerial CLEAR");
// SHsensor::displayMem("Server::onReadyReadSensorValueSerial ENDE");
#endif // OLD
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
/*
*
*/
void Server::onNewClientConnection()
{
mutex.lock();
QWebSocket *pSocket = m_webSocketServer->nextPendingConnection();
if (m_webSocketClients.size() < maxClientNo) {
if (pSocket and pSocket->peerPort() != 0) {
connect(pSocket, &QWebSocket::textMessageReceived, this, &Server::processClientMessage);
// connect(pSocket, &QWebSocket::binaryMessageReceived, this, &ServerInterface::processBinaryMessage);
connect(pSocket, &QWebSocket::disconnected, this, &Server::socketClientDisconnected);
m_webSocketClients.push_back(pSocket);
qDebug() << "New Connection No" << m_webSocketClients.size() << "ID" << pSocket->peerPort();
// showClientsInfo();
} else
qDebug() << "No new Connection (strange) " + QString::number(pSocket->peerPort());
} else
qDebug() << "No new Connection (too many clients) " + QString::number(pSocket->peerPort());
mutex.unlock();
}
/*
*
*/
void Server::processClientMessage(QString message)
{
webSocketMsg wmsg(message);
if (not wmsg.corrupted()) {
if (wmsg.request()) { // fulfill request
QJsonObject jsonObj = wmsg.processGet();
sendToClient(jsonObj);
} else { // set value / mode:
wmsg.processSet();
}
}
}
/*
*
*/
void Server::socketClientDisconnected()
{
mutex.lock();
QWebSocket *pClient = nullptr;
if (m_webSocketClients.size() > 0)
pClient = qobject_cast<QWebSocket *>(sender());
// find disconnected client and erase from vector
for (int i=0; i < m_webSocketClients.size(); i++)
if (m_webSocketClients[i] == pClient) {
m_webSocketClients.erase(m_webSocketClients.begin()+i);
qDebug() << "Delete Connection No" << i << "ID" << pClient->peerPort();
break;
}
// showClientsInfo();
mutex.unlock();
}