6161#define UNATTENDED_FLIP " UNATTENDED_FLIP"
6262#define WAKE_ON_LAN_MAC " WAKE_ON_LAN_MAC"
6363#define WAKE_ON_LAN_SEND " WAKE_ON_LAN_SEND"
64+ #define MOUNT_SHUTDOWN " MOUNT_SHUTDOWN"
6465
6566LX200_10MICRON ::LX200_10MICRON () : LX200Generic()
6667{
@@ -197,6 +198,9 @@ bool LX200_10MICRON::initProperties()
197198
198199 IUFillSwitch (&WoLSendS[0 ], " SEND" , " Wake Mount" , ISS_OFF );
199200 IUFillSwitchVector (&WoLSendSP, WoLSendS, 1 , getDeviceName (), WAKE_ON_LAN_SEND , " Wake on LAN" , CONNECTION_TAB , IP_RW , ISR_ATMOST1 , 60 , IPS_IDLE );
201+
202+ MountShutdownSP[0 ].fill (" SHUTDOWN" , " Shutdown Mount" , ISS_OFF );
203+ MountShutdownSP.fill (getDeviceName (), MOUNT_SHUTDOWN , " Shutdown" , MAIN_CONTROL_TAB , IP_RW , ISR_ATMOST1 , 60 , IPS_IDLE );
200204 }
201205 return result;
202206}
@@ -220,6 +224,11 @@ bool LX200_10MICRON::saveConfigItems(FILE *fp)
220224// Called by INDI::Telescope when connected state changes to add/remove properties
221225bool LX200_10MICRON::updateProperties ()
222226{
227+ // Define MountShutdownSP before the parent call so it appears immediately on connect,
228+ // not after the slow getBasicData() mount queries inside LX200Generic::updateProperties().
229+ if (isConnected ())
230+ defineProperty (MountShutdownSP);
231+
223232 bool result = LX200Generic::updateProperties ();
224233
225234 if (isConnected ())
@@ -266,6 +275,7 @@ bool LX200_10MICRON::updateProperties()
266275 }
267276 else
268277 {
278+ deleteProperty (MountShutdownSP);
269279 deleteProperty (UnattendedFlipSP.name );
270280 deleteProperty (ProductTP.name );
271281 deleteProperty (RefractionModelTemperatureNP.name );
@@ -1335,6 +1345,32 @@ bool LX200_10MICRON::ISNewSwitch(const char *dev, const char *name, ISState *sta
13351345 IDSetSwitch (&WoLSendSP, nullptr );
13361346 return true ;
13371347 }
1348+ if (MountShutdownSP.isNameMatch (name))
1349+ {
1350+ MountShutdownSP.reset ();
1351+ if (!isParked ())
1352+ {
1353+ MountShutdownSP.setState (IPS_ALERT );
1354+ LOG_WARN (" Mount must be parked before shutdown." );
1355+ MountShutdownSP.apply ();
1356+ return false ;
1357+ }
1358+ // :shutdown# — returns '1' on success, '0' on failure; ~20 s until power-off
1359+ if (0 != setStandardProcedureAndExpectChar (fd, " :shutdown#" , " 1" ))
1360+ {
1361+ MountShutdownSP.setState (IPS_ALERT );
1362+ LOG_ERROR (" Mount shutdown command failed." );
1363+ MountShutdownSP.apply ();
1364+ return false ;
1365+ }
1366+ MountShutdownSP.setState (IPS_OK );
1367+ LOG_INFO (" Mount shutdown initiated. Disconnecting before mount powers off." );
1368+ MountShutdownSP.apply ();
1369+ // Defer disconnect so ISNewSwitch returns cleanly before we tear down the property list
1370+ m_ShutdownPending = true ;
1371+ SetTimer (100 );
1372+ return true ;
1373+ }
13381374 }
13391375
13401376 return LX200Generic::ISNewSwitch (dev, name, states, names, n);
@@ -1500,6 +1536,20 @@ int LX200_10MICRON::setStandardProcedureAndReturnResponse(int fd, const char *da
15001536 return 0 ;
15011537}
15021538
1539+ void LX200_10MICRON::TimerHit ()
1540+ {
1541+ if (m_ShutdownPending)
1542+ {
1543+ m_ShutdownPending = false ;
1544+ // Standard INDI disconnect sequence — same as clicking Disconnect in the UI
1545+ Disconnect ();
1546+ setConnected (false , IPS_IDLE );
1547+ updateProperties ();
1548+ return ; // do not reschedule polling
1549+ }
1550+ LX200Generic::TimerHit ();
1551+ }
1552+
15031553bool LX200_10MICRON::sendWakeOnLanPacket ()
15041554{
15051555 const char *macStr = WoLMacT[0 ].text ;
0 commit comments