--- /dev/null
+#!/usr/bin/env python3
+import sys
+from pathlib import Path
+import random
+sys.path.insert(0, str(Path.cwd().parent))
+from pyindi.device import device
+
+from buildhat import Motor
+from buildhat.motors import MotorRunmode
+
+"""
+This file uses a skeleton xml file to initialize and
+define properties. Similar to this example at indilib
+https://www.indilib.org/developers/driver-howto.html#h2-properties
+"""
+
+
+class LegoFocuser(device):
+
+ motor = Motor('A')
+
+ def ISGetProperties(self, device=None):
+ """Property Definiations are generated
+ by initProperties and buildSkeleton. No
+ need to do it here. """
+ pass
+
+ def initProperties(self):
+ """Build the vector properties from
+ the skeleton file."""
+ self.buildSkeleton("legofocuser.xml")
+
+ def ISNewText(self, device, name, names, values):
+ """A new text vector has been updated from
+ the client. In this case we update the text
+ vector with the IUUpdate function. In a real
+ device driver you would probably want to do
+ something more than that.
+
+ This function is always called by the
+ mainloop
+ """
+
+ self.IUUpdate(device, name, names, values, Set=True)
+
+ def ISNewNumber(self, device, name, names, values):
+
+ """A number vector has been updated from the client.
+ """
+
+ # FOCUS_SPEED - the absolute speed at which the focuser travels
+
+ if name == "FOCUS_SPEED":
+
+ try:
+ # update our idea of speed to what the client said
+
+ focus = self.IUUpdate(device, name, names, values)
+
+ self.update_speed_direction()
+
+ # No exceptions, so set the status to OK
+
+ focus.state='Ok'
+ self.IDSet(focus)
+
+ except Exception as error:
+ self.IDMessage(f"FOCUS_SPEED error: {error}")
+
+ # Try to set the status to Alert (red)
+
+ focus.state='Alert'
+ self.IDSet(focus)
+
+ raise
+
+ # REL_FOCUS_POSITION - request a focuser move by
+ # FOCUS_RELATIVE_POSITION ticks
+
+ if name == "REL_FOCUS_POSITION":
+ try:
+
+ # Update our idea of the request
+
+ focpos = self.IUUpdate(device, name, names, values)
+ focposval = focpos["FOCUS_RELATIVE_POSITION"].value
+
+ # Ticks are degrees for us. Speed is the motor's
+ # default
+
+ self.motor.run_for_degrees(focposval, blocking=False)
+
+ # We now need to set the state to Busy until the motor
+ # stops running.
+
+ focpos.state='Busy'
+ self.IDSet(focpos)
+
+ # And set a callback to return to OK when the motor
+ # has finished
+
+ self.IEAddTimer(100, self.checkmotoridle)
+
+ except Exception as error:
+ self.IDMessage(f"IUUpdate error: {error}")
+ raise
+
+
+ if name == "FOCUS_TIMER":
+
+ try:
+ focus = self.IUUpdate(device, name, names, values)
+ if focus["FOCUS_TIMER_VALUE"].value != 0:
+ motor.run_for_seconds(1)
+ # focus["FOCUS_TIMER_VALUE"].value / 1000)
+ except Exception as error:
+ self.IDMessage(f"IUUpdate error: {error}")
+ raise
+
+
+ def ISNewSwitch(self, device, name, names, values):
+
+ """A numer switch has been updated from the client.
+ This function handles when a new switch
+
+ This function is always called by the
+ mainloop
+ """
+
+ if name == "CONNECTION":
+
+ try:
+ conn = self.IUUpdate(device, name, names, values)
+ if conn["CONNECT"].value == 'Off':
+ conn.state = "Idle"
+
+ else:
+ conn.state = "Ok"
+
+ self.IDSet(conn)
+
+ except Exception as error:
+ self.IDMessage(f"IUUpdate error: {error}")
+ raise
+
+ if name == "FOCUS_MOTION":
+ try:
+ focus = self.IUUpdate(device, name, names, values, Set=True)
+
+ self.update_speed_direction()
+
+ # No exceptions, so set the status to OK
+
+ focus.state='Ok'
+ self.IDSet(focus)
+
+ except Exception as error:
+ self.IDMessage(f"FOCUS_MOTION error: {error}")
+
+ # Try to set the status to Alert (red)
+
+ focus.state='Alert'
+ self.IDSet(focus)
+
+ if name == "FOCUS_ABORT_MOTION":
+ try:
+ self.motor.stop()
+ fam = self.IUFind("FOCUS_ABORT_MOTION")
+ fam["ABORT"].value = "Off"
+ fam.state = "Ok"
+ self.IDSet(fam)
+ except Exception as error:
+ self.IDMessage(f"FOCUS_ABORT_MOTION error: {error}")
+
+ fam.state='Alert'
+ self.IDSet(fam)
+
+ def checkmotoridle(self):
+ if self.motor._runmode == MotorRunmode.NONE:
+ focpos = self.IUFind("REL_FOCUS_POSITION")
+ focpos.state = "Ok"
+ self.IDSet(focpos)
+ else:
+ self.IEAddTimer(100, self.checkmotoridle)
+
+ def update_speed_direction(self):
+
+ # Absolute speed
+
+ speed = int(self.IUFind("FOCUS_SPEED")["FOCUS_SPEED_VALUE"].value)
+
+ # since the Build HAT API uses positive/negative speed
+ # for direction, pull out the direction of focus motion
+
+ direction = 1 if (self.IUFind("FOCUS_MOTION"))["FOCUS_INWARD"].value == 'On' else -1
+
+ # And flip if the INDI focus reverse switch is set
+
+ if (self.IUFind("FOCUS_REVERSE_MOTION"))["ENABLED"].value == 'On':
+ direction *= -1
+
+ # And send the result to the HAT.
+
+ self.motor.set_default_speed(speed * direction)
+
+
+lf = LegoFocuser()
+lf.start()