From: Alexandra Lanes Date: Fri, 3 Jun 2022 11:08:08 +0000 (+0200) Subject: Initial commit of legofocuser.py and xml X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ajlanes/git?a=commitdiff_plain;h=733feba5fc7764eaa820dcd42fd377ff40f3e6bb;p=legofocuser.git Initial commit of legofocuser.py and xml --- 733feba5fc7764eaa820dcd42fd377ff40f3e6bb diff --git a/legofocuser.py b/legofocuser.py new file mode 100755 index 0000000..3dc8f19 --- /dev/null +++ b/legofocuser.py @@ -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 index 0000000..8f55275 --- /dev/null +++ b/legofocuser.xml @@ -0,0 +1,51 @@ + + + + +Off + + +On + + + + + +On + + +Off + + + + + + +1 + + + + + + +50 + + + + + + Off + + + + + +Off + + +On + + + + +