43 return "Weather Safety Alpaca";
51 ServerAddressTP[0].
fill(
"HOST",
"Host",
"");
52 ServerAddressTP[1].
fill(
"PORT",
"Port",
"");
56 DeviceNumberNP[0].
fill(
"DEVICE_NUMBER",
"Device Number",
"%.0f", 0, 10, 1, 0);
60 ConnectionSettingsNP[0].
fill(
"TIMEOUT",
"Timeout (sec)",
"%.0f", 1, 30, 1, 5);
61 ConnectionSettingsNP[1].
fill(
"RETRIES",
"Max Retries",
"%.0f", 1, 10, 1, 3);
62 ConnectionSettingsNP[2].
fill(
"RETRY_DELAY",
"Retry Delay (ms)",
"%.0f", 100, 5000, 100, 1000);
65 addParameter(
"WEATHER_SAFETY",
"Weather Safety", 0, 1, 0);
88 if (ServerAddressTP[0].
getText() ==
nullptr || ServerAddressTP[1].
getText() ==
nullptr)
90 LOG_ERROR(
"Server address or port is not set.");
96 bool success = retryRequest([
this, &response]() {
97 std::string path =
"/api/v1/safetymonitor/" + std::to_string(
static_cast<int>(DeviceNumberNP[0].getValue())) +
"/issafe";
98 return makeAlpacaRequest(path, response);
103 LOG_ERROR(
"Failed to connect to Alpaca safety monitor. Please check server address and port.");
107 LOG_INFO(
"Successfully connected to Alpaca safety monitor.");
114 LOG_INFO(
"Disconnected from Alpaca safety monitor.");
127 LOGF_DEBUG(
"Updating weather status for device %d",
128 static_cast<int>(DeviceNumberNP[0].getValue()));
131 bool success = retryRequest([
this, &response]() {
132 std::string path =
"/api/v1/safetymonitor/" + std::to_string(
static_cast<int>(DeviceNumberNP[0].getValue())) +
"/issafe";
133 LOGF_DEBUG(
"Requesting safety status with path: %s", path.c_str());
134 return makeAlpacaRequest(path, response);
139 LOG_DEBUG(
"Safety status request failed");
140 LastParseSuccess =
false;
148 bool isSafe = response[
"Value"].
get<
bool>();
149 LOGF_DEBUG(
"Parsed safety status: %s", isSafe ?
"SAFE" :
"UNSAFE");
153 LastParseSuccess =
true;
159 LastParseSuccess =
false;
164bool WeatherSafetyAlpaca::makeAlpacaRequest(
const std::string& path,
nlohmann::json& response,
bool isPut)
166 if (ServerAddressTP[0].
getText() ==
nullptr || ServerAddressTP[1].
getText() ==
nullptr)
168 LOG_ERROR(
"Server address or port is not set.");
175 LOGF_DEBUG(
"Creating HTTP client for host: %s, port: %s",
182 LOGF_DEBUG(
"Setting timeouts - Connection: %d sec, Read: %d sec",
183 static_cast<int>(ConnectionSettingsNP[0].getValue()),
184 static_cast<int>(ConnectionSettingsNP[0].getValue()));
186 cli.set_connection_timeout(
static_cast<int>(ConnectionSettingsNP[0].getValue()));
187 cli.set_read_timeout(
static_cast<int>(ConnectionSettingsNP[0].getValue()));
191 isPut ?
"PUT" :
"GET",
194 auto result = isPut ? cli.Put(path.c_str()) : cli.Get(path.c_str());
204 LOGF_DEBUG(
"HTTP Status: %d", result->status);
205 for (
const auto& header : result->headers)
208 header.first.c_str(),
209 header.second.c_str());
213 LOGF_DEBUG(
"Response Body: %s", result->body.c_str());
215 if (result->status != 200)
221 response = nlohmann::json::parse(result->body);
226 if (response[
"ErrorNumber"].get<int>() != 0)
228 LOGF_ERROR(
"Alpaca error: %s (ErrorNumber: %d)",
229 response[
"ErrorMessage"].get<std::string>().c_str(),
230 response[
"ErrorNumber"].get<int>());
236 catch(
const std::exception &e)
243bool WeatherSafetyAlpaca::retryRequest(
const std::function<
bool()>& request)
245 int maxRetries =
static_cast<int>(ConnectionSettingsNP[1].getValue());
246 int retryDelay =
static_cast<int>(ConnectionSettingsNP[2].getValue());
248 for (
int attempt = 1; attempt <= maxRetries; attempt++)
255 catch(
const std::exception &e)
257 LOGF_ERROR(
"Request attempt %d failed: %s", attempt, e.what());
260 if (attempt < maxRetries)
262 LOGF_INFO(
"Retrying request in %d ms (attempt %d/%d)",
263 retryDelay, attempt, maxRetries);
264 std::this_thread::sleep_for(std::chrono::milliseconds(retryDelay));
274 ServerAddressTP.
update(texts, names, n);
276 ServerAddressTP.
apply();
290 ConnectionSettingsNP.
update(values, names, n);
292 ConnectionSettingsNP.
apply();
300 LOG_WARN(
"Cannot change device number while connected.");
304 DeviceNumberNP.
update(values, names, n);
306 DeviceNumberNP.
apply();
319 ServerAddressTP.
save(fp);
320 DeviceNumberNP.
save(fp);
321 ConnectionSettingsNP.
save(fp);
330 if (property ==
nullptr)
332 result &= ServerAddressTP.
load();
333 result &= DeviceNumberNP.
load();
334 result &= ConnectionSettingsNP.
load();
INDI::PropertyText getText(const char *name) const
bool isDeviceNameMatch(const char *otherName) const
Check that the device name matches the argument.
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool load()
load Attempt to load property values from configuration file.
void save(FILE *f) const
save Save property to configuration file.
bool isNameMatch(const char *otherName) const
bool update(const double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
bool update(const char *const texts[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
void addParameter(std::string name, std::string label, double numMinOk, double numMaxOk, double percWarning, bool flipWarning=false)
Add a physical weather measurable parameter to the weather driver.
bool setCriticalParameter(std::string name)
setCriticalParameter Set parameter that is considered critical to the operation of the observatory....
void setParameterValue(std::string name, double value)
setParameterValue Update weather parameter value
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
void setWeatherConnection(const uint8_t &value)
setWeatherConnection Set Weather connection mode. Child class should call this in the constructor bef...
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
bool Disconnect() override
Disconnect from device.
virtual IPState updateWeather() override
updateWeather Update weather conditions from device or service. The function should not change the st...
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
const char * getDefaultName() override
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool loadConfig(bool silent=false, const char *property=nullptr) override
Load the last saved configuration file.
a class to store JSON values
string_t dump(const int indent=-1, const char indent_char=' ', const bool ensure_ascii=false, const error_handler_t error_handler=error_handler_t::strict) const
serialization
auto get() const noexcept(noexcept(std::declval< const basic_json_t & >().template get_impl< ValueType >(detail::priority_tag< 4 > {}))) -> decltype(std::declval< const basic_json_t & >().template get_impl< ValueType >(detail::priority_tag< 4 > {}))
get a (pointer) value (explicit)
general exception of the basic_json class
const int id
the id of the exception
const char * what() const noexcept override
returns the explanatory string
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * SITE_TAB
SITE_TAB Where all site information setting are located.
#define LOGF_INFO(fmt,...)
#define LOGF_DEBUG(fmt,...)
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
#define LOGF_ERROR(fmt,...)
std::string to_string(Error error)
std::unique_ptr< WeatherSafetyAlpaca > weather_safety_alpaca(new WeatherSafetyAlpaca())