Skip to content

Commit

Permalink
Merge pull request #238 from lsst-ts/tickets/DM-46980
Browse files Browse the repository at this point in the history
tickets/DM-46980: Add home dome SAL script for MT
  • Loading branch information
cvillalon authored Nov 11, 2024
2 parents 63e0ab3 + 97c593b commit 3e27256
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 0 deletions.
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()

0 comments on commit 3e27256

Please sign in to comment.