Skip to content

Commit

Permalink
add climate control, fanpower, aux1, aux2; report focuser temperature
Browse files Browse the repository at this point in the history
  • Loading branch information
peter-englmaier committed Feb 2, 2024
1 parent 55297df commit 845c555
Show file tree
Hide file tree
Showing 2 changed files with 251 additions and 20 deletions.
242 changes: 224 additions & 18 deletions drivers/focuser/alluna_tcs2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
*/

/* TODO:
* - add inherience from dustcover class: maybe not a good idea, dust cap not useful for taking darks
* - add climate control, fanpower, aux1, aux2
* - update temp only if value is 30 seconds old
* - add handybox add/remove
* - create a python client looking like tcs2control
* - make serial port selection easier
* - add fanpower
* - add focuser optipos and jogg/skip forward/backward
* - add handybox add/remove and screensaver config
* - set default serial port default to 19200 @ 8-N-1
* - add rotator
* - make optional components optional (hide in gui)
* - add arbitrary command for special commands
* - cleanup for PR
*
* KNOWN PROBLEMS:
* https://indilib.org/forum/focusers-filter-wheels/14173-new-zwo-eaf-first-use-experience-and-questions.html#98014
Expand Down Expand Up @@ -70,17 +72,33 @@ bool AllunaTCS2::initProperties()
INDI::Focuser::initProperties();
//INDI::DustCapInterface::initDustCapProperties(getDeviceName(), "groupname");

// Focuser temperature / ambient temperature
IUFillNumber(&TemperatureN[0], "FOCUS_TEMPERATURE", "Focuser Temp [C]", "%6.2f", -100, 100, 0, 0);
// Focuser temperature / ambient temperature, ekos uses first number of "FOCUS_TEMPERATURE" property
IUFillNumber(&TemperatureN[0], "TEMPERATURE_AMBIENT", "Focuser Temp [C]", "%6.2f", -100, 100, 0, 0);
// Primary mirror temperature
IUFillNumber(&TemperatureN[1], "TEMPERATURE_PRIMARY", "Primary Temp [C]", "%6.2f", -100, 100, 0, 0);
// Secondary mirror temperature
IUFillNumber(&TemperatureN[2], "TEMPERATURE_SECONDARY", "Secondary Temp [C]", "%6.2f", -100, 100, 0, 0);
// Ambient humidity
IUFillNumber(&TemperatureN[3], "HUMIDITY", "Humidity [%]", "%6.2f", 0, 100, 0, 0);

IUFillNumberVector(&TemperatureNP, TemperatureN, 4, getDeviceName(), "CLIMATE", "Climate",
MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE);
IUFillNumberVector(&TemperatureNP, TemperatureN, 4, getDeviceName(), "FOCUS_TEMPERATURE", "Climate",
CLIMATE_TAB, IP_RO, 0, IPS_IDLE);

// Climate control
IUFillSwitch(&ClimateControlS[CLIMATECONTROL_AUTO], "CLIMATE_AUTO", "On", ISS_OFF);
IUFillSwitch(&ClimateControlS[CLIMATECONTROL_MANUAL], "CLIMATE_MANUAL", "Off", ISS_ON);
IUFillSwitchVector(&ClimateControlSP, ClimateControlS, 2, getDeviceName(), "CLIMATE_CONTROL", "Climate Control", CLIMATE_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);

IUFillSwitch(&PrimaryDewHeaterS[DEWHEATER_ON], "PRIMARY_HEATER_ON", "On", ISS_OFF);
IUFillSwitch(&PrimaryDewHeaterS[DEWHEATER_OFF], "PRIMARY_HEATER_OFF", "Off", ISS_ON);
IUFillSwitchVector(&PrimaryDewHeaterSP, PrimaryDewHeaterS, 2, getDeviceName(), "PRIMARY_HEATER", "Heat primary", CLIMATE_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
IUFillSwitch(&SecondaryDewHeaterS[DEWHEATER_ON], "SECONDARY_HEATER_ON", "On", ISS_OFF);
IUFillSwitch(&SecondaryDewHeaterS[DEWHEATER_OFF], "SECONDARY_HEATER_OFF", "Off", ISS_ON);
IUFillSwitchVector(&SecondaryDewHeaterSP, SecondaryDewHeaterS, 2, getDeviceName(), "SECONDARY_HEATER", "Heat secondary", CLIMATE_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);

IUFillNumber(&FanPowerN[0], "FANPOWER", "Fan power [0..255]", "%3.0f", 0, 100, 1, 100);
IUFillNumberVector(&FanPowerNP, FanPowerN, 1, getDeviceName(), "FANPOWER", "Fan Power",
CLIMATE_TAB, IP_RW, 60, IPS_IDLE);

// Stepping Modes "SpeedStep" and "MicroStep"
IUFillSwitch(&SteppingModeS[STEPPING_SPEED], "STEPPING_SPEED", "SpeedStep", ISS_ON);
Expand All @@ -102,10 +120,10 @@ bool AllunaTCS2::initProperties()
FocusMaxPosN[0].value = FocusAbsPosN[0].max;
FocusMaxPosNP.p = IP_RO;

// Dust Cover, by default closed
// Dust Cover
IUFillSwitch(&CoverS[COVER_OPEN], "COVER_OPEN", "Open", ISS_OFF);
IUFillSwitch(&CoverS[COVER_CLOSED], "COVER_CLOSED", "Closed", ISS_ON);
IUFillSwitchVector(&CoverSP, CoverS, 2, getDeviceName(), "COVER_CONTROL", "Cover Control", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
IUFillSwitch(&CoverS[COVER_CLOSED], "COVER_CLOSE", "Close", ISS_ON);
IUFillSwitchVector(&CoverSP, CoverS, 2, getDeviceName(), "COVER_CONTROL", "Cover Control", DUSTCOVER_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);

setDriverInterface(FOCUSER_INTERFACE); //| DUSTCAP_INTERFACE);

Expand Down Expand Up @@ -146,14 +164,20 @@ bool AllunaTCS2::updateProperties()
}
readDustCover();
readTemperature();
readClimateControl();

defineProperty(&TemperatureNP);

// Settings
// Focuser
defineProperty(&SteppingModeSP);
defineProperty(&FocusMaxPosNP);
defineProperty(&FocusAbsPosNP);

// Climate
defineProperty(&TemperatureNP);
defineProperty(&ClimateControlSP);
defineProperty(&PrimaryDewHeaterSP);
defineProperty(&SecondaryDewHeaterSP);
defineProperty(&FanPowerNP);

// Cover
defineProperty(&CoverSP);

Expand Down Expand Up @@ -417,7 +441,7 @@ bool AllunaTCS2::ISNewSwitch(const char * dev, const char * name, ISState * stat
IDSetSwitch(&CoverSP, NULL);
return true;
}

// Otherwise, let us update the switch state
IUUpdateSwitch(&CoverSP, states, names, n);
currentCoverIndex = IUFindOnSwitchIndex(&CoverSP);
Expand All @@ -434,7 +458,99 @@ bool AllunaTCS2::ISNewSwitch(const char * dev, const char * name, ISState * stat
}
}

DEBUGF(INDI::Logger::DBG_SESSION, "Unknown switch pressed: %s", name);
// Climate Control Switch?
if (!strcmp(name, ClimateControlSP.name))
{
// Find out which state is requested by the client
const char *actionName = IUFindOnSwitchName(states, names, n);
// Do nothing, if state is already what it should be
int currentClimateControlIndex = IUFindOnSwitchIndex(&ClimateControlSP);
if (!strcmp(actionName, ClimateControlS[currentClimateControlIndex].name))
{
DEBUGF(INDI::Logger::DBG_SESSION, "Climate Control is already %s", ClimateControlS[currentClimateControlIndex].label);
ClimateControlSP.s = IPS_IDLE;
IDSetSwitch(&ClimateControlSP, NULL);
return true;
}

// Otherwise, let us update the switch state
IUUpdateSwitch(&ClimateControlSP, states, names, n);
currentClimateControlIndex = IUFindOnSwitchIndex(&ClimateControlSP);
if ( setClimateControl((currentClimateControlIndex==CLIMATECONTROL_AUTO) ? CLIMATECONTROL_MANUAL: CLIMATECONTROL_AUTO) ) {
DEBUGF(INDI::Logger::DBG_SESSION, "ClimateControl is now %s", CoverS[currentClimateControlIndex].label);
ClimateControlSP.s = IPS_OK;
IDSetSwitch(&ClimateControlSP, NULL);
return true;
} else {
DEBUG(INDI::Logger::DBG_SESSION, "Cannot get lock, try again");
ClimateControlSP.s = IPS_ALERT;
IDSetSwitch(&ClimateControlSP, NULL);
}
}

// PrimaryDewHeater Switch?
if (!strcmp(name, PrimaryDewHeaterSP.name))
{
// Find out which state is requested by the client
const char *actionName = IUFindOnSwitchName(states, names, n);
// Do nothing, if state is already what it should be
int currentPrimaryDewHeaterIndex = IUFindOnSwitchIndex(&PrimaryDewHeaterSP);
if (!strcmp(actionName, PrimaryDewHeaterS[currentPrimaryDewHeaterIndex].name))
{
DEBUGF(INDI::Logger::DBG_SESSION, "PrimaryDewHeater is already %s", PrimaryDewHeaterS[currentPrimaryDewHeaterIndex].label);
PrimaryDewHeaterSP.s = IPS_IDLE;
IDSetSwitch(&PrimaryDewHeaterSP, NULL);
return true;
}

// Otherwise, let us update the switch state
IUUpdateSwitch(&PrimaryDewHeaterSP, states, names, n);
currentPrimaryDewHeaterIndex = IUFindOnSwitchIndex(&PrimaryDewHeaterSP);
if ( setPrimaryDewHeater((currentPrimaryDewHeaterIndex==DEWHEATER_OFF) ? DEWHEATER_ON: DEWHEATER_OFF) ) {
DEBUGF(INDI::Logger::DBG_SESSION, "PrimaryDewHeater is now %s", CoverS[currentPrimaryDewHeaterIndex].label);
PrimaryDewHeaterSP.s = IPS_OK;
IDSetSwitch(&PrimaryDewHeaterSP, NULL);
return true;
} else {
DEBUG(INDI::Logger::DBG_SESSION, "Cannot get lock, try again");
PrimaryDewHeaterSP.s = IPS_ALERT;
IDSetSwitch(&PrimaryDewHeaterSP, NULL);
}
}

// SecondaryDewHeater Switch?
if (!strcmp(name, SecondaryDewHeaterSP.name))
{
// Find out which state is requested by the client
const char *actionName = IUFindOnSwitchName(states, names, n);
// Do nothing, if state is already what it should be
int currentSecondaryDewHeaterIndex = IUFindOnSwitchIndex(&SecondaryDewHeaterSP);
if (!strcmp(actionName, SecondaryDewHeaterS[currentSecondaryDewHeaterIndex].name))
{
DEBUGF(INDI::Logger::DBG_SESSION, "SecondaryDewHeater is already %s", ClimateControlS[currentSecondaryDewHeaterIndex].label);
SecondaryDewHeaterSP.s = IPS_IDLE;
IDSetSwitch(&SecondaryDewHeaterSP, NULL);
return true;
}

// Otherwise, let us update the switch state
IUUpdateSwitch(&SecondaryDewHeaterSP, states, names, n);
currentSecondaryDewHeaterIndex = IUFindOnSwitchIndex(&SecondaryDewHeaterSP);
if ( setSecondaryDewHeater((currentSecondaryDewHeaterIndex==DEWHEATER_OFF) ? DEWHEATER_ON: DEWHEATER_OFF) ) {
DEBUGF(INDI::Logger::DBG_SESSION, "SecondaryDewHeater is now %s", CoverS[currentSecondaryDewHeaterIndex].label);
SecondaryDewHeaterSP.s = IPS_OK;
IDSetSwitch(&SecondaryDewHeaterSP, NULL);
return true;
} else {
DEBUG(INDI::Logger::DBG_SESSION, "Cannot get lock, try again");
SecondaryDewHeaterSP.s = IPS_ALERT;
IDSetSwitch(&SecondaryDewHeaterSP, NULL);
}
}

// FanPower Number?


}
return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
}
Expand Down Expand Up @@ -768,6 +884,96 @@ bool AllunaTCS2::setDustCover()
return sendCommandOnly(cmd); // response is processed in TimerHit
}

bool AllunaTCS2::readClimateControl()
{
char res[DRIVER_LEN] = {0};

if (sendCommand("GetClimateControl\n", res, 0) == false)
return false;

int32_t value = -1;
sscanf(res, "%d", &value);

if (value == -1)
return false;

DEBUGF(INDI::Logger::DBG_SESSION, "Climate Control status read to be %s (%d)", (value==1)?"automatic":"manual", value);
ClimateControlS[CLIMATECONTROL_AUTO ].s = (value==1)?ISS_ON:ISS_OFF;
ClimateControlS[CLIMATECONTROL_MANUAL].s = (value!=1)?ISS_ON:ISS_OFF;
ClimateControlSP.s = IPS_OK;

return true;
}

bool AllunaTCS2::setClimateControl(ClimateControlMode mode)
{
char cmd[DRIVER_LEN] = {0};
int value;
value = (mode == CLIMATECONTROL_AUTO) ? 1 : 0;
snprintf(cmd, DRIVER_LEN, "SetClimateControl %d\n", value); // enable/disable climate control
return sendCommand(cmd);
}

bool AllunaTCS2::readPrimaryDewHeater()
{
char res[DRIVER_LEN] = {0};

if (sendCommand("GetAux1\n", res, 0) == false)
return false;

int32_t value = -1;
sscanf(res, "%d", &value);

if (value == -1)
return false;

DEBUGF(INDI::Logger::DBG_SESSION, "PrimaryDewHeater status read to be %s (%d)", (value==1)?"ON":"OFF", value);
PrimaryDewHeaterS[DEWHEATER_ON ].s = (value==1)?ISS_ON:ISS_OFF;
PrimaryDewHeaterS[DEWHEATER_OFF].s = (value!=1)?ISS_ON:ISS_OFF;
PrimaryDewHeaterSP.s = IPS_OK;

return true;
}

bool AllunaTCS2::setPrimaryDewHeater(DewHeaterMode mode)
{
char cmd[DRIVER_LEN] = {0};
int value;
value = (mode == DEWHEATER_ON) ? 1 : 0;
snprintf(cmd, DRIVER_LEN, "SetAux1 %d\n", value); // enable/disable heating
return sendCommand(cmd);
}

bool AllunaTCS2::readSecondaryDewHeater()
{
char res[DRIVER_LEN] = {0};

if (sendCommand("GetAux2\n", res, 0) == false)
return false;

int32_t value = -1;
sscanf(res, "%d", &value);

if (value == -1)
return false;

DEBUGF(INDI::Logger::DBG_SESSION, "SecondaryDewHeater status read to be %s (%d)", (value==1)?"ON":"OFF", value);
SecondaryDewHeaterS[DEWHEATER_ON ].s = (value==1)?ISS_ON:ISS_OFF;
SecondaryDewHeaterS[DEWHEATER_OFF].s = (value!=1)?ISS_ON:ISS_OFF;
SecondaryDewHeaterSP.s = IPS_OK;

return true;
}

bool AllunaTCS2::setSecondaryDewHeater(DewHeaterMode mode)
{
char cmd[DRIVER_LEN] = {0};
int value;
value = (mode == DEWHEATER_ON) ? 1 : 0;
snprintf(cmd, DRIVER_LEN, "SetAux2 %d\n", value); // enable/disable heating
return sendCommand(cmd);
}


bool AllunaTCS2::saveConfigItems(FILE *fp)
{
Expand Down
29 changes: 27 additions & 2 deletions drivers/focuser/alluna_tcs2.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,23 @@ class AllunaTCS2 : public INDI::Focuser //, public INDI::DustCapInterface
// Climate

INumberVectorProperty TemperatureNP;
INumber TemperatureN[4];
INumber TemperatureN[4]; // note: last value is humidity, not temperature.
ISwitchVectorProperty ClimateControlSP;
ISwitch ClimateControlS[2];
typedef enum
{
CLIMATECONTROL_AUTO,
CLIMATECONTROL_MANUAL,
} ClimateControlMode;
ISwitchVectorProperty PrimaryDewHeaterSP, SecondaryDewHeaterSP;
ISwitch PrimaryDewHeaterS[2], SecondaryDewHeaterS[2];
typedef enum
{
DEWHEATER_ON,
DEWHEATER_OFF,
} DewHeaterMode;
INumberVectorProperty FanPowerNP;
INumber FanPowerN[1];

// Focuser
ISwitchVectorProperty SteppingModeSP;
Expand All @@ -100,12 +116,18 @@ class AllunaTCS2 : public INDI::Focuser //, public INDI::DustCapInterface
bool readPosition();
bool readStepping();
bool readDustCover();
bool readClimateControl();
bool readPrimaryDewHeater();
bool readSecondaryDewHeater();

///////////////////////////////////////////////////////////////////////////////
/// Write Data to Controller
///////////////////////////////////////////////////////////////////////////////
bool setStepping(SteppingMode mode);
bool setDustCover(void); // open/close dust cover
bool setClimateControl(ClimateControlMode mode); // turn on/off climate control
bool setPrimaryDewHeater(DewHeaterMode mode); // turn on/off climate control
bool setSecondaryDewHeater(DewHeaterMode mode); // turn on/off climate control

///////////////////////////////////////////////////////////////////////////////
/// Utility Functions
Expand Down Expand Up @@ -150,7 +172,10 @@ class AllunaTCS2 : public INDI::Focuser //, public INDI::DustCapInterface
/////////////////////////////////////////////////////////////////////////////
/// Static Helper Values
/////////////////////////////////////////////////////////////////////////////
static constexpr const char * STEPPING_TAB = "Stepping";
static constexpr const char * FOCUSER_TAB = "Focus";
static constexpr const char * ROTATOR_TAB = "Rotate";
static constexpr const char * CLIMATE_TAB = "Climate";
static constexpr const char * DUSTCOVER_TAB = "Dust Cover";
// 'LF' is the stop char
static const char DRIVER_STOP_CHAR { 0x0A };
// Update temperature every 10x POLLMS. For 500ms, we would
Expand Down

0 comments on commit 845c555

Please sign in to comment.