41static size_t WriteCallback(
void *contents,
size_t size,
size_t nmemb,
void *userp)
43 ((std::string*)userp)->append((
char*)contents, size * nmemb);
61 return (
const char *)
"Hakos Roll Off Roof";
77 RoofDataTP[0].
fill(
"MSG",
"Last Command",
"");
78 RoofDataTP[1].
fill(
"STAT",
"Stat",
"");
79 RoofDataTP[2].
fill(
"STEXT",
"Status",
"");
80 RoofDataTP[3].
fill(
"POS",
"Position",
"");
81 RoofDataTP[4].
fill(
"REL_POSITION",
"Current Position %",
"");
85 DataSourceTP[0].
fill(
"URL",
"URL",
"");
90 RoofTokenTP[0].
fill(
"TOKEN",
"Token",
"");
95 EncoderTicksNP[0].
fill(
"ENCODER_TICKS",
"Encoder Ticks",
"%6.0f", 0, 100000, 1, 0);
97 EncoderTicksNP.
load();
100 SimulationSP[0].
fill(
"SIMULATE",
"Simulate Device",
ISS_OFF);
110 if (DataSourceTP[0].
getText() ==
nullptr || DataSourceTP[0].
getText()[0] ==
'\0')
165 EncoderTicksNP.
update(values, names, n);
167 EncoderTicksNP.
apply();
184 SimulationSP.
update(states, names, n);
187 SimulationSP.
apply();
191 LOG_INFO(
"Simulation mode enabled.");
192 simulatedPosition = 0;
196 LOG_INFO(
"Simulation mode disabled.");
213 DataSourceTP.
update(texts, names, n);
215 DataSourceTP.
apply();
224 RoofTokenTP.
update(texts, names, n);
235 RoofDataTP.
update(texts, names, n);
255 simulateRoofCommand(
"status");
259 sendRoofCommand(
"status");
297 if (strcmp(RoofDataTP[2].
getText() ,
"not parked") == 0 )
314 if (strcmp(RoofDataTP[2].
getText() ,
"open") == 0)
323 if (strcmp(RoofDataTP[2].
getText() ,
"closed") == 0)
332 if (strcmp(RoofDataTP[2].
getText() ,
"opening") == 0)
337 if (strcmp(RoofDataTP[2].
getText() ,
"closing") == 0)
345 if (strcmp(RoofDataTP[2].
getText() ,
"idle") == 0)
347 LOG_INFO(
"Roof motion is stopped.");
370 RoofTokenTP.
save(fp);
371 DataSourceTP.
save(fp);
372 EncoderTicksNP.
save(fp);
386 if (dir ==
DOME_CW && strcmp(RoofDataTP[2].
getText() ,
"open") == 0)
388 LOG_WARN(
"Roof is already fully opened.");
391 else if (dir ==
DOME_CCW && strcmp(RoofDataTP[2].
getText() ,
"closed") == 0)
393 LOG_WARN(
"Roof is already fully closed.");
399 "Cannot close dome when mount is locking. See: Telescope parking policy, in options tab");
415 sendRoofCommand(
"close");
428 sendRoofCommand(
"open");
441 sendRoofCommand(
"stop");
456bool HakosRoof::sendRoofCommand(
const char *action)
461 if (DataSourceTP[0].
getText() ==
nullptr || DataSourceTP[0].
getText()[0] ==
'\0')
463 LOG_WARN(
"Data source URL not configured. Falling back to simulation mode.");
464 return simulateRoofCommand(action);
467 if (RoofTokenTP[0].
getText() ==
nullptr || RoofTokenTP[0].
getText()[0] ==
'\0')
469 LOG_WARN(
"Roof token not configured. Falling back to simulation mode.");
470 return simulateRoofCommand(action);
473 std::string readBuffer =
"";
475 curl_global_init(CURL_GLOBAL_ALL);
476 CURL* easyhandle = curl_easy_init();
477 CURLcode res = CURLE_OK;
479 std::string reqCommand = DataSourceTP[0].
getText();
480 reqCommand +=
"/remobs?key=";
481 reqCommand += RoofTokenTP[0].
getText();
482 reqCommand +=
"&action=";
483 reqCommand += action;
485 curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION, 1);
486 curl_easy_setopt(easyhandle, CURLOPT_VERBOSE, 1);
487 curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, WriteCallback);
488 curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &readBuffer);
489 curl_easy_setopt(easyhandle, CURLOPT_TIMEOUT, 2);
490 curl_easy_setopt(easyhandle, CURLOPT_URL, reqCommand.c_str());
492 res = curl_easy_perform(easyhandle);
493 curl_easy_cleanup(easyhandle);
495 if (res != CURLE_OK) {
496 LOGF_WARN(
"Error %s. Falling back to simulation mode.", curl_easy_strerror(res));
497 return simulateRoofCommand(action);
501 LOGF_INFO(
"json data %s", readBuffer.c_str());
502 if (strcmp(action ,
"status") == 0)
504 json j = json::parse(readBuffer);
506 std::string msg = j[
"msg"];
507 std::string stat= j[
"stat"];
508 std::string stext= j[
"stext"];
510 std::string pos = std::to_string(i);
512 RoofDataTP[0].setText(msg.c_str());
513 RoofDataTP[1].setText(stat.c_str());
514 RoofDataTP[2].setText(stext.c_str());
515 RoofDataTP[3].setText(pos.c_str());
528 std::string statString = RoofDataTP[1].
getText();
529 std::vector<std::string> statVector{};
530 std::stringstream sstream(statString);
531 std::string statElement;
532 while (std::getline(sstream, statElement,
',')){
533 statVector.push_back(statElement);
536 if (strcmp(statVector.at(9).c_str() ,
"0") == 0)
544bool HakosRoof::simulateRoofCommand(
const char *action)
548 const int SIMULATION_TIME_MS = 10000;
550 if (strcmp(action,
"open") == 0)
552 simulationTargetPosition = 100;
553 gettimeofday(&simulationStartTime,
nullptr);
555 LOG_INFO(
"Simulated: Roof opening (10 second transition)...");
557 else if (strcmp(action,
"close") == 0)
559 simulationTargetPosition = 0;
560 gettimeofday(&simulationStartTime,
nullptr);
562 LOG_INFO(
"Simulated: Roof closing (10 second transition)...");
564 else if (strcmp(action,
"stop") == 0)
567 LOG_INFO(
"Simulated: Roof stopped.");
569 else if (strcmp(action,
"status") == 0)
575 gettimeofday(&now,
nullptr);
578 long elapsedMs = (now.tv_sec - simulationStartTime.tv_sec) * 1000 +
579 (now.tv_usec - simulationStartTime.tv_usec) / 1000;
582 float progress = (float)elapsedMs / SIMULATION_TIME_MS;
584 if (progress >= 1.0f)
587 simulatedPosition = simulationTargetPosition;
589 const char *endMsg = (simulationTargetPosition == 100) ?
"Roof fully open" :
"Roof fully closed";
595 int startPos = (simulationTargetPosition == 100) ? 0 : 100;
596 simulatedPosition = startPos + (simulationTargetPosition - startPos) * progress;
601 const char *status_msg = isMoving ?
"Moving..." :
"Idle";
603 const char *stext = (simulatedPosition >= 100) ?
"open" : (simulatedPosition <= 0) ?
"closed" :
"moving";
605 snprintf(pos_str,
sizeof(pos_str),
"%d", simulatedPosition);
607 const char *stat =
"0,0,0,0,0,0,0,0,0,1";
609 RoofDataTP[0].setText(status_msg);
610 RoofDataTP[1].setText(stat);
611 RoofDataTP[2].setText(stext);
612 RoofDataTP[3].setText(pos_str);
613 RoofDataTP[4].setText(pos_str);
619 LOGF_INFO(
"Simulated roof moving: Position=%d%%, Target=%d%%, Status=%s", simulatedPosition, simulationTargetPosition, stext);
623 LOGF_INFO(
"Simulated roof status: Position=%d%%, Status=%s", simulatedPosition, stext);
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 ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual IPState Park() override
Goto Park Position. The park position is an absolute azimuth value.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool Abort() override
Abort all dome motion.
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...
virtual IPState Move(DomeDirection dir, DomeMotionCommand operation) override
Move the Dome in a particular direction.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Dome Presets in the configuration file
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
const char * getDefaultName() override
virtual IPState UnPark() override
UnPark dome. The action of the Unpark command is dome specific, but it may include opening the shutte...
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool getMountSensorSwitch()
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
INDI::PropertyText getText(const char *name) const
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 deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
void SetDomeCapability(uint32_t cap)
SetDomeCapability set the dome capabilities. All capabilities must be initialized.
void setDomeConnection(const uint8_t &value)
setDomeConnection Set Dome connection mode. Child class should call this in the constructor before Do...
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 initProperties() override
Initialize properties initial state and value. The child class must implement this function.
bool isLocked()
isLocked, is the dome currently locked?
INDI::PropertySwitch ParkSP
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
INDI::PropertySwitch DomeMotionSP
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Dome Presets in the configuration file
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
void setDomeState(const DomeState &value)
void SetParkDataType(DomeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
DomeState getDomeState() const
virtual IPState Move(DomeDirection dir, DomeMotionCommand operation)
Move the Dome in a particular direction.
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 ISState states[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, 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)
INDI::PropertyViewText * getText() const
a class to store JSON values
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
std::unique_ptr< HakosRoof > hakosRoof(new HakosRoof())
Implementations for common driver routines.
#define LOGF_INFO(fmt,...)
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
#define LOGF_WARN(fmt,...)