Loading noctua/api/__init__.py +9 −12 Original line number Diff line number Diff line Loading @@ -26,8 +26,8 @@ api_blueprint.register_blueprint(blocks_api, url_prefix='/blocks') api_blueprint.register_blueprint(defaults_api, url_prefix='/templates') api_blueprint.register_blueprint(sequencer_api, url_prefix='/sequencer') # This will store { "/telescope/power": <Instance of State>, ... } resource_registry = {} # # Uncomment to test dependecy errors # resource_registry = {} api_blueprint = Blueprint('api', __name__) Loading @@ -40,23 +40,20 @@ def dynamic_import(url_path): if url_path.startswith(("/blocks", "/sequencer")): return res_class_name = ends.get(url_path, "resource") dev_name = ends.get(url_path, "device") dev_instance = getattr(devices, dev_name) mod_name = dev_instance.__class__.__name__.lower() module = importlib.import_module(f"noctua.api.{mod_name}") resource_class = getattr(module, res_class_name) dev = getattr(devices, ends.get(url_path,"device")) # devices.light instance cls = dev.__class__.__name__ # string "Switch" mod_name = cls.lower() # string "switch" module = importlib.import_module(f"noctua.api.{mod_name}") # module noctua.api.switch resource_class = getattr(module, ends.get(url_path,"resource")) # class noctua.api.switch.State # Identify supported HTTP methods by checking for lowercase method names in the class methods = [m for m in ["GET", "POST", "PUT", "DELETE"] if hasattr(resource_class, m.lower())] # Populate internal registry resource_registry[url_path] = resource_class(dev=dev_instance) resource_registry[url_path] = resource_class(dev=dev) # Register route view = resource_class.as_view(url_path, dev=dev_instance) view = resource_class.as_view(url_path, dev=dev) api_blueprint.add_url_rule(url_path, view_func=view) # Improved debug print with methods list Loading noctua/api/stage.py +27 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,10 @@ class Position(BaseResource): res = await self.run_blocking(action) return self.make_response(res) async def delete(self): """Check if the stage is currently moving.""" res = await self.run_blocking(lambda: self.dev.abort) return self.make_response(res) class Named(BaseResource): """Manage named positions (e.g., 'imaging', 'spectroscopy').""" Loading @@ -35,9 +39,15 @@ class Named(BaseResource): async def put(self): """Move the stage to a named position.""" target_name = await self.get_payload() # expected string named_positions = self.dev.named_positions def action(): if target_name in self.dev.named_positions: self.dev.named = target_name return self.dev.named else: return self.make_response(None, errors=[f"Not in: {named_positions}"], status_code=500) try: res = await self.run_blocking(action) Loading @@ -45,6 +55,11 @@ class Named(BaseResource): except KeyError as e: return self.make_response(None, errors=[str(e)], status_code=400) async def delete(self): """Check if the stage is currently moving.""" res = await self.run_blocking(lambda: self.dev.abort) return self.make_response(res) class Initialization(BaseResource): """Handle stage homing and status.""" Loading @@ -60,6 +75,11 @@ class Initialization(BaseResource): res = await self.run_blocking(lambda: self.dev.is_init) return self.make_response(res) async def delete(self): """Check if the stage is currently moving.""" res = await self.run_blocking(lambda: self.dev.abort) return self.make_response(res) class Movement(BaseResource): """Monitor stage motion status.""" Loading @@ -69,6 +89,11 @@ class Movement(BaseResource): res = await self.run_blocking(lambda: self.dev.is_moving) return self.make_response(res) async def delete(self): """Check if the stage is currently moving.""" res = await self.run_blocking(lambda: self.dev.abort) return self.make_response(res) class Limits(BaseResource): """Manage software movement limits.""" Loading noctua/app.py +13 −6 Original line number Diff line number Diff line #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Third-party modules import uvicorn from quart import Quart from quart_cors import cors # Custom modules from noctua.api import api_blueprint #from noctua.web import web_blueprint from noctua.api.baseresource import register_error_handlers from noctua.web import web_blueprint app = Quart(__name__) app = cors(app) # Centralized error handling (400, 404, 405, 500) register_error_handlers(app) # API blueprint in api/__init__.py app.register_blueprint(api_blueprint, url_prefix='/api') #app.register_blueprint(web_blueprint, url_prefix='/web') app.register_blueprint(web_blueprint, url_prefix='/web') # Added Web Blueprint def run(): """Server run using uvicorn""" """ Server run using uvicorn. """ try: uvicorn.run(app, host="0.0.0.0", port=5533) Loading @@ -27,5 +32,7 @@ def run(): print(f"Shutting down: {e}") pass if __name__ == "__main__": run() noctua/config/api.ini +4 −4 Original line number Diff line number Diff line Loading @@ -232,10 +232,10 @@ resource = CoolerWarmup device = cam depends-on = /camera/power [/camera/filters] resource = Filters device = cam depends-on = /camera/power # [/camera/filters] # resource = Filters # device = cam # depends-on = /camera/power [/camera/filter] resource = Filter Loading noctua/config/constants.py +7 −7 Original line number Diff line number Diff line Loading @@ -66,13 +66,13 @@ filter_state = { filter_name = { 0: "Undef.", 1: "U", 2: "B", 3: "V", 4: "R", 5: "I", 6: "Halpha", 7: "Free", 1: "SDSS g", 2: "SDSS r", 3: "SDSS i", 4: "SDSS z", 5: "SDSS y", 6: "FREE", 7: "SDSS u", 15: "Filter_error", None: "Off", } Loading Loading
noctua/api/__init__.py +9 −12 Original line number Diff line number Diff line Loading @@ -26,8 +26,8 @@ api_blueprint.register_blueprint(blocks_api, url_prefix='/blocks') api_blueprint.register_blueprint(defaults_api, url_prefix='/templates') api_blueprint.register_blueprint(sequencer_api, url_prefix='/sequencer') # This will store { "/telescope/power": <Instance of State>, ... } resource_registry = {} # # Uncomment to test dependecy errors # resource_registry = {} api_blueprint = Blueprint('api', __name__) Loading @@ -40,23 +40,20 @@ def dynamic_import(url_path): if url_path.startswith(("/blocks", "/sequencer")): return res_class_name = ends.get(url_path, "resource") dev_name = ends.get(url_path, "device") dev_instance = getattr(devices, dev_name) mod_name = dev_instance.__class__.__name__.lower() module = importlib.import_module(f"noctua.api.{mod_name}") resource_class = getattr(module, res_class_name) dev = getattr(devices, ends.get(url_path,"device")) # devices.light instance cls = dev.__class__.__name__ # string "Switch" mod_name = cls.lower() # string "switch" module = importlib.import_module(f"noctua.api.{mod_name}") # module noctua.api.switch resource_class = getattr(module, ends.get(url_path,"resource")) # class noctua.api.switch.State # Identify supported HTTP methods by checking for lowercase method names in the class methods = [m for m in ["GET", "POST", "PUT", "DELETE"] if hasattr(resource_class, m.lower())] # Populate internal registry resource_registry[url_path] = resource_class(dev=dev_instance) resource_registry[url_path] = resource_class(dev=dev) # Register route view = resource_class.as_view(url_path, dev=dev_instance) view = resource_class.as_view(url_path, dev=dev) api_blueprint.add_url_rule(url_path, view_func=view) # Improved debug print with methods list Loading
noctua/api/stage.py +27 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,10 @@ class Position(BaseResource): res = await self.run_blocking(action) return self.make_response(res) async def delete(self): """Check if the stage is currently moving.""" res = await self.run_blocking(lambda: self.dev.abort) return self.make_response(res) class Named(BaseResource): """Manage named positions (e.g., 'imaging', 'spectroscopy').""" Loading @@ -35,9 +39,15 @@ class Named(BaseResource): async def put(self): """Move the stage to a named position.""" target_name = await self.get_payload() # expected string named_positions = self.dev.named_positions def action(): if target_name in self.dev.named_positions: self.dev.named = target_name return self.dev.named else: return self.make_response(None, errors=[f"Not in: {named_positions}"], status_code=500) try: res = await self.run_blocking(action) Loading @@ -45,6 +55,11 @@ class Named(BaseResource): except KeyError as e: return self.make_response(None, errors=[str(e)], status_code=400) async def delete(self): """Check if the stage is currently moving.""" res = await self.run_blocking(lambda: self.dev.abort) return self.make_response(res) class Initialization(BaseResource): """Handle stage homing and status.""" Loading @@ -60,6 +75,11 @@ class Initialization(BaseResource): res = await self.run_blocking(lambda: self.dev.is_init) return self.make_response(res) async def delete(self): """Check if the stage is currently moving.""" res = await self.run_blocking(lambda: self.dev.abort) return self.make_response(res) class Movement(BaseResource): """Monitor stage motion status.""" Loading @@ -69,6 +89,11 @@ class Movement(BaseResource): res = await self.run_blocking(lambda: self.dev.is_moving) return self.make_response(res) async def delete(self): """Check if the stage is currently moving.""" res = await self.run_blocking(lambda: self.dev.abort) return self.make_response(res) class Limits(BaseResource): """Manage software movement limits.""" Loading
noctua/app.py +13 −6 Original line number Diff line number Diff line #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Third-party modules import uvicorn from quart import Quart from quart_cors import cors # Custom modules from noctua.api import api_blueprint #from noctua.web import web_blueprint from noctua.api.baseresource import register_error_handlers from noctua.web import web_blueprint app = Quart(__name__) app = cors(app) # Centralized error handling (400, 404, 405, 500) register_error_handlers(app) # API blueprint in api/__init__.py app.register_blueprint(api_blueprint, url_prefix='/api') #app.register_blueprint(web_blueprint, url_prefix='/web') app.register_blueprint(web_blueprint, url_prefix='/web') # Added Web Blueprint def run(): """Server run using uvicorn""" """ Server run using uvicorn. """ try: uvicorn.run(app, host="0.0.0.0", port=5533) Loading @@ -27,5 +32,7 @@ def run(): print(f"Shutting down: {e}") pass if __name__ == "__main__": run()
noctua/config/api.ini +4 −4 Original line number Diff line number Diff line Loading @@ -232,10 +232,10 @@ resource = CoolerWarmup device = cam depends-on = /camera/power [/camera/filters] resource = Filters device = cam depends-on = /camera/power # [/camera/filters] # resource = Filters # device = cam # depends-on = /camera/power [/camera/filter] resource = Filter Loading
noctua/config/constants.py +7 −7 Original line number Diff line number Diff line Loading @@ -66,13 +66,13 @@ filter_state = { filter_name = { 0: "Undef.", 1: "U", 2: "B", 3: "V", 4: "R", 5: "I", 6: "Halpha", 7: "Free", 1: "SDSS g", 2: "SDSS r", 3: "SDSS i", 4: "SDSS z", 5: "SDSS y", 6: "FREE", 7: "SDSS u", 15: "Filter_error", None: "Off", } Loading