34#ifdef _USE_SYSTEM_JSONLIB
35#include <nlohmann/json.hpp>
51 DefaultDevice::initProperties();
58 MinimumOutputNP[0].
fill(
"MINIMUMOUTPUT",
"Power (%)",
"%3.0f", 0, 99, 1, prevMinOutput);
62 MaximumOutputNP[0].
fill(
"MAXIMUMOUTPUT",
"Power (%)",
"%3.0f", 1, 100, 1, prevMaxOutput);
65 XtrnTemperatureNP[WEATHER_QUERY].
fill(
"WEATHERQUERY",
"Weather Source (\u2103)",
"%3.2f", -50., 120., 0., 0.);
66 XtrnTemperatureNP[EXTERNAL_INPUT].
fill(
"EXTERNALINPUT",
"Focuser Device (\u2103)",
"%3.2f", -50., 120., 0., 0.);
69 HumidityNP[0].
fill(
"HUMIDITY",
"Relative (%)",
"%3.0f", 0., 100., 0., 0.);
73 DewpointNP[0].
fill(
"DEWPOINT",
"(\u2103)",
"%3.2f", -50., 120., 0., 0.);
77 SetPointTemperatureNP[0].
fill(
"SETPOINT",
"Set Point (\u2103)",
"%3.2f", -50., 120., 0., 0.);
81 TrackPointOffsetNP[0].
fill(
"TRACKPOINTOFFSET",
"-5.0 to 5.0 (\u2103)",
"%2.1f", -5., 5., 0.5, 0.);
85 TrackingRangeNP[0].
fill(
"TRACKINGRANGE",
"4.0 to 10.0 (\u2103)",
"%2.1f", 4, 10, .5, 5.0);
89 TemperatureModeSP[WEATHER_QUERY].
fill(
"WEATHER_QUERY",
"Weather Source",
ISS_ON);
90 TemperatureModeSP[EXTERNAL_INPUT].
fill(
"EXTERNAL_INPUT",
"Focuser Device",
ISS_OFF);
94 SetPointModeSP[DEWPOINT].
fill(
"DEWPOINT",
"Dew Point",
ISS_ON);
95 SetPointModeSP[TEMPERATURE].
fill(
"TEMPERATURE",
"Temperature",
ISS_OFF);
96 SetPointModeSP[MIDPOINT].
fill(
"MIDPOINT",
"Midpoint",
ISS_OFF);
100 UpdateOutputEveryNP[0].
fill(
"UPDATE_PERIOD",
"Period (min)",
"%2.0f", 1, 20, 1, 1);
104 QueryWeatherEveryNP[0].
fill(
"UPDATE_PERIOD",
"Period (min)",
"%2.0f", 0, 20, 1, 5);
108 FWversionTP[0].
fill(
"FIRMWARE",
"Firmware Version",
nullptr);
112 WeatherSourceSP[OPENMETEO].
fill(
"OPENMETEO",
"Open-Meteo",
ISS_ON);
113 WeatherSourceSP[OPENWEATHER].
fill(
"OPENWEATHER",
"OpenWeather",
ISS_OFF);
114 WeatherSourceSP[EXTERNALSOURCE].
fill(
"EXTERNALSOURCE",
"Weather Device",
ISS_OFF);
115 WeatherSourceSP[INTERNALSOURCE].
fill(
"INTERNALSOURCE",
"CheapoDC Sensor",
ISS_OFF);
119 WeatherQueryAPIKeyTP[0].
fill(
"API_KEY",
"OpenWeather API Key",
nullptr);
123 WeatherUpdatedTP[0].
fill(
"LAST_UPDATED",
"Last Updated",
nullptr);
132 DeviceTimeTP[LOCAL_TIME].
fill(
"CDC_DEVICE_TIME",
"Local Time",
nullptr);
133 DeviceTimeTP[UTC_OFFSET].
fill(
"UTC_OFFSET",
"UTC Offset (hours)",
nullptr);
138 ActiveDeviceTP[ACTIVE_TELESCOPE].
fill(
"ACTIVE_TELESCOPE",
"Telescope", activeTelescopeDevice);
139 ActiveDeviceTP[ACTIVE_FOCUSER].
fill(
"ACTIVE_FOCUSER",
"Focuser", activeFocuserDevice);
140 ActiveDeviceTP[ACTIVE_WEATHER].
fill(
"ACTIVE_WEATHER",
"Weather", activeWeatherDevice);
142 ActiveDeviceTP.
load();
163 {
return Handshake(); });
173 DefaultDevice::updateProperties();
179 indi_strlcpy(activeTelescopeDevice, ActiveDeviceTP[ACTIVE_TELESCOPE].
getText(),
MAXINDINAME);
180 if (strlen(activeTelescopeDevice) > 0)
187 indi_strlcpy(activeFocuserDevice, ActiveDeviceTP[ACTIVE_FOCUSER].
getText(),
MAXINDINAME);
188 if (strlen(activeFocuserDevice) > 0)
193 ActiveDeviceTP[ACTIVE_WEATHER].setText(
"");
195 indi_strlcpy(activeWeatherDevice, ActiveDeviceTP[ACTIVE_WEATHER].
getText(),
MAXINDINAME);
196 if (strlen(activeWeatherDevice) > 0)
234 LOG_WARN(
"Go to https://github.com/hcomet/CheapoDC/releases to download the latest firmware release");
235 LOGF_WARN(
"CheapoDC firmware V%s detected. Please upgrade firmware to latest V2+.", FWversionTP[0].
getText());
277int CheapoDC::msleep(
long duration)
288 ts.tv_sec = duration / 1000;
289 ts.tv_nsec = (duration % 1000) * 1000000;
293 res = nanosleep(&ts, &ts);
294 }
while (res &&
errno == EINTR);
299bool CheapoDC::sendCommand(
const char *
cmd,
char *resp)
301 int nbytes_written = 0, nbytes_read = 0, rc = -1;
305 tcflush(PortFD, TCIOFLUSH);
314 msleep(CDC_SMALL_DELAY);
321 LOGF_ERROR(
"Error reading response for command [%s]: %s.",
cmd, errstr);
327 LOGF_ERROR(
"Invalid response [%s] for command [%s].", resp,
cmd);
335bool CheapoDC::sendGetCommand(
const char *
cmd,
char *resp)
342 if (!this->sendCommand(getCommand, getResponse))
346 std::string getResponseST(getResponse, strlen(getResponse));
349 json jsonResponse = json::parse(getResponseST);
353 std::string jsonValue;
355 strcpy(resp, jsonValue.c_str());
357 catch (
const std::exception &e)
362 jsonResponse[
"RESULT"].
get_to(errorCode);
366 catch(
const std::exception& e)
368 LOGF_ERROR(
"Error parsing GET %s response for value: %s Error: %s",
cmd, getResponse, e.what());
377 LOGF_ERROR(
"Error parsing GET %s response %s Error: %s",
cmd, getResponseST.c_str(), e.
what());
384bool CheapoDC::sendSetCommand(
const char *
cmd,
char *value)
392 if (this->sendCommand(setCommand, setResponse))
394 std::string setResponseST(setResponse, strlen(setResponse));
397 json jsonResponse = json::parse(setResponseST);
401 jsonResponse[
"RESULT"].
get_to(result);
403 catch (
const std::exception &e)
405 LOGF_ERROR(
"Error parsing SET %s response for RESULT: %s Error: %s",
cmd, setResponse, e.what());
412 LOGF_ERROR(
"Error parsing SET %s response %s Error: %s",
cmd, setResponse, e.
what());
416 return (result == 0);
419bool CheapoDC::Handshake()
439 LOG_ERROR(
"Error retrieving data from CheapoDC, retrying...");
440 }
while (--tries > 0);
442 LOG_ERROR(
"Error retrieving data from CheapoDC, please ensure controller "
443 "is powered and the port is correct.");
452 fwVOneDetected =
false;
453 additionalOutputsSupported =
false;
454 internalHumiditySensorSupported =
false;
456 memset(resp,
'\0',
sizeof(resp));
461 FWversionTP[0].setText(resp);
467 if (!sscanf(resp,
"%d.%d.%d", &fwMajorVersion, &fwMinorVersion, &fwPatchVersion))
469 LOGF_ERROR(
"Parsing Firmware Version: Response (%s) for Command (%s) not valid.", resp,
CDC_CMD_FW);
473 if (fwMajorVersion == 1)
475 fwVOneDetected =
true;
480 if ((fwMajorVersion > 2) || (fwMinorVersion >= 2))
482 additionalOutputsSupported =
true;
486 if ((fwMajorVersion > 2) || (fwMinorVersion >= 3))
488 internalHumiditySensorSupported =
false;
491 memset(resp,
'\0',
sizeof(resp));
496 if (sscanf(resp,
"%d", &internalSDAPin) == 1)
498 if (internalSDAPin >= 0)
500 internalHumiditySensorSupported =
true;
507 return checkOutputConfiguration();
511bool CheapoDC::checkOutputConfiguration()
514 int powerOutputs = 0;
517 bool useDewLabels =
false;
518 bool usePowerLabels =
false;
520 if (additionalOutputsSupported)
528 memset(resp,
'\0',
sizeof(resp));
529 memset(command,
'\0',
sizeof(command));
532 if (!this->sendGetCommand(command, resp))
535 if (sscanf(resp,
"%d", &mode)) {
539 case CONTROLLER_PIN_MODE_DISABLED:
542 case CONTROLLER_PIN_MODE_CONTROLLER:
545 case CONTROLLER_PIN_MODE_PWM:
548 case CONTROLLER_PIN_MODE_BOOLEAN:
552 LOGF_ERROR(
"Get Output Mode Pin %d: Response [%s] for Command [%s] not valid.", pin, resp, command);
555 lastControllerPinMode[i] = mode;
559 LOGF_ERROR(
"Get Output Mode Pin %d: Response [%s] for Command [%s] not valid.", pin, resp, command);
569 memset(resp,
'\0',
sizeof(resp));
574 if (!sscanf(resp,
"%d", &prevMinOutput))
577 memset(resp,
'\0',
sizeof(resp));
582 if (!sscanf(resp,
"%d", &prevMaxOutput))
588 MinimumOutputNP[0].setMax(prevMaxOutput - 1);
589 MinimumOutputNP[0].setValue(prevMinOutput);
590 MinimumOutputNP.
apply();
591 MaximumOutputNP[0].setMin(prevMinOutput + 1);
592 MaximumOutputNP[0].setValue(prevMaxOutput);
593 MaximumOutputNP.
apply();
600 LOG_INFO(
"Setting default Dew Channel Labels.");
607 if (powerOutputs > 0)
612 if ((dewOutputs + powerOutputs) > 0)
621 memset(labelC,
'\0',
sizeof(labelC));
622 memset(dewLabel,
'\0',
sizeof(dewLabel));
624 snprintf(labelC,
MAXINDILABEL, channelLabels[lastControllerPinMode[i]], pin);
629 outputToChannel[i] = -1;
631 switch (lastControllerPinMode[i])
633 case CONTROLLER_PIN_MODE_DISABLED:
636 case CONTROLLER_PIN_MODE_CONTROLLER:
637 case CONTROLLER_PIN_MODE_PWM:
647 if (lastControllerPinMode[i] == CONTROLLER_PIN_MODE_CONTROLLER)
649 useDewLabels = (strcmp(lastMode,
"Controller") == 0);
653 useDewLabels = (strcmp(lastMode,
"PWM") == 0);
655 useDewLabels = (lastPin == pin) && useDewLabels;
664 dewChannelToOutput[dewOutputs] = pin;
665 outputToChannel[i] = dewOutputs;
669 case CONTROLLER_PIN_MODE_BOOLEAN:
677 usePowerLabels = (lastPin == pin);
685 powerChannelToOutput[powerOutputs] = pin;
686 outputToChannel[i] = powerOutputs;
698 if (powerOutputs > 0)
705void CheapoDC::getWeatherSource()
708 bool usingOpenWeather =
false;
714 usingOpenWeather = (strcmp(resp,
"OpenWeather") == 0);
715 WeatherSourceSP.
reset();
716 if (usingOpenWeather)
722 WeatherSourceSP.
apply();
726 int newWeatherSource;
729 ok = sscanf(resp,
"%d", &newWeatherSource);
730 usingExternalWeatherSource = (newWeatherSource == EXTERNALSOURCE);
732 if ((ok == 1) && (newWeatherSource <= INTERNALSOURCE))
734 WeatherSourceSP.
reset();
737 WeatherSourceSP.
apply();
746bool CheapoDC::setControllerMode(
int value)
748 if ((value < AUTOMATIC) || (value >
OFF))
760bool CheapoDC::setTemperatureMode(
int value)
762 if ((value < WEATHER_QUERY) || (value > EXTERNAL_INPUT))
764 LOGF_ERROR(
"Invalid Temperature Mode value: %d.", value);
773 if ((value == EXTERNAL_INPUT) && (strlen(ActiveDeviceTP[ACTIVE_FOCUSER].
getText()) == 0))
774 LOG_INFO(
"Temperature Mode set to Focuser Device. Configure Snoop Device for Focuser to send temperatures from the Focuser Device.");
782bool CheapoDC::setSetPointMode(
int value)
784 if ((value < DEWPOINT) || (value > MIDPOINT))
795bool CheapoDC::setWeatherSource(
int value)
797 int maxValue = internalHumiditySensorSupported ? INTERNALSOURCE : EXTERNALSOURCE;
801 LOGF_WARN(
"CheapoDC firmware V%s does not support Set Weather Source. Please upgrade firmware to latest V2+.", FWversionTP[0].
getText());
804 if ((value < OPENMETEO) || (value > maxValue))
806 if (value == INTERNALSOURCE)
808 LOG_WARN(
"Setting Weather Source to CheapoDC Sensor requires firmware v2.3.0+ with a configured sensor.");
812 LOGF_ERROR(
"Invalid Weather Source value: %d.", value);
814 refreshSettings(
true );
821 if (value == EXTERNALSOURCE)
822 LOG_INFO(
"Weather Source set to Weather Device. Configure Snoop Device for Weather to receive weather data.");
831 bool returnValue =
false;
832 int output = powerChannelToOutput[port];
840 returnValue = setAdditionalOutput(output, 100);
844 returnValue = setAdditionalOutput(output, 0);
849 LOGF_ERROR(
"SetPowerPort: Invalid Output %d to port mapping %zu.", output, port);
866 LOGF_WARN(
"SetAutoDewEnabled: Invalid port number %zu.", port);
870 if (setControllerMode(enabled ? AUTOMATIC :
OFF))
882 bool returnValue =
false;
889 LOG_WARN(
"Cannot set duty cycle for Controller while Auto Dew Control is enabled.");
890 refreshSettings(
true );
895 if (previousControllerMode != MANUAL)
898 returnValue = setControllerMode(MANUAL);
900 else if ((dutyCycle < prevMinOutput) || (dutyCycle > prevMaxOutput))
902 LOGF_WARN(
"Controller Duty cycle %.2f is out of range (%.2f - %.2f).",
903 dutyCycle,
static_cast<double>(prevMinOutput),
static_cast<double>(prevMaxOutput));
907 returnValue = setControllerMode(MANUAL) && setOutput(
static_cast<int>(dutyCycle));
912 returnValue = setControllerMode(
OFF);
917 int output = dewChannelToOutput[port];
923 returnValue = setAdditionalOutput(output,
static_cast<int>(dutyCycle));
927 returnValue = setAdditionalOutput(output, 0);
944 refreshSettings(
true );
953 LOG_DEBUG(
"SetVariablePort not supported by CheapoDC.");
960 LOG_DEBUG(
"SetLEDEnabled not supported by CheapoDC.");
966 LOG_DEBUG(
"CyclePower not supported by CheapoDC.");
974 LOG_DEBUG(
"SetUSBPort not supported by CheapoDC.");
989 TemperatureModeSP.
update(states, names, n);
991 TemperatureModeSP.
apply();
993 return result && readSettings();
998 SetPointModeSP.
update(states, names, n);
1000 SetPointModeSP.
apply();
1002 return result && readSettings();
1007 WeatherSourceSP.
update(states, names, n);
1009 WeatherSourceSP.
apply();
1011 return result && readSettings();
1016 char buf[3] = {
"NA"};
1018 RefreshSP.
update(states, names, n);
1022 return result && readSettings();
1028bool CheapoDC::setSetPoint(
float value)
1036bool CheapoDC::setTrackPointOffset(
float value)
1038 if ((value < -5.0) || (value > 5.0))
1049bool CheapoDC::setTrackingRange(
float value)
1051 if ((value < 4.0) || (value > 10.0))
1062bool CheapoDC::setOutput(
int value)
1064 if ((value < MinimumOutputNP[0].getValue()) || (value > MaximumOutputNP[0].getValue()))
1075bool CheapoDC::setAdditionalOutput(
int pin,
int value)
1077 if ((value < 0) || (value > 100))
1086 return sendSetCommand(command, valBuf);
1090bool CheapoDC::setMinimumOutput(
int value)
1092 if (value >= MaximumOutputNP[0].getValue())
1094 LOGF_WARN(
"Minimum Output %d must be less than Maximum Output %d.", value, MaximumOutputNP[0].getValue());
1106bool CheapoDC::setMaximumOutput(
int value)
1108 if (value <= MinimumOutputNP[0].getValue())
1110 LOGF_WARN(
"Maximum Output %d must be greater than Minimum Output %d.", value, MinimumOutputNP[0].getValue());
1122bool CheapoDC::setUpdateOutputEvery(
int value)
1124 if ((value < 0) || (value > 20))
1135bool CheapoDC::setWeatherQueryEvery(
int value)
1137 if ((value < 0) || (value > 20))
1148bool CheapoDC::setWeatherQueryEnabled(
bool enabled)
1150 char disabledBuf[2] =
"0";
1151 char enabledBuf[2] =
"1";
1159bool CheapoDC::setLatitude(
float value)
1161 if ((value < -90.0) || (value > 90.0))
1172bool CheapoDC::setLongitude(
float value)
1175 value = value - 360;
1176 if ((value < -180.0) || (value > 180.0))
1187bool CheapoDC::setUTCOffset(
int offset)
1199bool CheapoDC::setLocation(
float latitude,
float longitude)
1202 char buf[3] = {
"NA"};
1204 if (longitude > 180)
1207 if (!fwVOneDetected)
1208 result = result && setWeatherQueryEnabled(
false);
1210 result = result && setLatitude(latitude);
1211 result = result && setLongitude(longitude);
1213 if (!fwVOneDetected)
1215 result = result && setWeatherQueryEnabled(
true);
1216 result = result && sendSetCommand(
CDC_CMD_QN, buf);
1221bool CheapoDC::setExternalTemperature(
float value)
1229bool CheapoDC::setWeatherTemperature(
float value)
1232 if (usingExternalWeatherSource)
1240bool CheapoDC::setWeatherHumidity(
float value)
1243 if (usingExternalWeatherSource)
1253 bool result =
false;
1263 TrackPointOffsetNP.
update(values, names, n);
1265 TrackPointOffsetNP.
apply();
1266 result = setTrackPointOffset(TrackPointOffsetNP[0].getValue());
1267 return result && readSettings();
1272 TrackingRangeNP.
update(values, names, n);
1274 TrackingRangeNP.
apply();
1275 result = setTrackingRange(TrackingRangeNP[0].getValue());
1276 return result && readSettings();
1281 MinimumOutputNP.
update(values, names, n);
1283 MinimumOutputNP.
apply();
1284 result = setMinimumOutput(MinimumOutputNP[0].getValue());
1285 return result && readSettings();
1290 MaximumOutputNP.
update(values, names, n);
1292 MaximumOutputNP.
apply();
1293 result = setMaximumOutput(MaximumOutputNP[0].getValue());
1294 return result && readSettings();
1299 SetPointTemperatureNP.
update(values, names, n);
1301 SetPointTemperatureNP.
apply();
1302 result = setSetPoint(SetPointTemperatureNP[0].getValue());
1303 return result && readSettings();
1308 UpdateOutputEveryNP.
update(values, names, n);
1310 UpdateOutputEveryNP.
apply();
1311 result = setUpdateOutputEvery(UpdateOutputEveryNP[0].getValue());
1312 return result && readSettings();
1317 QueryWeatherEveryNP.
update(values, names, n);
1319 QueryWeatherEveryNP.
apply();
1320 result = setWeatherQueryEvery(QueryWeatherEveryNP[0].getValue());
1321 return result && readSettings();
1326 LocationNP.
update(values, names, n);
1329 result = setLocation(LocationNP[LOCATION_LATITUDE].getValue(), LocationNP[LOCATION_LONGITUDE].getValue());
1330 return result && readSettings();
1336void CheapoDC::setActiveDevice(
const char *telescopeDevice,
const char *focuserDevice,
const char *weatherDevice)
1338 if (strcmp(telescopeDevice, activeTelescopeDevice) != 0)
1340 indi_strlcpy(activeTelescopeDevice, telescopeDevice,
MAXINDINAME);
1341 LOGF_DEBUG(
"Set snoop for %s device", activeTelescopeDevice);
1342 if (strlen(activeTelescopeDevice) > 0)
1345 if (!fwVOneDetected)
1350 if (strcmp(focuserDevice, activeFocuserDevice) != 0)
1352 indi_strlcpy(activeFocuserDevice, focuserDevice,
MAXINDINAME);
1353 LOGF_DEBUG(
"Set snoop for %s device", activeFocuserDevice);
1354 if (strlen(activeFocuserDevice) > 0)
1358 if (strcmp(weatherDevice, activeWeatherDevice) != 0)
1361 if (fwVOneDetected && (strlen(weatherDevice) > 0))
1363 indi_strlcpy(activeWeatherDevice,
"",
MAXINDINAME);
1364 LOG_WARN(
"Snoop Weather Device not supported by CheapoDC firmware V1. Upgrade to V2+ for support.");
1367 indi_strlcpy(activeWeatherDevice, weatherDevice,
MAXINDINAME);
1368 LOGF_DEBUG(
"Set snoop for %s device", activeWeatherDevice);
1369 if (strlen(activeWeatherDevice) > 0)
1375bool CheapoDC::setWeatherQueryAPIKey(
const char *key)
1386 bool result =
false;
1396 WeatherQueryAPIKeyTP.
update(texts, names, n);
1398 WeatherQueryAPIKeyTP.
apply();
1399 result = setWeatherQueryAPIKey(WeatherQueryAPIKeyTP[0].
getText());
1400 return readSettings() && result;
1405 ActiveDeviceTP.
update(texts, names, n);
1407 ActiveDeviceTP.
apply();
1408 setActiveDevice(ActiveDeviceTP[ACTIVE_TELESCOPE].
getText(),
1409 ActiveDeviceTP[ACTIVE_FOCUSER].
getText(),
1410 ActiveDeviceTP[ACTIVE_WEATHER].
getText());
1411 return readSettings();
1423 bool result =
false;
1425 LOGF_DEBUG(
"ISSNoopDevice %s, %s", deviceName, propName);
1433 (!strcmp(deviceName, activeFocuserDevice)))
1435 bool tempAtributeFound =
false;
1445 if (externalTemp != XtrnTemperatureNP[EXTERNAL_INPUT].getValue())
1446 result = setExternalTemperature(externalTemp) || result;
1447 LOGF_DEBUG(
"External Temp set to: %.2f", externalTemp);
1448 tempAtributeFound =
true;
1452 if (!tempAtributeFound)
1456 if ((!fwVOneDetected) && (!strcmp(propName,
CDC_SNOOP_TIME_PROPERTY)) && (!strcmp(deviceName, activeTelescopeDevice)))
1474 bool latAtributeFound =
false;
1475 bool longAtributeFound =
false;
1477 float latitude = LocationNP[LOCATION_LATITUDE].getValue();
1478 float longitude = LocationNP[LOCATION_LONGITUDE].getValue();
1488 longAtributeFound =
true;
1492 latAtributeFound =
true;
1498 result= setLocation(latitude, longitude) || result;
1500 if (!longAtributeFound)
1502 if (!latAtributeFound)
1507 (!strcmp(deviceName, ActiveDeviceTP[ACTIVE_WEATHER].
getText())))
1509 bool temperatureAttributeFound =
false;
1510 bool humidityAttributeFound =
false;
1520 if (
temperature != XtrnTemperatureNP[WEATHER_QUERY].getValue())
1521 result = setWeatherTemperature(
temperature) || result;
1522 temperatureAttributeFound =
true;
1528 if (
humidity != HumidityNP[0].getValue())
1529 result = setWeatherHumidity(
humidity) || result;
1530 humidityAttributeFound =
true;
1533 if (!temperatureAttributeFound)
1535 if (!humidityAttributeFound)
1540 result = readSettings() || result;
1544bool CheapoDC::readSettings()
1547 char dateBuf[32] = {};
1548 char timeBuf[32] = {};
1551 float temp_ambient, temp_external,
humidity, dewpoint, setPoint, trackingRange;
1552 unsigned int output, minOutput, maxOutput, updatePeriod;
1553 float trackPointOffset, latitude, longitude;
1554 unsigned int controllerMode, temperatureMode, setPointMode, queryPeriod;
1555 bool powerChannelsExist =
false;
1561 ok = sscanf(resp,
"%f", &temp_ambient);
1563 memset(resp,
'\0',
sizeof(resp));
1567 ok = ok * sscanf(resp,
"%f", &temp_external);
1571 XtrnTemperatureNP[0].setValue(temp_ambient);
1572 XtrnTemperatureNP[1].setValue(temp_external);
1574 XtrnTemperatureNP.
apply();
1577 LOG_ERROR(
"GET temperature values failure");
1580 memset(resp,
'\0',
sizeof(resp));
1585 ok = sscanf(resp,
"%f", &
humidity);
1597 memset(resp,
'\0',
sizeof(resp));
1602 ok = sscanf(resp,
"%f", &dewpoint);
1606 DewpointNP[0].setValue(dewpoint);
1613 memset(resp,
'\0',
sizeof(resp));
1618 ok = sscanf(resp,
"%f", &setPoint);
1622 SetPointTemperatureNP[0].setValue(setPoint);
1624 SetPointTemperatureNP.
apply();
1630 memset(resp,
'\0',
sizeof(resp));
1634 ok = sscanf(resp,
"%d", &controllerMode);
1639 previousControllerMode = controllerMode;
1640 if (controllerMode ==
OFF)
1651 memset(resp,
'\0',
sizeof(resp));
1656 if (sscanf(resp,
"%d", &output))
1665 if (additionalOutputsSupported)
1670 if (outputToChannel[p] >= 0)
1675 memset(resp,
'\0',
sizeof(resp));
1678 if (!this->sendGetCommand(command, resp))
1681 if (sscanf(resp,
"%d", &output))
1683 switch (lastControllerPinMode[p])
1685 case CONTROLLER_PIN_MODE_CONTROLLER:
1690 case CONTROLLER_PIN_MODE_PWM:
1697 case CONTROLLER_PIN_MODE_BOOLEAN:
1700 powerChannelsExist =
true;
1716 if (powerChannelsExist)
1723 memset(resp,
'\0',
sizeof(resp));
1728 ok = sscanf(resp,
"%d", &minOutput);
1732 if (minOutput != prevMinOutput)
1734 MinimumOutputNP[0].setValue(minOutput);
1737 MaximumOutputNP[0].setMin(minOutput + 1);
1738 MaximumOutputNP.
apply();
1739 prevMinOutput = minOutput;
1742 MinimumOutputNP.
apply();
1748 memset(resp,
'\0',
sizeof(resp));
1753 ok = sscanf(resp,
"%d", &maxOutput);
1758 if (maxOutput != prevMaxOutput)
1760 MaximumOutputNP[0].setValue(maxOutput);
1763 MinimumOutputNP[0].setMax(maxOutput - 1);
1764 MinimumOutputNP.
apply();
1765 prevMaxOutput = maxOutput;
1768 MaximumOutputNP.
apply();
1774 memset(resp,
'\0',
sizeof(resp));
1779 ok = sscanf(resp,
"%f", &trackPointOffset);
1783 TrackPointOffsetNP[0].setValue(trackPointOffset);
1785 TrackPointOffsetNP.
apply();
1791 memset(resp,
'\0',
sizeof(resp));
1796 ok = sscanf(resp,
"%f", &trackingRange);
1800 TrackingRangeNP[0].setValue(trackingRange);
1802 TrackingRangeNP.
apply();
1808 memset(resp,
'\0',
sizeof(resp));
1813 ok = sscanf(resp,
"%d", &updatePeriod);
1817 UpdateOutputEveryNP[0].setValue(updatePeriod);
1819 UpdateOutputEveryNP.
apply();
1825 memset(resp,
'\0',
sizeof(resp));
1830 ok = sscanf(resp,
"%d", &queryPeriod);
1834 QueryWeatherEveryNP[0].setValue(queryPeriod);
1836 QueryWeatherEveryNP.
apply();
1842 if (!fwVOneDetected)
1844 memset(resp,
'\0',
sizeof(resp));
1849 DeviceTimeTP[LOCAL_TIME].setText(resp);
1851 memset(resp,
'\0',
sizeof(resp));
1856 ok = sscanf(resp,
"%d", &tmzOffset);
1860 memset(resp,
'\0',
sizeof(resp));
1862 DeviceTimeTP[UTC_OFFSET].setText(resp);
1864 DeviceTimeTP.
apply();
1874 memset(resp,
'\0',
sizeof(resp));
1879 ok = sscanf(resp,
"%f", &latitude);
1881 if ((ok == 1) && (latitude >= -90.0) && (latitude <= 90.0))
1883 LocationNP[LOCATION_LATITUDE].setValue(latitude);
1891 memset(resp,
'\0',
sizeof(resp));
1896 ok = sscanf(resp,
"%f", &longitude);
1898 if ((ok == 1) && (longitude >= -180.0) && (longitude <= 180.0))
1901 longitude = longitude + 360;
1902 LocationNP[LOCATION_LONGITUDE].setValue(longitude);
1910 memset(resp,
'\0',
sizeof(resp));
1915 ok = sscanf(resp,
"%d", &setPointMode);
1917 if ((ok == 1) && (setPointMode <= MIDPOINT))
1919 SetPointModeSP.
reset();
1922 SetPointModeSP.
apply();
1931 memset(resp,
'\0',
sizeof(resp));
1936 WeatherQueryAPIKeyTP[0].setText(resp);
1938 WeatherQueryAPIKeyTP.
apply();
1941 memset(resp,
'\0',
sizeof(resp));
1949 sprintf(resp,
"%s %s", dateBuf, timeBuf);
1951 WeatherUpdatedTP[0].setText(resp);
1953 WeatherUpdatedTP.
apply();
1956 ActiveDeviceTP[ACTIVE_TELESCOPE].setText(activeTelescopeDevice);
1957 ActiveDeviceTP[ACTIVE_FOCUSER].setText(activeFocuserDevice);
1958 ActiveDeviceTP[ACTIVE_WEATHER].setText(activeWeatherDevice);
1960 ActiveDeviceTP.
apply();
1963 memset(resp,
'\0',
sizeof(resp));
1968 ok = sscanf(resp,
"%d", &temperatureMode);
1970 if ((ok == 1) && (temperatureMode <= TEMPERATURE))
1972 TemperatureModeSP.
reset();
1975 TemperatureModeSP.
apply();
1988 if ((previousTemperatureMode != temperatureMode) &&
1989 (temperatureMode == EXTERNAL_INPUT) &&
1990 (strlen(ActiveDeviceTP[ACTIVE_FOCUSER].
getText()) == 0))
1992 LOG_INFO(
"Temperature Mode set to External Input. Set Snoop Device for Focuser to send temperature from the Focuser Device.");
1994 previousTemperatureMode = temperatureMode;
1997 if (!fwVOneDetected)
1999 if ((usingExternalWeatherSource) &&
2000 (!previuoslyUsingExternalWeatherSource) &&
2001 (strlen(ActiveDeviceTP[ACTIVE_WEATHER].
getText()) == 0))
2003 LOG_INFO(
"Weather Source set to Weather Device. Configure Snoop Device for Weather to send temperature/humidity from the Weather Device.");
2005 previuoslyUsingExternalWeatherSource = usingExternalWeatherSource;
2016 ActiveDeviceTP.
save(fp);
2032void CheapoDC::refreshSettings(
bool delayRefresh )
2035 if (timerIndex != -1)
int updateLocation(double lng, double lat)
std::unique_ptr< CheapoDC > cheapodc(new CheapoDC())
#define CDC_COMMAND_LENGTH
#define CDC_SNOOP_WEATHER_HUMIDITY
#define CDC_SNOOP_FOCUSER_PROPERTY
#define CDC_SNOOP_WEATHER_TEMPERATURE
#define CDC_SNOOP_WEATHER_PROPERTY
#define CHEAPODC_VERSION_MAJOR
#define CDC_SET_VALUE_LENGTH
#define CDC_MIN_ADDITIONAL_OUTPUT
#define CHEAPODC_VERSION_MINOR
#define CDC_DEFAULT_POLLING_PERIOD
#define CDC_SNOOP_TIME_PROPERTY
#define CDC_SNOOP_LOCATION_LATITUDE
#define CDC_RESPONSE_LENGTH
#define CDC_SNOOP_LOCATION_PROPERTY
#define CDC_SNOOP_LOCATION_LONGITUDE
#define CDC_SNOOP_FOCUSER_TEMPERATURE
#define CDC_SNOOP_TIME_OFFSET
#define CDC_TOTAL_ADDITIONAL_OUTPUTS
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool SetPowerPort(size_t port, bool enabled) override
SetPowerPort Set power port on/off.
virtual bool SetDewPort(size_t port, bool enabled, double dutyCycle) override
SetDewPort Set DEW/Dew port duty cycle.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool CyclePower() override
CyclePower Cycle power to all ports.
virtual bool SetAutoDewEnabled(size_t port, bool enabled) override
SetAutoDewEnabled Enable/disable automatic dew control.
virtual const char * getDefaultName() override
virtual bool SetUSBPort(size_t port, bool enabled) override
SetUSBPort Set USB port on/off.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool SetLEDEnabled(bool enabled) override
SetLEDEnabled Enable/disable power LEDs.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
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.
virtual bool ISSnoopDevice(XMLEle *root) override
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the initial connection to the devic...
The TCP class manages connection with devices over the network via TCP/IP. Upon successful connection...
void setDefaultHost(const char *addressHost)
void setDefaultPort(uint32_t addressPort)
const char * getDeviceName() const
INDI::PropertyText getText(const char *name) 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 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 ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
void RemoveTimer(int id)
Remove timer added with SetTimer.
Connection::Interface * getActiveConnection()
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
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.
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
void setPermission(IPerm permission)
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)
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)
a class to store JSON values
ValueType & get_to(ValueType &v) const noexcept(noexcept(JSONSerializer< ValueType >::from_json(std::declval< const basic_json_t & >(), v)))
get a value (explicit)
general exception of the basic_json class
const char * what() const noexcept override
returns the explanatory string
const char * CONNECTION_TAB
CONNECTION_TAB Where all device connection settings (serial, usb, ethernet) are defined and controlle...
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.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
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.
void IDSnoopDevice(const char *snooped_device, const char *snooped_property)
Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevi...
#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,...)
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
int setUTCOffset(int fd, double hours)
Namespace to encapsulate INDI client, drivers, and mediator classes.
basic_json<> json
default specialization