Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions python/PiFinder/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,48 @@ def from_json(cls, json_str):
return cls.from_dict(data)


@dataclass
class SQM:
"""
Represents the sky brightness (SQM) value and its source.
"""

value: float = 20.15 # Standard value set to 20.15
source: str = "None"
last_update: Optional[str] = None

def __str__(self):
return (
f"SQM(value={self.value:.2f}, "
f"source={self.source}, "
f"last_update={self.last_update})"
)

def reset(self):
self.value = 0.0
self.source = "None"
self.last_update = None

def to_dict(self):
"""Convert the SQM object to a dictionary."""
return asdict(self)

def to_json(self):
"""Convert the SQM object to a JSON string."""
return json.dumps(self.to_dict())

@classmethod
def from_dict(cls, data):
"""Create a SQM object from a dictionary."""
return cls(**data)

@classmethod
def from_json(cls, json_str):
"""Create a SQM object from a JSON string."""
data = json.loads(json_str)
return cls.from_dict(data)


class SharedStateObj:
def __init__(self):
self.__power_state = 1
Expand All @@ -215,6 +257,7 @@ def __init__(self):
self.__sats = None
self.__imu = None
self.__location: Location = Location()
self.__sqm: SQM = SQM()
self.__datetime = None
self.__datetime_time = None
self.__screen = None
Expand Down Expand Up @@ -298,6 +341,13 @@ def set_location(self, v):
v.timezone = self.__tz_finder.timezone_at(lat=v.lat, lng=v.lon)
self.__location = v

def sqm(self):
"""Return the current SQM object"""
return self.__sqm

def set_sqm(self, sqm: SQM):
self.__sqm = sqm

def last_image_metadata(self):
return self.__last_image_metadata

Expand Down Expand Up @@ -355,6 +405,12 @@ def ui_state(self):
def set_ui_state(self, v):
self.__ui_state = v

def get_sky_brightness(self):
"""
Returns the current sky brightness (SQM) value from the shared state.
"""
return self.__sqm.value

def __repr__(self):
# A simple representation showing key attributes (adjust as needed)
return (
Expand Down
17 changes: 17 additions & 0 deletions python/PiFinder/ui/menu_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from PiFinder import utils
from PiFinder.ui.base import UIModule
from PiFinder.ui import menu_structure
from PiFinder.ui.sqmentry import UISqmEntry
from PiFinder.ui.object_details import UIObjectDetails
from PiFinder.displays import DisplayBase
from PiFinder.ui.text_menu import UITextMenu
Expand All @@ -13,6 +14,7 @@
MarkingMenuOption,
render_marking_menu,
)
from PiFinder.ui.textentry import UITextEntry


def collect_preloads() -> list[dict]:
Expand Down Expand Up @@ -104,6 +106,19 @@ def dyn_menu_equipment(cfg):
equipment_menu_item["items"] = [telescope_menu, eyepiece_menu]


def dyn_menu_sqm(shared_state):
"""
Adds a submenu to the SQM page to manually set the SQM value
"""
sqm_menu_item = find_menu_by_label("sqm")
sqm_menu = {
"name": _("SQM Value"),
"class": UISqmEntry,
"label": "set_sqm",
}
sqm_menu_item["items"] = [sqm_menu]


class MenuManager:
def __init__(
self,
Expand Down Expand Up @@ -142,6 +157,8 @@ def __init__(
self.ss_count = 0

dyn_menu_equipment(self.config_object)
dyn_menu_sqm(shared_state)
self.preload_modules()

def screengrab(self):
self.ss_count += 1
Expand Down
3 changes: 3 additions & 0 deletions python/PiFinder/ui/menu_structure.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from typing import Any
from PiFinder.ui.timeentry import UITimeEntry
from PiFinder.ui.sqmentry import UISqmEntry
from PiFinder.ui.text_menu import UITextMenu
from PiFinder.ui.object_list import UIObjectList
from PiFinder.ui.status import UIStatus
from PiFinder.ui.console import UIConsole
from PiFinder.ui.software import UISoftware
from PiFinder.ui.gpsstatus import UIGPSStatus
from PiFinder.ui.sqm import UIsqm
from PiFinder.ui.chart import UIChart
from PiFinder.ui.align import UIAlign
from PiFinder.ui.textentry import UITextEntry
Expand Down Expand Up @@ -1036,6 +1038,7 @@ def _(key: str) -> Any:
"items": [
{"name": _("Status"), "class": UIStatus},
{"name": _("Equipment"), "class": UIEquipment, "label": "equipment"},
{"name": _("SQM"), "class": UIsqm, "label": "sqm"},
{
"name": _("Place & Time"),
"class": UITextMenu,
Expand Down
102 changes: 99 additions & 3 deletions python/PiFinder/ui/object_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

"""

from pydeepskylog.exceptions import InvalidParameterError

from PiFinder import cat_images
from PiFinder.ui.marking_menus import MarkingMenuOption, MarkingMenu
from PiFinder.obj_types import OBJ_TYPES
Expand All @@ -25,6 +27,7 @@
from PiFinder.db.observations_db import ObservationsDatabase
import numpy as np
import time
import pydeepskylog as pds


# Constants for display modes
Expand All @@ -46,6 +49,7 @@ class UIObjectDetails(UIModule):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

self.contrast = None
self.screen_direction = self.config_object.get_option("screen_direction")
self.mount_type = self.config_object.get_option("mount_type")
self.object = self.item_definition["object"]
Expand All @@ -68,7 +72,7 @@ def __init__(self, *args, **kwargs):
),
)

# Used for displaying obsevation counts
# Used for displaying observation counts
self.observations_db = ObservationsDatabase()

self.simpleTextLayout = functools.partial(
Expand Down Expand Up @@ -117,8 +121,15 @@ def _layout_designator(self):
designator_color = 255
if not self.object.last_filtered_result:
designator_color = 128

# layout the name - contrast reserve line
space_calculator = SpaceCalculatorFixed(14)

_, typeconst = space_calculator.calculate_spaces(
self.object.display_name, self.contrast
)
return self.simpleTextLayout(
self.object.display_name,
typeconst,
font=self.fonts.large,
color=self.colors.get(designator_color),
)
Expand Down Expand Up @@ -197,6 +208,82 @@ def update_object_info(self):
scrollspeed=self._get_scrollspeed_config(),
)

# Get the SQM from the shared state
sqm = self.shared_state.get_sky_brightness()

# Check if a telescope and eyepiece are set
if (
self.config_object.equipment.active_eyepiece is None
or self.config_object.equipment.active_eyepiece is None
):
self.contrast = ""
else:
# Calculate contrast reserve. The object diameters are given in arc seconds.
magnification = self.config_object.equipment.calc_magnification(
self.config_object.equipment.active_telescope,
self.config_object.equipment.active_eyepiece,
)
if self.object.mag_str == "-":
self.contrast = ""
else:
try:
if self.object.size:
# Check if the size contains 'x'
if "x" in self.object.size:
diameter1, diameter2 = map(
float, self.object.size.split("x")
)
diameter1 = (
diameter1 * 60.0
) # Convert arc seconds to arc minutes
diameter2 = diameter2 * 60.0
elif "'" in self.object.size:
# Convert arc minutes to arc seconds
diameter1 = float(self.object.size.replace("'", "")) * 60.0
diameter2 = diameter1
else:
diameter1 = diameter2 = float(self.object.size) * 60.0
else:
diameter1 = diameter2 = None

self.contrast = pds.contrast_reserve(
sqm=sqm,
telescope_diameter=self.config_object.equipment.active_telescope.aperture_mm,
magnification=magnification,
surf_brightness=None,
magnitude=float(self.object.mag_str),
object_diameter1=diameter1,
object_diameter2=diameter2,
)
except InvalidParameterError as e:
print(f"Error calculating contrast reserve: {e}")
self.contrast = ""
if self.contrast is not None and self.contrast != "":
self.contrast = f"{self.contrast: .1f}"
else:
self.contrast = ""

# Add contrast reserve line to details with interpretation
if self.contrast:
contrast_val = float(self.contrast)
if contrast_val < -0.2:
contrast_str = f"Object is not visible"
elif -0.2 <= contrast_val < 0.1:
contrast_str = f"Questionable detection"
elif 0.1 <= contrast_val < 0.35:
contrast_str = f"Difficult to see"
elif 0.35 <= contrast_val < 0.5:
contrast_str = f"Quite difficult to see"
elif 0.5 <= contrast_val < 1.0:
contrast_str = f"Easy to see"
elif contrast_val >= 1.0:
contrast_str = f"Very easy to see"
else:
contrast_str = f""
self.texts["contrast_reserve"] = self.ScrollTextLayout(
contrast_str, font=self.fonts.base, color=self.colors.get(255), scrollspeed=self._get_scrollspeed_config(),
)

# NGC description....
logs = self.observations_db.get_logs_for_object(self.object)
desc = ""
Expand Down Expand Up @@ -228,6 +315,7 @@ def update_object_info(self):
magnification=magnification,
)


def active(self):
self.activation_time = time.time()

Expand Down Expand Up @@ -368,7 +456,7 @@ def update(self, force=True):
if self.object_display_mode == DM_DESC or self.object_display_mode == DM_LOCATE:
# catalog and entry field i.e. NGC-311
self.refresh_designator()
desc_available_lines = 4
desc_available_lines = 3
desig = self.texts["designator"]
desig.draw((0, 20))

Expand Down Expand Up @@ -409,6 +497,14 @@ def update(self, force=True):
else:
desc_available_lines += 1 # extra lines for description

contrast = self.texts.get("contrast_reserve")

if contrast and contrast.text.strip():
contrast.draw((0, posy))
posy += 11
else:
desc_available_lines +=1

# Remaining lines with object description
desc = self.texts.get("desc")
if desc:
Expand Down
67 changes: 67 additions & 0 deletions python/PiFinder/ui/sqm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from PiFinder.ui.base import UIModule
from PiFinder.state_utils import sleep_for_framerate
from PiFinder.ui.marking_menus import MarkingMenu, MarkingMenuOption
from PiFinder.ui.textentry import UITextEntry
from PiFinder import config

class UIsqm(UIModule):
"""
Displays current SQM value and provides entry to manually set SQM value
"""
__title__ = "SQM"

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.menu_index = 0
self.marking_menu = MarkingMenu(
left=MarkingMenuOption(),
right=MarkingMenuOption(),
down=MarkingMenuOption(),
)

def update(self, force=False):
sleep_for_framerate(self.shared_state)
self.clear_screen()
sqm_value = self.shared_state.get_sky_brightness()
self.draw.text((10, 20), f"Current SQM: {sqm_value}", font=self.fonts.large.font, fill=self.colors.get(128))
if sqm_value is not None:
self.draw.text((10, 40), f" {sqm_value}", font=self.fonts.large.font, fill=self.colors.get(128))
else:
self.draw.text((10, 40), "No SQM value set", font=self.fonts.small.font, fill=self.colors.get(128))

self.draw.text(
(10, 80),
_("Manually..."),
font=self.fonts.large.font,
fill=self.colors.get(192),
)
if self.menu_index == 0:
self.draw_menu_pointer(80)

def key_down(self):
self.menu_index += 1
if self.menu_index > 1:
self.menu_index = 1

def key_up(self):
self.menu_index -= 1
if self.menu_index < 0:
self.menu_index = 0

def key_right(self):
if self.menu_index == 0:
self.jump_to_label("set_sqm")

def draw_menu_pointer(self, horiz_position: int):
self.draw.text(
(2, horiz_position),
self._RIGHT_ARROW,
font=self.fonts.large.font,
fill=self.colors.get(255),
)

def active(self):
"""
Called when a module becomes active
i.e. foreground controlling display
"""
Loading