Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tickets/DM-46980: Add home dome SAL script for MT #238

Merged
merged 3 commits into from
Nov 11, 2024
Merged
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
1 change: 1 addition & 0 deletions doc/news/DM-46980.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add home dome SAL Script for ``maintel``.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env python
# This file is part of ts_standardscripts
#
# Developed for the LSST Telescope and Site Systems.
# This product includes software developed by the LSST Project
# (https://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import asyncio

from lsst.ts.standardscripts.maintel.mtdome import HomeDome

asyncio.run(HomeDome.amain())
1 change: 1 addition & 0 deletions python/lsst/ts/standardscripts/maintel/mtdome/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from .crawl_az import *
from .disable_dome_following import *
from .enable_dome_following import *
from .home_dome import *
from .park_dome import *
from .slew_dome import *
from .unpark_dome import *
111 changes: 111 additions & 0 deletions python/lsst/ts/standardscripts/maintel/mtdome/home_dome.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# This file is part of ts_standardscripts
#
# Developed for the LSST Telescope and Site Systems.
# This product includes software developed by the LSST Project
# (https://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.``

__all__ = ["HomeDome"]

import yaml
from lsst.ts import salobj
from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages


class HomeDome(salobj.BaseScript):
"""Home azimuth of the MTDome.

Parameters
----------
index : `int`
Index of Script SAL component.

Notes
-----
**Checkpoints**

Homing dome: Before commanding azimuth dome to be homed.
"""

def __init__(self, index, add_remotes: bool = True):
super().__init__(index=index, descr="Home MT dome.")

self.mtcs = None
self.physical_az = None
self.home_dome_duration = 60.0

@classmethod
def get_schema(cls):
schema_yaml = """
$schema: http://json-schema.org/draft-07/schema#
$id: https://github.com/lsst-ts/ts_standardscripts/maintel/mtdome/home_dome.yaml
title: HomeDome v1
description: Configuration for HomeDome.
type: object
properties:
physical_az:
description: Physical azimuth position for the dome as read by markings.
type: number
ignore:
description: >-
CSCs from the group to ignore in status check. Name must
match those in self.group.components, e.g.; hexapod_1.
type: array
items:
type: string
additionalProperties: false
required: [physical_az]
"""
return yaml.safe_load(schema_yaml)

async def configure(self, config):
"""Configure script.

Parameters
----------
config : `types.SimpleNamespace`
Script configuration, as defined by `schema`.
"""
self.config = config
self.physical_az = config.physical_az

if self.mtcs is None:
self.mtcs = MTCS(
domain=self.domain,
intended_usage=MTCSUsages.Slew | MTCSUsages.StateTransition,
log=self.log,
)
await self.mtcs.start_task

if hasattr(self.config, "ignore"):
for comp in self.config.ignore:
if comp not in self.mtcs.components_attr:
self.log.warning(
f"Component {comp} not in CSC Group. "
f"Must be one of {self.mtcs.components_attr}. Ignoring."
)
else:
self.log.debug(f"Ignoring component {comp}.")
setattr(self.mtcs.check, comp, False)

def set_metadata(self, metadata):
metadata.duration = self.home_dome_duration

async def run(self):
await self.mtcs.assert_all_enabled()
await self.checkpoint("Homing dome")
await self.mtcs.home_dome(physical_az=self.physical_az)
97 changes: 97 additions & 0 deletions tests/test_maintel_mtdome_home_dome.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# This file is part of ts_standardscripts
#
# Developed for the LSST Telescope and Site Systems.
# This product includes software developed by the LSST Project
# (https://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import contextlib
import unittest

import pytest
from lsst.ts import salobj, standardscripts
from lsst.ts.idl.enums.Script import ScriptState
from lsst.ts.standardscripts.maintel.mtdome import HomeDome


class TestHomeDome(
standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase
):
async def basic_make_script(self, index):
self.script = HomeDome(index=index)

return (self.script,)

@contextlib.asynccontextmanager
async def make_dry_script(self):
async with self.make_script(self):
self.script.mtcs = unittest.mock.AsyncMock()
self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock()
self.script.mtcs.home_dome = unittest.mock.AsyncMock()
yield

async def test_run(self):
async with self.make_dry_script():
await self.configure_script(physical_az=300.0)

await self.run_script()
self.script.mtcs.assert_all_enabled.assert_awaited_once()
self.script.mtcs.home_dome.assert_awaited_once()
self.script.mtcs.home_dome.assert_called_with(physical_az=300.0)

async def test_executable(self):
scripts_dir = standardscripts.get_scripts_dir()
script_path = scripts_dir / "maintel" / "mtdome" / "home_dome.py"
await self.check_executable(script_path)

async def test_config(self):
async with self.make_script():
await self.configure_script(physical_az=300.0)
assert self.script.physical_az == 300.0

async def test_invalid_configurations(self):
# Set of invalid configurations to test, all should fail to configure
configs_bad = [
dict(physical_az="not_valid"),
dict(physical_az=[1, 3]),
dict(physical_az=None),
]

async with self.make_script():
for config in configs_bad:
with pytest.raises(salobj.ExpectedError):
await self.configure_script(**config)
assert self.script.state == ScriptState.CONFIGURE_FAILED

async def test_configure_ignore(self):
async with self.make_script():
components = ["mtptg"]
await self.configure_script(physical_az=300.0, ignore=components)

assert self.script.mtcs.check.mtptg is False

async def test_configure_ignore_not_csc_component(self):
async with self.make_script():
components = ["not_csc_comp", "mtptg"]
await self.configure_script(physical_az=300.0, ignore=components)

assert hasattr(self.script.mtcs, "not_csc_comp") is False
assert self.script.mtcs.check.mtptg is False


if __name__ == "__main__":
unittest.main()
Loading