diff --git a/.gitignore b/.gitignore index ce3986f6..0b7a5eb3 100644 --- a/.gitignore +++ b/.gitignore @@ -52,7 +52,6 @@ coverage.xml .pytest_cache/ # Translations -*.mo *.pot # Django stuff: diff --git a/astro_data/pifinder_objects.db b/astro_data/pifinder_objects.db index 1a36d8ce..66fde3e8 100644 Binary files a/astro_data/pifinder_objects.db and b/astro_data/pifinder_objects.db differ diff --git a/default_config.json b/default_config.json index 64604981..fbaae5f5 100644 --- a/default_config.json +++ b/default_config.json @@ -22,7 +22,7 @@ "chart_reticle": 128, "chart_constellations": 64, "solve_pixel": [256, 256], - "active_catalogs": [ + "filter.selected_catalogs": [ "NGC", "M", "H", @@ -30,6 +30,113 @@ "PL", "RDS" ], + "filter.object_types": [ + "Gx", + "OC", + "Gb", + "Nb", + "DN", + "PN", + "C+N", + "Ast", + "Kt", + "***", + "D*", + "*", + "?", + "Pla", + "CM" + ], + "filter.constellations": [ + "And", + "Ant", + "Aps", + "Aql", + "Aqr", + "Ara", + "Ari", + "Aur", + "Boo", + "CMa", + "CMi", + "CVn", + "Cae", + "Cam", + "Cap", + "Car", + "Cas", + "Cen", + "Cep", + "Cet", + "Cha", + "Cir", + "Cnc", + "Col", + "Com", + "CrA", + "CrB", + "Crt", + "Cru", + "Crv", + "Cyg", + "Del", + "Dor", + "Dra", + "Equ", + "Eri", + "For", + "Gem", + "Gru", + "Her", + "Hor", + "Hya", + "Hyi", + "Ind", + "LMi", + "Lac", + "Leo", + "Lep", + "Lib", + "Lup", + "Lyn", + "Lyr", + "Men", + "Mic", + "Mon", + "Mus", + "Nor", + "Oct", + "Oph", + "Ori", + "Pav", + "Peg", + "Per", + "Phe", + "Pic", + "PsA", + "Psc", + "Pup", + "Pyx", + "Ret", + "Scl", + "Sco", + "Sct", + "Ser", + "Sex", + "Sge", + "Sgr", + "Tau", + "Tel", + "TrA", + "Tri", + "Tuc", + "UMa", + "UMi", + "Vel", + "Vir", + "Vol", + "Vul" + ], "equipment": { "telescopes": [ { diff --git a/docs/source/user_guide.rst b/docs/source/user_guide.rst index 8fc2bfc8..c7d006db 100644 --- a/docs/source/user_guide.rst +++ b/docs/source/user_guide.rst @@ -536,6 +536,12 @@ The PiFinder provides an easy to use web interface which allows you to: To access the web interface for the first time, make sure the PiFinder is in Access Point mode (see :ref:`user_guide:settings menu`). This is the default for new PiFinders to make first time set up easier. Using a phone, tablet or computer, connect to the PiFinder's wireless network called PiFinderAP. It's an open network with no password required. Once connected, open your web browser and visit: ``http://pifinder.local`` + +.. note:: + If you are connected to the PiFinderAP network and can't load the PiFinder web interface using + http://pifinder.local try http://10.10.10.1 as some systems may not support the network features + required to resolve local computer names + .. list-table:: :width: 100% diff --git a/python/PiFinder/camera_pi.py b/python/PiFinder/camera_pi.py index ac5bc9ed..d5d47509 100644 --- a/python/PiFinder/camera_pi.py +++ b/python/PiFinder/camera_pi.py @@ -35,6 +35,11 @@ def __init__(self, exposure_time) -> None: self.camera_type = "imx296" # maximum analog gain for this sensor self.gain = 15 + + if "imx290" in self.camera.camera.id: + self.camera_type = "imx462" + self.gain = 30 + self.camType = f"PI {self.camera_type}" self.initialize() @@ -51,6 +56,13 @@ def initialize(self) -> None: }, raw={"size": (1456, 1088), "format": "R10"}, ) + elif self.camera_type == "imx462": + cam_config = self.camera.create_still_configuration( + { + "size": (512, 512), + }, + raw={"size": (1920, 1080), "format": "SRGGB12"}, + ) else: # using this smaller scale auto-selects binning on the sensor... # cam_config = self.camera.create_still_configuration({"size": (512, 512)}) @@ -78,6 +90,10 @@ def capture(self) -> Image.Image: raw_capture = raw_capture.copy().view(np.uint16)[:, 184:-184] # Sensor orientation is different raw_capture = np.rot90(raw_capture, 2) + elif self.camera_type == "imx462": + # crop to square and resample to 16 bit from 2 8 bit entries + # to get the right FOV, we want a 980 square.... + raw_capture = raw_capture.copy().view(np.uint16)[50:-50, 470:-470] else: # crop to square and resample to 16 bit from 2 8 bit entries raw_capture = raw_capture.copy().view(np.uint16)[:, 256:-256] diff --git a/python/PiFinder/catalog_import.py b/python/PiFinder/catalog_import.py index 1c34c2ac..7b5ea223 100644 --- a/python/PiFinder/catalog_import.py +++ b/python/PiFinder/catalog_import.py @@ -1,6 +1,6 @@ """ This module holds various utils -and importers used during setup +and importers used during catalog setup """ @@ -1442,6 +1442,49 @@ def load_ngc_catalog(): insert_catalog_max_sequence("M") +def fix_object_types(): + """ + Runs some global queries to normalize object types from various catalogs + """ + logging.info("FIX: Object Types") + conn, db_c = objects_db.get_conn_cursor() + + type_mappings = { + "Dark Nebula": "DN", + "* ": "*", + "*?": "?", + "-": "?", + "": "?", + "Bright Nebula": "Nb", + "D*?": "D*", + "Open Cluster": "OC", + "Pl": "PN", + "PD": "PN", + "Supernova Remnant": "Nb", + } + + for k, v in type_mappings.items(): + db_c.execute(f"update objects set obj_type = '{v}' where obj_type='{k}'") + + conn.commit() + + +def fix_m45(): + """ + m45 coordinates are wrong in our NGC source + """ + logging.info("FIX: m45 location") + conn, db_c = objects_db.get_conn_cursor() + + db_c.execute( + "update objects set ra=56.85, dec=24.1167 where " + "id = (select object_id from catalog_objects " + "where catalog_code='M' and sequence=45)" + ) + + conn.commit() + + if __name__ == "__main__": logging.info("starting main") logger = logging.getLogger() @@ -1505,6 +1548,10 @@ def load_ngc_catalog(): load_arp() load_tlk_90_vars() + # Fix data issues + fix_object_types() + fix_m45() + # Populate the images table logging.info("Resolving object images...") resolve_object_images() diff --git a/python/PiFinder/catalogs.py b/python/PiFinder/catalogs.py index 151899db..dff8384d 100644 --- a/python/PiFinder/catalogs.py +++ b/python/PiFinder/catalogs.py @@ -16,6 +16,7 @@ from PiFinder.composite_object import CompositeObject, MagnitudeObject import PiFinder.comets as comets from PiFinder.utils import Timer, comet_file +from PiFinder.config import Config logger = logging.getLogger("Catalog") @@ -94,6 +95,7 @@ def __init__( object_types: Union[list[str], None] = None, altitude: int = -1, observed: str = "Any", + constellations: list[str] = [], selected_catalogs: list[str] = [], ): self.shared_state = shared_state @@ -104,9 +106,22 @@ def __init__( self._object_types = object_types self._altitude = altitude self._observed = observed + self._constellations = constellations self._selected_catalogs = set(selected_catalogs) self.last_filtered_time = 0 + def load_from_config(self, config_object: Config): + """ + Loads filter values from configuration object + """ + self._magnitude = config_object.get_option("filter.magnitude") + self._object_types = config_object.get_option("filter.object_types", []) + self._altitude = config_object.get_option("filter.altitude", -1) + self._observed = config_object.get_option("filter.observed", "Any") + self._constellations = config_object.get_option("filter.constellations", []) + self._selected_catalogs = config_object.get_option("filter.selected_catalogs") + self.last_filtered_time = 0 + @property def magnitude(self): return self._magnitude @@ -143,6 +158,15 @@ def observed(self, observed: str): self._observed = observed self.dirty_time = time.time() + @property + def constellations(self): + return self._constellations + + @constellations.setter + def constellations(self, constellations: list[str]): + self._constellations = constellations + self.dirty_time = time.time() + @property def selected_catalogs(self): return self._selected_catalogs @@ -183,6 +207,16 @@ def apply_filter(self, obj: CompositeObject): obj.last_filtered_time = time.time() self.last_filtered_time = time.time() + + # check constellation + if self._constellations: + if obj.const not in self._constellations: + obj.last_filtered_result = False + return False + else: + obj.last_filtered_result = False + return False + # check altitude if self._altitude != -1 and self.fast_aa: obj_altitude, _ = self.fast_aa.radec_to_altaz( @@ -202,7 +236,11 @@ def apply_filter(self, obj: CompositeObject): return False # check type - if self._object_types is not None and obj.obj_type not in self._object_types: + if self._object_types: + if obj.obj_type not in self._object_types: + obj.last_filtered_result = False + return False + else: obj.last_filtered_result = False return False diff --git a/python/PiFinder/main.py b/python/PiFinder/main.py index 7b6ee09a..33ab0980 100644 --- a/python/PiFinder/main.py +++ b/python/PiFinder/main.py @@ -440,16 +440,9 @@ def main( catalogs: Catalogs = CatalogBuilder().build(shared_state) # Establish the common catalog filter object - catalogs.set_catalog_filter( - CatalogFilter( - shared_state=shared_state, - magnitude=cfg.get_option("filter.magnitude"), - object_types=cfg.get_option("filter.object_types"), - altitude=cfg.get_option("filter.altitude", -1), - observed=cfg.get_option("filter.observed", "Any"), - selected_catalogs=cfg.get_option("active_catalogs"), - ) - ) + _new_filter = CatalogFilter(shared_state=shared_state) + _new_filter.load_from_config(cfg) + catalogs.set_catalog_filter(_new_filter) console.write(" Menus") console.update() diff --git a/python/PiFinder/obj_types.py b/python/PiFinder/obj_types.py index d89ecf43..39b3ff2f 100644 --- a/python/PiFinder/obj_types.py +++ b/python/PiFinder/obj_types.py @@ -3,14 +3,15 @@ "OC": "Open Cluster", "Gb": "Globular", "Nb": "Nebula", - "Pl": "Planetary", + "DN": "Dark Nebula", + "PN": "Planetary", "C+N": "Cluster + Neb", "Ast": "Asterism", "Kt": "Knot", "***": "Triple star", "D*": "Double star", - "* ": "Star", - "? ": "Unkn", + "*": "Star", + "?": "Unkn", "Pla": "Planet", "CM": "Comet", } @@ -20,7 +21,7 @@ "OC": "oc", "Gb": "gc", "Nb": "neb", - "Pl": "pneb", + "PN": "pneb", "D*": "dstar", "***": "dstar", "Ast": "ast", diff --git a/python/PiFinder/pos_server.py b/python/PiFinder/pos_server.py index 4aa274ce..8049be20 100644 --- a/python/PiFinder/pos_server.py +++ b/python/PiFinder/pos_server.py @@ -170,6 +170,7 @@ def handle_goto_command(shared_state, ra_parsed, dec_parsed): ) logger.debug("handle_goto_command: Pushing object: %s", obj) shared_state.ui_state().add_recent(obj) + shared_state.ui_state().set_new_pushto(True) ui_queue.put("push_object") return "1" @@ -239,7 +240,7 @@ def run_server(shared_state, p_ui_queue, log_queue): logger.info("SkySafari server started and listening") while True: client_socket, address = server_socket.accept() - logger.info("New connection from %s", address) + logger.debug("New connection from %s", address) handle_client(client_socket, shared_state) except Exception: logger.exception("Unexpected server error") diff --git a/python/PiFinder/state.py b/python/PiFinder/state.py index 343aa951..ef2174b2 100644 --- a/python/PiFinder/state.py +++ b/python/PiFinder/state.py @@ -52,6 +52,11 @@ def __init__(self): self.__message_timeout = 0 self.__hint_timeout = 0 self.__show_fps = False + # Set to true when an object is pushed + # to the recent list from the pos_server + # proccess (i.e. skysafari goto). Used + # to jump from object list to object details + self.__new_pushto = False def observing_list(self): return self.__observing_list @@ -65,6 +70,12 @@ def recent_list(self) -> List[CompositeObject]: def add_recent(self, v: CompositeObject): self.__recent.append(v) + def set_new_pushto(self, v: bool): + self.__new_pushto = v + + def new_pushto(self) -> bool: + return self.__new_pushto + def target(self): return self.__target diff --git a/python/PiFinder/switch_camera.py b/python/PiFinder/switch_camera.py index 0978f65d..485d8af4 100644 --- a/python/PiFinder/switch_camera.py +++ b/python/PiFinder/switch_camera.py @@ -7,6 +7,9 @@ def switch_boot(cam_type: str) -> None: Edit /boot/config.txt to swap camera drive must be run as roo """ + if cam_type == "imx462": + # The 462 uses the 290 driver + cam_type = "imx290" # read config.txt into a list with open("/boot/config.txt", "r") as boot_in: @@ -28,7 +31,10 @@ def switch_boot(cam_type: str) -> None: cam_added = True if not cam_added: - boot_lines.append(f"dtoverlay={cam_type}\n") + if cam_type == "imx290": + boot_lines.append(f"dtoverlay={cam_type},clock-frequency=74250000\n") + else: + boot_lines.append(f"dtoverlay={cam_type}\n") cam_added = True with open("/boot/config.txt", "w") as boot_out: diff --git a/python/PiFinder/sys_utils.py b/python/PiFinder/sys_utils.py index 53c0b23b..7eddbc49 100644 --- a/python/PiFinder/sys_utils.py +++ b/python/PiFinder/sys_utils.py @@ -2,13 +2,8 @@ import re from typing import Dict, Any -try: - import sh - from sh import wpa_cli, unzip, su, passwd - - REAL_SYS_UTILS = True -except ImportError: - REAL_SYS_UTILS = False +import sh +from sh import wpa_cli, unzip, su, passwd import socket from PiFinder import utils @@ -152,19 +147,22 @@ def set_ap_name(self, ap_name): def get_host_name(self): return socket.gethostname() - def get_connected_ssid(self): + def get_connected_ssid(self) -> str: """ Returns the SSID of the connected wifi network or None if not connected or in AP mode """ if self.wifi_mode() == "AP": - return None + return "" # get output from iwgetid - iwgetid = sh.Command("iwgetid") - _t = iwgetid(_ok_code=(0, 255)).strip() - return _t.split(":")[-1].strip('"') + try: + iwgetid = sh.Command("iwgetid") + _t = iwgetid(_ok_code=(0, 255)).strip() + return _t.split(":")[-1].strip('"') + except sh.CommandNotFound: + return "ssid_not_found" - def set_host_name(self, hostname): + def set_host_name(self, hostname) -> None: if hostname == self.get_host_name(): return _result = sh.sudo("hostnamectl", "set-hostname", hostname) @@ -319,3 +317,8 @@ def switch_cam_imx477() -> None: def switch_cam_imx296() -> None: logger.info("SYS: Switching cam to imx296") sh.sudo("python", "-m", "PiFinder.switch_camera", "imx296") + + +def switch_cam_imx462() -> None: + logger.info("SYS: Switching cam to imx462") + sh.sudo("python", "-m", "PiFinder.switch_camera", "imx462") diff --git a/python/PiFinder/ui/callbacks.py b/python/PiFinder/ui/callbacks.py index b963dea4..8fd83d36 100644 --- a/python/PiFinder/ui/callbacks.py +++ b/python/PiFinder/ui/callbacks.py @@ -33,10 +33,12 @@ def reset_filters(ui_module: UIModule) -> None: """ Reset all filters to default """ - ui_module.catalogs.set_catalog_filter( - CatalogFilter(shared_state=ui_module.shared_state) - ) ui_module.config_object.reset_filters() + + new_filter = CatalogFilter(shared_state=ui_module.shared_state) + new_filter.load_from_config(ui_module.config_object) + + ui_module.catalogs.set_catalog_filter(new_filter) ui_module.catalogs.filter_catalogs() ui_module.message("Filters Reset") ui_module.remove_from_stack() @@ -101,6 +103,30 @@ def switch_cam_imx296(ui_module: UIModule) -> None: restart_system(ui_module) +def switch_cam_imx462(ui_module: UIModule) -> None: + ui_module.message("Switching cam", 2) + sys_utils.switch_cam_imx462() + restart_system(ui_module) + + +def get_camera_type(ui_module: UIModule) -> list[str]: + cam_id = "000" + + # read config.txt into a list + with open("/boot/config.txt", "r") as boot_in: + boot_lines = list(boot_in) + + # Look for the line without a comment... + for line in boot_lines: + if line.startswith("dtoverlay=imx"): + cam_id = line[10:16] + # imx462 uses imx290 driver + if cam_id == "imx290": + cam_id = "imx462" + + return [cam_id] + + def go_wifi_ap(ui_module: UIModule) -> None: ui_module.message("WiFi to AP", 2) sys_utils.go_wifi_ap() @@ -111,3 +137,9 @@ def go_wifi_cli(ui_module: UIModule) -> None: ui_module.message("WiFi to Client", 2) sys_utils.go_wifi_cli() restart_system(ui_module) + + +def get_wifi_mode(ui_module: UIModule) -> list[str]: + wifi_txt = f"{utils.pifinder_dir}/wifi_status.txt" + with open(wifi_txt, "r") as wfs: + return [wfs.read()] diff --git a/python/PiFinder/ui/menu_manager.py b/python/PiFinder/ui/menu_manager.py index 53c5f53f..ca107d6a 100644 --- a/python/PiFinder/ui/menu_manager.py +++ b/python/PiFinder/ui/menu_manager.py @@ -221,6 +221,19 @@ def message(self, message: str, timeout: float) -> None: self.stack[-1].message(message, timeout) # type: ignore[arg-type] def jump_to_label(self, label: str) -> None: + # to prevent many recent/object UI modules + # being added to the list upon repeated object + # pushes, check for existing 'recent' in the + # stack and jump to that, rather than adding + # a new one + if label in ["recent"]: + for stack_index, ui_module in enumerate(self.stack): + if ui_module.item_definition.get("label", "") == label: + self.stack = self.stack[: stack_index + 1] + self.stack[-1].active() # type: ignore[call-arg] + return + # either this is not a special case, or we didn't find + # the label already in the stack menu_to_jump = find_menu_by_label(label) if menu_to_jump is not None: self.add_to_stack(menu_to_jump) diff --git a/python/PiFinder/ui/menu_structure.py b/python/PiFinder/ui/menu_structure.py index 366f221b..70954dfc 100644 --- a/python/PiFinder/ui/menu_structure.py +++ b/python/PiFinder/ui/menu_structure.py @@ -226,7 +226,7 @@ "name": "Catalogs", "class": UITextMenu, "select": "multi", - "config_option": "active_catalogs", + "config_option": "filter.selected_catalogs", "items": [ { "name": "Planets", @@ -244,7 +244,7 @@ "name": "DSO...", "class": UITextMenu, "select": "multi", - "config_option": "active_catalogs", + "config_option": "filter.selected_catalogs", "items": [ { "name": "Abell Pn", @@ -300,7 +300,7 @@ "name": "Stars...", "class": UITextMenu, "select": "multi", - "config_option": "active_catalogs", + "config_option": "filter.selected_catalogs", "items": [ { "name": "Bright Named", @@ -344,6 +344,10 @@ "name": "Open Cluster", "value": "OC", }, + { + "name": "Cluster/Neb", + "value": "C+N", + }, { "name": "Globular", "value": "Gb", @@ -354,12 +358,28 @@ }, { "name": "P. Nebula", - "value": "Pl", + "value": "PN", + }, + { + "name": "Dark Nebula", + "value": "DN", + }, + { + "name": "Star", + "value": "*", }, { "name": "Double Str", "value": "D*", }, + { + "name": "Triple Str", + "value": "***", + }, + { + "name": "Knot", + "value": "Kt", + }, { "name": "Asterism", "value": "Ast", @@ -368,6 +388,10 @@ "name": "Planet", "value": "Pla", }, + { + "name": "Comet", + "value": "CM", + }, ], }, { @@ -606,6 +630,23 @@ }, ], }, + { + "name": "Az Arrows", + "class": UITextMenu, + "select": "single", + "config_option": "pushto_az_arrows", + "label": "pushto_az_arrows", + "items": [ + { + "name": "Default", + "value": "Default", + }, + { + "name": "Reverse", + "value": "Reverse", + }, + ], + }, ], }, { @@ -750,9 +791,18 @@ "name": "WiFi Mode", "class": UITextMenu, "select": "single", + "value_callback": callbacks.get_wifi_mode, "items": [ - {"name": "Client Mode", "callback": callbacks.go_wifi_cli}, - {"name": "AP Mode", "callback": callbacks.go_wifi_ap}, + { + "name": "Client Mode", + "value": "Client", + "callback": callbacks.go_wifi_cli, + }, + { + "name": "AP Mode", + "value": "AP", + "callback": callbacks.go_wifi_ap, + }, ], }, { @@ -805,14 +855,22 @@ "name": "Camera Type", "class": UITextMenu, "select": "single", + "value_callback": callbacks.get_camera_type, "items": [ { "name": "v2 - imx477", "callback": callbacks.switch_cam_imx477, + "value": "imx477", }, { "name": "v3 - imx296", "callback": callbacks.switch_cam_imx296, + "value": "imx296", + }, + { + "name": "v3 - imx462", + "callback": callbacks.switch_cam_imx462, + "value": "imx462", }, ], }, diff --git a/python/PiFinder/ui/object_details.py b/python/PiFinder/ui/object_details.py index bec5b078..7cc92920 100644 --- a/python/PiFinder/ui/object_details.py +++ b/python/PiFinder/ui/object_details.py @@ -224,6 +224,9 @@ def active(self): def _check_catalog_initialised(self): code = self.object.catalog_code + if code == "PUSH": + # Special code for objects pushed from sky-safari + return True catalog = self.catalogs.get_catalog_by_code(code) return catalog and catalog.initialised @@ -286,6 +289,16 @@ def _render_pointing_instructions(self): else: az_arrow = self._RIGHT_ARROW + # Check az arrow config + if ( + self.config_object.get_option("pushto_az_arrows", "Default") + == "Reverse" + ): + if az_arrow is self._LEFT_ARROW: + az_arrow = self._RIGHT_ARROW + else: + az_arrow = self._LEFT_ARROW + # Change decimal points when within 1 degree if point_az < 1: self.draw.text( diff --git a/python/PiFinder/ui/object_list.py b/python/PiFinder/ui/object_list.py index ec76b6d6..8e8b4d29 100644 --- a/python/PiFinder/ui/object_list.py +++ b/python/PiFinder/ui/object_list.py @@ -211,6 +211,16 @@ def format_az_alt(self, point_az, point_alt): point_az *= -1 az_arrow_symbol = self._LEFT_ARROW + # Check az arrow config + if ( + self.config_object.get_option("pushto_az_arrows", "Default") + == "Reverse" + ): + if az_arrow_symbol == self._LEFT_ARROW: + az_arrow_symbol = self._RIGHT_ARROW + else: + az_arrow_symbol = self._LEFT_ARROW + if point_az > 100: point_az = 99 @@ -358,7 +368,14 @@ def line_position(self, line_number, title_offset=20): def active(self): # trigger refilter super().active() - self.refresh_object_list() + + # check for new push_to + if self.ui_state.new_pushto(): + self.refresh_object_list(force_update=True) + self.ui_state.set_new_pushto(False) + self.show_object_details(0) + else: + self.refresh_object_list() def update(self, force: bool = False) -> None: self.clear_screen() @@ -575,6 +592,22 @@ def marking_menu_right(self): self._marking_menu_items[3].selected = False self.sort() + def show_object_details(self, object_index): + """ + Adds the object details UI module for the object + at object_index to the top of the stack. + """ + _menu_item = self._menu_items_sorted[object_index] + + object_item_definition = { + "name": _menu_item.display_name, + "class": UIObjectDetails, + "object": _menu_item, + "object_list": self._menu_items_sorted, + "label": "object_details", + } + self.add_to_stack(object_item_definition) + def key_right(self): """ When right is pressed, move to @@ -589,16 +622,7 @@ def key_right(self): self.jump_input_display = False self.jump_to_number.reset_number() - _menu_item = self._menu_items_sorted[self._current_item_index] - - object_item_definition = { - "name": _menu_item.display_name, - "class": UIObjectDetails, - "object": _menu_item, - "object_list": self._menu_items_sorted, - "label": "object_details", - } - self.add_to_stack(object_item_definition) + self.show_object_details(self._current_item_index) def key_number(self, number): self.jump_to_number.append_number(number) diff --git a/python/PiFinder/ui/preview.py b/python/PiFinder/ui/preview.py index d82f4c48..e93fce91 100644 --- a/python/PiFinder/ui/preview.py +++ b/python/PiFinder/ui/preview.py @@ -42,8 +42,6 @@ def __init__(self, *args, **kwargs): self.capture_prefix = f"{self.__uuid__}_diag" self.capture_count = 0 - self.align_mode = False - # the centroiding returns an ndarray # so we're initialiazing one here self.star_list = np.empty((0, 2)) @@ -180,15 +178,8 @@ def update(self, force=False): if last_image_time > self.last_update: image_obj = self.camera_image.copy() - # Fetch Centroids before image is altered - # Do this at least once to get a numpy array in - # star_list - if self.align_mode and self.shared_state and self.shared_state.solution(): - matched_centroids = self.shared_state.solution()["matched_centroids"] - self.star_list = np.array(matched_centroids) - # Resize - if self.zoom_level == 0 or self.align_mode: + if self.zoom_level == 0: image_obj = image_obj.resize((128, 128)) elif self.zoom_level == 1: image_obj = image_obj.resize((256, 256)) @@ -217,23 +208,18 @@ def update(self, force=False): self.screen.paste(image_obj) self.last_update = last_image_time - if self.align_mode: - self.draw_star_selectors() + if self.zoom_level > 0: + zoom_number = self.zoom_level * 2 + self.draw.text( + (75, 112), + f"Zoom x{zoom_number}", + font=self.fonts.bold.font, + fill=self.colors.get(128), + ) else: - if self.zoom_level > 0: - zoom_number = self.zoom_level * 2 - self.draw.text( - (75, 112), - f"Zoom x{zoom_number}", - font=self.fonts.bold.font, - fill=self.colors.get(128), - ) - else: - self.draw_reticle() - - return self.screen_update( - title_bar=not self.align_mode, button_hints=not self.align_mode - ) + self.draw_reticle() + + return self.screen_update() def key_plus(self): self.zoom_level += 1 @@ -244,36 +230,3 @@ def key_minus(self): self.zoom_level -= 1 if self.zoom_level < 0: self.zoom_level = 0 - - def key_square(self): - if self.align_mode: - self.align_mode = False - self.shared_state.set_camera_align(self.align_mode) - self.update(force=True) - else: - self.align_mode = True - self.shared_state.set_camera_align(self.align_mode) - self.update(force=True) - - def key_number(self, number): - if self.align_mode: - if number == 0: - # reset reticle - self.shared_state.set_solve_pixel((256, 256)) - self.config_object.set_option("solve_pixel", (256, 256)) - self.align_mode = False - if number in list(range(1, self.highlight_count + 1)): - # They picked a star to align.... - star_index = number - 1 - if self.star_list.shape[0] > star_index: - star_cam_x = self.star_list[star_index][0] - star_cam_y = self.star_list[star_index][1] - self.shared_state.set_solve_pixel((star_cam_x, star_cam_y)) - self.config_object.set_option( - "solve_pixel", - (star_cam_x, star_cam_y), - ) - self.align_mode = False - - self.shared_state.set_camera_align(self.align_mode) - self.update(force=True) diff --git a/python/PiFinder/ui/text_menu.py b/python/PiFinder/ui/text_menu.py index 011c9308..f6805e96 100644 --- a/python/PiFinder/ui/text_menu.py +++ b/python/PiFinder/ui/text_menu.py @@ -40,6 +40,13 @@ def __init__( ) self._selected_values = [] + if self.item_definition.get("value_callback"): + self._selected_values = self.item_definition.get("value_callback")(self) + # Set current item index based on selection + for i, _item in enumerate(self.item_definition["items"]): + if _item["value"] == self._selected_values[0]: + self._current_item_index = i + if config_option := self.item_definition.get("config_option"): if self._menu_type == "multi": self._selected_values = self.config_object.get_option(config_option) @@ -221,7 +228,7 @@ def key_right(self): self.config_object.set_option(config_option, self._selected_values) # are we setting active catalogs - if config_option == "active_catalogs": + if config_option == "filter.selected_catalogs": self.catalogs.select_no_catalogs() self.catalogs.select_catalogs(self._selected_values) self.catalogs.catalog_filter.selected_catalogs = ( diff --git a/python/tests/test_sys_utils.py b/python/tests/test_sys_utils.py index b0dbd407..6115dc88 100644 --- a/python/tests/test_sys_utils.py +++ b/python/tests/test_sys_utils.py @@ -1,38 +1,39 @@ import pytest -from PiFinder import sys_utils +try: + from PiFinder import sys_utils -@pytest.mark.unit -def test_wpa_supplicant_parsing(): - # This could be read from a file or passed from another function - wpa_supplicant_example = """ - ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev - update_config=1 - country=US + @pytest.mark.unit + def test_wpa_supplicant_parsing(): + # This could be read from a file or passed from another function + wpa_supplicant_example = """ + ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev + update_config=1 + country=US - network={ - ssid="My Home Network" - psk="password123" - key_mgmt=WPA-PSK - } + network={ + ssid="My Home Network" + psk="password123" + key_mgmt=WPA-PSK + } - network={ - ssid="Work Network" - psk="compl3x=p@ssw0rd!" - key_mgmt=WPA-PSK - } - """ - wpa_list = [ - line.strip() - for line in wpa_supplicant_example.strip().split("\n") - if line.strip() - ] - result = sys_utils.Network._parse_wpa_supplicant(wpa_list) - assert result[1]["psk"] == "compl3x=p@ssw0rd!" + network={ + ssid="Work Network" + psk="compl3x=p@ssw0rd!" + key_mgmt=WPA-PSK + } + """ + wpa_list = [ + line.strip() + for line in wpa_supplicant_example.strip().split("\n") + if line.strip() + ] + result = sys_utils.Network._parse_wpa_supplicant(wpa_list) + assert result[1]["psk"] == "compl3x=p@ssw0rd!" - example2 = """ - ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev - update_config=1 + example2 = """ + ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev + update_config=1 @@ -50,18 +51,22 @@ def test_wpa_supplicant_parsing(): - network={ - ssid="testytest" - psk="oesrucoeahu1234" - key_mgmt=WPA-PSK - } + network={ + ssid="testytest" + psk="oesrucoeahu1234" + key_mgmt=WPA-PSK + } - network={ - ssid="00xx33" - psk="1234@===!!!" - key_mgmt=WPA-PSK - } - """ - wpa_list = [line for line in example2.split("\n") if line.strip()] - result = sys_utils.Network._parse_wpa_supplicant(wpa_list) - assert result[1]["psk"] == "1234@===!!!" + network={ + ssid="00xx33" + psk="1234@===!!!" + key_mgmt=WPA-PSK + } + """ + wpa_list = [line for line in example2.split("\n") if line.strip()] + result = sys_utils.Network._parse_wpa_supplicant(wpa_list) + assert result[1]["psk"] == "1234@===!!!" + + +except ImportError: + pass