Dev
This commit is contained in:
@@ -11,6 +11,7 @@ CChaletMainStatus::CChaletMainStatus()
|
||||
mIsOnline = false;
|
||||
mHarakiriDone = false;
|
||||
mStatusToggleBit = 0;
|
||||
mLostRequestPercentage = 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -52,6 +53,10 @@ QByteArray CChaletMainStatus::ToByteArray()
|
||||
Strm << mBatterySOC;
|
||||
Strm << mIsOnline;
|
||||
Strm << mCurrentSensorStatus;
|
||||
Strm << mLostRequestPercentage;
|
||||
Strm << mThisStatusDateTime;
|
||||
Strm << mLastLoraStatus;
|
||||
Strm << mStatusToggleBit;
|
||||
|
||||
return Data;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ public:
|
||||
bool mStatusToggleBit;
|
||||
|
||||
QDateTime mLastLoraStatus;
|
||||
QDateTime mThisStatusDateTime;
|
||||
|
||||
float mLostRequestPercentage;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,36 +1,231 @@
|
||||
#include "ChaletDataLogger.h"
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QDataStream>
|
||||
#include <QFileInfo>
|
||||
|
||||
|
||||
|
||||
CChaletDataLogger::CChaletDataLogger(QObject *parent) : QObject(parent)
|
||||
{
|
||||
mChaletLogFile = 0;
|
||||
OpenTodaysFile();
|
||||
mChaletNewLogFileTimer = new QTimer;
|
||||
connect(mChaletNewLogFileTimer,SIGNAL(timeout()),this,SLOT(NewLogFileTimerExpired()));
|
||||
mChaletNewLogFileTimer->setInterval(1000);
|
||||
mChaletNewLogFileTimer->setSingleShot(false);
|
||||
mChaletNewLogFileTimer->start();
|
||||
|
||||
}
|
||||
|
||||
int CChaletDataLogger::OpenTodaysFile()
|
||||
{
|
||||
mTodaysDate = QDateTime::currentDateTime().date();
|
||||
bool create = false;
|
||||
mChaletLogFile = new QFile(CHALET_LORA_DATA_LOG_FILENAME);
|
||||
if(QFile::exists(CHALET_LORA_DATA_LOG_FILENAME) == false)
|
||||
QString LogFileName(CHALET_LORA_DATA_LOG_DIR);
|
||||
LogFileName.append("ChaletLora-");
|
||||
LogFileName.append(mTodaysDate.toString("yyyy-MM-dd"));
|
||||
LogFileName.append(".csv");
|
||||
|
||||
if(mChaletLogFile != 0)
|
||||
{
|
||||
if(mChaletLogFile->isOpen())
|
||||
{
|
||||
mChaletLogFile->close();
|
||||
}
|
||||
mChaletLogFile->setFileName(LogFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
mChaletLogFile = new QFile(LogFileName);
|
||||
}
|
||||
|
||||
//Check if today's file already exist, otherwise create it...
|
||||
if(QFile::exists(LogFileName) == false)
|
||||
create = true;
|
||||
|
||||
if(mChaletLogFile->open(QIODevice::ReadWrite|QIODevice::Append/*|QIODevice::Text*/) == false)
|
||||
if(mChaletLogFile->open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Unbuffered) == false)
|
||||
{
|
||||
delete mChaletLogFile;
|
||||
mChaletLogFile = 0;
|
||||
qDebug("Cannot open chalet LORA log file...");
|
||||
return;
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
if(create)
|
||||
{
|
||||
qDebug("Creating new chalet LORA log file...");
|
||||
QString Header("Date;Heure;Courant Batterie;Tension Batterie;Inverter;Wifi\n");
|
||||
int bytes = mChaletLogFile->write(qPrintable(Header));
|
||||
mChaletLogFile->write(qPrintable(Header));
|
||||
mChaletLogFile->flush();
|
||||
|
||||
}
|
||||
// mChaletLogFile->close();
|
||||
|
||||
qDebug("Chalet LORA log file created successfully");
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
QByteArray *CChaletDataLogger::GetChaletData(QDate StartDate)
|
||||
{
|
||||
|
||||
if(StartDate > QDate::currentDate())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
QFile *LogFile =0;
|
||||
|
||||
bool done = false;
|
||||
QByteArray WorkArray, *DataArray;
|
||||
DataArray = new QByteArray;
|
||||
int NbReadings = 0;
|
||||
DataArray->clear();
|
||||
|
||||
while(!done)
|
||||
{
|
||||
|
||||
if(StartDate > QDate::currentDate())
|
||||
{
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
// else if(StartDate == QDate::currentDate())
|
||||
// {
|
||||
// LogFile = mChaletLogFile;
|
||||
// }
|
||||
else
|
||||
{
|
||||
QString LogFileName(CHALET_LORA_DATA_LOG_DIR);
|
||||
LogFileName.append("ChaletLora-");
|
||||
LogFileName.append(StartDate.toString("yyyy-MM-dd"));
|
||||
LogFileName.append(".csv");
|
||||
|
||||
if(QFileInfo::exists(LogFileName))
|
||||
{
|
||||
LogFile = new QFile(LogFileName);
|
||||
if(LogFile->open(QIODevice::ReadOnly|QIODevice::Unbuffered) == false)
|
||||
{
|
||||
delete LogFile;
|
||||
LogFile = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if(mChaletLogFile == 0)
|
||||
// {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// if(mChaletLogFile->isOpen() == false)
|
||||
// {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
if(LogFile != 0)
|
||||
{
|
||||
|
||||
LogFile->seek(0); //seek to the beginning of the log file
|
||||
WorkArray = LogFile->readLine(); //read and discard the header line.
|
||||
bool Finished = false;
|
||||
while(!Finished)
|
||||
{
|
||||
WorkArray.clear();
|
||||
WorkArray = LogFile->readLine();
|
||||
if(WorkArray.isEmpty())
|
||||
{
|
||||
Finished = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
QStringList LineData = QString(WorkArray).remove("\n").split(QChar(';'));
|
||||
if(LineData.size() == 6) //if we don't have 6 parameters, something went very wrong
|
||||
{ //"Date;Heure;Courant Batterie;Tension Batterie;Inverter;Wifi\n");
|
||||
|
||||
QString date = LineData.at(0);
|
||||
// QDate Date = QDate::fromString("yyyy-MM-dd",LineData.at(0));
|
||||
QDate Date = QDate::currentDate();
|
||||
Date = QDate::fromString(date,"yyyy-MM-dd");
|
||||
QString time = LineData.at(1);
|
||||
// QTime Time = QTime::fromString("hh:mm:ss",LineData.at(1));
|
||||
QTime Time = QTime::currentTime();
|
||||
Time= QTime::fromString(time,"hh:mm:ss");
|
||||
QDateTime DateTime(Date,Time);
|
||||
// qDebug("Date: %s",qPrintable(Date.toString("yyyy-MM-dd")));
|
||||
// qDebug("Time: %s",qPrintable(Time.toString("hh:mm:ss")));
|
||||
// qDebug("Date Time: %s",qPrintable(DateTime.toString("yyyy-MM-dd-hh:mm:ss")));
|
||||
|
||||
// time.setDate(QDate().fromString("yyyy-MM-dd",LineData.at(0)));
|
||||
// time.setTime(QTime().fromString("hh:mm:ss",LineData.at(1)));
|
||||
QString temp = LineData.at(2);
|
||||
bool OK;
|
||||
qint16 BattCurrent = temp.toInt(&OK);
|
||||
temp = LineData.at(3);
|
||||
float BattVoltage = temp.toFloat(&OK);
|
||||
temp = LineData.at(4);
|
||||
quint8 InverterStatus = 0;
|
||||
if(temp == "ON")
|
||||
{
|
||||
InverterStatus = 1;
|
||||
}
|
||||
temp = LineData.at(5);
|
||||
quint8 WiFiStatus = 0;
|
||||
if(temp == "ON")
|
||||
{
|
||||
WiFiStatus = 1;
|
||||
}
|
||||
CChaletMainStatus CurBlob;
|
||||
CurBlob.mThisStatusDateTime = DateTime;
|
||||
CurBlob.mBatteryCurrent = BattCurrent;
|
||||
CurBlob.mBatteryVoltage = BattVoltage;
|
||||
CurBlob.mInverterRelayStatus = InverterStatus;
|
||||
CurBlob.mWiFiModuleStatus = WiFiStatus;
|
||||
|
||||
DataArray->append(CurBlob.ToByteArray());
|
||||
NbReadings++;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("Invalid nb. of parameters in today's data extraction");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(LogFile != mChaletLogFile && LogFile != 0)
|
||||
{
|
||||
LogFile->close();
|
||||
delete LogFile;
|
||||
}
|
||||
LogFile = 0;
|
||||
StartDate = StartDate.addDays(1);
|
||||
|
||||
}
|
||||
|
||||
QByteArray Readings;
|
||||
QDataStream strm(&Readings,QIODevice::WriteOnly);
|
||||
strm.device()->seek(0);
|
||||
strm << NbReadings;
|
||||
DataArray->prepend(Readings);
|
||||
|
||||
return DataArray; //Don't forget to delete!!!
|
||||
}
|
||||
|
||||
QByteArray *CChaletDataLogger::GetTodaysData()
|
||||
{
|
||||
return GetChaletData(QDate::currentDate());
|
||||
}
|
||||
|
||||
|
||||
CChaletDataLogger::~CChaletDataLogger()
|
||||
{
|
||||
if(mChaletLogFile)
|
||||
@@ -38,6 +233,7 @@ CChaletDataLogger::~CChaletDataLogger()
|
||||
mChaletLogFile->close();
|
||||
delete mChaletLogFile;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool CChaletDataLogger::LogChaletLORAData(CChaletMainStatus *Data)
|
||||
@@ -82,7 +278,21 @@ bool CChaletDataLogger::LogChaletLORAData(CChaletMainStatus *Data)
|
||||
mChaletLogFile->write(qPrintable(CSVData));
|
||||
mChaletLogFile->flush();
|
||||
|
||||
|
||||
|
||||
|
||||
// mChaletLogFile->close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CChaletDataLogger::NewLogFileTimerExpired()
|
||||
{
|
||||
if(QDateTime::currentDateTime().date() > mTodaysDate) //If it's midnight...
|
||||
{
|
||||
qDebug("It's midnight... creating today's file...");
|
||||
OpenTodaysFile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
#include <QObject>
|
||||
#include <QFile>
|
||||
#include "ChaletData.h"
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
//#define CHALET_LORA_DATA_LOG_FILENAME "./ChaletLogs/ChaletLora.csv"
|
||||
#define CHALET_LORA_DATA_LOG_FILENAME "D:/Main/Chalet/LoraLogs/ChaletLora.csv"
|
||||
#define CHALET_LORA_DATA_LOG_DIR "D:/Main/Chalet/LoraLogs/"
|
||||
|
||||
class CChaletMainStatus;
|
||||
|
||||
@@ -18,13 +20,25 @@ public:
|
||||
~CChaletDataLogger();
|
||||
|
||||
bool LogChaletLORAData(CChaletMainStatus *Data);
|
||||
QByteArray *GetTodaysData();
|
||||
QByteArray *GetChaletData(QDate StartDate);
|
||||
|
||||
QFile *mChaletLogFile;
|
||||
QTimer *mChaletNewLogFileTimer;
|
||||
QDate mTodaysDate;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private:
|
||||
int OpenTodaysFile();
|
||||
|
||||
signals:
|
||||
|
||||
|
||||
public slots:
|
||||
void NewLogFileTimerExpired();
|
||||
};
|
||||
|
||||
#endif // CHALETDATALOGGER_H
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "ChaletInterface.h"
|
||||
#include "ChaletDataLogger.h"
|
||||
|
||||
CChaletInterface::CChaletInterface(int Address, CAbstractNetworkCommIF *NetworkInterface, CChaletLoraDevice *DevicePtr):
|
||||
CNetworkDevice(ID_CHALET_INTERFACE,Address,NetworkInterface)
|
||||
{
|
||||
mChaletLoraDevice = DevicePtr;
|
||||
mChaletDataLogger = mChaletLoraDevice->GetDataLoggerHandle();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +27,7 @@ int CChaletInterface::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, in
|
||||
case CHALET_INTERFACE_GENERAL_STATUS_REQUEST:
|
||||
{
|
||||
QByteArray data = mChaletLoraDevice->GetChaletMainStatus().ToByteArray();
|
||||
mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_INTERFACE,mDeviceAddress,CHALET_INTERFACE_GENERAL_STATUS_RESPONSE,data.size(),data);
|
||||
mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_INTERFACE,mDeviceAddress,CHALET_INTERFACE_GENERAL_STATUS_RESPONSE,data.size(),&data);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -74,6 +77,25 @@ int CChaletInterface::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, in
|
||||
mChaletLoraDevice->SendRebootCmd();
|
||||
break;
|
||||
}
|
||||
case CHALET_INTERFACE_GET_TODAYS_DATA_LOG_REQUEST:
|
||||
{
|
||||
QByteArray *data = mChaletDataLogger->GetTodaysData();
|
||||
mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_INTERFACE,mDeviceAddress,CHALET_INTERFACE_GET_TODAYS_DATA_LOG_RESPONSE,data->size(),data);
|
||||
delete data;
|
||||
break;
|
||||
}
|
||||
case CHALET_INTERFACE_GET_DATA_LOG_REQUEST:
|
||||
{
|
||||
QDate StartDate;
|
||||
QDataStream Strm(Data);
|
||||
Strm >> StartDate;
|
||||
QByteArray *data = mChaletDataLogger->GetChaletData(StartDate);
|
||||
mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_INTERFACE,mDeviceAddress,CHALET_INTERFACE_GET_DATA_LOG_RESPONSE,data->size(),data);
|
||||
delete data;
|
||||
break;
|
||||
}
|
||||
case CHALET_INTERFACE_GET_DATA_LOG_RESPONSE:
|
||||
case CHALET_INTERFACE_GET_TODAYS_DATA_LOG_RESPONSE:
|
||||
case CHALET_INTERFACE_GENERAL_STATUS_RESPONSE:
|
||||
case CHALET_INTERFACE_AC_POWER_STATE_STATUS_RESPONSE:
|
||||
case CHALET_INTERFACE_AC_POWER_SET_STATE_RESPONSE:
|
||||
@@ -93,3 +115,8 @@ int CChaletInterface::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, in
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
void CChaletInterface::SendChaletCommActivityBeacon()
|
||||
{
|
||||
mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_INTERFACE,mDeviceAddress,CHALET_INTERFACE_CHALET_ACTIVITY_RESPONSE,0,0);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#define CCHALETINTERFACE_H
|
||||
|
||||
#include "NetworkDevice.h"
|
||||
#include "ChaletLoraDevice.h"
|
||||
|
||||
#include "ChaletLoraDevice.h"
|
||||
|
||||
class CChaletInterface: public QObject, public CNetworkDevice
|
||||
{
|
||||
@@ -13,8 +13,10 @@ public:
|
||||
CChaletInterface(int Address, CAbstractNetworkCommIF *NetworkInterface, CChaletLoraDevice *DevicePtr);
|
||||
virtual int NewDeviceFrameReceived(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data);
|
||||
|
||||
void SendChaletCommActivityBeacon();
|
||||
private:
|
||||
CChaletLoraDevice *mChaletLoraDevice;
|
||||
CChaletDataLogger *mChaletDataLogger;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ChaletLoraDevice.h"
|
||||
#include "GlobalDefine.h"
|
||||
#include "ChaletInterface.h"
|
||||
|
||||
|
||||
|
||||
@@ -10,11 +11,16 @@ CChaletLoraDevice::CChaletLoraDevice(int Address, CAbstractNetworkCommIF *Networ
|
||||
mDeviceAddress = Address;
|
||||
mDeviceID = ID_CHALET_DEVICE;
|
||||
|
||||
|
||||
mChaletStatusTimer = new QTimer();
|
||||
mChaletStatusTimer->setInterval(1000);
|
||||
mChaletStatusTimer->setSingleShot(true);
|
||||
connect(mChaletStatusTimer,SIGNAL(timeout()),this,SLOT(CommTimerExpired()));
|
||||
|
||||
mJFUbidotsInterface = new CChaletJFUbidotsInterface("BBFF-tEq4lGAegEyP1H4EaYckNQ7ZHdZYzI");
|
||||
|
||||
mThingsBoardInterface.mChaletLoraDevice = this;
|
||||
|
||||
ResetCommStats();
|
||||
}
|
||||
|
||||
CChaletLoraDevice::~CChaletLoraDevice()
|
||||
@@ -26,11 +32,16 @@ int CChaletLoraDevice::Start()
|
||||
{
|
||||
ScheduleChaletStatusRequest();
|
||||
mChaletStatusTimer->start(1000);
|
||||
mThingsBoardInterface.RegisterThingsboardRPC();
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int CChaletLoraDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data)
|
||||
{
|
||||
Q_UNUSED(DeviceID)
|
||||
Q_UNUSED(DeviceAddress)
|
||||
Q_UNUSED(DataSize)
|
||||
|
||||
switch(MessageID)
|
||||
{
|
||||
case CHALET_ACK:
|
||||
@@ -69,20 +80,28 @@ int CChaletLoraDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, i
|
||||
mChaletMainStatus.mBatterySOC = temp2;
|
||||
|
||||
mChaletMainStatus.mStatusToggleBit = !mChaletMainStatus.mStatusToggleBit;
|
||||
mChaletMainStatus.mLastLoraStatus = QDateTime::currentDateTime();
|
||||
|
||||
CmdResponseReceived(CHALET_GENERAL_STATUS_REQUEST);
|
||||
qDebug("voltage: %f",mChaletMainStatus.mBatteryVoltage);
|
||||
qDebug("Current: %d",mChaletMainStatus.mBatteryCurrent);
|
||||
qDebug("SOC: %d",mChaletMainStatus.mBatterySOC);
|
||||
// qDebug("Current: %d",mChaletMainStatus.mBatteryCurrent);
|
||||
// qDebug("SOC: %d",mChaletMainStatus.mBatterySOC);
|
||||
qDebug("Inverter: %d",mChaletMainStatus.mInverterRelayStatus);
|
||||
|
||||
mChaletDataLogger.LogChaletLORAData(&mChaletMainStatus);
|
||||
|
||||
mJFUbidotsInterface->LogUbidotsChaletData(&mChaletMainStatus);
|
||||
|
||||
mBlynkInterface.UpdateChaletCurrent(mChaletMainStatus.mBatteryCurrent);
|
||||
mBlynkInterface.UpdateChaletVoltage(mChaletMainStatus.mBatteryVoltage);
|
||||
// mBlynkInterface.UpdateChaletWifiStatus((int)mChaletMainStatus.mInverterRelayStatus);
|
||||
mBlynkInterface.UpdateChaletInverterStatus((int)mChaletMainStatus.mInverterRelayStatus);
|
||||
mBlynkInterface.UpdateChaletStatusLed(((int)mChaletMainStatus.mStatusToggleBit)*255);
|
||||
|
||||
// mThingsBoardInterface.UpdateChaletVoltage(mChaletMainStatus.mBatteryVoltage);
|
||||
mThingsBoardInterface.UpdateChaletData(mChaletMainStatus.mInverterRelayStatus,mChaletMainStatus.mWiFiModuleStatus,mChaletMainStatus.mCurrentSensorStatus,mChaletMainStatus.mBatteryVoltage,mChaletMainStatus.mBatteryCurrent,mChaletMainStatus.mBatterySOC,mChaletMainStatus.mIsOnline);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
case CHALET_AC_POWER_STATE_STATUS_RESPONSE:
|
||||
@@ -185,6 +204,8 @@ void CChaletLoraDevice::CommTimerExpired()
|
||||
}
|
||||
}
|
||||
mPendingNetworkMsgList[0].ResendCounter++;
|
||||
mNbLostRequest++;
|
||||
ComputeCommStats();
|
||||
}
|
||||
|
||||
qDebug("Sending chalet request 0x%x",mPendingNetworkMsgList.at(0).mMessageID);
|
||||
@@ -262,7 +283,9 @@ int CChaletLoraDevice::SendRebootCmd()
|
||||
|
||||
int CChaletLoraDevice::SendChaletCommand(int CmdID, int DataSize, QByteArray Data)
|
||||
{
|
||||
mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_DEVICE,mDeviceAddress,CmdID,DataSize,Data);
|
||||
mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_DEVICE,mDeviceAddress,CmdID,DataSize,&Data);
|
||||
mTotalNbRequest++;
|
||||
ComputeCommStats();
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
@@ -351,3 +374,20 @@ int CChaletLoraDevice::ScheduleChaletCommand(int CmdID, QByteArray Data)
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int CChaletLoraDevice::ResetCommStats()
|
||||
{
|
||||
mLostRequestPercentage = 0.0;
|
||||
mTotalNbRequest = 0;
|
||||
mNbLostRequest = 0;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int CChaletLoraDevice::ComputeCommStats()
|
||||
{
|
||||
mLostRequestPercentage = ((float)mNbLostRequest/(float)mTotalNbRequest)*100;
|
||||
mChaletMainStatus.mLostRequestPercentage = mLostRequestPercentage;
|
||||
|
||||
// qDebug("Percent lost request: %f%%",mLostRequestPercentage);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#include <QList>
|
||||
#include "BlynkCloudClient.h"
|
||||
#include "ChaletDataLogger.h"
|
||||
#include "ChaletUbidotsInterface.h"
|
||||
#include "ThingsBoardInterface.h"
|
||||
|
||||
|
||||
#define LORA_MAGIC_WORD 0xBAADCAFE
|
||||
#define LORA_NORMAL_REQUEST_TIMEOUT 3000
|
||||
@@ -37,22 +40,34 @@ public:
|
||||
|
||||
CChaletMainStatus GetChaletMainStatus() {return mChaletMainStatus;}
|
||||
CBlynkCloudClient mBlynkInterface;
|
||||
CThingsBoardInterface mThingsBoardInterface;
|
||||
|
||||
CChaletMainStatus mChaletMainStatus;
|
||||
QList<CChaletNetworkMessage> mPendingNetworkMsgList;
|
||||
CChaletDataLogger mChaletDataLogger;
|
||||
CChaletJFUbidotsInterface *mJFUbidotsInterface;
|
||||
|
||||
unsigned long long int mNbLostRequest, mTotalNbRequest;
|
||||
float mLostRequestPercentage;
|
||||
|
||||
CChaletDataLogger *GetDataLoggerHandle() {return &mChaletDataLogger;} //for Interface use...
|
||||
|
||||
|
||||
|
||||
int SendWiFiModuleSetState(bool State);
|
||||
int SendInverterPowerRelayState(bool State);
|
||||
int SendDOHarakiri();
|
||||
int SendRebootCmd();
|
||||
int SendChaletCommand(int CmdID,int DataSize, QByteArray Data);
|
||||
int ResetCommStats();
|
||||
int ComputeCommStats();
|
||||
|
||||
int CmdResponseReceived(int CmdID);
|
||||
int ScheduleChaletStatusRequest();
|
||||
int ScheduleChaletCommand(int CmdID, int DataSize, QByteArray Data);
|
||||
int ScheduleChaletCommand(int CmdID,QByteArray Data);
|
||||
|
||||
|
||||
public slots:
|
||||
void CommTimerExpired();
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "ChaletModbusServer.h"
|
||||
|
||||
CChaletModbusServer::CChaletModbusServer(CModbusRepository *Repo, int ModbusPort, int DevID) :
|
||||
CModbusBackend(Repo)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef CHALETMODBUSSERVER_H
|
||||
#define CHALETMODBUSSERVER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <ModbusBackend.h>
|
||||
|
||||
class CChaletModbusServer : public CModbusBackend
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CChaletModbusServer(CModbusRepository *Repo, int ModbusPort, int DevID);
|
||||
virtual ~CChaletModbusServer();
|
||||
|
||||
int StartChaletModbusServer();
|
||||
int CloseChaletModbusServer();
|
||||
bool IsModbusConnected();
|
||||
|
||||
|
||||
|
||||
virtual void RegistersDatabaseUpdated(quint16 StartAddress, quint16 Length);
|
||||
virtual void ModbusRequestException(quint8 ExceptionCode, quint8 FctCode);
|
||||
};
|
||||
|
||||
#endif // CHALETMODUBSERVER_H
|
||||
@@ -0,0 +1,89 @@
|
||||
#include "ChaletUbidotsInterface.h"
|
||||
|
||||
CChaletUbidotsInterface::CChaletUbidotsInterface(QString UbidotsUsername, QObject *parent) : QObject(parent)
|
||||
{
|
||||
mUbidotsUsername = UbidotsUsername;
|
||||
// mUbidotsPascalChaletClient = new QMqttClient(this);
|
||||
// mUbidotsPascalChaletClient->setHostname("things.ubidots.com");
|
||||
// mUbidotsPascalChaletClient->setPort(1883);
|
||||
// mUbidotsPascalChaletClient->setUsername("BBFF-tEq4lGAegEyP1H4EaYckNQ7ZHdZYzI");
|
||||
// mUbidotsPascalChaletClient->setPassword("12");
|
||||
// mUbidotsPascalChaletClient->connectToHost();
|
||||
|
||||
mUbidotsChaletClient= new QMqttClient(this);
|
||||
mUbidotsChaletClient->setHostname(UBIDOTS_URL);
|
||||
mUbidotsChaletClient->setPort(UBIDOTS_PORT);
|
||||
mUbidotsChaletClient->setUsername(mUbidotsUsername);//"BBFF-tEq4lGAegEyP1H4EaYckNQ7ZHdZYzI");
|
||||
mUbidotsChaletClient->setPassword("12");
|
||||
|
||||
connect(mUbidotsChaletClient,SIGNAL(stateChanged(ClientState)),this,SLOT(UbidotsStateChanged(ClientState)));
|
||||
|
||||
mUbidotsChaletClient->connectToHost();
|
||||
}
|
||||
|
||||
CChaletUbidotsInterface::~CChaletUbidotsInterface()
|
||||
{
|
||||
mUbidotsChaletClient->disconnectFromHost();
|
||||
|
||||
delete mUbidotsChaletClient;
|
||||
}
|
||||
|
||||
int CChaletUbidotsInterface::LogUbidotsChaletData(CChaletMainStatus *Data)
|
||||
{
|
||||
Q_UNUSED(Data)
|
||||
|
||||
|
||||
qDebug("LogUbidotsChaletData() should only be called from derived class...");
|
||||
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
void CChaletUbidotsInterface::UbidotsStateChanged(QMqttClient::ClientState state)
|
||||
{
|
||||
qDebug("MQTT client %s is now in state %d",qPrintable(mInterfaceOwnerName),state);
|
||||
//MQTTStateChanged(state);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////implementation
|
||||
CChaletJFUbidotsInterface::CChaletJFUbidotsInterface(QString Username) : CChaletUbidotsInterface(Username)
|
||||
{
|
||||
mInterfaceOwnerName = "J-F";
|
||||
//mUbidotsChaletClient->subscribe(QMqttTopicFilter("/v1.6/devices/ChaletDuino"))
|
||||
|
||||
//connect(mInverterBtnSubscritption,SIGNAL(messageReceived(QMqttMessage)),this,SLOT(InverterBtnSubscriptionMsgReceived(QMqttMessage)));
|
||||
|
||||
|
||||
qDebug("JF Ubidots interface created");
|
||||
}
|
||||
|
||||
int CChaletJFUbidotsInterface::LogUbidotsChaletData(CChaletMainStatus *Data)
|
||||
{
|
||||
QString MQTTMsg = QString("{\"BattVoltage\": %1}").arg(Data->mBatteryVoltage);
|
||||
mUbidotsChaletClient->publish(QMqttTopicName("/v1.6/devices/ChaletDuino"),MQTTMsg.toUtf8());
|
||||
MQTTMsg.clear();
|
||||
MQTTMsg = QString("{\"InverterSwitch\": %1}").arg(Data->mWiFiModuleStatus !=0);
|
||||
mUbidotsChaletClient->publish(QMqttTopicName("/v1.6/devices/ChaletDuino"),MQTTMsg.toUtf8(),0,true);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
void CChaletJFUbidotsInterface::InverterBtnSubscriptionMsgReceived(QMqttMessage msg)
|
||||
{
|
||||
qDebug("subscription msg. Topic name: %s",qPrintable(msg.topic().name()));
|
||||
}
|
||||
|
||||
void CChaletJFUbidotsInterface::WiFiBtnSubscriptionMsgReceived(QMqttMessage msg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CChaletJFUbidotsInterface::MQTTStateChanged(QMqttClient::ClientState)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef CHALETUBIDOTSINTERFACE_H
|
||||
#define CHALETUBIDOTSINTERFACE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QtMqtt/QtMqtt>
|
||||
#include <QMqttClient>
|
||||
#include "ChaletData.h"
|
||||
#include <QString>
|
||||
|
||||
#define UBIDOTS_URL "things.ubidots.com"
|
||||
#define UBIDOTS_PORT 1883
|
||||
|
||||
class CChaletUbidotsInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CChaletUbidotsInterface(QString UbidotsUsername, QObject *parent = 0);
|
||||
~CChaletUbidotsInterface();
|
||||
virtual int LogUbidotsChaletData(CChaletMainStatus *Data);
|
||||
virtual void MQTTStateChanged(QMqttClient::ClientState)=0;
|
||||
|
||||
QMqttClient *mUbidotsChaletClient;
|
||||
QString mUbidotsUsername;
|
||||
QString mInterfaceOwnerName;
|
||||
|
||||
|
||||
|
||||
public slots:
|
||||
void UbidotsStateChanged(QMqttClient::ClientState);
|
||||
};
|
||||
|
||||
class CChaletJFUbidotsInterface: public CChaletUbidotsInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CChaletJFUbidotsInterface(QString Username);
|
||||
virtual int LogUbidotsChaletData(CChaletMainStatus *Data);
|
||||
void MQTTStateChanged(QMqttClient::ClientState);
|
||||
|
||||
QMqttSubscription *mInverterBtnSubscritption, *mWiFiBtnSubscription;
|
||||
|
||||
public slots:
|
||||
void InverterBtnSubscriptionMsgReceived(QMqttMessage);
|
||||
void WiFiBtnSubscriptionMsgReceived(QMqttMessage);
|
||||
|
||||
|
||||
};
|
||||
#endif // CHALETUBIDOTSINTERFACE_H
|
||||
@@ -0,0 +1,285 @@
|
||||
#include "ThingsBoardInterface.h"
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include "ChaletLoraDevice.h"
|
||||
|
||||
|
||||
CThingsBoardInterface::CThingsBoardInterface()
|
||||
{
|
||||
mThingsBoardSocket = new QNetworkAccessManager;
|
||||
mThingsBoardRPCSocket = new QNetworkAccessManager;
|
||||
|
||||
|
||||
connect(mThingsBoardSocket,SIGNAL(finished(QNetworkReply*)),this,SLOT(ThingsBoardServerFinished(QNetworkReply*)));
|
||||
connect(mThingsBoardSocket,SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),this,SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
|
||||
|
||||
connect(mThingsBoardRPCSocket,SIGNAL(finished(QNetworkReply*)),this,SLOT(ThingsBoardRPCFinished(QNetworkReply*)));
|
||||
connect(mThingsBoardRPCSocket,SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),this,SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
|
||||
}
|
||||
|
||||
CThingsBoardInterface::~CThingsBoardInterface()
|
||||
{
|
||||
mThingsBoardRPCReply->deleteLater();
|
||||
delete mThingsBoardRPCSocket;
|
||||
delete mThingsBoardSocket;
|
||||
|
||||
}
|
||||
|
||||
int CThingsBoardInterface::RegisterThingsboardRPC()
|
||||
{
|
||||
|
||||
QNetworkRequest Req;
|
||||
Req.setUrl(QUrl("http://192.168.50.100:8085/api/v1/aQIocLkJM2ECSqVT2VRx/rpc"));
|
||||
|
||||
mThingsBoardRPCReply = mThingsBoardRPCSocket->get(Req);
|
||||
// connect(mThingsBoardRPCReply,SIGNAL(readyRead()),this,SLOT(RPCData()));
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CThingsBoardInterface::UpdateChaletVoltage(float Voltage)
|
||||
{
|
||||
// "{\"temperature\": 25}" http://localhost:8080/api/v1/$ACCESS_TOKEN/telemetry --header "Content-Type:application/json"
|
||||
//{"doubleKey":42.0}
|
||||
|
||||
QByteArray JsonByteArray = "{\"Bat_Voltage\":";
|
||||
JsonByteArray.append((QString("%1}").arg(Voltage)).toUtf8().data());
|
||||
|
||||
QNetworkRequest Req;
|
||||
Req.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");
|
||||
Req.setUrl(QUrl("http://192.168.50.100:8085/api/v1/aQIocLkJM2ECSqVT2VRx/telemetry"));
|
||||
|
||||
mThingsBoardSocket->post(Req,JsonByteArray);
|
||||
|
||||
}
|
||||
|
||||
void CThingsBoardInterface::UpdateChaletData(quint8 mInverterRelayStatus, quint8 mWiFiModuleStatus, qint8 mCurrentSensorStatus, float mBatteryVoltage, qint16 mBatteryCurrent, qint16 mBatterySOC, qint8 LoraState)
|
||||
{
|
||||
//{"key1":"value1", "key2":"value2"}
|
||||
|
||||
QByteArray JsonByteArray = "{\"Bat_Voltage\":";
|
||||
JsonByteArray.append((QString("%1, ").arg(mBatteryVoltage)).toUtf8().data());
|
||||
|
||||
JsonByteArray.append("\"Bat_SOC\":");
|
||||
JsonByteArray.append((QString("%1, ").arg(mBatterySOC)).toUtf8().data());
|
||||
|
||||
JsonByteArray.append("\"WiFi_State\":");
|
||||
JsonByteArray.append((QString("%1, ").arg(mWiFiModuleStatus)).toUtf8().data());
|
||||
|
||||
JsonByteArray.append("\"CurrentSensor_State\":");
|
||||
JsonByteArray.append((QString("%1, ").arg(mCurrentSensorStatus)).toUtf8().data());
|
||||
|
||||
JsonByteArray.append("\"Bat_Current\":");
|
||||
JsonByteArray.append((QString("%1, ").arg(mBatteryCurrent)).toUtf8().data());
|
||||
|
||||
JsonByteArray.append("\"LoRa_State\":");
|
||||
JsonByteArray.append((QString("%1, ").arg(LoraState)).toUtf8().data());
|
||||
|
||||
JsonByteArray.append("\"Inverter_State\":");
|
||||
JsonByteArray.append((QString("%1}").arg(mInverterRelayStatus)).toUtf8().data());
|
||||
|
||||
QNetworkRequest Req;
|
||||
Req.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");
|
||||
Req.setUrl(QUrl("http://192.168.50.100:8085/api/v1/aQIocLkJM2ECSqVT2VRx/telemetry"));
|
||||
|
||||
mThingsBoardSocket->post(Req,JsonByteArray);
|
||||
|
||||
// if(mThingsBoardRPCReply->isRunning() == true)
|
||||
// {
|
||||
// qDebug("RPC socket running...");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// qDebug("RPC socket not runnging");
|
||||
// }
|
||||
}
|
||||
|
||||
void CThingsBoardInterface::ThingsBoardServerFinished(QNetworkReply *NetworkReply)
|
||||
{
|
||||
if(NetworkReply->isFinished() == false)
|
||||
return;
|
||||
|
||||
if(NetworkReply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
qDebug("Network error... %d", NetworkReply->error());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QByteArray Reply = NetworkReply->readAll();
|
||||
if(Reply.isEmpty())
|
||||
return;
|
||||
|
||||
NetworkReply->deleteLater();
|
||||
|
||||
QString ReplyString(Reply);
|
||||
qDebug("ThingsBoard Server Reply: %s",ReplyString.toUtf8().data());
|
||||
ReplyString.remove("[\"");
|
||||
ReplyString.remove("\"]");
|
||||
QJsonValue Result(ReplyString);
|
||||
// QJsonParseError error;
|
||||
// QJsonDocument JsonReply = QJsonDocument::fromJson(Reply,&error);
|
||||
// QJsonObject JsonObject = JsonReply.object();
|
||||
// QStringList Keys = JsonObject.keys();
|
||||
|
||||
// int toto = ReplyString.toInt();
|
||||
// qDebug("Switch = %d",toto);
|
||||
}
|
||||
|
||||
void CThingsBoardInterface::sslErrors(QNetworkReply *ServerReply, QList<QSslError> ErrorList)
|
||||
{
|
||||
|
||||
qDebug("Ssl errors...");
|
||||
ServerReply->ignoreSslErrors();
|
||||
}
|
||||
|
||||
|
||||
void CThingsBoardInterface::ThingsBoardRPCFinished(QNetworkReply *NetworkReply)
|
||||
{
|
||||
if(mThingsBoardRPCReply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
qDebug("Network error (ThingsBoardRPC)... %d", mThingsBoardRPCReply->error());
|
||||
RegisterThingsboardRPC();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QByteArray Reply = mThingsBoardRPCReply->readAll();
|
||||
if(Reply.isEmpty())
|
||||
{
|
||||
qDebug("Received an empty RPC reply in ThiungsBoard...");
|
||||
RegisterThingsboardRPC();
|
||||
return;
|
||||
}
|
||||
|
||||
mThingsBoardRPCReply->deleteLater();
|
||||
|
||||
QString ReplyString(Reply);
|
||||
qDebug("ThingsBoard RPC Reply: %s",ReplyString.toUtf8().data());
|
||||
QJsonDocument JSonReply = QJsonDocument::fromJson(Reply);
|
||||
|
||||
QJsonObject RPCCmd = JSonReply.object();
|
||||
|
||||
QJsonValue RequestedCmd = RPCCmd.value("method");
|
||||
{
|
||||
if(RequestedCmd.toString().contains("setChaletInverterState"))
|
||||
{
|
||||
//Fetch the required state.
|
||||
bool RequestedState = RPCCmd.value("params").toBool();
|
||||
if(RequestedState == true)
|
||||
{
|
||||
qDebug("Server Inverter TURN ON request received.");
|
||||
mChaletLoraDevice->SendInverterPowerRelayState(true);
|
||||
}
|
||||
if(RequestedState == false)
|
||||
{
|
||||
qDebug("Server Inverter TURN OFF request received.");
|
||||
mChaletLoraDevice->SendInverterPowerRelayState(false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if(RequestedCmd.toString().contains("setWiFiState"))
|
||||
{
|
||||
//Fetch the required state.
|
||||
QString RequestedState = RPCCmd.value("params").toString();
|
||||
if(RequestedState == "true")
|
||||
{
|
||||
qDebug("Server WiFi TURN ON request received.");
|
||||
}
|
||||
if(RequestedState == "false")
|
||||
{
|
||||
qDebug("Server WiFi TURN OFF request received.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("Received an unknown RPC call from ThingsBoard server");
|
||||
}
|
||||
}
|
||||
|
||||
//Re-register for next request..
|
||||
RegisterThingsboardRPC();
|
||||
}
|
||||
|
||||
void CThingsBoardInterface::RPCsslErrors(QNetworkReply *ServerReply, QList<QSslError> ErrorList)
|
||||
{
|
||||
|
||||
qDebug("Ssl errors...");
|
||||
ServerReply->ignoreSslErrors();
|
||||
}
|
||||
|
||||
void CThingsBoardInterface::RPCData()
|
||||
{
|
||||
// if(mThingsBoardRPCReply->isFinished() == false)
|
||||
// return;
|
||||
|
||||
// if(mThingsBoardRPCReply->error() != QNetworkReply::NoError)
|
||||
// {
|
||||
// qDebug("Network error (RPCData)... %d", mThingsBoardRPCReply->error());
|
||||
// RegisterThingsboardRPC();
|
||||
// return;
|
||||
// }
|
||||
|
||||
|
||||
// QByteArray Reply = mThingsBoardRPCReply->readAll();
|
||||
// if(Reply.isEmpty())
|
||||
// {
|
||||
// qDebug("Received an empty RPC reply in ThiungsBoard...");
|
||||
// RegisterThingsboardRPC();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// mThingsBoardRPCReply->deleteLater();
|
||||
|
||||
// QString ReplyString(Reply);
|
||||
// qDebug("ThingsBoard RPC Reply: %s",ReplyString.toUtf8().data());
|
||||
// QJsonDocument JSonReply = QJsonDocument::fromJson(Reply);
|
||||
|
||||
// QJsonObject RPCCmd = JSonReply.object();
|
||||
|
||||
// QJsonValue RequestedCmd = RPCCmd.value("method");
|
||||
// {
|
||||
// if(RequestedCmd.toString().contains("setChaletInverterState"))
|
||||
// {
|
||||
// //Fetch the required state.
|
||||
// bool RequestedState = RPCCmd.value("params").toBool();
|
||||
// if(RequestedState == true)
|
||||
// {
|
||||
// qDebug("Server Inverter TURN ON request received.");
|
||||
// //mChaletLoraDevice->SendInverterPowerRelayState(true);
|
||||
// }
|
||||
// if(RequestedState == false)
|
||||
// {
|
||||
// qDebug("Server Inverter TURN OFF request received.");
|
||||
// // mChaletLoraDevice->SendInverterPowerRelayState(false);
|
||||
// }
|
||||
|
||||
|
||||
// }
|
||||
// else if(RequestedCmd.toString().contains("setWiFiState"))
|
||||
// {
|
||||
// //Fetch the required state.
|
||||
// QString RequestedState = RPCCmd.value("params").toString();
|
||||
// if(RequestedState == "true")
|
||||
// {
|
||||
// qDebug("Server WiFi TURN ON request received.");
|
||||
// }
|
||||
// if(RequestedState == "false")
|
||||
// {
|
||||
// qDebug("Server WiFi TURN OFF request received.");
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// qDebug("Received an unknown RPC call from ThingsBoard server");
|
||||
// }
|
||||
// }
|
||||
|
||||
// //Re-register for next request..
|
||||
// RegisterThingsboardRPC();
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef THINGSBOARDINTERFACE_H
|
||||
#define THINGSBOARDINTERFACE_H
|
||||
|
||||
class CChaletLoraDevice;
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
class CThingsBoardInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CThingsBoardInterface();
|
||||
~CThingsBoardInterface();
|
||||
|
||||
CChaletLoraDevice *mChaletLoraDevice;
|
||||
|
||||
int RegisterThingsboardRPC();
|
||||
void UpdateChaletVoltage(float Voltage);
|
||||
void UpdateChaletData(quint8 mInverterRelayStatus, quint8 mWiFiModuleStatus, qint8 mCurrentSensorStatus, float mBatteryVoltage, qint16 mBatteryCurrent, qint16 mBatterySOC, qint8 LoraState);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *mThingsBoardSocket, *mThingsBoardRPCSocket;
|
||||
QNetworkReply *mThingsBoardRPCReply;
|
||||
|
||||
public slots:
|
||||
void ThingsBoardServerFinished(QNetworkReply*);
|
||||
void sslErrors(QNetworkReply*,QList<QSslError>);
|
||||
|
||||
void ThingsBoardRPCFinished(QNetworkReply*);
|
||||
void RPCsslErrors(QNetworkReply*,QList<QSslError>);
|
||||
|
||||
void RPCData();
|
||||
};
|
||||
|
||||
#endif // THINGSBOARDINTERFACE_H
|
||||
Reference in New Issue
Block a user