File indexing completed on 2024-04-21 03:43:35

0001 /*
0002     SPDX-FileCopyrightText: 2015 Jasem Mutlaq <mutlaqja@ikarustech.com>
0003 
0004     DBus calls from GSoC 2015 Ekos Scheduler project:
0005     SPDX-FileCopyrightText: 2015 Daniel Leu <daniel_mihai.leu@cti.pub.ro>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #pragma once
0011 
0012 #include "ui_scheduler.h"
0013 #include "schedulertypes.h"
0014 #include "ekos/align/align.h"
0015 #include "indi/indiweather.h"
0016 #include "schedulerjob.h"
0017 #include "ekos/auxiliary/modulelogger.h"
0018 
0019 #include <lilxml.h>
0020 
0021 #include <QTime>
0022 #include <QTimer>
0023 #include <QUrl>
0024 #include <QDBusInterface>
0025 
0026 #include <cstdint>
0027 
0028 class QProgressIndicator;
0029 
0030 class GeoLocation;
0031 class SkyObject;
0032 class KConfigDialog;
0033 class TestSchedulerUnit;
0034 class SolverUtils;
0035 class TestEkosSchedulerOps;
0036 
0037 namespace Ekos
0038 {
0039 
0040 class SequenceJob;
0041 class GreedyScheduler;
0042 class SchedulerProcess;
0043 class SchedulerModuleState;
0044 class SequenceEditor;
0045 
0046 /**
0047  * @brief The Ekos scheduler is a simple scheduler class to orchestrate automated multi object observation jobs.
0048  * @author Jasem Mutlaq
0049  * @version 1.2
0050  */
0051 class Scheduler : public QWidget, public Ui::Scheduler, public ModuleLogger
0052 {
0053         Q_OBJECT
0054         Q_CLASSINFO("D-Bus Interface", "org.kde.kstars.Ekos.Scheduler")
0055         Q_PROPERTY(Ekos::SchedulerState status READ status NOTIFY newStatus)
0056         Q_PROPERTY(QStringList logText READ logText NOTIFY newLog)
0057         Q_PROPERTY(QString profile READ profile WRITE setProfile)
0058 
0059         friend class FramingAssistantUI;
0060 
0061 public:
0062 
0063         /** @brief Columns, in the same order as UI. */
0064         typedef enum
0065         {
0066             SCHEDCOL_NAME = 0,
0067             SCHEDCOL_STATUS,
0068             SCHEDCOL_CAPTURES,
0069             SCHEDCOL_ALTITUDE,
0070             SCHEDCOL_STARTTIME,
0071             SCHEDCOL_ENDTIME,
0072         } SchedulerColumns;
0073 
0074         /** @brief Constructor, the starndard scheduler constructor. */
0075         Scheduler();
0076         /** @brief DebugConstructor, a constructor used in testing with a mock ekos. */
0077         Scheduler(const QString path, const QString interface,
0078                   const QString &ekosPathStr, const QString &ekosInterfaceStr);
0079         ~Scheduler() = default;
0080 
0081         QString getCurrentJobName();
0082 
0083         // shortcut
0084         SchedulerJob *activeJob();
0085 
0086         void appendLogText(const QString &) override;
0087         QStringList logText()
0088         {
0089             return m_LogText;
0090         }
0091         QString getLogText()
0092         {
0093             return m_LogText.join("\n");
0094         }
0095         Q_SCRIPTABLE void clearLog();
0096         void applyConfig();
0097 
0098         void addObject(SkyObject *object);
0099 
0100         /**
0101          * @brief importMosaic Import mosaic into planner and generate jobs for the scheduler.
0102          * @param payload metadata for the mosaic information.
0103          * @note Only Telescopius.com mosaic format is now supported.
0104          */
0105         bool importMosaic(const QJsonObject &payload);
0106 
0107         /** @defgroup SchedulerDBusInterface Ekos DBus Interface - Scheduler Module
0108              * Ekos::Align interface provides primary functions to run and stop the scheduler.
0109             */
0110 
0111         /*@{*/
0112 
0113         /** DBUS interface function.
0114              * @brief Start the scheduler main loop and evaluate jobs and execute them accordingly.
0115              */
0116         Q_SCRIPTABLE Q_NOREPLY void start();
0117 
0118         /** DBUS interface function.
0119              * @brief Stop the scheduler.
0120              */
0121         Q_SCRIPTABLE Q_NOREPLY void stop();
0122 
0123         /** DBUS interface function.
0124              * @brief Remove all scheduler jobs
0125              */
0126         Q_SCRIPTABLE Q_NOREPLY void removeAllJobs();
0127 
0128         /** DBUS interface function.
0129              * @brief Loads the Ekos Scheduler List (.esl) file.
0130              * @param fileURL path to a file
0131              * @return true if loading file is successful, false otherwise.
0132              */
0133         Q_SCRIPTABLE bool loadScheduler(const QString &fileURL);
0134 
0135         /** DBUS interface function.
0136          * @brief Set the file URL pointing to the capture sequence file
0137          * @param sequenceFileURL URL of the capture sequence file
0138          */
0139         Q_SCRIPTABLE void setSequence(const QString &sequenceFileURL);
0140 
0141         /** DBUS interface function.
0142              * @brief Resets all jobs to IDLE
0143              */
0144         Q_SCRIPTABLE void resetAllJobs();
0145 
0146         /** DBUS interface function.
0147              * @brief Resets all jobs to IDLE
0148              */
0149         Q_SCRIPTABLE void sortJobsPerAltitude();
0150 
0151         Ekos::SchedulerState status();
0152 
0153         void setProfile(const QString &profile)
0154         {
0155             schedulerProfileCombo->setCurrentText(profile);
0156         }
0157         QString profile()
0158         {
0159             return schedulerProfileCombo->currentText();
0160         }
0161 
0162         /**
0163          * @brief retrieve the error handling strategy from the UI
0164          */
0165         ErrorHandlingStrategy getErrorHandlingStrategy();
0166 
0167         /**
0168          * @brief select the error handling strategy (no restart, restart after all terminated, restart immediately)
0169          */
0170         void setErrorHandlingStrategy (ErrorHandlingStrategy strategy);
0171 
0172         /** @}*/
0173 
0174         // TODO: This section of static public and private methods should someday
0175         // be moved from Scheduler and placed in a separate class,
0176         // e.g. SchedulerPlanner or SchedulerJobEval        
0177         /**
0178          * @brief Remove a job from current table row.
0179          * @param index
0180          */
0181         void removeJob();
0182 
0183         /**
0184          * @brief Remove a job by selecting a table row.
0185          * @param index
0186          */
0187         void removeOneJob(int index);
0188 
0189         /**
0190          * @brief addJob Add a new job from form values
0191          */
0192         void addJob(SchedulerJob *job = nullptr);
0193 
0194         /**
0195          * @brief createJob Create a new job from form values.
0196          * @param job job to be filled from UI values
0197          * @return true iff update was successful
0198          */
0199         bool fillJobFromUI(SchedulerJob *job);
0200 
0201         /**
0202          * @brief addToQueue Construct a SchedulerJob and add it to the queue or save job settings from current form values.
0203          * jobUnderEdit determines whether to add or edit
0204          */
0205         void saveJob(SchedulerJob *job = nullptr);
0206 
0207         void toggleScheduler();
0208 
0209         QJsonObject getSchedulerSettings();
0210         /**
0211              * @brief createJobSequence Creates a job sequence for the mosaic tool given the prefix and output dir. The currently selected sequence file is modified
0212              * and a new version given the supplied parameters are saved to the output directory
0213              * @param prefix Prefix to set for the job sequence
0214              * @param outputDir Output dir to set for the job sequence
0215              * @return True if new file is saved, false otherwise
0216              */
0217         bool createJobSequence(XMLEle *root, const QString &prefix, const QString &outputDir);
0218 
0219         XMLEle *getSequenceJobRoot(const QString &filename);
0220 
0221         /**
0222              * @brief saveScheduler Save scheduler jobs to a file
0223              * @param path path of a file
0224              * @return true on success, false on failure.
0225              */
0226         Q_SCRIPTABLE bool saveScheduler(const QUrl &fileURL);
0227 
0228         // the state machine
0229         QSharedPointer<SchedulerModuleState> moduleState() const
0230         {
0231             return m_moduleState;
0232         }
0233 
0234         // Settings
0235         QVariantMap getAllSettings() const;
0236         void setAllSettings(const QVariantMap &settings);
0237         
0238 private:
0239 
0240         void setAlgorithm(int alg);
0241 
0242         friend TestSchedulerUnit;
0243 
0244         // TODO: See above TODO. End of static methods that might be moved to
0245         // a separate Scheduler-related class.
0246 
0247         /*@{*/
0248         /** @internal Safeguard flag to avoid registering signals from widgets multiple times.
0249          */
0250         bool jobChangesAreWatched { false };
0251 
0252 protected:
0253 
0254         /** @internal Enables signal watch on SchedulerJob form values in order to apply changes to current job.
0255           * @param enable is the toggle flag, true to watch for changes, false to ignore them.
0256           */
0257         void watchJobChanges(bool enable);
0258 
0259         /** @internal Marks the currently selected SchedulerJob as modified change.
0260          *
0261          * This triggers job re-evaluation.
0262          * Next time save button is invoked, the complete content is written to disk.
0263           */
0264         void setDirty();
0265         /** @} */
0266 
0267         /**
0268          * @brief updateJobTable Update the job's row in the job table. If the row does not exist, it will
0269          * be created on the fly. If job is null, update the entire table
0270          * @param job
0271          */
0272         void updateJobTable(SchedulerJob *job = nullptr);
0273 
0274         /**
0275          * @brief insertJobTableRow Insert a new row (empty) into the job table
0276          * @param row row number (starting with 0)
0277          * @param above insert above the given row (=true) or below (=false)
0278          */
0279         void insertJobTableRow(int row, bool above = true);
0280 
0281         /**
0282          * @brief Update the style of a cell, depending on the job's state
0283          */
0284         void updateCellStyle(SchedulerJob *job, QTableWidgetItem *cell);
0285 
0286 protected slots:
0287 
0288         /**
0289          * @brief registerNewModule Register an Ekos module as it arrives via DBus
0290          * and create the appropriate DBus interface to communicate with it.
0291          * @param name of module
0292          */
0293         void registerNewModule(const QString &name);
0294 
0295         /**
0296            * @brief registerNewDevice register interfaces associated with devices
0297            * @param name Device name
0298            * @param interface Device driver interface
0299            */
0300         void registerNewDevice(const QString &name, int interface);
0301 
0302         /**
0303          * @brief syncProperties Sync startup properties from the various device to enable/disable features in the scheduler
0304          * like the ability to park/unpark..etc
0305          */
0306         void syncProperties();
0307 
0308         /**
0309          * @brief checkInterfaceReady Sometimes syncProperties() is not sufficient since the ready signal could have fired already
0310          * and cannot be relied on to know once a module interface is ready. Therefore, we explicitly check if the module interface
0311          * is ready.
0312          * @param iface interface to test for readiness.
0313          */
0314         void checkInterfaceReady(QDBusInterface *iface);
0315 
0316         void setAlignStatus(Ekos::AlignState status);
0317         void setGuideStatus(Ekos::GuideState status);
0318         void setCaptureStatus(Ekos::CaptureState status);
0319         void setFocusStatus(Ekos::FocusState status);
0320         void setMountStatus(ISD::Mount::Status status);
0321         void setWeatherStatus(ISD::Weather::Status status);
0322 
0323         /**
0324              * @brief select object from KStars's find dialog.
0325              */
0326         void selectObject();
0327 
0328         /**
0329              * @brief Selects FITS file for solving.
0330              */
0331         void selectFITS();
0332 
0333         /**
0334              * @brief Selects sequence queue.
0335              */
0336         void selectSequence();
0337 
0338         /**
0339              * @brief Selects sequence queue.
0340              */
0341         void selectStartupScript();
0342 
0343         /**
0344              * @brief Selects sequence queue.
0345              */
0346         void selectShutdownScript();
0347 
0348         /**
0349              * @brief editJob Edit an observation job
0350              * @param i index model in queue table
0351              */
0352         void loadJob(QModelIndex i);
0353 
0354         /**
0355          * @brief updateSchedulerURL Update scheduler URL after succesful loading a new file.
0356          */
0357         void updateSchedulerURL(const QString &fileURL);
0358 
0359         /**
0360              * @brief setJobAddApply Set first button state to add new job or apply changes.
0361              */
0362         void setJobAddApply(bool add_mode);
0363 
0364         /**
0365              * @brief setJobManipulation Enable or disable job manipulation buttons.
0366              */
0367         void setJobManipulation(bool can_reorder, bool can_delete);
0368 
0369         /**
0370          * @brief set all GUI fields to the values of the given scheduler job
0371          */
0372         void syncGUIToJob(SchedulerJob *job);
0373 
0374         /**
0375          * @brief syncGUIToGeneralSettings set all UI fields that are not job specific
0376          */
0377         void syncGUIToGeneralSettings();
0378 
0379         /**
0380              * @brief jobSelectionChanged Update UI state when the job list is clicked once.
0381              */
0382         void clickQueueTable(QModelIndex index);
0383 
0384         /**
0385          * @brief Update scheduler parameters to the currently selected scheduler job
0386          * @param selected table position
0387          * @param deselected table position
0388          */
0389         void queueTableSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
0390 
0391         /**
0392              * @brief reorderJobs Change the order of jobs in the UI based on a subset of its jobs.
0393              */
0394         bool reorderJobs(QList<SchedulerJob*> reordered_sublist);
0395 
0396         /**
0397              * @brief moveJobUp Move the selected job up in the job list.
0398              */
0399         void moveJobUp();
0400 
0401         /**
0402             * @brief moveJobDown Move the selected job down in the list.
0403             */
0404         void moveJobDown();
0405 
0406         /**
0407          * @brief handleSchedulerSleeping Update UI if scheduler is set to sleep
0408          * @param shutdown flag if a preemptive shutdown is executed
0409          * @param sleep flag if the scheduler will sleep
0410          */
0411         void handleSchedulerSleeping(bool shutdown, bool sleep);
0412 
0413         /**
0414          * @brief handleSchedulerStateChanged Update UI when the scheduler state changes
0415          */
0416         void handleSchedulerStateChanged(SchedulerState newState);
0417 
0418         /**
0419          * @brief handleSetPaused Update the UI when {@see #setPaused()} is called.
0420          */
0421         void handleSetPaused();
0422 
0423         void pause();
0424         void save();
0425         void saveAs();
0426 
0427         /**
0428          * @brief load Open a file dialog to select an ESL file, and load its contents.
0429          * @param clearQueue Clear the queue before loading, or append ESL contents to queue.
0430          * @param filename If not empty, this file will be used instead of poping up a dialog.
0431          */
0432         void load(bool clearQueue, const QString &filename = "");
0433 
0434         void resetJobEdit();
0435 
0436         /**
0437          * @brief updateNightTime update the Twilight restriction with the argument job properties.
0438          * @param job SchedulerJob for which to display the next dawn and dusk, or the job currently selected if null, or today's next dawn and dusk if no job is selected.
0439          */
0440         void updateNightTime(SchedulerJob const * job = nullptr);
0441 
0442         /**
0443          * @brief schedulerStopped React when the process engine has stopped the scheduler
0444          */
0445         void schedulerStopped();
0446 
0447         /**
0448              * @brief resumeCheckStatus If the scheduler primary loop was suspended due to weather or sleep event, resume it again.
0449              */
0450         void resumeCheckStatus();
0451 
0452         /**
0453              * @brief checkWeather Check weather status and act accordingly depending on the current status of the scheduler and running jobs.
0454              */
0455         //void checkWeather();
0456 
0457         /**
0458              * @brief startJobEvaluation Start job evaluation only without starting the scheduler process itself. Display the result to the user.
0459              */
0460         void startJobEvaluation();
0461 
0462         /**
0463              * @brief displayTwilightWarning Display twilight warning to user if it is unchecked.
0464              */
0465         void checkTwilightWarning(bool enabled);
0466 
0467         void setINDICommunicationStatus(Ekos::CommunicationStatus status);
0468         void setEkosCommunicationStatus(Ekos::CommunicationStatus status);
0469 
0470         void simClockScaleChanged(float);
0471         void simClockTimeChanged();
0472 
0473         /**
0474          * @brief solverDone Process solver solution after it is done.
0475          * @param timedOut True if the process timed out.
0476          * @param success True if successful, false otherwise.
0477          * @param solution The solver solution if successful.
0478          * @param elapsedSeconds How many seconds elapsed to solve the image.
0479          */
0480         void solverDone(bool timedOut, bool success, const FITSImage::Solution &solution, double elapsedSeconds);
0481 
0482         /**
0483          * @brief setCaptureComplete Handle one sequence image completion. This is used now only to run alignment check
0484          * to ensure it does not deviation from current scheduler job target.
0485          * @param metadata Metadata for image including filename, exposure, filter, hfr..etc.
0486          */
0487         void setCaptureComplete(const QVariantMap &metadata);
0488 
0489 signals:
0490         void newLog(const QString &text);
0491         void newStatus(Ekos::SchedulerState state);
0492         void weatherChanged(ISD::Weather::Status state);
0493         void newTarget(const QString &);
0494         // distance in arc-seconds measured by plate solving the a captured image and
0495         // comparing that position to the target position.
0496         void targetDistance(double distance);
0497         // Below 2 are for the Analyze timeline.
0498         void jobStarted(const QString &jobName);
0499         void jobEnded(const QString &jobName, const QString &endReason);
0500         void jobsUpdated(QJsonArray jobsList);
0501         void settingsUpdated(const QVariantMap &settings);
0502 
0503 private:
0504         /**
0505          * @brief handleJobsUpdated Update UI when jobs have been updated
0506          * @param jobsList
0507          */
0508         void handleJobsUpdated(QJsonArray jobsList);
0509 
0510         /**
0511          * @brief handleShutdownStarted Show that the shutdown has been started.
0512          */
0513         void handleShutdownStarted();
0514 
0515         /**
0516          * @brief processFITSSelection When a FITS file is selected, open it and try to guess
0517          * the object name, and its J2000 RA/DE to fill the UI with such info automatically.
0518          */
0519         void processFITSSelection(const QUrl &url);
0520 
0521         /**
0522          * @brief updateProfiles React upon changed profiles and update the UI
0523          */
0524         void updateProfiles();
0525 
0526         /**
0527          * @brief updateStageLabel Helper function that updates the stage label.
0528          */
0529         void updateJobStageUI(SchedulerJobStage stage);
0530 
0531         ////////////////////////////////////////////////////////////////////
0532         /// Settings
0533         ////////////////////////////////////////////////////////////////////
0534 
0535         /**
0536          * @brief Connect GUI elements to sync settings once updated.
0537          */
0538         void connectSettings();
0539         /**
0540          * @brief Stop updating settings when GUI elements are updated.
0541          */
0542         void disconnectSettings();
0543         /**
0544          * @brief loadSettings Load setting from Options and set them accordingly.
0545          */
0546         void loadGlobalSettings();
0547 
0548         /**
0549          * @brief syncSettings When checkboxes, comboboxes, or spin boxes are updated, save their values in the
0550          * global and per-train settings.
0551          */
0552         void syncSettings();
0553 
0554         /**
0555          * @brief syncControl Sync setting to widget. The value depends on the widget type.
0556          * @param settings Map of all settings
0557          * @param key name of widget to sync
0558          * @param widget pointer of widget to set
0559          * @return True if sync successful, false otherwise
0560          */
0561         bool syncControl(const QVariantMap &settings, const QString &key, QWidget * widget);
0562 
0563         /**
0564          * @brief checkJobInputComplete Check if all inputs are filled such that a new job could be added.
0565          */
0566         void checkJobInputComplete();
0567 
0568         Ekos::Scheduler *ui { nullptr };
0569 
0570         // Interface strings for the dbus. Changeable for mocks when testing. Private so only tests can change.
0571         QString schedulerPathString { "/KStars/Ekos/Scheduler" };
0572         QString kstarsInterfaceString { "org.kde.kstars" };
0573 
0574         QString focusInterfaceString { "org.kde.kstars.Ekos.Focus" };
0575         void setFocusInterfaceString(const QString &interface)
0576         {
0577             focusInterfaceString = interface;
0578         }
0579         QString focusPathString { "/KStars/Ekos/Focus" };
0580         void setFocusPathString(const QString &interface)
0581         {
0582             focusPathString = interface;
0583         }
0584 
0585         // This is only used in the constructor
0586         QString ekosInterfaceString { "org.kde.kstars.Ekos" };
0587         QString ekosPathString { "/KStars/Ekos" };
0588 
0589         QString mountInterfaceString { "org.kde.kstars.Ekos.Mount" };
0590         void setMountInterfaceString(const QString &interface)
0591         {
0592             mountInterfaceString = interface;
0593         }
0594         QString mountPathString { "/KStars/Ekos/Mount" };
0595         void setMountPathString(const QString &interface)
0596         {
0597             mountPathString = interface;
0598         }
0599 
0600         QString captureInterfaceString { "org.kde.kstars.Ekos.Capture" };
0601         void setCaptureInterfaceString(const QString &interface)
0602         {
0603             captureInterfaceString = interface;
0604         }
0605         QString capturePathString { "/KStars/Ekos/Capture" };
0606         void setCapturePathString(const QString &interface)
0607         {
0608             capturePathString = interface;
0609         }
0610 
0611         QString alignInterfaceString { "org.kde.kstars.Ekos.Align" };
0612         void setAlignInterfaceString(const QString &interface)
0613         {
0614             alignInterfaceString = interface;
0615         }
0616         QString alignPathString { "/KStars/Ekos/Align" };
0617         void setAlignPathString(const QString &interface)
0618         {
0619             alignPathString = interface;
0620         }
0621 
0622         QString guideInterfaceString { "org.kde.kstars.Ekos.Guide" };
0623         void setGuideInterfaceString(const QString &interface)
0624         {
0625             guideInterfaceString = interface;
0626         }
0627         QString guidePathString { "/KStars/Ekos/Guide" };
0628         void setGuidePathString(const QString &interface)
0629         {
0630             guidePathString = interface;
0631         }
0632 
0633         QString INDIInterfaceString { "org.kde.kstars.INDI" };
0634         void setINDIInterfaceString(const QString &interface)
0635         {
0636             INDIInterfaceString = interface;
0637         }
0638 
0639         QString INDIPathString {"/KStars/INDI"};
0640         void setINDIPathString(const QString &interface)
0641         {
0642             INDIPathString = interface;
0643         }
0644 
0645         QString domeInterfaceString { "org.kde.kstars.INDI.Dome" };
0646         void setDomeInterfaceString(const QString &interface)
0647         {
0648             domeInterfaceString = interface;
0649         }
0650 
0651         QString domePathString;
0652         void setDomePathString(const QString &interface)
0653         {
0654             domePathString = interface;
0655         }
0656 
0657         QString weatherInterfaceString { "org.kde.kstars.INDI.Weather" };
0658         void setWeatherInterfaceString(const QString &interface)
0659         {
0660             weatherInterfaceString = interface;
0661         }
0662         QString weatherPathString;
0663         void setWeatherPathString(const QString &interface)
0664         {
0665             weatherPathString = interface;
0666         }
0667 
0668         QString dustCapInterfaceString { "org.kde.kstars.INDI.DustCap" };
0669         void setDustCapInterfaceString(const QString &interface)
0670         {
0671             dustCapInterfaceString = interface;
0672         }
0673         QString dustCapPathString;
0674         void setDustCapPathString(const QString &interface)
0675         {
0676             dustCapPathString = interface;
0677         }
0678 
0679         // the state machine holding all states
0680         QSharedPointer<SchedulerModuleState> m_moduleState;
0681         // process engine implementing all process steps
0682         QSharedPointer<SchedulerProcess> m_process;
0683         QSharedPointer<SchedulerProcess> process()
0684         {
0685             return m_process;
0686         }
0687 
0688         // react upon changes of EKOS and INDI state
0689         void ekosStateChanged(EkosState state);
0690         void indiStateChanged(INDIState state);
0691 
0692         // react upon state changes
0693         void startupStateChanged(StartupState state);
0694         void shutdownStateChanged(ShutdownState state);
0695         void parkWaitStateChanged(ParkWaitState state);
0696 
0697         /// URL to store the scheduler file
0698         QUrl schedulerURL;
0699         /// URL for Ekos Sequence
0700         QUrl sequenceURL;
0701         /// FITS URL to solve
0702         QUrl fitsURL;
0703         /// Store all log strings
0704         QStringList m_LogText;
0705         /// Busy indicator widget
0706         QProgressIndicator *pi { nullptr };
0707         /// Are we editing a job right now? Job row index
0708         int jobUnderEdit { -1 };
0709         /// Pointer to Geographic location
0710         GeoLocation *geo { nullptr };
0711 
0712         /// Call checkWeather when weatherTimer time expires. It is equal to the UpdatePeriod time in INDI::Weather device.
0713         //QTimer weatherTimer;
0714 
0715         QUrl dirPath;
0716 
0717         // update the sleep label and its visibility
0718         void changeSleepLabel(QString text, bool show = true);
0719         // Used by the constructor in testing mainly so a mock ekos could be used.
0720         void setupScheduler(const QString &ekosPathStr, const QString &ekosInterfaceStr);
0721 
0722 
0723         /// Target coordinates for pointing check
0724         QSharedPointer<SolverUtils> m_Solver;
0725         // Used when solving position every nth capture.
0726         uint32_t m_SolverIteration {0};
0727 
0728         void syncGreedyParams();
0729 
0730         friend TestEkosSchedulerOps;
0731 
0732         QSharedPointer<SequenceEditor> m_SequenceEditor;
0733 
0734         QVariantMap m_Settings;
0735         QVariantMap m_GlobalSettings;
0736 };
0737 }