10static std::unique_ptr<PegasusSPB> spb(
new PegasusSPB());
21 lastSensorData.reserve(
PA_N);
22 lastConsumptionData.reserve(
PS_N);
23 lastMetricsData.reserve(
PC_N);
27double PegasusSPB::map(
double value,
double from1,
double to1,
double from2,
double to2)
30 value = std::max(from1, std::min(to1, value));
33 double mappedValue = from2 + (value - from1) * (to2 - from2) / (to1 - from1);
61 PowerDewSwitchASP[1].
fill(
"POWER",
"Power",
ISS_ON);
66 PowerDewSwitchBSP[1].
fill(
"POWER",
"Power",
ISS_ON);
70 DewAggressNP[0].
fill(
"DEW_AGGRESS",
"Agg Level",
"%.2f", 0, 100, 1, 0);
77 std::string name (1,
static_cast<char>(
'A' + i));
115 PowerStatisticsNP[STATS_AVG_AMPS].
fill(
"STATS_AVG_AMPS",
"Average Current (A)",
"%4.2f", 0, 999, 100, 0);
116 PowerStatisticsNP[STATS_AMP_HOURS].
fill(
"STATS_AMP_HOURS",
"Amp hours (Ah)",
"%4.2f", 0, 999, 100, 0);
117 PowerStatisticsNP[STATS_WATT_HOURS].
fill(
"STATS_WATT_HOURS",
"Watt hours (Wh)",
"%4.2f", 0, 999, 100, 0);
118 PowerStatisticsNP[STATS_TOTAL_CURRENT].
fill(
"STATS_TOTAL_CURRENT",
"Total current (A)",
"%4.2f", 0, 999, 100, 0);
122 FirmwareTP[FIRMWARE_VERSION].
fill(
"VERSION",
"Version",
"NA");
123 FirmwareTP[FIRMWARE_UPTIME].
fill(
"UPTIME",
"Uptime (h)",
"NA");
128 addParameter(
"WEATHER_TEMPERATURE",
"Temperature (C)", -15, 35, 15);
129 addParameter(
"WEATHER_HUMIDITY",
"Humidity %", 0, 100, 15);
130 addParameter(
"WEATHER_DEWPOINT",
"Dew Point (C)", 0, 100, 15);
134 HumidityOffsetNP[0].
fill(
"HUM_OFFSET",
"Level",
"%.0f", -50, 50, 1, 0);
137 TemperatureOffsetNP[0].
fill(
"TEMP_OFFSET",
"Level",
"%.0f", -40, 40, 1, 0);
151 int aggressiveness = getDewAggressiveness();
152 DewAggressNP[0].setValue(
static_cast<double>(aggressiveness));
154 DewAggressNP.
apply();
158 int mode = getPowerDewPortMode(portNumber);
159 PowerDewSwitchASP.
reset();
163 PowerDewSwitchASP.
apply();
167 mode = getPowerDewPortMode(portNumber);
168 PowerDewSwitchBSP.
reset();
172 PowerDewSwitchBSP.
apply();
175 int humidityOffset = getHumidityOffset();
176 HumidityOffsetNP[0].setValue(
static_cast<double>(humidityOffset));
178 HumidityOffsetNP.
apply();
181 int temperatureOffset = getTemperatureOffset();
182 TemperatureOffsetNP[0].setValue(
static_cast<double>(temperatureOffset));
184 TemperatureOffsetNP.
apply();
194 setupComplete =
true;
207 setupComplete =
false;
215 return "Pegasus SPB";
219bool PegasusSPB::Handshake()
221 int tty_rc = 0, nbytes_written = 0, nbytes_read = 0;
222 char command[PEGASUS_LEN] = {0}, response[PEGASUS_LEN] = {0};
228 tcflush(PortFD, TCIOFLUSH);
229 strncpy(command,
"P#\n", PEGASUS_LEN);
234 LOGF_ERROR(
"Serial write error: %s", errorMessage);
244 tcflush(PortFD, TCIOFLUSH);
247 tty_rc =
tty_nread_section(PortFD, response, PEGASUS_LEN, stopChar, 1, &nbytes_read);
254 LOGF_ERROR(
"Serial read error: %s", errorMessage);
259 tcflush(PortFD, TCIOFLUSH);
260 response[nbytes_read - 1] =
'\0';
263 setupComplete =
false;
265 return (strstr(response,
"SPB") !=
nullptr);
277 getConsumptionData();
294 PowerDewSwitchASP.
update(states, names, n);
298 PowerDewSwitchASP.
apply();
306 PowerDewSwitchBSP.
update(states, names, n);
310 PowerDewSwitchBSP.
apply();
316 return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
330 DewAggressNP.
update(values, names, n);
334 if(!setDewAggressiveness(
static_cast<uint8_t
>(values[0])))
340 DewAggressNP.
apply();
346 HumidityOffsetNP.
update(values, names, n);
350 if(!setHumdityOffset(
static_cast<int>(values[0])))
356 HumidityOffsetNP.
apply();
362 TemperatureOffsetNP.
update(values, names, n);
366 if(!setTemperatureOffset(
static_cast<int>(values[0])))
371 TemperatureOffsetNP.
setState(result);
372 TemperatureOffsetNP.
apply();
390int PegasusSPB::getDewPortPower(
int portNumber)
392 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
393 snprintf(
cmd, PEGASUS_LEN,
"PA");
395 if(sendCommand(
cmd, res))
397 std::vector<std::string> result = split(res,
":");
400 power = std::stod(result[
PA_DEW_1]);
401 else if(portNumber == 2)
402 power = std::stod(result[
PA_DEW_2]);
406 LOGF_ERROR(
"Error on set power-dew port mode [Port=%d]", portNumber);
408 return power / 255.0 * 100.0;
413bool PegasusSPB::setDewPortPower(
int portNumber,
int power)
415 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
416 snprintf(
cmd, PEGASUS_LEN,
"P%d:%d", portNumber + 2,
static_cast<uint8_t
>(power / 100.0 * 255.0));
417 if(sendCommand(
cmd, res))
419 if(!strstr(
cmd, res))
421 LOGF_ERROR(
"Error on set dew port power [Cmd=%s Res=%s]",
cmd, res);
427 LOGF_ERROR(
"Error on set dew port power [Port=%d Power=%d]", portNumber, power);
433int PegasusSPB::getPowerDewPortMode(
int portNumber)
435 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
436 snprintf(
cmd, PEGASUS_LEN,
"D%d:99", portNumber + 2);
437 if(sendCommand(
cmd, res))
439 std::vector<std::string> result = split(res,
":");
440 return std::stod(result[1]);
444 LOGF_ERROR(
"Error on set power-dew port mode [Port=%d]", portNumber);
449bool PegasusSPB::setPowerDewPortMode(
int portNumber,
int mode)
451 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
452 snprintf(
cmd, PEGASUS_LEN,
"D%d:%d", portNumber + 2, mode);
453 if(sendCommand(
cmd, res))
455 if(!strstr(
cmd, res))
457 LOGF_ERROR(
"Error on set power-dew port mode [Cmd=%s Res=%s]",
cmd, res);
463 LOGF_ERROR(
"Error on set power-dew port mode [Port=%d Mode=%d]", portNumber, mode);
469bool PegasusSPB::setDewAutoState(
bool enabled)
471 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
472 snprintf(
cmd, PEGASUS_LEN,
"PD:%d", enabled ? 1 : 0);
473 if(sendCommand(
cmd, res))
475 if(!strstr(
cmd, res))
477 LOGF_ERROR(
"Error on set dew auto state [Cmd=%s Res=%s]",
cmd, res);
483 LOG_ERROR(
"Error on set set dew auto state");
489bool PegasusSPB::setDewAggressiveness(uint8_t level)
491 int mappedLevel = map(level, 0, 100, 10, 255);
492 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
493 snprintf(
cmd, PEGASUS_LEN,
"PD:%d", mappedLevel);
494 if(sendCommand(
cmd, res))
496 if(!strstr(
cmd, res))
498 LOGF_ERROR(
"Error on set dew aggresiveness [Cmd=%s Res=%s]",
cmd, res);
504 LOG_ERROR(
"Error on set dew aggresiveness");
510int PegasusSPB::getDewAggressiveness()
512 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
513 snprintf(
cmd, PEGASUS_LEN,
"DA");
514 if(sendCommand(
cmd, res))
516 std::vector<std::string> result = split(res,
":");
517 int value = map(std::stoi(result[1]), 10, 255, 0, 100);
522 LOGF_ERROR(
"Error on get dew aggresiveness [Cmd=%s Res=%s]",
cmd, res);
527bool PegasusSPB::setHumdityOffset(
int level)
529 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
530 snprintf(
cmd, PEGASUS_LEN,
"CH:%d", level);
531 if(sendCommand(
cmd, res))
533 if(!strstr(
cmd, res))
535 LOGF_ERROR(
"Error on set humidity offset [Cmd=%s Res=%s]",
cmd, res);
541 LOG_ERROR(
"Error on set humidity offset");
547int PegasusSPB::getHumidityOffset()
549 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
550 snprintf(
cmd, PEGASUS_LEN,
"CR");
551 if(sendCommand(
cmd, res))
553 std::vector<std::string> result = split(res,
":");
554 int value = std::stoi(result[2]);
559 LOGF_ERROR(
"Error on get humidity offset [Cmd=%s Res=%s]",
cmd, res);
564bool PegasusSPB::setTemperatureOffset(
int level)
566 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
567 snprintf(
cmd, PEGASUS_LEN,
"CT:%d", (level * 100));
568 if(sendCommand(
cmd, res))
570 if(!strstr(
cmd, res))
572 LOGF_ERROR(
"Error on set temperature offset [Cmd=%s Res=%s]",
cmd, res);
578 LOG_ERROR(
"Error on set temperature offset");
584int PegasusSPB::getTemperatureOffset()
586 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
587 snprintf(
cmd, PEGASUS_LEN,
"CR");
588 if(sendCommand(
cmd, res))
590 std::vector<std::string> result = split(res,
":");
591 int value = std::stoi(result[1]);
592 return (value / 100);
596 LOGF_ERROR(
"Error on get temperature offset [Cmd=%s Res=%s]",
cmd, res);
601bool PegasusSPB::getFirmware()
603 char res[PEGASUS_LEN] = {0};
604 if (sendCommand(
"PV", res))
606 std::vector<std::string> result = split(res,
":");
607 if (result.size() > 1)
609 LOGF_INFO(
"Detected firmware %s", result[1].c_str());
610 FirmwareTP[FIRMWARE_VERSION].setText(result[1]);
617 LOGF_WARN(
"Unexpected firmware response: %s", res);
623 LOGF_WARN(
"Retreiving firmware failed: %s", res);
631bool PegasusSPB::setFixedPowerPortState(
int portNumber,
bool enabled)
633 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
636 snprintf(
cmd, PEGASUS_LEN,
"P%d:%d", portNumber + 1, enabled ? 1 : 0);
637 if (sendCommand(
cmd, res))
639 return (!strstr(
cmd, res));
644bool PegasusSPB::getSensorData()
646 char res[PEGASUS_LEN] = {0};
647 if (sendCommand(
"PA", res))
649 std::vector<std::string> result = split(res,
":");
650 if (result.size() <
PA_N)
652 LOG_WARN(
"Received wrong number of detailed sensor data. Retrying...");
656 if (result == lastSensorData)
710 bool changed =
false;
716 LOGF_INFO(
"Auto dew on, enabling channel %s", (i == 0 ?
"A" :
"B"));
728 if (lastSensorData.size() <
PA_N ||
739 lastSensorData = result;
746bool PegasusSPB::getConsumptionData()
748 char res[PEGASUS_LEN] = {0};
749 if (sendCommand(
"PS", res))
751 std::vector<std::string> result = split(res,
":");
752 if (result.size() <
PS_N)
754 LOG_WARN(
"Received wrong number of detailed consumption data. Retrying...");
758 if (result == lastConsumptionData)
762 PowerStatisticsNP[STATS_AVG_AMPS].setValue(std::stod(result[
PS_AVG_AMPS]));
763 PowerStatisticsNP[STATS_AMP_HOURS].setValue(std::stod(result[
PS_AMP_HOURS]));
764 PowerStatisticsNP[STATS_WATT_HOURS].setValue(std::stod(result[
PS_WATT_HOURS]));
766 if (lastConsumptionData.size() <
PS_N ||
770 PowerStatisticsNP.
apply();
772 lastConsumptionData = result;
780bool PegasusSPB::getMetricsData()
782 char res[PEGASUS_LEN] = {0};
783 if (sendCommand(
"PC", res))
785 std::vector<std::string> result = split(res,
":");
786 if (result.size() <
PC_N)
788 LOG_WARN(
"Received wrong number of detailed metrics data. Retrying...");
792 if (result == lastMetricsData)
796 PowerStatisticsNP[STATS_TOTAL_CURRENT].setValue(std::stod(result[
PC_TOTAL_CURRENT]));
798 PowerStatisticsNP.
apply();
817 if (lastMetricsData.size() <
PC_N ||
823 std::chrono::milliseconds uptime(std::stol(result[
PC_UPTIME]));
824 using dhours = std::chrono::duration<double, std::ratio<3600 >>;
825 std::stringstream ss;
826 ss << std::fixed << std::setprecision(3) << dhours(uptime).count();
827 FirmwareTP[FIRMWARE_UPTIME].setText(ss.str().c_str());
830 lastMetricsData = result;
839bool PegasusSPB::sendCommand(
const char *
cmd,
char * res)
841 int nbytes_read = 0, nbytes_written = 0, tty_rc = 0;
842 char command[PEGASUS_LEN] = {0};
845 for (
int i = 0; i < 2; i++)
847 tcflush(PortFD, TCIOFLUSH);
848 snprintf(command, PEGASUS_LEN,
"%s\n",
cmd);
854 tcflush(PortFD, TCIOFLUSH);
862 tcflush(PortFD, TCIOFLUSH);
863 res[nbytes_read - 1] =
'\0';
878std::vector<std::string> PegasusSPB::split(
const std::string &input,
const std::string ®ex)
881 std::regex re(regex);
882 std::sregex_token_iterator
883 first{input.begin(), input.end(), re, -1},
885 return {first, last};
894 DewAggressNP.
save(fp);
895 HumidityOffsetNP.
save(fp);
896 TemperatureOffsetNP.
save(fp);
897 PowerDewSwitchASP.
save(fp);
898 PowerDewSwitchBSP.
save(fp);
908 return setFixedPowerPortState(port, enabled);
916 int originalPortNumber = port + 1;
920 return setDewPortPower(originalPortNumber, enabled ? dutyCycle : 0);
929 return setFixedPowerPortState(originalPortNumber + 1, enabled);
953 return setDewAutoState(enabled);
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the initial connection to the devic...
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
const char * getDeviceName() const
INDI::PropertyText getText(const char *name) const
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
void setDriverInterface(uint32_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
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)
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
virtual bool initProperties()
Initialize properties initial state and value. The child class must implement this function.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
INDI::PropertySwitch DewChannelsSP
bool saveConfigItems(FILE *fp)
saveConfigItems Save power properties in config file
INDI::PropertySwitch AutoDewSP
void SetCapability(uint32_t cap)
SetPowerCapability sets the Power capabilities. All capabilities must be initialized.
@ POWER_HAS_VOLTAGE_SENSOR
@ POWER_HAS_OVERALL_CURRENT
@ POWER_HAS_PER_PORT_CURRENT
INDI::PropertyNumber PowerSensorsNP
INDI::PropertyNumber PowerChannelCurrentNP
INDI::PropertyNumber DewChannelCurrentNP
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process Power number properties.
void initProperties(const char *groupName, size_t nPowerPorts=0, size_t nDewPorts=0, size_t nVariablePorts=0, size_t nAutoDewPorts=0, size_t nUSBPorts=0)
Initialize Power properties. It is recommended to call this function within initProperties() of your ...
INDI::PropertyText PowerChannelLabelsTP
bool processText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process Power text properties.
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process Power switch properties.
INDI::PropertySwitch PowerChannelsSP
INDI::PropertyNumber DewChannelDutyCycleNP
bool updateProperties()
updateProperties Define or Delete Power properties based on the connection status of the base device
INDI::PropertyText DewChannelLabelsTP
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.
void setLabel(const char *label)
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)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
Provides interface to implement weather reporting and safety monitoring functionality.
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....
bool syncCriticalParameters()
Synchronize and update the state of all critical parameters.
void setParameterValue(std::string name, double value)
setParameterValue Update weather parameter value
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save parameters ranges in the config file.
INDI::PropertyNumber ParametersNP
void initProperties(const char *statusGroup, const char *paramsGroup)
Initialize focuser properties. It is recommended to call this function within initProperties() of you...
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
INDI::PropertyLight critialParametersLP
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
virtual bool SetAutoDewEnabled(size_t port, bool enabled) override
SetAutoDewEnabled Enable/disable automatic dew control.
virtual bool SetPowerPort(size_t port, bool enabled) override
Power Interface Implementations.
virtual bool SetLEDEnabled(bool enabled) override
SetLEDEnabled Enable/disable power LEDs.
virtual bool SetVariablePort(size_t port, bool enabled, double voltage) override
SetVariablePort Set variable voltage port.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
const char * getDefaultName() override
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool SetDewPort(size_t port, bool enabled, double dutyCycle) override
SetDewPort Set DEW/Dew port duty cycle.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool SetUSBPort(size_t port, bool enabled) override
SetUSBPort Set USB port on/off.
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Implementations for common driver routines.
#define LOGF_INFO(fmt,...)
#define LOGF_WARN(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,...)
Namespace to encapsulate INDI client, drivers, and mediator classes.