1 /*
2     Weather Interface
3     Copyright (C) 2018 Jasem Mutlaq (mutlaqja@ikarustech.com)
4 
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9 
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 
19 */
20 
21 #pragma once
22 
23 #include "indibase.h"
24 
25 #include <stdint.h>
26 #include <string>
27 
28 // Alias
29 using WI = INDI::WeatherInterface;
30 
31 namespace INDI
32 {
33 
34 /**
35  * \class WeatherInterface
36    \brief Provides interface to implement weather reporting functionality.
37 
38    The weather functionality can be an independent device (e.g. weather station), or weather-related reports within another device.
39 
40    When developing a driver for a fully independent weather device, use INDI::Weather directly. To add focus functionality to
41    an existing driver, subclass INDI::WeatherInterface. In your driver, then call the necessary focuser interface functions.
42 
43    <table>
44    <tr><th>Function</th><th>Where to call it from your driver</th></tr>
45    <tr><td>WI::initProperties</td><td>initProperties()</td></tr>
46    <tr><td>WI::updateProperties</td><td>updateProperties()</td></tr>
47    <tr><td>WI::processNumber</td><td>ISNewNumber(...) Check if the property name contains WEATHER_* and then call WI::processNumber(..) for such properties</td></tr>
48    <tr><td>WI::processSwitch</td><td>ISNewSwitch(...)</td></tr>
49    </table>
50 
51    Implement and overwrite the rest of the virtual functions as needed. INDI Pegasus Ultimate Power Box driver is a good example to check for an actual implementation
52    of a weather interface within an auxiliary driver.
53 \author Jasem Mutlaq
54 */
55 class WeatherInterface
56 {
57     public:
58 
59     protected:
60         explicit WeatherInterface(DefaultDevice *defaultDevice);
61         virtual ~WeatherInterface();
62 
63         /**
64          * \brief Initilize focuser properties. It is recommended to call this function within
65          * initProperties() of your primary device
66          * \param statusGroup group for status properties
67          * \param paramsGroup group for parameter properties
68          */
69         void initProperties(const char *statusGroup, const char *paramsGroup);
70 
71         /**
72          * @brief updateProperties Define or Delete Rotator properties based on the connection status of the base device
73          * @return True if successful, false otherwise.
74          */
75         bool updateProperties();
76 
77         /** \brief Process focus number properties */
78         bool processNumber(const char *dev, const char *name, double values[], char *names[], int n);
79 
80         /**
81          * @brief updateWeather Update weather conditions from device or service. The function should
82          * not change the state of any property in the device as this is handled by Weather. It
83          * should only update the raw values.
84          * @return Return overall state. The state should be IPS_OK if data is valid. IPS_BUSY if
85          * weather update is in progress. IPS_ALERT is there is an error. The clients will only accept
86          * values with IPS_OK state.
87          */
88         virtual IPState updateWeather();
89 
90         /**
91          * @brief saveConfigItems Save parameters ranges in the config file.
92          * @param fp pointer to open config file
93          * @return true of success, false otherwise.
94          */
95         virtual bool saveConfigItems(FILE *fp);
96 
97         /**
98          * @brief addParameter Add a physical weather measurable parameter to the weather driver.
99          * The weather value has three zones:
100          * <ol>
101          * <li>OK: Set minimum and maximum values for acceptable values.</li>
102          * <li>Warning: Set minimum and maximum values for values outside of Ok range and in the
103          * dangerous warning zone.</li>
104          * <li>Alert: Any value outsize of Ok and Warning zone is marked as Alert.</li>
105          * </ol>
106          * @param name Name of parameter
107          * @param label Label of paremeter (in GUI)
108          * @param numMinOk minimum Ok range value.
109          * @param numMaxOk maximum Ok range value.
110          * @param percWarning percentage for Warning.
111          */
112         void addParameter(std::string name, std::string label, double numMinOk, double numMaxOk, double percWarning);
113 
114         /**
115          * @brief setCriticalParameter Set parameter that is considered critical to the operation of the
116          * observatory. The parameter state can affect the overall weather driver state which signals
117          * the client to take appropriate action depending on the severity of the state.
118          * @param param Name of critical parameter.
119          * @return True if critical parameter was set, false if parameter is not found.
120          */
121         bool setCriticalParameter(std::string param);
122 
123         /**
124          * @brief setParameterValue Update weather parameter value
125          * @param name name of weather parameter
126          * @param value new value of weather parameter;
127          */
128         void setParameterValue(std::string name, double value);
129 
130         /**
131          * @brief checkParameterState Checks the given parameter against the defined bounds
132          * @param param Name of parameter to check.
133          * @returns IPS_IDLE:  The given parameter name is not valid.
134          * @returns IPS_OK:    The given parameter is within the safe zone.
135          * @returns IPS_BUSY:  The given parameter is in the warning zone.
136          * @returns IPS_ALERT: The given parameter is in the danger zone.
137          */
138         IPState checkParameterState(const std::string &param) const;
139 
140         IPState checkParameterState(const INumber &parameter) const;
141 
142         /**
143          * @brief updateWeatherState Send update weather state to client
144          * @returns true if any parameters changed from last update. False if no states changed.
145          */
146         bool syncCriticalParameters();
147 
148         // Parameters
149         INumber *ParametersN {nullptr};
150         INumberVectorProperty ParametersNP;
151 
152         // Parameter Ranges
153         INumberVectorProperty *ParametersRangeNP {nullptr};
154         uint8_t nRanges {0};
155 
156         // Weather status
157         ILight *critialParametersL {nullptr};
158         ILightVectorProperty critialParametersLP;
159 
160     private:
161         void createParameterRange(std::string name, std::string label);
162         DefaultDevice *m_defaultDevice { nullptr };
163         std::string m_ParametersGroup;
164 };
165 }
166