9#include "analyze/analyze.h"
10#include "capture/capture.h"
11#include "scheduler/scheduler.h"
12#include "scheduler/schedulerprocess.h"
13#include "scheduler/schedulermodulestate.h"
14#include "focus/focus.h"
15#include "align/align.h"
16#include "guide/guide.h"
17#include "mount/mount.h"
18#include "observatory/observatory.h"
21#include "ekosadaptor.h"
23#include "kstarsdata.h"
25#include "ekos/capture/rotatorsettings.h"
26#include "profileeditor.h"
27#include "profilewizard.h"
29#include "auxiliary/darklibrary.h"
30#include "auxiliary/ksmessagebox.h"
31#include "auxiliary/profilesettings.h"
32#include "capture/sequencejob.h"
33#include "capture/captureprocess.h"
34#include "fitsviewer/fitsview.h"
35#include "fitsviewer/fitsdata.h"
36#include "indi/clientmanager.h"
37#include "indi/driverinfo.h"
38#include "indi/drivermanager.h"
39#include "indi/guimanager.h"
40#include "indi/indilistener.h"
41#include "auxiliary/opticaltrainmanager.h"
42#include "auxiliary/opticaltrainsettings.h"
43#include "indi/indiwebmanager.h"
44#include "indi/indigps.h"
45#include "indi/indiguider.h"
46#include "indi/indirotator.h"
47#include "mount/meridianflipstatuswidget.h"
48#include "ekos/auxiliary/rotatorutils.h"
50#include "ekoslive/ekosliveclient.h"
51#include "ekoslive/message.h"
52#include "ekoslive/media.h"
54#include <basedevice.h>
56#include <KConfigDialog>
58#include <KActionCollection>
59#include <KNotifications/KNotification>
61#include <QFutureWatcher>
64#include <ekos_debug.h>
66#define MAX_REMOTE_INDI_TIMEOUT 15000
67#define MAX_LOCAL_INDI_TIMEOUT 10000
72Manager *Manager::_Manager =
nullptr;
76 if (_Manager ==
nullptr)
77 _Manager =
new Manager(Options::independentWindowEkos() ?
nullptr :
KStars::Instance());
82void Manager::release()
84 ProfileSettings::release();
85 OpticalTrainManager::release();
86 OpticalTrainSettings::release();
87 RotatorUtils::release();
95 if (Options::independentWindowEkos())
104 if (Options::independentWindowEkos())
110 capturePreview->targetLabel->setVisible(
false);
111 capturePreview->mountTarget->setVisible(
false);
125 profileModel->setHorizontalHeaderLabels(
QStringList() <<
"id"
130 m_CountdownTimer.setInterval(1000);
153 ekosLiveClient.reset(
new EkosLive::Client(
this));
154 connect(ekosLiveClient.get(), &EkosLive::Client::connected,
this, [
this]()
156 emit ekosLiveStatusChanged(true);
158 connect(ekosLiveClient.get(), &EkosLive::Client::disconnected,
this, [
this]()
160 emit ekosLiveStatusChanged(false);
167 ekosLiveClient.get()->show();
168 ekosLiveClient.get()->raise();
171 connect(
this, &Manager::ekosStatusChanged, ekosLiveClient.get()->message(), &EkosLive::Message::setEkosStatingStatus);
172 connect(
this, &Manager::indiStatusChanged, ekosLiveClient.get()->message(), &EkosLive::Message::setINDIStatus);
173 connect(ekosLiveClient.get()->message(), &EkosLive::Message::connected,
this, [&]()
175 ekosLiveB->setIcon(QIcon(
":/icons/cloud-online.svg"));
177 connect(ekosLiveClient.get()->message(), &EkosLive::Message::disconnected,
this, [&]()
179 ekosLiveB->setIcon(QIcon::fromTheme(
"folder-cloud"));
181 connect(ekosLiveClient.get()->media(), &EkosLive::Media::newBoundingRect, ekosLiveClient.get()->message(),
182 &EkosLive::Message::setBoundingRect);
183 connect(ekosLiveClient.get()->message(), &EkosLive::Message::resetPolarView, ekosLiveClient.get()->media(),
184 &EkosLive::Media::resetPolarView);
185 connect(KSMessageBox::Instance(), &KSMessageBox::newMessage, ekosLiveClient.get()->message(),
186 &EkosLive::Message::sendDialog);
189 m_PortSelectorTimer.setInterval(500);
190 m_PortSelectorTimer.setSingleShot(
true);
193 if (m_PortSelector && m_CurrentProfile->portSelector)
195 if (m_PortSelector->shouldShow())
197 m_PortSelector->show();
198 m_PortSelector->raise();
200 ekosLiveClient.get()->message()->requestPortSelection(true);
203 else if (m_CurrentProfile->autoConnect)
204 setPortSelectionComplete();
206 else if (m_CurrentProfile->autoConnect)
207 setPortSelectionComplete();
213 m_PortSelector->show();
214 m_PortSelector->raise();
218 connect(
this, &Ekos::Manager::ekosStatusChanged,
this, [&](Ekos::CommunicationStatus status)
223 profileGroup->setEnabled(status == Ekos::Idle || status == Ekos::Error);
224 m_isStarted = (
status == Ekos::Success ||
status == Ekos::Pending);
225 if (status == Ekos::Success)
229 setWindowTitle(
i18nc(
"@title:window",
"Ekos - %1 Profile", m_CurrentProfile->name));
231 else if (status == Ekos::Error || status == Ekos::Idle)
244 KStars::Instance()->actionCollection()->action(
"show_control_panel")->trigger();
272 Options::setProfile(text);
273 if (text ==
"Simulators")
287 settleTimer.setInterval(1000);
290 if (m_settleStatus != Ekos::Success)
292 m_settleStatus = Ekos::Success;
293 emit settleStatusChanged(m_settleStatus);
333 schedulerProcess.reset(
new Scheduler());
334 int index = addModuleTab(EkosModule::Scheduler, schedulerModule(),
QIcon(
":/icons/ekos_scheduler.png"));
336 capturePreview->shareSchedulerModuleState(schedulerModule()->moduleState());
337 connect(schedulerModule()->process().data(), &SchedulerProcess::newLog,
this, &Ekos::Manager::updateLog);
338 connect(schedulerModule(), &Ekos::Scheduler::newTarget,
this, &Manager::setTarget);
340 connect(schedulerModule(), &Ekos::Scheduler::jobsUpdated, ekosLiveClient.get()->message(),
342 connect(schedulerModule(), &Ekos::Scheduler::settingsUpdated, ekosLiveClient.get()->message(),
344 connect(schedulerModule()->process().data(), &SchedulerProcess::newLog, ekosLiveClient.get()->message(),
347 QJsonObject cStatus =
349 {
"log", schedulerModule()->moduleState()->getLogText()}
352 ekosLiveClient.get()->message()->sendSchedulerStatus(
cStatus);
354 connect(schedulerModule(), &Ekos::Scheduler::newStatus, ekosLiveClient.get()->message(),
355 [
this](Ekos::SchedulerState state)
357 QJsonObject cStatus =
362 ekosLiveClient.get()->message()->sendSchedulerStatus(
cStatus);
367 connect(analyzeProcess.get(), &Ekos::Analyze::newLog,
this, &Ekos::Manager::updateLog);
369 index = addModuleTab(EkosModule::Analyze, analyzeProcess.get(),
QIcon(
":/icons/ekos_analyze.png"));
372 numPermanentTabs = index + 1;
380 m_SummaryView.reset(
new SummaryFITSView(capturePreview->previewWidget));
384 m_SummaryView->createFloatingToolBar();
385 m_SummaryView->setCursorMode(FITSView::dragCursor);
386 m_SummaryView->showProcessInfo(
false);
387 capturePreview->setSummaryFITSView(m_SummaryView.get());
390 if (Options::ekosLeftIcons())
396 for (
int i = 0; i < numPermanentTabs; ++i)
410 button->setAutoDefault(
false);
413 resize(Options::ekosWindowWidth(), Options::ekosWindowHeight());
447 Options::setEkosWindowWidth(width());
448 Options::setEkosWindowHeight(height());
460 if (profileWizardLaunched ==
false && profiles.count() == 1)
462 profileWizardLaunched =
true;
473void Manager::loadProfiles()
476 KStarsData::Instance()->userdb()->GetAllProfiles(profiles);
478 profileModel->clear();
480 for (
auto &pi : profiles)
486 profileModel->appendRow(info);
489 profileModel->sort(0);
508 case EkosModule::Observatory:
509 index += guideProcess ? 1 : 0;
510 case EkosModule::Guide:
511 index += alignProcess ? 1 : 0;
512 case EkosModule::Align:
513 index += mountProcess ? 1 : 0;
514 case EkosModule::Mount:
515 index += focusProcess ? 1 : 0;
516 case EkosModule::Focus:
517 index += captureProcess ? 1 : 0;
518 case EkosModule::Capture:
519 index += analyzeProcess ? 1 : 0;
520 case EkosModule::Analyze:
521 index += schedulerProcess ? 1 : 0;
522 case EkosModule::Scheduler:
524 case EkosModule::Setup:
536void Manager::loadDrivers()
540 if (
dv->getDriverSource() != HOST_SOURCE)
541 driversList[
dv->getLabel()] =
dv;
547 qCDebug(
KSTARS_EKOS) <<
"Resetting Ekos Manager...";
549 ProfileSettings::release();
550 OpticalTrainManager::release();
551 OpticalTrainSettings::release();
552 RotatorUtils::release();
554 m_DriverDevicesCount = 0;
558 captureProcess.reset();
559 focusProcess.reset();
560 guideProcess.reset();
561 alignProcess.reset();
562 mountProcess.reset();
563 observatoryProcess.reset();
567 m_FilterManagers.clear();
571 m_RotatorControllers.clear();
573 DarkLibrary::Release();
574 m_PortSelector.reset();
575 m_PortSelectorTimer.stop();
580 m_settleStatus = Ekos::Idle;
582 emit settleStatusChanged(m_settleStatus);
585 m_ekosStatus = Ekos::Idle;
587 emit ekosStatusChanged(m_ekosStatus);
590 m_indiStatus = Ekos::Idle;
592 emit indiStatusChanged(m_indiStatus);
600 capturePreview->setEnabled(
false);
601 capturePreview->reset();
613void Manager::processINDI()
615 if (m_isStarted ==
false)
624 m_PortSelector.reset();
625 m_PortSelectorTimer.stop();
626 m_CountdownTimer.stop();
630 indiHubAgent->terminate();
634 setWindowTitle(
i18nc(
"@title:window",
"Ekos"));
640 if (m_ekosStatus == Ekos::Pending || m_ekosStatus == Ekos::Success)
642 qCWarning(
KSTARS_EKOS) <<
"Ekos Manager start called but current Ekos Status is" << m_ekosStatus <<
"Ignoring request.";
646 managedDrivers.clear();
649 if (KStarsData::Instance()->clock()->isActive() ==
false)
652 KStarsData::Instance()->clock()->start();
659 getCurrentProfile(m_CurrentProfile);
660 m_LocalMode = m_CurrentProfile->isLocal();
662 ProfileSettings::Instance()->setProfile(m_CurrentProfile);
665 updateProfileLocation(m_CurrentProfile);
671 if (m_CurrentProfile->guidertype == Ekos::Guide::GUIDE_PHD2)
673 Options::setPHD2Host(m_CurrentProfile->guiderhost);
674 Options::setPHD2Port(m_CurrentProfile->guiderport);
676 else if (m_CurrentProfile->guidertype == Ekos::Guide::GUIDE_LINGUIDER)
678 Options::setLinGuiderHost(m_CurrentProfile->guiderhost);
679 Options::setLinGuiderPort(m_CurrentProfile->guiderport);
693 auto drv = driversList.value(m_CurrentProfile->mount());
696 managedDrivers.append(
drv->clone());
698 drv = driversList.value(m_CurrentProfile->ccd());
701 managedDrivers.append(
drv->clone());
705 Options::setGuiderType(m_CurrentProfile->guidertype);
707 drv = driversList.value(m_CurrentProfile->guider());
718 if (
haveCCD && m_CurrentProfile->guider() == m_CurrentProfile->ccd())
720 if (checkUniqueBinaryDriver( driversList.value(m_CurrentProfile->ccd()),
drv))
726 drv->setUniqueLabel(
drv->getLabel() +
" Guide");
731 managedDrivers.append(
drv->clone());
734 drv = driversList.value(m_CurrentProfile->ao());
736 managedDrivers.append(
drv->clone());
738 drv = driversList.value(m_CurrentProfile->filter());
740 managedDrivers.append(
drv->clone());
742 drv = driversList.value(m_CurrentProfile->focuser());
744 managedDrivers.append(
drv->clone());
746 drv = driversList.value(m_CurrentProfile->dome());
748 managedDrivers.append(
drv->clone());
750 drv = driversList.value(m_CurrentProfile->weather());
752 managedDrivers.append(
drv->clone());
754 drv = driversList.value(m_CurrentProfile->aux1());
757 if (!checkUniqueBinaryDriver(driversList.value(m_CurrentProfile->ccd()),
drv) &&
758 !checkUniqueBinaryDriver(driversList.value(m_CurrentProfile->guider()),
drv))
759 managedDrivers.append(
drv->clone());
761 drv = driversList.value(m_CurrentProfile->aux2());
764 if (!checkUniqueBinaryDriver(driversList.value(m_CurrentProfile->ccd()),
drv) &&
765 !checkUniqueBinaryDriver(driversList.value(m_CurrentProfile->guider()),
drv))
766 managedDrivers.append(
drv->clone());
769 drv = driversList.value(m_CurrentProfile->aux3());
772 if (!checkUniqueBinaryDriver(driversList.value(m_CurrentProfile->ccd()),
drv) &&
773 !checkUniqueBinaryDriver(driversList.value(m_CurrentProfile->guider()),
drv))
774 managedDrivers.append(
drv->clone());
777 drv = driversList.value(m_CurrentProfile->aux4());
780 if (!checkUniqueBinaryDriver(driversList.value(m_CurrentProfile->ccd()),
drv) &&
781 !checkUniqueBinaryDriver(driversList.value(m_CurrentProfile->guider()),
drv))
782 managedDrivers.append(
drv->clone());
786 if (m_CurrentProfile->remotedrivers.isEmpty() ==
false && m_CurrentProfile->remotedrivers.contains(
"@"))
788 for (
auto remoteDriver : m_CurrentProfile->remotedrivers.split(
","))
824 dv->setRemoteHost(host);
825 dv->setRemotePort(port);
831 dv->setUniqueLabel(label);
832 managedDrivers.append(
dv);
837 if (
haveCCD ==
false &&
haveGuider ==
false && m_CurrentProfile->remotedrivers.isEmpty())
839 KSNotification::error(
i18n(
"Ekos requires at least one CCD or Guider to operate."));
840 managedDrivers.clear();
841 m_ekosStatus = Ekos::Error;
842 emit ekosStatusChanged(m_ekosStatus);
846 m_DriverDevicesCount = managedDrivers.count();
852 remote_indi->setHostParameters(m_CurrentProfile->host, m_CurrentProfile->port);
858 haveCCD = m_CurrentProfile->drivers.contains(
"CCD");
859 haveGuider = m_CurrentProfile->drivers.contains(
"Guider");
861 Options::setGuiderType(m_CurrentProfile->guidertype);
863 if (
haveCCD ==
false &&
haveGuider ==
false && m_CurrentProfile->remotedrivers.isEmpty())
865 KSNotification::error(
i18n(
"Ekos requires at least one CCD or Guider to operate."));
866 m_DriverDevicesCount = 0;
867 m_ekosStatus = Ekos::Error;
868 emit ekosStatusChanged(m_ekosStatus);
872 m_DriverDevicesCount = m_CurrentProfile->drivers.count();
882 return oneDriver->getLabel() == oneRule.toObject()[
"Driver"].toString();
887 (*matchingDriver)->setStartupRule(
oneRule.toObject());
905 connect(DriverManager::Instance(), &DriverManager::serverStarted,
this,
907 connect(DriverManager::Instance(), &DriverManager::serverFailed,
this,
909 connect(DriverManager::Instance(), &DriverManager::clientStarted,
this,
911 connect(DriverManager::Instance(), &DriverManager::clientFailed,
this,
913 connect(DriverManager::Instance(), &DriverManager::clientTerminated,
this,
916 connect(INDIListener::Instance(), &INDIListener::newDevice,
this, &Ekos::Manager::processNewDevice);
921 if (m_LocalMode || m_CurrentProfile->host ==
"localhost")
923 if (isRunning(
"PTPCamera"))
925 if (KMessageBox::Yes ==
926 (KMessageBox::questionYesNo(
nullptr,
927 i18n(
"Ekos detected that PTP Camera is running and may prevent a Canon or Nikon camera from connecting to Ekos. Do you want to quit PTP Camera now?"),
928 i18n(
"PTP Camera"), KStandardGuiItem::yes(), KStandardGuiItem::no(),
929 "ekos_shutdown_PTPCamera")))
933 p.
start(
"killall PTPCamera");
943 appendLogText(
i18n(
"Starting INDI services..."));
945 m_ekosStatus = Ekos::Pending;
946 emit ekosStatusChanged(m_ekosStatus);
948 DriverManager::Instance()->startDevices(managedDrivers);
952 if (isRunning(
"indiserver"))
956 KSMessageBox::Instance()->disconnect(
this);
957 DriverManager::Instance()->stopAllDevices();
960 const QString program =
"pkill";
962 arguments <<
"indiserver";
963 p.
start(program, arguments);
970 KSMessageBox::Instance()->disconnect(
this);
974 KSMessageBox::Instance()->questionYesNo(
i18n(
"Ekos detected an instance of INDI server running. Do you wish to "
975 "shut down the existing instance before starting a new one?"),
976 i18n(
"INDI Server"), 5);
987 if (m_ekosStatus != Ekos::Pending)
991 i18n(
"Connecting to remote INDI server at %1 on port %2 ...", m_CurrentProfile->host, m_CurrentProfile->port));
993 DriverManager::Instance()->connectRemoteHost(managedDrivers.first());
999 if (m_ekosStatus != Ekos::Pending)
1002 INDI::WebManager::syncCustomDrivers(m_CurrentProfile);
1003 INDI::WebManager::checkVersion(m_CurrentProfile);
1005 if (INDI::WebManager::areDriversRunning(m_CurrentProfile) ==
false)
1007 INDI::WebManager::stopProfile(m_CurrentProfile);
1009 if (INDI::WebManager::startProfile(m_CurrentProfile) ==
false)
1011 appendLogText(
i18n(
"Failed to start profile on remote INDI Web Manager."));
1015 appendLogText(
i18n(
"Starting profile on remote INDI Web Manager..."));
1016 m_RemoteManagerStart =
true;
1022 m_ekosStatus = Ekos::Pending;
1023 emit ekosStatusChanged(m_ekosStatus);
1026 if (m_CurrentProfile->INDIWebManagerPort > 0)
1028 appendLogText(
i18n(
"Establishing communication with remote INDI Web Manager..."));
1029 m_RemoteManagerStart =
false;
1033 watcher->deleteLater();
1036 if (m_ekosStatus != Ekos::Pending)
1040 if (watcher->result())
1048 appendLogText(i18n(
"Warning: INDI Web Manager is not online."));
1054 QFuture<bool> result = INDI::AsyncWebManager::isOnline(m_CurrentProfile);
1055 watcher->setFuture(result);
1064void Manager::setClientStarted(
const QString &host,
int port)
1066 if (managedDrivers.size() > 0)
1070 if (m_CurrentProfile->autoConnect)
1071 appendLogText(
i18n(
"INDI services started on port %1.", port));
1074 i18n(
"INDI services started on port %1. Please connect devices.", port));
1079 i18n(
"INDI services started. Connection to remote INDI server %1:%2 is successful. Waiting for devices...", host, port));
1086void Manager::setClientFailed(
const QString &host,
int port,
const QString &errorMessage)
1089 appendLogText(
i18n(
"Failed to connect to local INDI server %1:%2", host, port));
1091 appendLogText(
i18n(
"Failed to connect to remote INDI server %1:%2", host, port));
1096 m_ekosStatus = Ekos::Error;
1097 emit ekosStatusChanged(m_ekosStatus);
1098 KSNotification::error(errorMessage,
i18n(
"Error"), 15);
1101void Manager::setClientTerminated(
const QString &host,
int port,
const QString &errorMessage)
1104 appendLogText(
i18n(
"Lost connection to local INDI server %1:%2", host, port));
1106 appendLogText(
i18n(
"Lost connection to remote INDI server %1:%2", host, port));
1111 m_ekosStatus = Ekos::Error;
1112 emit ekosStatusChanged(m_ekosStatus);
1113 KSNotification::error(errorMessage,
i18n(
"Error"), 15);
1116void Manager::setServerStarted(
const QString &host,
int port)
1118 if (m_LocalMode && m_CurrentProfile->indihub != INDIHub::None)
1120 if (
QFile(Options::iNDIHubAgent()).exists())
1126 if (m_CurrentProfile->guidertype == Ekos::Guide::GUIDE_PHD2)
1127 args <<
"--phd2-server" <<
QString(
"%1:%2").
arg(m_CurrentProfile->guiderhost).
arg(m_CurrentProfile->guiderport);
1128 args <<
"--mode" << INDIHub::toString(m_CurrentProfile->indihub);
1129 indiHubAgent->start(Options::iNDIHubAgent(),
args);
1136void Manager::setServerFailed(
const QString &host,
int port,
const QString &message)
1140 managedDrivers.clear();
1141 m_ekosStatus = Ekos::Error;
1142 emit ekosStatusChanged(m_ekosStatus);
1143 KSNotification::error(message,
i18n(
"Error"), 15);
1164void Manager::checkINDITimeout()
1167 if (m_ekosStatus != Ekos::Pending)
1170 if (m_indiStatus != Ekos::Pending || m_CurrentProfile->portSelector || m_CurrentProfile->autoConnect ==
false)
1183 message =
i18n(
"Failed to connect to %1. Please ensure device is connected and powered on.",
disconnectedDevices.first());
1185 message =
i18n(
"Failed to connect to \n%1\nPlease ensure each device is connected and powered on.",
1188 appendLogText(message);
1189 KSNotification::event(
QLatin1String(
"IndiServerMessage"), message, KSNotification::General, KSNotification::Warn);
1194 if (m_DriverDevicesCount <= 0)
1196 m_ekosStatus = Ekos::Success;
1197 emit ekosStatusChanged(m_ekosStatus);
1204 for (
auto &
drv : managedDrivers)
1206 if (
drv->getDevices().count() == 0)
1208 drv->getUniqueLabel().isEmpty() ==
false ?
drv->getUniqueLabel() :
drv->getName());
1213 QString message =
i18n(
"Unable to establish:\n%1\nPlease ensure the device is connected and powered on.",
1215 appendLogText(message);
1216 KSNotification::event(
QLatin1String(
"IndiServerMessage"), message, KSNotification::General, KSNotification::Warn);
1221 QString message =
i18n(
"Unable to establish the following devices:\n%1\nPlease ensure each device is connected "
1223 appendLogText(message);
1224 KSNotification::event(
QLatin1String(
"IndiServerMessage"), message, KSNotification::General, KSNotification::Warn);
1232 for (
auto &driver : m_CurrentProfile->drivers.values())
1238 if (device->getBaseDevice().getDriverName() == driver)
1251 QString message =
i18n(
"Unable to remotely establish:\n%1\nPlease ensure the device is connected and powered on.",
1253 appendLogText(message);
1254 KSNotification::event(
QLatin1String(
"IndiServerMessage"), message, KSNotification::General, KSNotification::Warn);
1259 QString message =
i18n(
"Unable to remotely establish the following devices:\n%1\nPlease ensure each device is connected "
1261 appendLogText(message);
1262 KSNotification::event(
QLatin1String(
"IndiServerMessage"), message, KSNotification::General, KSNotification::Warn);
1267 m_ekosStatus = Ekos::Error;
1270bool Manager::isINDIReady()
1277 auto devices = INDIListener::devices();
1278 for (
auto &device : devices)
1281 if (device->isConnected() && device->isReady())
1286 m_indiStatus = Ekos::Success;
1287 emit indiStatusChanged(m_indiStatus);
1291 m_indiStatus = Ekos::Pending;
1293 emit indiStatusChanged(m_indiStatus);
1298void Manager::connectDevices()
1303 auto devices = INDIListener::devices();
1305 for (
auto &device : devices)
1307 qCDebug(
KSTARS_EKOS) <<
"Connecting " << device->getDeviceName();
1314 appendLogText(
i18n(
"Connecting INDI devices..."));
1317void Manager::disconnectDevices()
1321 qCDebug(
KSTARS_EKOS) <<
"Disconnecting " << device->getDeviceName();
1322 device->Disconnect();
1325 appendLogText(
i18n(
"Disconnecting INDI devices..."));
1330 if (m_ekosStatus == Ekos::Idle)
1334 mountModule()->stopTimers();
1336 ekosLiveClient->message()->clearPendingProperties();
1337 INDIListener::Instance()->disconnect(
this);
1338 DriverManager::Instance()->disconnect(
this);
1340 if (managedDrivers.isEmpty() ==
false)
1345 DriverManager::Instance()->stopDevices(managedDrivers);
1351 DriverManager::Instance()->disconnectRemoteHost(managedDrivers.first());
1353 if (m_RemoteManagerStart && m_CurrentProfile->INDIWebManagerPort != -1)
1354 INDI::WebManager::stopProfile(m_CurrentProfile);
1356 m_RemoteManagerStart =
false;
1364 appendLogText(
i18n(
"INDI services stopped."));
1369 qCInfo(
KSTARS_EKOS) <<
"Ekos received a new device: " << device->getDeviceName();
1383 m_indiStatus = Ekos::Idle;
1385 emit indiStatusChanged(m_indiStatus);
1387 m_DriverDevicesCount--;
1405 connect(device.get(), &ISD::GenericDevice::propertyDeleted,
this, &Ekos::Manager::processDeleteProperty,
1407 connect(device.get(), &ISD::GenericDevice::propertyUpdated,
this, &Ekos::Manager::processUpdateProperty,
1415 if (m_CurrentProfile->ccd() != m_CurrentProfile->guider())
1426 if (m_DriverDevicesCount <= 0)
1428 m_ekosStatus = Ekos::Success;
1429 emit ekosStatusChanged(m_ekosStatus);
1434 if (m_LocalMode ==
false && m_DriverDevicesCount == 0)
1436 if (m_CurrentProfile->autoConnect)
1437 appendLogText(
i18n(
"Remote devices established."));
1439 appendLogText(
i18n(
"Remote devices established. Please connect devices."));
1444void Manager::deviceConnected()
1452 if (Options::verboseLogging())
1455 <<
"Version:" << device->getDriverVersion()
1456 <<
"Interface:" << device->getDriverInterface()
1460 if (Options::neverLoadConfig() ==
false)
1462 INDIConfig
tConfig = Options::loadConfigOnConnection() ? LOAD_LAST_CONFIG : LOAD_DEFAULT_CONFIG;
1470 auto configProp = device->getBaseDevice().getSwitch(
"CONFIG_PROCESS");
1479void Manager::deviceDisconnected()
1488 m_indiStatus = Ekos::Error;
1490 m_indiStatus = Ekos::Pending;
1492 m_indiStatus = Ekos::Idle;
1494 if (Options::verboseLogging())
1495 qCDebug(
KSTARS_EKOS) <<
dev->getDeviceName() <<
" is disconnected.";
1498 if (m_indiStatus == Ekos::Error)
1500 QString message =
i18n(
"%1 failed to connect.\nPlease ensure the device is connected and powered on.",
1501 dev->getDeviceName());
1502 appendLogText(message);
1503 KSNotification::event(
QLatin1String(
"IndiServerMessage"), message, KSNotification::General, KSNotification::Warn);
1505 else if (m_indiStatus == Ekos::Idle)
1507 QString message =
i18n(
"%1 is disconnected.",
dev->getDeviceName());
1508 appendLogText(message);
1512 m_indiStatus = Ekos::Idle;
1515 emit indiStatusChanged(m_indiStatus);
1524 ekosLiveClient->message()->sendScopes();
1526 appendLogText(
i18n(
"%1 is online.", device->getDeviceName()));
1528 emit newDevice(device->getDeviceName(), device->getDriverInterface());
1533 ekosLiveClient.get()->media()->registerCameras();
1535 appendLogText(
i18n(
"%1 is online.", device->getDeviceName()));
1537 emit newDevice(device->getDeviceName(), device->getDriverInterface());
1540void Manager::addFilterWheel(ISD::FilterWheel * device)
1543 appendLogText(
i18n(
"%1 filter is online.", name));
1545 createFilterManager(device);
1547 emit newDevice(name, device->getDriverInterface());
1552 appendLogText(
i18n(
"%1 focuser is online.", device->getDeviceName()));
1554 emit newDevice(device->getDeviceName(), device->getDriverInterface());
1559 appendLogText(
i18n(
"Rotator %1 is online.", device->getDeviceName()));
1563 emit newDevice(device->getDeviceName(), device->getDriverInterface());
1566void Manager::addDome(
ISD::Dome * device)
1568 appendLogText(
i18n(
"%1 is online.", device->getDeviceName()));
1570 emit newDevice(device->getDeviceName(), device->getDriverInterface());
1575 appendLogText(
i18n(
"%1 Weather is online.", device->getDeviceName()));
1577 emit newDevice(device->getDeviceName(), device->getDriverInterface());
1580void Manager::addGPS(ISD::GPS * device)
1582 appendLogText(
i18n(
"%1 GPS is online.", device->getDeviceName()));
1584 emit newDevice(device->getDeviceName(), device->getDriverInterface());
1589 OpticalTrainManager::Instance()->syncDevices();
1591 appendLogText(
i18n(
"%1 Dust cap is online.", device->getDeviceName()));
1593 emit newDevice(device->getDeviceName(), device->getDriverInterface());
1598 appendLogText(
i18n(
"%1 Light box is online.", device->getDeviceName()));
1600 emit newDevice(device->getDeviceName(), device->getDriverInterface());
1605 createModules(device);
1610 auto camera = device->getCamera();
1616 if (camera->hasCooler())
1619 if (INDIListener::findDevice(camera->getDeviceName(),
generic))
1620 focusModule()->addTemperatureSource(
generic);
1633 auto focuser = device->getFocuser();
1640 if (INDIListener::findDevice(focuser->getDeviceName(),
generic))
1641 focusModule()->addTemperatureSource(
generic);
1656 auto dome = device->getDome();
1660 captureProcess->setDome(dome);
1662 alignProcess->setDome(dome);
1663 if (observatoryProcess)
1664 observatoryProcess->setDome(dome);
1670 auto weather = device->getWeather();
1673 if (observatoryProcess)
1674 observatoryProcess->addWeatherSource(weather);
1679 if (INDIListener::findDevice(weather->getDeviceName(),
generic))
1680 focusModule()->addTemperatureSource(
generic);
1687 auto gps = device->getGPS();
1691 mountModule()->addGPS(
gps);
1706 alignModule()->removeDevice(device);
1708 captureProcess->removeDevice(device);
1710 focusModule()->removeDevice(device);
1712 mountModule()->removeDevice(device);
1714 guideProcess->removeDevice(device);
1715 if (observatoryProcess)
1716 observatoryProcess->removeDevice(device);
1718 m_PortSelector->removeDevice(device->getDeviceName());
1720 DarkLibrary::Instance()->removeDevice(device);
1734 appendLogText(
i18n(
"%1 is offline.", device->getDeviceName()));
1737 if (INDIListener::devices().isEmpty())
1744void Manager::processDeleteProperty(INDI::Property
prop)
1746 ekosLiveClient.get()->message()->processDeleteProperty(
prop);
1749void Manager::processMessage(
int id)
1756 if (!INDIListener::findDevice(origin->getDeviceName(), device))
1759 ekosLiveClient.get()->message()->processMessage(device,
id);
1762void Manager::processUpdateProperty(INDI::Property
prop)
1764 ekosLiveClient.get()->message()->processUpdateProperty(
prop);
1766 if (
prop.isNameMatch(
"CCD_INFO") ||
1767 prop.isNameMatch(
"GUIDER_INFO") ||
1768 prop.isNameMatch(
"CCD_FRAME") ||
1769 prop.isNameMatch(
"GUIDER_FRAME"))
1771 if (focusModule() !=
nullptr)
1772 focusModule()->syncCameraInfo();
1774 if (guideModule() !=
nullptr)
1775 guideModule()->syncCameraInfo();
1777 if (alignModule() !=
nullptr)
1778 alignModule()->syncCameraInfo();
1784void Manager::processNewProperty(INDI::Property
prop)
1787 if (!INDIListener::findDevice(
prop.getDeviceName(), device))
1790 settleTimer.start();
1792 ekosLiveClient.get()->message()->processNewProperty(
prop);
1794 if (
prop.isNameMatch(
"DEVICE_PORT_SCAN") ||
prop.isNameMatch(
"CONNECTION_TYPE"))
1796 if (!m_PortSelector)
1801 m_PortSelectorTimer.start();
1803 m_PortSelector->addDevice(device);
1808 if (
prop.isNameMatch(
"DEBUG"))
1810 uint16_t
interface = device->getDriverInterface();
1811 if ( opsLogs->getINDIDebugInterface() & interface )
1817 device->sendNewProperty(
debugSP);
1823 if (
prop.isNameMatch(
"DEBUG_LEVEL"))
1825 uint16_t
interface = device->getDriverInterface();
1827 if ( opsLogs->getINDIDebugInterface() & interface )
1839 if (
prop.isNameMatch(
"ASTROMETRY_SOLVER"))
1846 alignModule()->setAstrometryDevice(
oneDevice);
1854 if (focusModule() !=
nullptr &&
strstr(
prop.getName(),
"FOCUS_"))
1856 focusModule()->checkFocuser();
1861void Manager::processTabChange()
1863 auto currentWidget =
toolsWidget->currentWidget();
1865 if (alignProcess && alignModule() == currentWidget)
1867 auto alignReady = alignModule()->isEnabled() ==
false && alignModule()->isParserOK();
1868 auto captureReady = captureProcess && captureModule()->isEnabled();
1869 auto mountReady = mountProcess && mountModule()->isEnabled();
1870 if (
alignReady && captureReady && mountReady)
1871 alignModule()->setEnabled(
true);
1873 alignModule()->checkCamera();
1875 else if (captureProcess && currentWidget == captureModule())
1877 captureModule()->process()->checkCamera();
1879 else if (focusProcess && currentWidget == focusModule())
1881 focusModule()->checkCamera();
1883 else if (guideProcess && currentWidget == guideModule())
1885 guideModule()->checkCamera();
1891void Manager::updateLog()
1896 ekosLogOut->setPlainText(m_LogText.join(
"\n"));
1897 else if (currentWidget == alignModule())
1898 ekosLogOut->setPlainText(alignModule()->getLogText());
1899 else if (currentWidget == captureModule())
1900 ekosLogOut->setPlainText(captureModule()->getLogText());
1901 else if (currentWidget == focusModule())
1902 ekosLogOut->setPlainText(focusModule()->getLogText());
1903 else if (currentWidget == guideModule())
1904 ekosLogOut->setPlainText(guideModule()->getLogText());
1905 else if (currentWidget == mountModule())
1906 ekosLogOut->setPlainText(mountModule()->getLogText());
1907 else if (currentWidget == schedulerModule())
1908 ekosLogOut->setPlainText(schedulerModule()->moduleState()->getLogText());
1909 else if (currentWidget == observatoryProcess.get())
1910 ekosLogOut->setPlainText(observatoryProcess->getLogText());
1911 else if (currentWidget == analyzeProcess.get())
1912 ekosLogOut->setPlainText(analyzeProcess->getLogText());
1919void Manager::appendLogText(
const QString &text)
1921 m_LogText.insert(0,
i18nc(
"log entry; %1 is the date, %2 is the text",
"%1 %2",
1922 KStarsData::Instance()->lt().
toString(
"yyyy-MM-ddThh:mm:ss"), text));
1931void Manager::clearLog()
1940 else if (currentWidget == alignModule())
1941 alignModule()->clearLog();
1942 else if (currentWidget == captureModule())
1943 captureModule()->clearLog();
1944 else if (currentWidget == focusModule())
1945 focusModule()->clearLog();
1946 else if (currentWidget == guideModule())
1947 guideModule()->clearLog();
1948 else if (currentWidget == mountModule())
1949 mountModule()->clearLog();
1950 else if (currentWidget == schedulerModule())
1951 schedulerModule()->moduleState()->clearLog();
1952 else if (currentWidget == observatoryProcess.get())
1953 observatoryProcess->clearLog();
1954 else if (currentWidget == analyzeProcess.get())
1955 analyzeProcess->clearLog();
1958void Manager::initCapture()
1960 if (captureModule() !=
nullptr)
1963 captureProcess.reset(
new Capture());
1965 emit newModule(
"Capture");
1968 if (mountModule() !=
nullptr)
1969 captureModule()->setMeridianFlipState(mountModule()->getMeridianFlipState());
1971 capturePreview->shareCaptureModule(captureModule());
1972 int index = addModuleTab(EkosModule::Capture, captureModule(),
QIcon(
":/icons/ekos_ccd.png"));
1973 toolsWidget->tabBar()->setTabToolTip(index,
i18nc(
"Charge-Coupled Device",
"CCD"));
1974 if (Options::ekosLeftIcons())
1983 connect(captureModule(), &Ekos::Capture::newLog,
this, &Ekos::Manager::updateLog);
1984 connect(captureModule(), &Ekos::Capture::newLog, ekosLiveClient.get()->message(),
1987 QJsonObject cStatus =
1989 {
"log", captureModule()->getLogText()}
1992 ekosLiveClient.get()->message()->updateCaptureStatus(
cStatus);
1994 connect(captureModule(), &Ekos::Capture::newStatus,
this, &Ekos::Manager::updateCaptureStatus);
1995 connect(captureModule(), &Ekos::Capture::newImage,
this, &Ekos::Manager::updateCaptureProgress);
1996 connect(captureModule(), &Ekos::Capture::driverTimedout,
this, &Ekos::Manager::restartDriver);
1997 connect(captureModule(), &Ekos::Capture::newExposureProgress,
this, &Ekos::Manager::updateExposureProgress);
1998 capturePreview->setEnabled(
true);
2001 connect(captureModule(), &Ekos::Capture::newFilterStatus, capturePreview->captureStatusWidget,
2002 &LedStatusWidget::setFilterState);
2005 connect(schedulerModule(), &Ekos::Scheduler::targetDistance,
2007 connect(schedulerModule(), &Ekos::Scheduler::targetDistance,
this, [
this](
double distance)
2009 capturePreview->updateTargetDistance(distance);
2016void Manager::initAlign()
2018 if (alignModule() !=
nullptr)
2021 alignProcess.reset(
new Ekos::Align(m_CurrentProfile));
2023 emit newModule(
"Align");
2025 int index = addModuleTab(EkosModule::Align, alignModule(),
QIcon(
":/icons/ekos_align.png"));
2027 connect(alignModule(), &Ekos::Align::newLog,
this, &Ekos::Manager::updateLog);
2028 if (Options::ekosLeftIcons())
2041void Manager::initFocus()
2043 if (focusModule() !=
nullptr)
2048 emit newModule(
"Focus");
2050 int index = addModuleTab(EkosModule::Focus, focusModule(),
QIcon(
":/icons/ekos_focus.png"));
2055 connect(focusModule(), &Ekos::Focus::newLog,
this, &Ekos::Manager::updateLog);
2056 connect(focusModule(), &Ekos::Focus::newStatus,
this, &Ekos::Manager::updateFocusStatus);
2057 connect(focusModule(), &Ekos::Focus::newStarPixmap,
focusManager, &Ekos::FocusManager::updateFocusStarPixmap);
2058 connect(focusModule(), &Ekos::Focus::newHFR,
this, &Ekos::Manager::updateCurrentHFR);
2073 if (Options::ekosLeftIcons())
2092 focusModule()->addTemperatureSource(
oneDevice);
2098void Manager::updateCurrentHFR(
double newHFR,
int position,
bool inAutofocus)
2109 ekosLiveClient.get()->message()->updateFocusStatus(
cStatus);
2112void Manager::updateSigmas(
double ra,
double de)
2118 ekosLiveClient.get()->message()->updateGuideStatus(
cStatus);
2121void Manager::initMount()
2123 if (mountModule() !=
nullptr)
2129 if (captureModule() !=
nullptr)
2130 captureModule()->setMeridianFlipState(mountModule()->getMeridianFlipState());
2132 emit newModule(
"Mount");
2134 int index = addModuleTab(EkosModule::Mount, mountModule(),
QIcon(
":/icons/ekos_mount.png"));
2137 connect(mountModule(), &Ekos::Mount::newLog,
this, &Ekos::Manager::updateLog);
2144 connect(mountModule(), &Ekos::Mount::pierSideChanged,
this, [&](ISD::Mount::PierSide side)
2146 ekosLiveClient.get()->message()->updateMountStatus(
QJsonObject({{
"pierSide", side}}));
2148 connect(mountModule()->getMeridianFlipState().
get(),
2149 &Ekos::MeridianFlipState::newMountMFStatus, [&](MeridianFlipState::MeridianFlipMountState status)
2151 ekosLiveClient.get()->message()->updateMountStatus(
QJsonObject(
2153 {
"meridianFlipStatus",
status},
2156 connect(mountModule()->getMeridianFlipState().
get(),
2157 &Ekos::MeridianFlipState::newMeridianFlipMountStatusText, [&](
const QString & text)
2160 ekosLiveClient.get()->message()->updateMountStatus(
QJsonObject(
2162 {
"meridianFlipText", text},
2163 }), mountModule()->getMeridianFlipState()->getMeridianFlipMountState() == MeridianFlipState::MOUNT_FLIP_NONE);
2166 connect(mountModule(), &Ekos::Mount::autoParkCountdownUpdated,
this, [&](
const QString & text)
2168 ekosLiveClient.get()->message()->updateMountStatus(
QJsonObject({{
"autoParkCountdown", text}}),
true);
2171 connect(mountModule(), &Ekos::Mount::trainChanged, ekosLiveClient.get()->message(),
2174 connect(mountModule(), &Ekos::Mount::slewRateChanged,
this, [&](
int slewRate)
2177 ekosLiveClient.get()->message()->updateMountStatus(status);
2180 if (Options::ekosLeftIcons())
2191 capturePreview->shareMountModule(mountModule());
2196void Manager::initGuide()
2198 if (guideModule() ==
nullptr)
2202 emit newModule(
"Guide");
2210 int index = addModuleTab(EkosModule::Guide, guideModule(),
QIcon(
":/icons/ekos_guide.png"));
2212 connect(guideModule(), &Ekos::Guide::newLog,
this, &Ekos::Manager::updateLog);
2213 connect(guideModule(), &Ekos::Guide::driverTimedout,
this, &Ekos::Manager::restartDriver);
2217 connect(guideModule(), &Ekos::Guide::newStatus,
this, &Ekos::Manager::updateGuideStatus);
2218 connect(guideModule(), &Ekos::Guide::newStarPixmap,
guideManager, &Ekos::GuideManager::updateGuideStarPixmap);
2219 connect(guideModule(), &Ekos::Guide::newAxisSigma,
this, &Ekos::Manager::updateSigmas);
2220 connect(guideModule(), &Ekos::Guide::newAxisDelta, [&](
double ra,
double de)
2223 ekosLiveClient.get()->message()->updateGuideStatus(status);
2226 if (Options::ekosLeftIcons())
2241void Manager::initObservatory()
2243 if (observatoryProcess.get() ==
nullptr)
2246 observatoryProcess.reset(
new Ekos::Observatory());
2248 emit newModule(
"Observatory");
2250 int index = addModuleTab(EkosModule::Observatory, observatoryProcess.get(),
QIcon(
":/icons/ekos_observatory.png"));
2252 connect(observatoryProcess.get(), &Ekos::Observatory::newLog,
this, &Ekos::Manager::updateLog);
2254 if (Options::ekosLeftIcons())
2266void Manager::addGuider(ISD::Guider * device)
2268 appendLogText(
i18n(
"Guider port from %1 is ready.", device->getDeviceName()));
2271void Manager::removeTabs()
2275 for (
int i = numPermanentTabs; i <
toolsWidget->count(); i++)
2278 alignProcess.reset();
2279 captureProcess.reset();
2280 focusProcess.reset();
2281 guideProcess.reset();
2282 mountProcess.reset();
2283 observatoryProcess.reset();
2288bool Manager::isRunning(
const QString &process)
2293 ps.waitForFinished();
2294 QString output =
ps.readAllStandardOutput();
2295 return output.
length() > 0;
2300 <<
"-C" << process);
2301 ps.waitForFinished();
2302 QString output =
ps.readAllStandardOutput();
2307void Manager::addObjectToScheduler(
SkyObject *
object)
2309 if (schedulerModule() !=
nullptr)
2310 schedulerModule()->addObject(
object);
2313QString Manager::getCurrentJobName()
2315 return schedulerModule()->getCurrentJobName();
2318bool Manager::setProfile(
const QString &profileName)
2332 ProfileEditor editor(
this);
2334 if (getCurrentProfile(m_CurrentProfile))
2336 editor.setPi(m_CurrentProfile);
2338 editor.saveProfile();
2344 ProfileEditor editor(
this);
2347 editor.saveProfile();
2351 getCurrentProfile(m_CurrentProfile);
2354void Manager::deleteNamedProfile(
const QString &name)
2356 if (!getCurrentProfile(m_CurrentProfile))
2359 for (
auto &pi : profiles)
2363 if (pi->name ==
"Simulators" || pi->name != name || (pi.get() == m_CurrentProfile && ekosStatus() != Idle))
2366 KStarsData::Instance()->userdb()->PurgeProfile(pi);
2369 getCurrentProfile(m_CurrentProfile);
2379 for (
auto &pi : profiles)
2381 if (name == pi->name)
2382 return pi->toJson();
2398void Manager::addProfile()
2400 ProfileEditor editor(
this);
2409 getCurrentProfile(m_CurrentProfile);
2412void Manager::editProfile()
2414 ProfileEditor editor(
this);
2416 if (getCurrentProfile(m_CurrentProfile))
2419 editor.setPi(m_CurrentProfile);
2430 getCurrentProfile(m_CurrentProfile);
2434void Manager::deleteProfile()
2436 if (!getCurrentProfile(m_CurrentProfile))
2439 if (m_CurrentProfile->name ==
"Simulators")
2444 KStarsData::Instance()->userdb()->PurgeProfile(m_CurrentProfile);
2447 getCurrentProfile(m_CurrentProfile);
2453 KSMessageBox::Instance()->disconnect(
this);
2457 KSMessageBox::Instance()->questionYesNo(
i18n(
"Are you sure you want to delete the profile?"),
2458 i18n(
"Confirm Delete"));
2462void Manager::wizardProfile()
2468 ProfileEditor editor(
this);
2470 editor.setProfileName(
wz.profileName);
2471 editor.setAuxDrivers(
wz.selectedAuxDrivers());
2472 if (
wz.useInternalServer ==
false)
2473 editor.setHostPort(
wz.host,
wz.port);
2474 editor.setWebManager(
wz.useWebManager);
2475 editor.setGuiderType(
wz.selectedExternalGuider());
2477 editor.setConnectionOptionsEnabled(
false);
2486 getCurrentProfile(m_CurrentProfile);
2492 for (
auto &pi : profiles)
2506 if (profile->city.isEmpty() ==
false)
2510 appendLogText(
i18n(
"Site location updated to %1.", KStarsData::Instance()->
geo()->
fullName()));
2512 appendLogText(
i18n(
"Failed to update site location to %1. City not found.",
2517void Manager::updateMountStatus(ISD::Mount::Status status)
2519 static ISD::Mount::Status
lastStatus = ISD::Mount::MOUNT_IDLE;
2526 mountStatus->setMountState(mountModule()->statusString(), status);
2531 {
"status", mountModule()->statusString(
false)}
2534 ekosLiveClient.get()->message()->updateMountStatus(
cStatus);
2537void Manager::updateMountCoords(
const SkyPoint position, ISD::Mount::PierSide pierSide,
const dms &ha)
2540 raOUT->setText(position.
ra().toHMSString());
2541 decOUT->setText(position.
dec().toDMSString());
2542 azOUT->setText(position.
az().toDMSString());
2543 altOUT->setText(position.
alt().toDMSString());
2549 {
"ra0", position.
ra0().Degrees()},
2550 {
"de0", position.
dec0().Degrees()},
2556 ekosLiveClient.get()->message()->updateMountStatus(
cStatus,
true);
2561 capturePreview->updateCaptureStatus(status);
2570 m_CountdownTimer.stop();
2573 m_CountdownTimer.start();
2581 {
"status", captureStates[
status]},
2582 {
"seqt", capturePreview->captureCountsWidget->sequenceRemainingTime->text()},
2583 {
"ovt", capturePreview->captureCountsWidget->overallRemainingTime->text()}
2586 ekosLiveClient.get()->message()->updateCaptureStatus(
cStatus);
2591 capturePreview->updateJobProgress(job, data);
2595 {
"seqv", job->getCompleted()},
2596 {
"seqr", job->getCoreProperty(SequenceJob::SJ_Count).
toInt()},
2597 {
"seql", capturePreview->captureCountsWidget->sequenceRemainingTime->text()}
2600 ekosLiveClient.get()->message()->updateCaptureStatus(status);
2604 if (data && job->getStatus() == JOB_BUSY)
2611 if (Options::useFITSViewer() ==
false)
2613 if (Options::useSummaryPreview())
2614 ekosLiveClient.get()->media()->sendView(m_SummaryView, uuid);
2617 ekosLiveClient.get()->media()->sendData(data, uuid);
2620 if (job->jobType() != SequenceJob::JOBTYPE_PREVIEW)
2621 ekosLiveClient.get()->cloud()->upload(data, uuid);
2626void Manager::updateExposureProgress(Ekos::SequenceJob * job)
2630 {
"expv", job->getExposeLeft()},
2631 {
"expr", job->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble()}
2634 ekosLiveClient.get()->message()->updateCaptureStatus(status);
2637void Manager::updateCaptureCountDown()
2639 capturePreview->updateCaptureCountDown(-1);
2643 {
"seqt", capturePreview->captureCountsWidget->sequenceRemainingTime->text()},
2644 {
"ovt", capturePreview->captureCountsWidget->overallRemainingTime->text()},
2645 {
"ovp", capturePreview->captureCountsWidget->gr_overallProgressBar->value()},
2646 {
"ovl", capturePreview->captureCountsWidget->gr_overallLabel->text()}
2649 ekosLiveClient.get()->message()->updateCaptureStatus(status);
2653void Manager::updateFocusStatus(Ekos::FocusState status)
2659 {
"status", getFocusStatusString(status,
false)}
2662 ekosLiveClient.get()->message()->updateFocusStatus(
cStatus);
2665void Manager::updateGuideStatus(Ekos::GuideState status)
2670 {
"status", getGuideStatusString(status,
false)}
2673 ekosLiveClient.get()->message()->updateGuideStatus(
cStatus);
2676void Manager::setTarget(
const QString &name)
2678 capturePreview->targetLabel->setVisible(!
name.
isEmpty());
2679 capturePreview->mountTarget->setVisible(!
name.
isEmpty());
2680 capturePreview->mountTarget->setText(name);
2681 ekosLiveClient.get()->message()->updateMountStatus(
QJsonObject({{
"target",
name}}));
2684void Manager::showEkosOptions()
2688 if (alignModule() && alignModule() == currentWidget)
2699 if (guideModule() && guideModule() == currentWidget)
2705 if (focusModule() && focusModule() == currentWidget)
2716 if ((captureModule() && captureModule() == currentWidget) ||
2717 (schedulerModule() && schedulerModule() == currentWidget))
2722 const int index = schedulerModule() == currentWidget ? 1 : 2;
2723 opsEkos->setCurrentIndex(index);
2728 cDialog->setCurrentPage(ekosOptionsWidget);
2736 if (ekosOptionsWidget ==
nullptr)
2745 cDialog->setCurrentPage(ekosOptionsWidget);
2753void Manager::updateDebugInterfaces()
2759 auto debugProp = device->getProperty(
"DEBUG");
2766 if ( ( opsLogs->getINDIDebugInterface() & device->getDriverInterface() ) &&
2772 appendLogText(
i18n(
"Enabling debug logging for %1...", device->getDeviceName()));
2774 else if ( !( opsLogs->getINDIDebugInterface() & device->getDriverInterface() ) &&
2780 appendLogText(
i18n(
"Disabling debug logging for %1...", device->getDeviceName()));
2783 if (opsLogs->isINDISettingsChanged())
2784 device->setConfig(SAVE_CONFIG);
2788void Manager::watchDebugProperty(INDI::Property
prop)
2790 if (
prop.isNameMatch(
"DEBUG"))
2797 if (
deviceInterface->getDriverInterface() == INDI::BaseDevice::GENERAL_INTERFACE)
2803 (opsLogs->getINDIDebugInterface() &
deviceInterface->getDriverInterface()))
2808 appendLogText(
i18n(
"Re-enabling debug logging for %1...",
deviceInterface->getDeviceName()));
2815 && !(opsLogs->getINDIDebugInterface() &
deviceInterface->getDriverInterface()))
2820 appendLogText(
i18n(
"Re-disabling debug logging for %1...",
deviceInterface->getDeviceName()));
2825void Manager::announceEvent(
const QString &message, KSNotification::EventSource source, KSNotification::EventType event)
2827 ekosLiveClient.get()->message()->sendEvent(message, source, event);
2830void Manager::connectModules()
2833 connect(DarkLibrary::Instance(), &DarkLibrary::newImage, ekosLiveClient.get()->media(),
2835 connect(DarkLibrary::Instance(), &DarkLibrary::trainChanged, ekosLiveClient.get()->message(),
2837 connect(DarkLibrary::Instance(), &DarkLibrary::newFrame, ekosLiveClient.get()->media(), &EkosLive::Media::sendModuleFrame,
2839 connect(DarkLibrary::Instance(), &DarkLibrary::settingsUpdated, ekosLiveClient.get()->message(),
2843 if (captureProcess && guideProcess)
2849 connect(guideModule(), &Ekos::Guide::newStatus, captureModule(), &Ekos::Capture::setGuideStatus,
2855 connect(captureModule(), &Ekos::Capture::newStatus, guideModule(), &Ekos::Guide::setCaptureStatus,
2863 connect(guideModule(), &Ekos::Guide::guideChipUpdated, captureModule(), &Ekos::Capture::setGuideChip,
2869 connect(captureModule(), &Ekos::Capture::guideAfterMeridianFlip, guideModule(),
2874 if (guideProcess && mountProcess)
2885 if (guideProcess && focusProcess)
2893 if (captureProcess && focusProcess)
2920 connect(focusModule(), &Ekos::Focus::focusAdaptiveComplete, captureModule(),
2928 connect(focusModule(), &Ekos::Focus::newFocusTemperatureDelta, captureModule(),
2937 if (captureProcess && alignProcess)
2940 connect(alignModule(), &Ekos::Align::newStatus, captureModule(), &Ekos::Capture::setAlignStatus,
2943 connect(alignModule(), &Ekos::Align::newSolverResults, captureModule(), &Ekos::Capture::setAlignResults,
2946 connect(captureModule(), &Ekos::Capture::newStatus, alignModule(), &Ekos::Align::setCaptureStatus,
2951 if (captureProcess && mountProcess)
2955 captureModule()->registerNewModule(
"Mount");
2956 mountModule()->registerNewModule(
"Capture");
2972 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::updated, ekosLiveClient->message(),
2974 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::configurationRequested, ekosLiveClient->message(),
2979 if (captureProcess && ekosLiveClient)
2983 connect(captureModule(), &Ekos::Capture::dslrInfoRequested, ekosLiveClient.get()->message(),
2985 connect(captureModule(), &Ekos::Capture::sequenceChanged, ekosLiveClient.get()->message(),
2987 connect(captureModule(), &Ekos::Capture::settingsUpdated, ekosLiveClient.get()->message(),
2989 connect(captureModule(), &Ekos::Capture::newLocalPreview, ekosLiveClient.get()->message(),
2991 connect(captureModule(), &Ekos::Capture::trainChanged, ekosLiveClient.get()->message(),
2996 if (focusProcess && alignProcess)
2998 connect(focusModule(), &Ekos::Focus::newStatus, alignModule(), &Ekos::Align::setFocusStatus,
3003 if (focusProcess && mountProcess)
3012 if (mountProcess && alignProcess)
3025 if (mountProcess && guideProcess)
3027 connect(mountModule(), &Ekos::Mount::pierSideChanged, guideModule(), &Ekos::Guide::setPierSide,
3032 if (alignProcess && ekosLiveClient)
3037 connect(alignModule(), &Ekos::Align::newStatus, ekosLiveClient.get()->message(), &EkosLive::Message::setAlignStatus,
3039 connect(alignModule(), &Ekos::Align::newSolution, ekosLiveClient.get()->message(),
3041 connect(alignModule()->polarAlignmentAssistant(), &Ekos::PolarAlignmentAssistant::newPAHStage,
3042 ekosLiveClient.get()->message(), &EkosLive::Message::setPAHStage,
3044 connect(alignModule()->polarAlignmentAssistant(), &Ekos::PolarAlignmentAssistant::newPAHMessage,
3045 ekosLiveClient.get()->message(),
3047 connect(alignModule()->polarAlignmentAssistant(), &Ekos::PolarAlignmentAssistant::PAHEnabled,
3048 ekosLiveClient.get()->message(), &EkosLive::Message::setPAHEnabled,
3050 connect(alignModule()->polarAlignmentAssistant(), &Ekos::PolarAlignmentAssistant::polarResultUpdated,
3051 ekosLiveClient.get()->message(),
3053 connect(alignModule()->polarAlignmentAssistant(), &Ekos::PolarAlignmentAssistant::updatedErrorsChanged,
3054 ekosLiveClient.get()->message(),
3056 connect(alignModule()->polarAlignmentAssistant(), &Ekos::PolarAlignmentAssistant::newCorrectionVector,
3057 ekosLiveClient.get()->media(),
3060 connect(alignModule(), &Ekos::Align::newImage, ekosLiveClient.get()->media(), &EkosLive::Media::sendModuleFrame,
3062 connect(alignModule(), &Ekos::Align::newFrame, ekosLiveClient.get()->media(), &EkosLive::Media::sendUpdatedFrame,
3065 connect(alignModule(), &Ekos::Align::settingsUpdated, ekosLiveClient.get()->message(),
3068 connect(alignModule(), &Ekos::Align::trainChanged, ekosLiveClient.get()->message(),
3071 connect(alignModule(), &Ekos::Align::manualRotatorChanged, ekosLiveClient.get()->message(),
3076 if (focusProcess && ekosLiveClient)
3078 connect(focusModule(), &Ekos::Focus::settingsUpdated, ekosLiveClient.get()->message(),
3081 connect(focusModule(), &Ekos::Focus::newImage, ekosLiveClient.get()->media(), &EkosLive::Media::sendModuleFrame,
3084 connect(focusModule(), &Ekos::Focus::trainChanged, ekosLiveClient.get()->message(),
3085 &EkosLive::Message::sendTrainProfiles,
3088 connect(focusModule(), &Ekos::Focus::autofocusAborted,
3093 if (guideProcess && ekosLiveClient)
3095 connect(guideModule(), &Ekos::Guide::settingsUpdated, ekosLiveClient.get()->message(),
3098 connect(guideModule(), &Ekos::Guide::trainChanged, ekosLiveClient.get()->message(),
3101 connect(guideModule(), &Ekos::Guide::newImage, ekosLiveClient.get()->media(), &EkosLive::Media::sendModuleFrame,
3109 connect(schedulerModule(), &Ekos::Scheduler::jobStarted,
3111 connect(schedulerModule(), &Ekos::Scheduler::jobEnded,
3113 connect(schedulerModule(), &Ekos::Scheduler::targetDistance,
3119 connect(captureModule(), &Ekos::Capture::captureComplete,
3121 connect(captureModule(), &Ekos::Capture::captureStarting,
3123 connect(captureModule(), &Ekos::Capture::captureAborted,
3127 connect(captureModule(), &Ekos::Capture::meridianFlipStarted,
3129 connect(captureModule(), &Ekos::Capture::meridianFlipCompleted,
3137 connect(guideModule(), &Ekos::Guide::newStatus,
3140 connect(guideModule(), &Ekos::Guide::guideStats,
3147 if (focusProcess && analyzeProcess)
3149 connect(focusModule(), &Ekos::Focus::autofocusComplete,
3153 connect(focusModule(), &Ekos::Focus::autofocusStarting,
3155 connect(focusModule(), &Ekos::Focus::autofocusAborted,
3157 connect(focusModule(), &Ekos::Focus::newFocusTemperatureDelta,
3162 if (alignProcess && analyzeProcess)
3164 connect(alignModule(), &Ekos::Align::newStatus,
3170 if (mountProcess && analyzeProcess)
3176 connect(mountModule()->getMeridianFlipState().
get(), &Ekos::MeridianFlipState::newMountMFStatus,
3181void Manager::setEkosLiveConnected(
bool enabled)
3183 ekosLiveClient.get()->setConnected(enabled);
3191void Manager::setEkosLiveUser(
const QString &username,
const QString &password)
3193 ekosLiveClient.get()->setUser(username, password);
3196bool Manager::ekosLiveStatus()
3198 return ekosLiveClient.get()->isConnected();
3208 primaryDriver->getAuxInfo().value(
"mdpd",
false).toBool() ==
true);
3211void Manager::restartDriver(
const QString &deviceName)
3213 qCInfo(
KSTARS_EKOS) <<
"Restarting driver" << deviceName;
3218 if (
oneDevice->getDeviceName() == deviceName)
3220 DriverManager::Instance()->restartDriver(
oneDevice->getDriverInfo());
3226 INDI::WebManager::restartDriver(m_CurrentProfile, deviceName);
3229void Manager::setEkosLoggingEnabled(
const QString &name,
bool enabled)
3232 if (name ==
"LOGGING")
3234 Options::setDisableLogging(!enabled);
3238 else if (name ==
"FILE")
3240 Options::setLogToFile(enabled);
3244 else if (name ==
"DEFAULT")
3246 Options::setLogToDefault(enabled);
3251 else if (name ==
"VERBOSE")
3253 Options::setVerboseLogging(enabled);
3257 else if (name ==
"INDI")
3259 Options::setINDILogging(enabled);
3262 else if (name ==
"FITS")
3264 Options::setFITSLogging(enabled);
3267 else if (name ==
"CAPTURE")
3269 Options::setCaptureLogging(enabled);
3270 Options::setINDICCDLogging(enabled);
3271 Options::setINDIFilterWheelLogging(enabled);
3274 else if (name ==
"FOCUS")
3276 Options::setFocusLogging(enabled);
3277 Options::setINDIFocuserLogging(enabled);
3280 else if (name ==
"GUIDE")
3282 Options::setGuideLogging(enabled);
3283 Options::setINDICCDLogging(enabled);
3286 else if (name ==
"ALIGNMENT")
3288 Options::setAlignmentLogging(enabled);
3291 else if (name ==
"MOUNT")
3293 Options::setMountLogging(enabled);
3294 Options::setINDIMountLogging(enabled);
3297 else if (name ==
"SCHEDULER")
3299 Options::setSchedulerLogging(enabled);
3302 else if (name ==
"OBSERVATORY")
3304 Options::setObservatoryLogging(enabled);
3309void Manager::acceptPortSelection()
3312 m_PortSelector->accept();
3315void Manager::setPortSelectionComplete()
3317 if (m_CurrentProfile->portSelector)
3320 m_CurrentProfile->portSelector =
false;
3321 KStarsData::Instance()->userdb()->SaveProfile(m_CurrentProfile);
3324 if (m_CurrentProfile->autoConnect)
3328void Manager::activateModule(
const QString &name,
bool popup)
3345 if (device->isConnected())
3347 if (device->getDriverInterface() & INDI::BaseDevice::CCD_INTERFACE)
3354 if (device->getDriverInterface() & INDI::BaseDevice::FILTER_INTERFACE)
3360 if (device->getDriverInterface() & INDI::BaseDevice::FOCUSER_INTERFACE)
3362 if (device->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE)
3369 if (device->getDriverInterface() & INDI::BaseDevice::ROTATOR_INTERFACE)
3374 if (device->getDriverInterface() & INDI::BaseDevice::DOME_INTERFACE)
3380 if (device->getDriverInterface() & INDI::BaseDevice::WEATHER_INTERFACE)
3385 if (device->getDriverInterface() & INDI::BaseDevice::DUSTCAP_INTERFACE)
3389 if (device->getDriverInterface() & INDI::BaseDevice::LIGHTBOX_INTERFACE)
3393 if (device->getDriverInterface() & INDI::BaseDevice::GPS_INTERFACE)
3400void Manager::setDeviceReady()
3404 if (isINDIReady() ==
false)
3410 if (device->isConnected() ==
false && m_CurrentProfile->autoConnect)
3413 if (m_CurrentProfile->portSelector)
3419 if (!m_PortSelector)
3420 m_PortSelectorTimer.start();
3424 qCInfo(
KSTARS_EKOS) <<
"Connecting to" << device->getDeviceName();
3429 qCInfo(
KSTARS_EKOS) << device->getDeviceName() <<
"is connected and ready.";
3432 if (m_ekosStatus != Ekos::Success)
3437 if (m_DriverDevicesCount <= 0 && (m_CurrentProfile->portSelector ==
false || !m_PortSelector))
3440 syncGenericDevice(device);
3441 OpticalTrainManager::Instance()->setProfile(m_CurrentProfile);
3445void Manager::createFilterManager(ISD::FilterWheel *device)
3447 auto name = device->getDeviceName();
3448 if (m_FilterManagers.contains(name) ==
false)
3451 newFM->setFilterWheel(device);
3455 m_FilterManagers[
name]->setFilterWheel(device);
3461 if (m_FilterManagers.contains(name))
3463 fm = m_FilterManagers[
name];
3471 if (m_FilterManagers.size() > 0)
3473 fm = m_FilterManagers.values()[0];
3479void Manager::createRotatorController(
ISD::Rotator *device)
3481 auto Name = device->getDeviceName();
3482 if (m_RotatorControllers.contains(Name) ==
false)
3486 m_RotatorControllers[Name] =
newRC;
3492 if (m_RotatorControllers.contains(Name))
3494 rs = m_RotatorControllers[Name];
3500bool Manager::existRotatorController()
3502 return (!m_RotatorControllers.empty());
DriverInfo holds all metadata associated with a particular INDI driver.
DriverManager is the primary class to handle all operations related to starting and stopping INDI dri...
Align class handles plate-solving and polar alignment measurement and correction using astrometry....
Analysis tab for Ekos sessions.
void setFocusTemperatureDelta(double focusTemperatureDelta, double absTemperature)
updateAdaptiveFocusStatus Handle new focus state
void setHFR(double newHFR, int position, bool inAutofocus)
setHFR Receive the measured HFR value of the latest frame
void updateTargetDistance(double targetDiff)
Slot receiving the update of the current target distance.
void setFocusStatus(FocusState newstate)
setFocusStatus Forward the new focus state to the capture module state machine
void setGuideDeviation(double delta_ra, double delta_dec)
setGuideDeviation Set the guiding deviation as measured by the guiding module.
void focusAdaptiveComplete(bool success)
focusAdaptiveComplete Forward the new focus state to the capture module state machine
Supports manual focusing and auto focusing using relative and absolute INDI focusers.
void drawPolynomial(PolynomialFit *poly, bool isVShape, bool activate, bool plot=true)
draw the approximating polynomial into the HFR V-graph
void newHFRPlotPosition(double pos, double hfr, double sigma, bool outlier, int pulseDuration, bool plot=true)
new HFR plot position with sigma
void redrawHFRPlot(PolynomialFit *poly, double solutionPosition, double solutionValue)
redraw the entire HFR plot
void runAutoFocus(const AutofocusReason autofocusReason, const QString &reasonInfo)
Run the autofocus process for the currently selected filter.
void focuserTimedout(const QString &focuser)
focuserTimedout responding to requests
void initHFRPlot(QString str, double starUnits, bool minimum, bool useWeights, bool showPosition)
initialize the HFR V plot
void adaptiveFocus()
adaptiveFocus moves the focuser between subframes to stay at focus
Q_SCRIPTABLE Q_NOREPLY void resetFrame()
DBUS interface function.
void meridianFlipStarted()
React when a meridian flip has been started.
void drawCFZ(double minPosition, double minValue, int m_cfzSteps, bool plt)
Draw Critical Focus Zone on graph.
void finalUpdates(const QString &title, bool plot=true)
final updates after focus run comopletes on the focus plot
void minimumFound(double solutionPosition, double solutionValue, bool plot=true)
Focus solution with minimal HFR found.
void setTitle(const QString &title, bool plot=true)
draw a title on the focus plot
void drawCurve(CurveFitting *curve, bool isVShape, bool activate, bool plot=true)
draw the curve into the HFR V-graph
void adaptiveFocusComplete(const QString &filter, double temperature, double tempTicks, double altitude, double altTicks, int prevPosError, int thisPosError, int totalTicks, int position, bool focuserMoved)
Signal Analyze that an Adaptive Focus iteration is complete.
Performs calibration and autoguiding using an ST4 port or directly via the INDI driver.
Q_SCRIPTABLE bool resume()
DBUS interface function.
Q_SCRIPTABLE bool suspend()
DBUS interface function.
Q_SCRIPTABLE bool abort()
DBUS interface function.
Supports controlling INDI telescope devices including setting/retrieving mount properties,...
void newTarget(SkyPoint ¤tCoord)
The mount has finished the slew to a new target.
void paaStageChanged(int stage)
React upon status changes of the polar alignment - mainly to avoid meridian flips happening during po...
void newTargetName(const QString &name)
The mount has finished the slew to a new target.
void newStatus(ISD::Mount::Status status)
Change in the mount status.
void suspendAltLimits()
suspendAltLimits calls enableAltitudeLimits(false).
void newCoords(const SkyPoint &position, ISD::Mount::PierSide pierSide, const dms &ha)
Update event with the current telescope position.
void resumeAltLimits()
resumeAltLimits calls enableAltitudeLimits(true).
Enables the user to set logging options.
INDIListener is responsible for creating ISD::GDInterface generic devices as new devices arrive from ...
Camera class controls an INDI Camera device.
void sendNewProperty(INDI::Property prop)
Send new property command to server.
Class handles control of INDI dome devices.
Handles operation of a remotely controlled dust cover cap.
Focuser class handles control of INDI focuser devices.
GenericDevice is the Generic Device for INDI devices.
Handles operation of a remotely controlled light box.
device handle controlling Mounts.
Rotator class handles control of INDI Rotator devices.
Focuser class handles control of INDI Weather devices.
static bool showDialog(const QString &name)
KPageWidgetItem * addPage(QWidget *page, const QString &itemName, const QString &pixmapName=QString(), const QString &header=QString(), bool manage=true)
static KConfigDialog * exists(const QString &name)
static void beep(const QString &reason=QString())
QPushButton * button(QDialogButtonBox::StandardButton which) const
void setIcon(const QIcon &icon)
static void UseDefault()
Use the default logging mechanism.
static void SyncFilterRules()
SyncFilterRules Sync QtLogging filter rules from Options.
static void Disable()
Disable logging.
static void UseFile()
Store all logs into the specified file.
static KStarsDateTime currentDateTimeUtc()
This is the main window for KStars.
static KStars * Instance()
Primary class to handle all Ekos modules.
Provides all necessary information about an object in the sky: its coordinates, name(s),...
The sky coordinates of a point in the sky.
const CachingDms & dec() const
const CachingDms & ra0() const
const CachingDms & ra() const
const CachingDms & dec0() const
An angle, stored as degrees, but expressible in many ways.
static dms fromString(const QString &s, bool deg)
Static function to create a DMS object from a QString.
const double & Degrees() const
void setTarget(const SkyPoint &targetCoord)
Set the alignment target where the mount is expected to point at.
void setTelescopeCoordinates(const SkyPoint &position)
Set the coordinates that the mount reports as its position.
Q_SCRIPTABLE Q_NOREPLY void checkFocus(double requiredHFR)
checkFocus Given the minimum required HFR, check focus and calculate HFR.
Q_SCRIPTABLE Q_NOREPLY void abort()
DBUS interface function.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
QString fullName(const PartType &type)
char * toString(const EngineQuery &query)
Ekos is an advanced Astrophotography tool for Linux.
CaptureState
Capture states.
KIOCORE_EXPORT TransferJob * get(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
GeoCoordinates geo(const QVariant &location)
QVariant location(const QVariant &res)
QString label(StandardShortcut id)
QString name(StandardShortcut id)
NETWORKMANAGERQT_EXPORT NetworkManager::Status status()
void currentTextChanged(const QString &text)
QCoreApplication * instance()
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
QDBusConnection sessionBus()
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
QIcon fromTheme(const QString &name)
QJsonArray array() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
void start(OpenMode mode)
bool waitForFinished(int msecs)
QString arg(Args &&... args) const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype length() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString toString(StringFormat mode) const const
double toDouble(bool *ok) const const
int toInt(bool *ok) const const