27#define MYDEWHEATERPRO_TIMEOUT 3
28#define BOARD_FAN_TAB "Board Fan"
29#define TEMPERATURE_OFFSETS_TAB "Temperature/Tracking Offsets"
30#define LCD_DISPLAY_TAB "LCD Display"
42 DefaultDevice::initProperties();
60 FanSpeedNP[0].
fill(
"Fan Power",
"Fan Speed",
"%4.0f %%", 0., 100., 1., 0.);
63 FanModeSP[BOARD_TEMP].
fill(
"Board Temp",
"Board Temp Sensor",
ISS_OFF);
64 FanModeSP[MANUAL_FAN].
fill(
"Manual",
"Manual",
ISS_ON);
67 EEPROMSP[RESET_EEPROM].
fill(
"Reset EEPROM",
"Reset EEPROM to Defaults",
ISS_OFF);
68 EEPROMSP[SAVE_TO_EEPROM].
fill(
"Save to EEPROM",
"Save to EEPROM",
ISS_OFF);
71 FanTempTriggerNP[FANTEMPOFF].
fill(
"Board_Temp_Off",
"Board Fan Temp Off",
"%4.0f \u2103", 0., 100., 1., 0.);
72 FanTempTriggerNP[FANTEMPON].
fill(
"Board_Temp_On",
"Board Fan Temp On",
"%4.0f \u2103", 0., 100., 1., 0.);
75 LCDPageRefreshNP[0].
fill(
"Page Refresh Rate",
"Page Refresh Rate",
"%4.0f ms", 500., 5000., 500., 0.);
78 LCDDisplayTempUnitsSP[CELCIUS].
fill(
"Celsius",
"Celsius",
ISS_ON);
79 LCDDisplayTempUnitsSP[FAHRENHEIT].
fill(
"Fahrenheit",
"Fahrenheit",
ISS_OFF);
82 EnableLCDDisplaySP[DISABLE_LCD].
fill(
"Disabled",
"Disabled",
ISS_ON);
83 EnableLCDDisplaySP[ENABLE_LCD].
fill(
"Enabled",
"Enabled",
ISS_OFF);
87 CH1CH2BoostSP[CH1_BOOST_100].
fill(
"BOOST_CH1",
"Strap 1 Boost 100%",
ISS_OFF);
88 CH1CH2BoostSP[CH2_BOOST_100].
fill(
"BOOST_CH2",
"Strap 2 Boost 100%",
ISS_OFF);
91 CH3_ModeSP[DISABLED_STRAP].
fill(
"STRAP_DISABLED",
"Strap Disabled",
ISS_ON);
92 CH3_ModeSP[DEWSTRAP_ONE].
fill(
"SHADOW STRAP 1",
"Shadow Strap 1",
ISS_OFF);
93 CH3_ModeSP[DEWSTRAP_TWO].
fill(
"SHADOW STRAP 2",
"Shadow Strap 2",
ISS_OFF);
94 CH3_ModeSP[MANUAL_STRAP].
fill(
"Manual",
"Manual",
ISS_OFF);
95 CH3_ModeSP[TEMP_PROBE_THREE].
fill(
"TEMP_PROBE",
"Temp Probe",
ISS_OFF);
98 CH3_Manual_PowerNP[0].
fill(
"MANUAL_POWER",
"Strap 3 Manual Power",
"%4.0f %%", 0., 100., 1., 0.);
102 TemperaturesNP[PROBE_1].
fill(
"CHANNEL1",
"Strap 1",
"%3.2f \u2103", -50., 70., 0., 0.);
103 TemperaturesNP[PROBE_2].
fill(
"CHANNEL2",
"Strap 2",
"%3.2f \u2103", -50., 70., 0., 0.);
104 TemperaturesNP[PROBE_3].
fill(
"CHANNEL3",
"Strap 3",
"%3.2f \u2103", -50., 70., 0., 0.);
105 TemperaturesNP[BOARD_PROBE].
fill(
"BOARD Temp",
"Board",
"%3.2f \u2103", -50., 100., 0., 0.);
109 TemperatureOffsetsNP[TEMP_PROBE_ONE_OFFSET].
fill(
"CHANNEL1",
"Strap 1",
"%1.0f \u2103", -10., 10., 1., 0.);
110 TemperatureOffsetsNP[TEMP_PROBE_TWO_OFFSET].
fill(
"CHANNEL2",
"Strap 2",
"%1.0f \u2103", -10., 10., 1., 0.);
111 TemperatureOffsetsNP[TEMP_PROBE_THREE_OFFSET].
fill(
"CHANNEL3",
"Strap 3",
"%1.0f \u2103", -10., 10., 1., 0.);
112 TemperatureOffsetsNP[AMBIENT_TEMP_PROBE_OFFSET].
fill(
"AMBIENT",
"Ambient",
"%4.0f \u2103", -4, 3, 1, 0);
116 ZeroTempOffsetsSP[0].
fill(
"Zero_Temp",
"Zero Temperature Offsets",
ISS_OFF);
122 TrackingModeSP[AMBIENT].
fill(
"AMBIENT",
"Ambient",
ISS_OFF);
123 TrackingModeSP[DEWPOINT].
fill(
"DEWPOINT",
"Dew Point",
ISS_ON);
124 TrackingModeSP[MIDPOINT].
fill(
"MIDPOINT",
"Mid Point",
ISS_OFF);
128 TrackingModeOffsetNP[0].
fill(
"Offset",
"Offset",
"%4.0f \u2103", -4, 3, 1, 0);
132 FWVersionNP[0].
fill(
"FIRMWARE",
"Firmware Version",
"%4.0f", 0., 65535., 1., 0.);
160 auto pwmValue =
static_cast<uint8_t
>(dutyCycle / 100.0 * 255.0);
161 return setInt(enabled ? pwmValue : 0,
"S%d#",
"Failed to set Dew Port Power");
167 int mode = enabled ? DEWPOINT : AMBIENT;
171bool myDewControllerPro::cancelOutputBoost()
188 DefaultDevice::updateProperties();
220 if (!readMainValues())
222 LOG_INFO(
"Reading Main Values Error");
224 if (!readLCDDisplayValues())
226 LOG_INFO(
"Reading LCD Display Values Error");
228 if (!readBoardFanValues())
230 LOG_INFO(
"Reading Board Fan Values Error");
232 if (!readOffsetValues())
234 LOG_INFO(
"Reading Offset Values Error");
236 LOG_INFO(
"myDewControllerPro parameters updated, device ready for use.");
272 DefaultDevice::saveConfigItems(fp);
277 CH1CH2BoostSP.
save(fp);
279 CH3_Manual_PowerNP.
save(fp);
280 TemperaturesNP.
save(fp);
285 TemperatureOffsetsNP.
save(fp);
286 ZeroTempOffsetsSP.
save(fp);
287 TrackingModeSP.
save(fp);
288 TrackingModeOffsetNP.
save(fp);
289 FanTempTriggerNP.
save(fp);
290 EnableLCDDisplaySP.
save(fp);
291 LCDDisplayTempUnitsSP.
save(fp);
292 LCDPageRefreshNP.
save(fp);
294 FWVersionNP.
save(fp);
301 return "myDewContollerPro";
304bool myDewControllerPro::sendCommand(
const char *
cmd,
char *resp)
306 int nbytes_written = 0, nbytes_read = 0, rc = -1;
310 tcflush(PortFD, TCIOFLUSH);
323 LOGF_ERROR(
"Error reading response for command %s: %s.",
cmd, errstr);
332bool myDewControllerPro::Handshake()
341 LOG_INFO(
"myDewControllerPro is online. Getting device parameters...");
344 LOG_INFO(
"Error retrieving data from myDewControllerPro, trying resync...");
353bool myDewControllerPro::Ack()
356 tcflush(PortFD, TCIOFLUSH);
363 snprintf(resp, 40,
"Firmware Version: %d", firmware);
368 LOGF_ERROR(
"myDewControllerPro not properly identified! Answer was: %s.", resp);
373 LOG_INFO(
"Please update myDewControllerPro firmware");
374 LOG_INFO(
"https://sourceforge.net/projects/arduinonanodewcontrollerpro/files/myDewControllerPro%20v300%203channel/CODE%20ARDUINO/");
377 int numberProbes = 0;
380 sscanf(resp,
"g%u$", &numberProbes);
381 snprintf(resp, 40,
"The number of Temperature Probes are: %d", numberProbes);
383 if (numberProbes < 1)
385 LOG_INFO(
"Warning no temperature probes detected");
388 FWVersionNP[0].setValue(firmware);
396bool myDewControllerPro::setOutputBoost(
unsigned int channel)
405 else if (channel == 1)
417bool myDewControllerPro::setInt(
int mode,
const char *mask,
const char *errMessage)
422 if (!sendCommand(
cmd,
nullptr))
432bool myDewControllerPro::setChoice(
int testInt,
const char *positiveChoice,
const char *negativeChoice,
433 const char *errMessage)
435 const char* mask = testInt == 1 ? positiveChoice : negativeChoice;
436 if (!sendCommand(mask,
nullptr))
447bool myDewControllerPro::setTempCalibrations(
float ch1,
float ch2,
float ch3,
int ambient)
453 if (!sendCommand(
cmd,
nullptr))
455 LOG_INFO(
"Failed to set CH1 offset");
460 if (!sendCommand(
cmd,
nullptr))
462 LOG_INFO(
"Failed to set CH2 offset");
467 if (!sendCommand(
cmd,
nullptr))
469 LOG_INFO(
"Failed to set CH3 offset");
475 if (!sendCommand(
cmd,
nullptr))
477 LOG_INFO(
"Failed to set CH3 offset");
487bool myDewControllerPro::setFanTempTrigger(
int tempOn,
int tempOff)
493 if (!sendCommand(
cmd,
nullptr))
500 if (!sendCommand(
cmd,
nullptr))
502 LOG_INFO(
"Failed to set CH2 offset");
513bool myDewControllerPro::zeroTempCalibrations()
518 LOG_INFO(
"Failed to zero temp offset");
522 if (!sendCommand(
"e0#",
nullptr))
524 LOG_INFO(
"Failed to zero ambtemp offset");
555 CH1CH2BoostSP.
update( states, names, n);
558 if (CH1CH2BoostSP[CH1_BOOST_100].getState() ==
ISS_ON)
560 setOutputBoost(CH1_BOOST_100);
562 if (CH1CH2BoostSP[CH2_BOOST_100].getState() ==
ISS_ON)
564 setOutputBoost(CH2_BOOST_100);
567 CH1CH2BoostSP.
apply();
575 CH3_ModeSP.
update(states, names, n);
588 ZeroTempOffsetsSP.
update(states, names, n);
590 zeroTempCalibrations();
593 ZeroTempOffsetsSP.
apply();
600 TrackingModeSP.
update(states, names, n);
605 TrackingModeSP.
apply();
612 FanModeSP.
update(states, names, n);
618 readBoardFanValues();
624 EnableLCDDisplaySP.
update(states, names, n);
629 EnableLCDDisplaySP.
apply();
630 readLCDDisplayValues();
637 LCDDisplayTempUnitsSP.
update(states, names, n);
642 LCDDisplayTempUnitsSP.
apply();
643 readLCDDisplayValues();
650 EEPROMSP.
update(states, names, n);
655 const char* message = mode == 1 ?
"Saved to EEPPROM Successfully" :
"Reset EEPROM to Default";
660 readBoardFanValues();
661 readLCDDisplayValues();
687 CH3_Manual_PowerNP.
update(values, names, n);
689 int power = CH3_Manual_PowerNP[0].getValue();
692 CH3_Manual_PowerNP.
apply();
696 LOG_INFO(
"Power can only be manually adjusted in Strap 3 manual mode");
704 TemperatureOffsetsNP.
update(values, names, n);
706 int ch1 = TemperatureOffsetsNP[TEMP_PROBE_ONE_OFFSET].getValue();
707 int ch2 = TemperatureOffsetsNP[TEMP_PROBE_TWO_OFFSET].getValue();
708 int ch3 = TemperatureOffsetsNP[TEMP_PROBE_THREE_OFFSET].getValue();
709 int ambient = TemperatureOffsetsNP[AMBIENT_TEMP_PROBE_OFFSET].getValue();
710 setTempCalibrations(ch1, ch2, ch3, ambient);
712 TemperatureOffsetsNP.
apply();
720 TrackingModeOffsetNP.
update(values, names, n);
722 int offset = TrackingModeOffsetNP[0].getValue();
725 TrackingModeOffsetNP.
apply();
732 FanTempTriggerNP.
update(values, names, n);
734 int tempOn = FanTempTriggerNP[FANTEMPON].getValue();
735 int tempOff = FanTempTriggerNP[FANTEMPOFF].getValue();
736 setFanTempTrigger(tempOn, tempOff);
738 FanTempTriggerNP.
apply();
739 readBoardFanValues();
745 FanSpeedNP.
update(values, names, n);
747 int speed = FanSpeedNP[0].getValue();
751 readBoardFanValues();
758 LCDPageRefreshNP.
update(values, names, n);
760 int time = LCDPageRefreshNP[0].getValue();
763 LCDPageRefreshNP.
apply();
764 readLCDDisplayValues();
772bool myDewControllerPro::readMainValues()
776 float temp1, temp2, temp3, temp_ambient, dewpoint,
humidity;
787 TemperaturesNP[PROBE_1].setValue(temp1);
788 TemperaturesNP[PROBE_2].setValue(temp2);
789 TemperaturesNP[PROBE_3].setValue(temp3);
791 TemperaturesNP.
apply();
802 TemperaturesNP[AMBIENT_PROBE].setValue(temp_ambient);
804 TemperaturesNP.
apply();
815 TemperaturesNP[BOARD_PROBE].setValue(temp_ambient);
817 TemperaturesNP.
apply();
846 DewpointNP[0].setValue(dewpoint);
851 int power1, power2, power3;
861 OutputsNP[DEW_STRAP_ONE_POWER].setValue(power1);
862 OutputsNP[DEW_STRAP_TWO_POWER].setValue(power2);
863 OutputsNP[DEW_STRAP_THREE_POWER].setValue(power3);
866 CH3_Manual_PowerNP[0].setValue(power3);
867 CH3_Manual_PowerNP.
apply();
901 if (sscanf(resp,
"F%d$", &fanSpeed) == 1)
903 FanSpeedNP[0].setValue(fanSpeed);
911bool myDewControllerPro::readOffsetValues()
914 float temp1, temp2, temp3;
925 TemperatureOffsetsNP[TEMP_PROBE_ONE_OFFSET].setValue(temp1);
926 TemperatureOffsetsNP[TEMP_PROBE_TWO_OFFSET].setValue(temp2);
927 TemperatureOffsetsNP[TEMP_PROBE_THREE_OFFSET].setValue(temp3);
929 TemperatureOffsetsNP.
apply();
940 TemperatureOffsetsNP[AMBIENT_TEMP_PROBE_OFFSET].setValue(atBias);
942 TemperatureOffsetsNP.
apply();
953 TrackingModeSP.
reset();
956 TrackingModeSP.
apply();
966 if (sscanf(resp,
"y%d$", &toffset) == 1)
968 TrackingModeOffsetNP[0].setValue(toffset);
970 TrackingModeOffsetNP.
apply();
976bool myDewControllerPro::readBoardFanValues()
987 if (sscanf(resp,
"F%d$", &fanSpeed) == 1)
989 FanSpeedNP[0].setValue(fanSpeed);
1018 FanTempTriggerNP[FANTEMPON].setValue(fanTemp);
1020 FanTempTriggerNP.
apply();
1031 FanTempTriggerNP[FANTEMPOFF].setValue(fanTemp);
1033 FanTempTriggerNP.
apply();
1039bool myDewControllerPro::readLCDDisplayValues()
1051 LCDPageRefreshNP[0].setValue(value);
1053 LCDPageRefreshNP.
apply();
1064 EnableLCDDisplaySP.
reset();
1067 EnableLCDDisplaySP.
apply();
1078 LCDDisplayTempUnitsSP.
reset();
1081 LCDDisplayTempUnitsSP.
apply();
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 ...
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
const char * getDeviceName() const
void addPollPeriodControl()
Add Polling period control to the driver.
void addConfigurationControl()
Add Configuration control to the driver.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
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 loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
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.
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.
void addDebugControl()
Add Debug control to the driver.
bool saveConfigItems(FILE *fp)
saveConfigItems Save power properties in config file
void SetCapability(uint32_t cap)
SetPowerCapability sets the Power capabilities. All capabilities must be initialized.
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 ...
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process Power switch properties.
bool updateProperties()
updateProperties Define or Delete Power properties based on the connection status of the base device
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
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)
int findOnSwitchIndex() const
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, 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 processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process weather switch properties.
bool setCriticalParameter(std::string name)
setCriticalParameter Set parameter that is considered critical to the operation of the observatory....
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process weather number properties.
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save parameters ranges in the config file.
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...
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual const char * getDefaultName() override
virtual bool SetDewPort(size_t port, bool enabled, double dutyCycle) override
SetDewPort Set DEW/Dew port duty cycle.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, 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 void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool SetAutoDewEnabled(size_t port, bool enabled) override
SetAutoDewEnabled Enable/disable automatic dew control.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
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,...
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer 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_DEBUG(fmt,...)
#define LOGF_ERROR(fmt,...)
#define MYDEWHEATERPRO_TIMEOUT
#define TEMPERATURE_OFFSETS_TAB
std::unique_ptr< myDewControllerPro > mydewcontrollerpro(new myDewControllerPro())
#define MDCP_GET_TEMP_DISPLAY_RESPONSE
#define MDCP_GET_PROBE_TEMPS
#define MDCP_GET_AMB_TEMP_OFFSET
#define MDCP_GET_FAN_ON_TEMP_RESPONSE
#define MDCP_SET_TRACKING_MODE
#define MDCP_SET_TRACKING_MODE_OFFSET
#define MDCP_SAVE_TO_EEPROM
#define MDCP_GET_TRACKING_MODE
#define MDCP_GET_CH3_SETTINGS_RESPONSE
#define MDCP_GET_TRACKING_MODE_OFFSET
#define MDCP_GET_BOARD_TEMP_RESPONSE
#define MDCP_GET_CHANNEL_POWER_RESPONSE
#define MDCP_GET_FAN_OFF_TEMP_RESPONSE
#define MDCP_GET_AMB_TEMP
#define MDCP_GET_FAN_OFF_TEMP
#define MDCP_CLEAR_TEMP_OFFSETS
#define MDCP_GET_TEMP_DISPLAY
#define MDCP_GET_REL_HUMIDITY_REPSONSE
#define MDCP_GET_REL_HUMIDITY
#define MDCP_GET_TEMP_OFFSETS
#define MDCP_GET_FAN_MODE_RESPONSE
#define MDCP_CANCEL_BOOST
#define MDCP_GET_NUMBER_OF_PROBES
#define MDCP_LCD_DISPLAY_CELSIUS
#define MDCP_SET_LCD_DISPLAY_TIME
#define MDCP_LCD_DISPLAY_FAHRENHEIT
#define MDCP_SET_CH3_SETTINGS
#define MDCP_GET_LCD_STATE
#define MDCP_SET_CH3_MANUAL_POWER
#define MDCP_GET_FAN_SPEED
#define MDCP_GET_AMB_TEMP_REPSONSE
#define MDCP_GET_DEW_POINT_RESPONSE
#define MDCP_GET_AMB_TEMP_OFFSET_RESPONSE
#define MDCP_SET_TEMP_CH1_OFFSET
#define MDCP_IDENTIFY_RESPONSE
#define MDCP_GET_LCD_DISPLAY_TIME
#define MDCP_SET_FAN_SPEED
#define MDCP_SET_TEMP_CH2_OFFSET
#define MDCP_GET_CHANNEL_POWER
#define MDCP_GET_LCD_STATE_RESPONSE
#define MDCP_GET_FAN_ON_TEMP
#define MDCP_GET_FAN_MODE
#define MDCP_GET_TEMP_RESPONSE
#define MDCP_SET_FAN_MODE
#define MDCP_GET_LCD_DISPLAY_TIME_RESPONSE
#define MDCP_GET_BOARD_TEMP
#define MDCP_GET_TRACKING_MODE_RESPONSE
#define MDCP_SET_FAN_ON_TEMP
#define MDCP_GET_CH3_SETTINGS
#define MDCP_GET_DEW_POINT
#define MDCP_SET_TEMP_CH3_OFFSET
#define MDCP_SET_FAN_OFF_TEMP
#define MDCP_RESET_EEPROM_TO_DEFAULT
#define MDCP_GET_TEMP_OFFSETS_RESPONSE
#define MDCP_SET_AMB_TEMP_OFFSET
Namespace to encapsulate INDI client, drivers, and mediator classes.