Skip to content

Commit

Permalink
Merge branch 'main' into 493-v2-lakeshore
Browse files Browse the repository at this point in the history
  • Loading branch information
prjemian committed Jan 11, 2022
2 parents df58024 + 7645cf1 commit 237a2ae
Show file tree
Hide file tree
Showing 43 changed files with 1,547 additions and 14 deletions.
Binary file modified .coverage
Binary file not shown.
2 changes: 1 addition & 1 deletion .github/workflows/unit-tests-epics-base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
- name: Install dependencies
run: |
$CONDA/bin/conda install epics-base --name $ENV_NAME
$CONDA/bin/conda install epics-base "readline!=8.1.2" --name $ENV_NAME
$CONDA/bin/conda list -r --name $ENV_NAME
env:
ENV_NAME: anaconda-test-env
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# local developer code
dev_*.py

db/
log/
Expand Down
13 changes: 13 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ Moved ``command_list_as_table()`` from `utils` into ``plans/command_list``.

``utils/``: Reorganized ``utils.py`` and ``_utils/`` into ``utils/`` subpackage.

New Features and/or Enhancements
---------------------------------------------

* Add support for synApps calc ``sseq`` record.
* Add support for synApps calc ``userStringSeq`` database.
* Add support for synApps optics ``2slit`` database.
* Add support for Eurotherm 2216e temperature controller

Fixes
-----------

Convert ``None`` to ``"null"`` when saving ``PeakStats`` to stream.

Maintenance
---------------

Expand Down
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ include CHANGES*
include LICENSE.txt
include versioneer.py
include apstools/_version.py
include apstools/devices/aps_cycle_info.txt
include apstools/devices/aps_cycle_info.yml
include apstools/devices/pss_shutter.db
include apstools/devices/pss_shutter.ui
include apstools/migration/config
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Various Python tools for use with the Bluesky framework at the APS
[![Python version](https://img.shields.io/pypi/pyversions/apstools.svg)](https://pypi.python.org/pypi/apstools)
![Unit Tests](https://github.com/BCDA-APS/apstools/workflows/Unit%20Tests/badge.svg)
[![Documentation Status](https://readthedocs.org/projects/apstools/badge/?version=latest)](http://apstools.readthedocs.io/en/latest/?badge=latest)
[![Coverage Status](https://coveralls.io/repos/github/BCDA-APS/apstools/badge.svg?branch=master)](https://coveralls.io/github/BCDA-APS/apstools?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/BCDA-APS/apstools/badge.svg?branch=main)](https://coveralls.io/github/BCDA-APS/apstools?branch=main)

[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/BCDA-APS/apstools.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/BCDA-APS/apstools/context:python)
[![Total alerts](https://img.shields.io/lgtm/alerts/g/BCDA-APS/apstools.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/BCDA-APS/apstools/alerts/)
Expand Down
4 changes: 4 additions & 0 deletions apstools/devices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

from .description_mixin import EpicsDescriptionMixin

from .eurotherm_2216e import Eurotherm2216e

from .kohzu_monochromator import KohzuSeqCtl_Monochromator

from .lakeshore_controllers import LakeShore336Device
Expand Down Expand Up @@ -76,6 +78,8 @@
from .xia_pf4 import Pf4FilterSingle
from .xia_pf4 import Pf4FilterTriple

from .xia_slit import XiaSlit2D

# synApps
from ..synApps import AsynRecord
from ..synApps import BusyRecord
Expand Down
88 changes: 88 additions & 0 deletions apstools/devices/eurotherm_2216e.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""
Eurotherm 2216e Temperature Controller
++++++++++++++++++++++++++++++++++++++
The 2216e is a temperature controller from Eurotherm.
.. autosummary::
~Eurotherm2216e
According to their website, the [Eurotherm 2216e Temperature
Controller](https://www.eurothermcontrollers.com/eurotherm-2216e-series-controller-now-obsolete/)
is obsolete. Please see replacement
[EPC3016](https://www.eurothermcontrollers.com/eurotherm-epc3016-1-16-din-process-and-temperature-controller/)
in our [EPC3000 Series](https://www.eurothermcontrollers.com/epc3000-series).
New in apstools 1.6.0.
"""

import logging

from ophyd import Component
from ophyd import EpicsSignal
from ophyd import EpicsSignalRO
from ophyd import Signal

from .positioner_soft_done import PVPositionerSoftDoneWithStop

logger = logging.getLogger(__name__)


class Eurotherm2216e(PVPositionerSoftDoneWithStop):
"""
Eurotherm 2216e Temperature Controller
"""

# temperature value in dC, needs conversion: readback = 0.1 * sensor
sensor = Component(EpicsSignalRO, "SetPointSensor", kind="omitted")
readback = Component(Signal, value=0, kind="hinted")
setpoint = Component(
EpicsSignal,
"SetPointTemp",
kind="hinted",
write_pv="SetPointTempWrite",
put_complete=True,
)
# temp1 & temp2 PVs have no useful values : ignore here
# temp1 = Component(EpicsSignalRO, "Temp1", kind="hinted")
# temp2 = Component(EpicsSignalRO, "Temp2", kind="hinted")
power = Component(
EpicsSignal,
"SetPointPower",
kind="config",
write_pv="SetPointPowerWrite",
put_complete=True,
)

mode = Component(
EpicsSignal,
"SetPointSensor",
kind="config",
write_pv="ModeWrite",
string=True,
)
program_number = Component(EpicsSignalRO, "ProgramNumber", kind="config")
# program_status = Component(
# EpicsSignalRO,
# "ProgramStatus",
# kind="config",
# string=True
# )

target = None # remove from PVPositionerSoftDoneWithStop

def cb_sensor(self, *args, **kwargs):
"units: Convert dC from sensor to C"
self.readback.put(0.1 * self.sensor.get())

def __init__(self, prefix="", *, tolerance=1, **kwargs):
super().__init__(
prefix=prefix,
readback_pv="ignoreRBV",
setpoint_pv="ignore",
tolerance=tolerance,
update_target=False,
**kwargs
)
self.sensor.subscribe(self.cb_sensor)
2 changes: 1 addition & 1 deletion apstools/devices/positioner_soft_done.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def inposition(self):

def stop(self, *, success=False):
"""
Hold the current readback when stop() is called and not inposition.
Hold the current readback when stop() is called and not :meth:`inposition`.
"""
if not self.inposition:
self.setpoint.put(self.position)
Expand Down
31 changes: 31 additions & 0 deletions apstools/devices/tests/test_eurotherm_2216e.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
test the Eurotherm 2216e device support
Hardware is not available so test with best efforts
"""

from .. import eurotherm_2216e

IOC = "gp:"
PV_PREFIX = f"phony:{IOC}2216e:"


def test_device():
euro = eurotherm_2216e.Eurotherm2216e(PV_PREFIX, name="controller")
assert not euro.connected

assert euro.tolerance.get() == 1
assert euro.update_target is False
assert euro.target is None

cns = """
readback setpoint
""".split()
assert sorted(euro.read_attrs) == sorted(cns)

cns += """
sensor
done tolerance report_dmov_changes
mode power program_number
""".split()
assert sorted(euro.component_names) == sorted(cns)
5 changes: 4 additions & 1 deletion apstools/devices/tests/test_kohzu_monochromator.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class MyKohzu(KohzuSeqCtl_Monochromator):
m_y = Component(EpicsMotor, "m46")
m_z = Component(EpicsMotor, "m47")

def into_control_range(self, p_theta=2, p_y=-15, p_z=90):
def into_control_range(self, p_theta=11, p_y=-18, p_z=90):
"""
Move the Kohzu motors into range so the wavelength controls will work.
Expand All @@ -44,10 +44,13 @@ def into_control_range(self, p_theta=2, p_y=-15, p_z=90):
args = []
if self.m_theta.position < p_theta:
args += [self.m_theta, p_theta]
yield from bps.mv(self.m_theta.velocity, 5)
if self.m_y.position > p_y:
args += [self.m_y, p_y]
yield from bps.mv(self.m_y.velocity, 5)
if self.m_z.position < p_z:
args += [self.m_z, p_z]
yield from bps.mv(self.m_z.velocity, 5)
if (len(args) == 0):
# all motors in range, no work to do, MUST yield something
yield from bps.null()
Expand Down
46 changes: 46 additions & 0 deletions apstools/devices/tests/test_xia_slit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from ..xia_slit import XiaSlit2D
from ...utils import SlitGeometry

import pytest

IOC = "gp:"
PV_PREFIX = f"{IOC}phony_hsc1:"

# Full testing requires two XIA Slit controllers (a 2D H & V set)
# We don't have that for unit testing. Proceed with best efforts.


def test_XiaSlit_not_connected():
slit1 = XiaSlit2D(PV_PREFIX, name="slit1")
assert slit1 is not None

# slit1.wait_for_connection()
assert not slit1.connected


def test_XiaSlit_geometry(capsys):
slit1 = XiaSlit2D(PV_PREFIX, name="slit1")

g = None
with pytest.raises(TypeError):
g = slit1.geometry
assert not isinstance(g, SlitGeometry)

captured = capsys.readouterr()
assert captured.out.split("\n") == [""]
assert captured.err.split("\n") == [""]


def test_XiaSlit_components():
slit1 = XiaSlit2D(PV_PREFIX, name="slit1")
cns = """
inb out bot top
hsize vsize hcenter vcenter
hID horientation hbusy
vID vorientation vbusy
enable
error_code error_message message1 message2 message3
calibrate initialize locate stop_button
precision
""".split()
assert sorted(slit1.component_names) == sorted(cns)
Loading

0 comments on commit 237a2ae

Please sign in to comment.