chiark / gitweb /
Initial commit of legofocuser.py and xml
authorAlexandra Lanes <ajlanes@chiark.greenend.org.uk>
Fri, 3 Jun 2022 11:08:08 +0000 (13:08 +0200)
committerAlexandra Lanes <ajlanes@chiark.greenend.org.uk>
Fri, 3 Jun 2022 11:08:08 +0000 (13:08 +0200)
legofocuser.py [new file with mode: 0755]
legofocuser.xml [new file with mode: 0644]

diff --git a/legofocuser.py b/legofocuser.py
new file mode 100755 (executable)
index 0000000..3dc8f19
--- /dev/null
@@ -0,0 +1,208 @@
+#!/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()
diff --git a/legofocuser.xml b/legofocuser.xml
new file mode 100644 (file)
index 0000000..8f55275
--- /dev/null
@@ -0,0 +1,51 @@
+<INDIDriver>
+  
+<defSwitchVector device="LegoFocuser" name="CONNECTION" label="Connection" group="Main Control" state="Idle" perm="rw" rule="OneOfMany" timeout="60">
+    <defSwitch name="CONNECT" label="Connect">
+Off
+    </defSwitch>
+    <defSwitch name="DISCONNECT" label="Disconnect">
+On
+    </defSwitch>
+</defSwitchVector>
+
+<defSwitchVector device="LegoFocuser" name="FOCUS_MOTION" label="DIRECTION" group="Main Control" state="Ok" perm="rw" rule="OneOfMany" timeout="60">
+    <defSwitch name="FOCUS_INWARD" label="INWARD">
+On
+    </defSwitch>
+    <defSwitch name="FOCUS_OUTWARD" label="OUTWARD">
+Off
+    </defSwitch>
+</defSwitchVector>
+
+
+<defNumberVector device="LegoFocuser" name="REL_FOCUS_POSITION" label="Relative Position" group="Main Control" state="Ok" perm="rw" timeout="0">
+<defNumber name="FOCUS_RELATIVE_POSITION" label="Move" format="%d"  min="0" max="100000" step="1">
+1
+</defNumber>
+</defNumberVector>
+
+
+<defNumberVector device="LegoFocuser" name="FOCUS_SPEED" label="SPEED" group="Config" state="Ok" perm="rw" timeout="0">
+<defNumber name="FOCUS_SPEED_VALUE" label="SPEED" format="%d" min="0" max="100" step="1">
+50
+</defNumber>
+</defNumberVector>
+
+<defSwitchVector device="LegoFocuser" name="FOCUS_ABORT_MOTION" label="STOP" group="Main Control" state="Idle" perm="rw" rule="AtMostOne" timeout="60">
+  <defSwitch name="ABORT" label="STOP">
+    Off
+  </defSwitch>
+</defSwitchVector>
+
+<defSwitchVector device="LegoFocuser" name="FOCUS_REVERSE_MOTION" label="Reverse direction" group="Main Control" state="Ok" perm="rw" rule="OneOfMany" timeout="60">
+    <defSwitch name="ENABLED" label="Enabled">
+Off
+    </defSwitch>
+    <defSwitch name="DISABLED" label="Disabled">
+On
+    </defSwitch>
+</defSwitchVector>
+
+
+</INDIDriver>