6#include "clientmanagerlite.h"
10#include "inditelescopelite.h"
12#include "kstarslite.h"
14#include "skymaplite.h"
15#include "fitsviewer/fitsdata.h"
16#include "kstarslite/imageprovider.h"
17#include "kstarslite/skyitems/telescopesymbolsitem.h"
19#include <KLocalizedString>
21#include <QApplication>
24#include <QImageReader>
26#include <QJsonDocument>
28#include <QQmlApplicationEngine>
30#include <QTemporaryFile>
32const char *libindi_strings_context =
"string from libindi, used in the config dialog";
35#include "libraw/libraw.h"
38DeviceInfoLite::DeviceInfoLite(INDI::BaseDevice *
dev) : device(
dev)
42DeviceInfoLite::~DeviceInfoLite()
58ClientManagerLite::~ClientManagerLite()
62bool ClientManagerLite::setHost(
const QString &ip,
unsigned int port)
72 setLastUsedServer(ip);
73 setLastUsedPort(port);
81void ClientManagerLite::disconnectHost()
90 if (webMProfilesReply.get() !=
nullptr)
96 webMProfilesReply.reset(manager.
get(request));
100 setLastUsedServer(ip);
101 setLastUsedWebManagerPort(port);
106 if (webMStartProfileReply.get() !=
nullptr)
111 urlStr =
urlStr.arg(getLastUsedServer()).arg(getLastUsedWebManagerPort()).arg(profile);
123 if (webMStopProfileReply.get() !=
nullptr)
126 QString urlStr(
QString(
"http://%1:%2/api/server/stop").arg(getLastUsedServer()).arg(getLastUsedWebManagerPort()));
138 if (webMProfilesReply.get() !=
nullptr)
140 qWarning(
"Web Manager profile query error: %d", (
int)code);
142 webMProfilesReply.release()->deleteLater();
145 if (webMStatusReply.get() !=
nullptr)
147 qWarning(
"Web Manager status query error: %d", (
int)code);
149 webMStatusReply.release()->deleteLater();
152 if (webMStopProfileReply.get() !=
nullptr)
154 qWarning(
"Web Manager stop active profile error: %d", (
int)code);
156 webMStopProfileReply.release()->deleteLater();
159 if (webMStartProfileReply.get() !=
nullptr)
161 qWarning(
"Web Manager start active profile error: %d", (
int)code);
163 webMStartProfileReply.release()->deleteLater();
171 if (webMProfilesReply.get() !=
nullptr)
173 QByteArray responseData = webMProfilesReply->readAll();
176 webMProfilesReply.release()->deleteLater();
184 webMProfiles.
clear();
185 for (
int i = 0; i < array.
size(); ++i)
189 webMProfiles += array.
at(i).
toObject()[
"name"].toString();
193 QString urlStr(
QString(
"http://%1:%2/api/server/status").arg(getLastUsedServer()).arg(getLastUsedWebManagerPort()));
196 webMStatusReply.reset(manager.
get(request));
203 if (webMStatusReply.get() !=
nullptr)
205 QByteArray responseData = webMStatusReply->readAll();
208 webMStatusReply.release()->deleteLater();
217 if (!
object.contains(
"status") || !
object.contains(
"active_profile"))
222 QString statusStr =
object[
"status"].toString();
225 indiControlPage->
setProperty(
"webMBrowserButtonVisible",
true);
226 indiControlPage->
setProperty(
"webMStatusTextVisible",
true);
227 if (statusStr ==
"True")
230 indiControlPage->
setProperty(
"webMStatusText",
i18n(
"Web Manager Status: Online"));
231 indiControlPage->
setProperty(
"webMActiveProfileText",
233 indiControlPage->
setProperty(
"webMActiveProfileLayoutVisible",
true);
234 indiControlPage->
setProperty(
"webMProfileListVisible",
false);
237 indiControlPage->
setProperty(
"webMStatusText",
i18n(
"Web Manager Status: Offline"));
238 indiControlPage->
setProperty(
"webMActiveProfileLayoutVisible",
false);
240 indiControlPage->
setProperty(
"webMProfileListVisible",
true);
245 if (webMStopProfileReply.get() !=
nullptr)
247 webMStopProfileReply.release()->deleteLater();
249 indiControlPage->
setProperty(
"webMStatusTextVisible",
true);
250 indiControlPage->
setProperty(
"webMActiveProfileLayoutVisible",
false);
252 indiControlPage->
setProperty(
"webMProfileListVisible",
true);
256 if (webMStartProfileReply.get() !=
nullptr)
258 webMStartProfileReply.release()->deleteLater();
262 urlStr =
urlStr.arg(getLastUsedServer()).arg(getLastUsedWebManagerPort());
265 webMStatusReply.reset(manager.
get(request));
278 for (
auto&
devInfo : m_devices)
282 return devInfo->telescope.get();
288void ClientManagerLite::setConnectedHost(
const QString &connectedHost)
290 m_connectedHost = connectedHost;
291 setConnected(m_connectedHost.
size() > 0);
293 emit connectedHostChanged(connectedHost);
296void ClientManagerLite::setConnected(
bool connected)
298 m_connected = connected;
299 emit connectedChanged(connected);
304 foreach (DeviceInfoLite *
devInfo, m_devices)
306 if (
devInfo->device->getDeviceName() == device)
311 IPState state =
prop->getState();
315 for (
int i = 0; i <
prop->getLight()->
nlp; i++)
317 if (
lights[i].name == name)
322 if (i ==
prop->getLight()->nlp - 1)
354void ClientManagerLite::buildTextGUI(Property *property)
356 auto tvp =
property->getText();
360 for (
const auto &
it: *
tvp)
374 label =
tvp->getName();
384 switch (property->getPermission())
401 emit createINDIText(property->getDeviceName(), property->getName(), label, name, text, read, write);
405void ClientManagerLite::buildNumberGUI(Property *property)
407 auto nvp =
property->getNumber();
412 for (
const auto &
it:
nvp)
429 label = np->getName();
431 numberFormat(
iNumber, np.getFormat(), np.getValue());
443 if (
it.getStep() != 0 && (
it.getMax() -
it.getMin()) /
it.getStep() <= 100)
446 switch (property->getPermission())
463 emit createINDINumber(property->getDeviceName(), property->getName(), label, name, text, read, write,
468void ClientManagerLite::buildMenuGUI(INDI::Property property)
473 auto svp =
property->getSwitch();
480 buildSwitch(
false, &
it, property);
500void ClientManagerLite::buildSwitchGUI(INDI::Property property, PGui guiType)
502 auto svp =
property->getSwitch();
503 bool exclusive =
false;
508 if (guiType == PG_BUTTONS)
515 else if (guiType == PG_RADIO)
523 buildSwitch(
true, &
it, property, exclusive, guiType);
527void ClientManagerLite::buildSwitch(
bool buttonGroup,
ISwitch *
sw, INDI::Property property,
bool exclusive,
533 if (label ==
"(I18N_EMPTY_MESSAGE)")
540 if (label ==
"(I18N_EMPTY_MESSAGE)")
545 bool isSelected =
false;
548 emit createINDIMenu(property->getDeviceName(), property->getName(), label,
sw->name, isSelected);
560 emit createINDIButton(property->getDeviceName(), property->getName(), label, name,
true,
true, exclusive,
565 emit createINDIRadio(property->getDeviceName(), property->getName(), label, name,
true,
true, exclusive,
586void ClientManagerLite::buildLightGUI(INDI::Property property)
588 auto lvp =
property->getLight();
598 if (label ==
"(I18N_EMPTY_MESSAGE)")
604 if (label ==
"(I18N_EMPTY_MESSAGE)")
607 emit createINDILight(property->getDeviceName(), property->getName(), label, name);
649void ClientManagerLite::sendNewINDISwitch(
const QString &deviceName,
const QString &propName,
const QString &name)
651 foreach (DeviceInfoLite *
devInfo, m_devices)
653 INDI::BaseDevice *device =
devInfo->device;
654 if (device->getDeviceName() == deviceName)
656 auto property = device->getProperty(propName.
toLatin1());
659 auto svp =
property->getSwitch();
669 if (sp->isNameMatch(
"CONNECT"))
700 foreach (DeviceInfoLite *
devInfo, m_devices)
702 INDI::BaseDevice *device =
devInfo->device;
703 if (device->getDeviceName() == deviceName)
705 auto np = device->getNumber(propName.
toLatin1());
708 auto n = np->findWIdgetByName(
numberName.toLatin1());
716 qDebug() <<
"Could not find property: " << deviceName <<
"." << propName <<
"." <<
numberName;
720 qDebug() <<
"Could not find property: " << deviceName <<
"." << propName <<
"." <<
numberName;
726void ClientManagerLite::sendNewINDIText(
const QString &deviceName,
const QString &propName,
const QString &fieldName,
729 foreach (DeviceInfoLite *
devInfo, m_devices)
731 INDI::BaseDevice *device =
devInfo->device;
732 if (device->getDeviceName() == deviceName)
734 auto tp = device->getText(propName.
toLatin1());
737 auto t = tp->findWidgetByName(fieldName.
toLatin1());
745 qDebug() <<
"Could not find property: " << deviceName <<
"." << propName <<
"." << fieldName;
749 qDebug() <<
"Could not find property: " << deviceName <<
"." << propName <<
"." << fieldName;
755void ClientManagerLite::sendNewINDISwitch(
const QString &deviceName,
const QString &propName,
int index)
759 foreach (DeviceInfoLite *
devInfo, m_devices)
761 INDI::BaseDevice *device =
devInfo->device;
762 if (device->getDeviceName() == deviceName)
764 auto property = device->getProperty(propName.
toStdString().c_str());
767 auto svp =
property->getSwitch();
772 if (index >=
svp->count())
775 auto sp =
svp->at(index);
796 i18n(
"JPEG (*.jpeg);;JPG (*.jpg);;PNG (*.png);;BMP (*.bmp)"));
800 if (displayImage.
save(filename))
802 emit newINDIMessage(
"File " + filename +
" was successfully saved");
806 emit newINDIMessage(
"Couldn't save file " + filename);
810bool ClientManagerLite::isDeviceConnected(
const QString &deviceName)
812 INDI::BaseDevice *device = getDevice(deviceName.
toStdString().c_str());
814 if (device !=
nullptr)
816 return device->isConnected();
826void ClientManagerLite::newDevice(INDI::BaseDevice *dp)
830 QString deviceName = dp->getDeviceName();
834 qWarning() <<
"Received invalid device with empty name! Ignoring the device...";
838 if (Options::verboseLogging())
839 qDebug() <<
"Received new device " << deviceName;
840 emit newINDIDevice(deviceName);
842 DeviceInfoLite *
devInfo =
new DeviceInfoLite(dp);
850void ClientManagerLite::removeDevice(BaseDevice *dp)
852 emit removeINDIDevice(
QString(dp->getDeviceName()));
855void ClientManagerLite::newProperty(INDI::Property property)
857 QString deviceName =
property->getDeviceName();
859 QString groupName =
property->getGroupName();
862 DeviceInfoLite *
devInfo =
nullptr;
864 foreach (DeviceInfoLite *
di, m_devices)
866 if (
di->device->getDeviceName() == deviceName)
874 if ((!
strcmp(property->getName(),
"EQUATORIAL_EOD_COORD") ||
875 !
strcmp(property->getName(),
"EQUATORIAL_COORD") ||
876 !
strcmp(property->getName(),
"HORIZONTAL_COORD")))
879 m_telescope =
devInfo->telescope.get();
880 emit telescopeAdded(m_telescope);
883 if (
devInfo->telescope->isConnected())
885 emit deviceConnected(
devInfo->telescope->getDeviceName(),
true);
891 emit newINDIProperty(deviceName, name, groupName, type, label);
893 switch (property->getType())
898 else if (property->getSwitch()->nsp > 4)
901 guiType = PG_BUTTONS;
903 if (guiType == PG_MENU)
904 buildMenuGUI(property);
906 buildSwitchGUI(property, guiType);
910 buildTextGUI(property);
913 buildNumberGUI(property);
917 buildLightGUI(property);
929void ClientManagerLite::removeProperty(INDI::Property property)
931 if (property ==
nullptr)
934 emit removeINDIProperty(property->getDeviceName(), property->getGroupName(), property->getName());
936 DeviceInfoLite *
devInfo =
nullptr;
937 foreach (DeviceInfoLite *
di, m_devices)
939 if (
di->device == property->getBaseDevice())
947 if ((!
strcmp(property->getName(),
"EQUATORIAL_EOD_COORD") || !
strcmp(property->getName(),
"HORIZONTAL_COORD")))
949 if (
devInfo->telescope.get() !=
nullptr)
958void ClientManagerLite::newBLOB(
IBLOB *bp)
960 processBLOBasCCD(bp);
961 emit newLEDState(bp->bvp->device, bp->name);
964bool ClientManagerLite::processBLOBasCCD(
IBLOB *bp)
977 QString deviceName = bp->bvp->device;
984 else if (format.contains(
"fits"))
986 else if (format.contains(
"cr2"))
989 if (BType == BLOB_OTHER)
1002 if (
QDir(currentDir).exists() ==
false)
1005 QString filename(currentDir +
'/');
1013 qDebug() <<
"ISD:CCD Error: Unable to open " << filename <<
endl;
1020 for (
nr = 0;
nr < (int)bp->size;
nr += n)
1021 n =
out.writeRawData(
static_cast<char *
>(bp->blob) +
nr, bp->size -
nr);
1025 filename =
tmpFile.fileName();
1032 strncpy(BLOBFilename, filename.toLatin1(), MAXINDIFILENAME);
1033 bp->aux2 = BLOBFilename;
1045 if (BType == BLOB_IMAGE || BType ==
BLOB_CR2)
1051#define OUT RawProcessor.imgdata.params
1053 OUT.use_camera_wb = 1;
1087 QString cmd =
QString(
"/bin/sh -c \"dcraw -c -q 0 -w -H 5 -b 8 %1 | cjpeg -quality 80 > %2\"")
1091 dcraw.waitForFinished();
1097 emit newINDIMessage(
1098 i18n(
"Unable to find dcraw and cjpeg. Please install the required tools to convert CR2 to JPEG."));
1099 emit newINDIBLOBImage(deviceName,
false);
1105 displayImage.
load(filename);
1108 emit newINDIBLOBImage(deviceName,
true);
1111 else if (BType == BLOB_FITS)
1113 displayImage = FITSData::FITSToImage(filename);
1116 emit newINDIBLOBImage(deviceName,
true);
1119 emit newINDIBLOBImage(deviceName,
false);
1125 for (
int i = 0; i <
svp->nsp; ++i)
1131 if (m_telescope && m_telescope->getDeviceName() ==
svp->device)
1135 emit telescopeConnected(m_telescope);
1137 emit telescopeDisconnected();
1151 if ((!
strcmp(
nvp->name,
"EQUATORIAL_EOD_COORD") || !
strcmp(
nvp->name,
"HORIZONTAL_COORD")))
1158 for (
int i = 0; i <
nvp->nnp; ++i)
1162 numberFormat(
buf, num.format, num.value);
1166 emit newLEDState(deviceName, propName);
1174 for (
int i = 0; i <
tvp->ntp; ++i)
1177 QString fieldName = text.name;
1179 emit newINDIText(deviceName, propName, fieldName, text.text);
1180 emit newLEDState(deviceName, propName);
1190void ClientManagerLite::newMessage(INDI::BaseDevice *dp,
int messageID)
1195void ClientManagerLite::serverDisconnected(
int exit_code)
1199 setConnected(
false);
1202void ClientManagerLite::clearDevices()
1205 foreach (DeviceInfoLite *
devInfo, m_devices)
1207 if (
devInfo->telescope.get() !=
nullptr)
1216QString ClientManagerLite::getLastUsedServer()
1218 return Options::lastServer();
1221void ClientManagerLite::setLastUsedServer(
const QString &server)
1223 if (getLastUsedServer() != server)
1225 Options::setLastServer(server);
1226 lastUsedServerChanged();
1230int ClientManagerLite::getLastUsedPort()
1232 return Options::lastServerPort();
1235void ClientManagerLite::setLastUsedPort(
int port)
1237 if (getLastUsedPort() != port)
1239 Options::setLastServerPort(port);
1240 lastUsedPortChanged();
1244int ClientManagerLite::getLastUsedWebManagerPort()
1246 return Options::lastWebManagerPort();
1249void ClientManagerLite::setLastUsedWebManagerPort(
int port)
1251 if (getLastUsedWebManagerPort() != port)
1253 Options::setLastWebManagerPort(port);
1254 lastUsedWebManagerPortChanged();
Q_INVOKABLE QString syncLED(const QString &device, const QString &property, const QString &name="")
syncLED
Q_INVOKABLE void webManagerReplyError(QNetworkReply::NetworkError code)
Handle the errors of the async Web Manager requests.
Q_INVOKABLE void webManagerReplyFinished()
Do actions when async Web Manager requests are finished.
Q_INVOKABLE void getWebManagerProfiles(const QString &ip, unsigned int port)
Get the profiles from Web Manager.
Q_INVOKABLE bool saveDisplayImage()
saveDisplayImage
Q_INVOKABLE void startWebManagerProfile(const QString &profile)
Start an INDI server with a Web Manager profile.
Q_INVOKABLE void stopWebManagerProfile()
Stop the INDI server with an active Web Manager profile.
static KStarsLite * Instance()
device handle controlling telescope.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
QVariant read(const QByteArray &data, int versionOverride=0)
QString label(StandardShortcut id)
QString name(StandardShortcut id)
const char * constData() const const
QDateTime currentDateTime()
QString toString(QStringView format, QCalendar cal) const const
bool mkpath(const QString &dirPath) const const
QString path() const const
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
QString filePath() const const
bool load(QIODevice *device, const char *format)
bool save(QIODevice *device, const char *format, int quality) const const
QJsonValue at(qsizetype i) const const
qsizetype size() const const
QJsonArray array() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
bool isArray() const const
bool contains(QLatin1StringView key) const const
bool isObject() const const
QJsonObject toObject() const const
void append(QList< T > &&value)
QNetworkReply * get(const QNetworkRequest &request)
QNetworkReply * post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
bool setProperty(const char *name, QVariant &&value)
void setContextProperty(const QString &name, QObject *value)
QString findExecutable(const QString &executableName, const QStringList &paths)
QString arg(Args &&... args) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
QString fromStdString(const std::string &str)
bool isEmpty() const const
QString number(double n, char format, int precision)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
qsizetype size() const const
QByteArray toLatin1() const const
QString toLower() const const
std::string toStdString() const const
QByteArray toUtf8() const const
QTextStream & endl(QTextStream &stream)
QVariant fromValue(T &&value)