enhance documentation
- flatten hierarchy (some links do not work when using folders) + fix a bug with the redorder flag in Override + allow removal of parameters + clean description using inspect.cleandoc Change-Id: I3dde4f4cb29c46e8a21014f1fad7aa3ad610a1bf
This commit is contained in:
@ -1,9 +1,10 @@
|
||||
/* this is for the sphinx_rtd_theme
|
||||
/* this is for the sphinx_rtd_theme */
|
||||
div.wy-nav-content
|
||||
{
|
||||
max-width: 100% !important;
|
||||
}
|
||||
*/
|
||||
|
||||
/* this is for the alabaser theme */
|
||||
div.body {
|
||||
max-width: 100%;
|
||||
}
|
||||
@ -32,4 +33,19 @@ pre, tt, code {
|
||||
}
|
||||
}
|
||||
|
||||
dd {
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
|
||||
/* make nested bullet lists nicer (ales too much space above inner nested list) */
|
||||
.rst-content .section ul li ul {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/* make some bullet lists more dense (this rule exists in theme.css, but not important)*/
|
||||
.wy-plain-list-disc li p:last-child, .rst-content .section ul li p:last-child, .rst-content .toctree-wrapper ul li p:last-child, article ul li p:last-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
|
@ -89,9 +89,10 @@ pygments_style = 'sphinx'
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
|
||||
# sort by source instead of alphabetic
|
||||
autodoc_member_order = 'bysource'
|
||||
|
||||
autodoc_default_options = {
|
||||
'member-order': 'bysource',
|
||||
'show-inheritance': True,
|
||||
}
|
||||
default_role = 'any'
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
@ -99,9 +100,19 @@ default_role = 'any'
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
#import sphinx_rtd_theme
|
||||
#html_theme = 'sphinx_rtd_theme'
|
||||
html_theme = 'alabaster'
|
||||
if False: # alabaster
|
||||
html_theme = 'alabaster'
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
html_theme_options = {
|
||||
'page_width': '100%',
|
||||
'fixed_sidebar': True,
|
||||
}
|
||||
else:
|
||||
import sphinx_rtd_theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# If not None, a 'Last updated on:' timestamp is inserted at every page
|
||||
# bottom, using the given strftime format.
|
||||
@ -110,14 +121,6 @@ html_theme = 'alabaster'
|
||||
html_last_updated_fmt = '%Y-%m-%d %H:%M'
|
||||
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
html_theme_options = {
|
||||
'page_width': '100%',
|
||||
'fixed_sidebar': True,
|
||||
}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
|
@ -1,6 +0,0 @@
|
||||
Demo cryostat
|
||||
=============
|
||||
|
||||
.. automodule:: secop_demo.cryo
|
||||
:members:
|
||||
|
@ -1,12 +0,0 @@
|
||||
Demo
|
||||
====
|
||||
|
||||
Specific sample environments
|
||||
----------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
cryo
|
||||
test
|
||||
|
@ -1,6 +0,0 @@
|
||||
Test devices
|
||||
=============
|
||||
|
||||
.. automodule:: secop_demo.test
|
||||
:members:
|
||||
|
@ -1,11 +0,0 @@
|
||||
ESS
|
||||
===
|
||||
|
||||
Frameworks
|
||||
----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
epics
|
||||
|
@ -1,10 +0,0 @@
|
||||
Facility specific functionalities
|
||||
=================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
demo/index
|
||||
mlz/index
|
||||
ess/index
|
||||
psi/index
|
@ -1,6 +0,0 @@
|
||||
ANTARES magnet (amagnet)
|
||||
========================
|
||||
|
||||
.. automodule:: secop_mlz.amagnet
|
||||
:members:
|
||||
|
@ -1,6 +0,0 @@
|
||||
Entangle
|
||||
========
|
||||
|
||||
.. automodule:: secop_mlz.entangle
|
||||
:members:
|
||||
|
@ -1,20 +0,0 @@
|
||||
MLZ
|
||||
===
|
||||
|
||||
Frameworks
|
||||
----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
entangle
|
||||
|
||||
|
||||
Specific sample environments
|
||||
----------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
amagnet
|
||||
|
@ -1,10 +0,0 @@
|
||||
PSI
|
||||
===
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
ppms
|
||||
ls370res
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
LakeShore 370 resistivity
|
||||
=========================
|
||||
|
||||
.. automodule:: secop_psi.ls370res
|
||||
:members:
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
PPMS
|
||||
====
|
||||
|
||||
.. automodule:: secop_psi.ppms
|
||||
:members:
|
||||
|
||||
|
@ -1,67 +0,0 @@
|
||||
Framework documentation
|
||||
=======================
|
||||
|
||||
|
||||
Module Base Classes
|
||||
-------------------
|
||||
|
||||
.. autoclass:: secop.core.Module
|
||||
:members: startModule
|
||||
|
||||
.. autoclass:: secop.core.Readable
|
||||
:members: pollerClass, Status
|
||||
|
||||
.. autoclass:: secop.core.Writable
|
||||
|
||||
.. autoclass:: secop.core.Drivable
|
||||
:members: Status, isBusy, isDriving, do_stop
|
||||
|
||||
|
||||
Parameters, Commands and Properties
|
||||
-----------------------------------
|
||||
|
||||
.. autoclass:: secop.core.Parameter
|
||||
.. autoclass:: secop.core.Command
|
||||
.. autoclass:: secop.core.Override
|
||||
.. autoclass:: secop.core.Property
|
||||
.. autoclass:: secop.core.Attached
|
||||
|
||||
|
||||
Datatypes
|
||||
---------
|
||||
|
||||
.. autoclass:: secop.core.FloatRange
|
||||
.. autoclass:: secop.core.IntRange
|
||||
.. autoclass:: secop.core.BoolType
|
||||
.. autoclass:: secop.core.ScaledInteger
|
||||
.. autoclass:: secop.core.EnumType
|
||||
.. autoclass:: secop.core.StringType
|
||||
.. autoclass:: secop.core.TupleOf
|
||||
.. autoclass:: secop.core.ArrayOf
|
||||
.. autoclass:: secop.core.StructOf
|
||||
.. autoclass:: secop.core.BLOBType
|
||||
|
||||
|
||||
Communication
|
||||
-------------
|
||||
|
||||
.. autoclass:: secop.core.Communicator
|
||||
:members: do_communicate
|
||||
|
||||
.. autoclass:: secop.core.StringIO
|
||||
:members: do_communicate, do_multicomm
|
||||
|
||||
.. autoclass:: secop.core.HasIodev
|
||||
|
||||
.. autoclass:: secop.core.IOHandlerBase
|
||||
:members:
|
||||
|
||||
.. autoclass:: secop.core.IOHandler
|
||||
:members:
|
||||
|
||||
|
||||
Exception classes
|
||||
-----------------
|
||||
|
||||
.. automodule:: secop.errors
|
||||
:members:
|
@ -1,18 +1,16 @@
|
||||
Welcome to the FRAPPY documentation!
|
||||
====================================
|
||||
Frappy Programming Guide
|
||||
========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
tutorial/tutorial
|
||||
server
|
||||
framework
|
||||
facility/index
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
introduction
|
||||
tutorial
|
||||
reference
|
||||
secop_psi
|
||||
secop_demo
|
||||
secop_mlz
|
||||
secop_ess
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
|
70
doc/source/introduction.rst
Normal file
70
doc/source/introduction.rst
Normal file
@ -0,0 +1,70 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
Frappy - a Python Framework for SECoP
|
||||
-------------------------------------
|
||||
|
||||
*Frappy* is a Python framework for creating Sample Environment Control Nodes (SEC Node) with
|
||||
a SECoP interface. A *SEC Node* is a service, running usually a computer or microcomputer,
|
||||
which accesses the hardware over the interfaces given by the manufacturer of the used
|
||||
electronic devices. It provides access to the data in an abstracted form over the SECoP interface.
|
||||
`SECoP <https://github.com/SampleEnvironment/SECoP/tree/master/protocol>`_ is a protocol for
|
||||
communicating with Sample Environment and other mobile devices, specified by a committee of
|
||||
the `ISSE <https://sampleenvironment.org>`_.
|
||||
|
||||
The Frappy framework deals with all the details of the SECoP protocol, so the programmer
|
||||
can concentrate on the details of accessing the hardware with support for different types
|
||||
of interfaces (TCP or Serial, ASCII or binary). However, the programmer should be aware of
|
||||
the basic principle of the SECoP protocol: the hardware abstraction.
|
||||
|
||||
|
||||
Hardware Abstraction
|
||||
--------------------
|
||||
|
||||
The idea of hardware abstraction is to hide the details of hardware access from the SECoP interface.
|
||||
A SECoP module is a logical component of an abstract view of the sample environment.
|
||||
It is one independent value of measurement like a temperature or pressure or a physical output like
|
||||
a current or voltage. This corresponds roughly to an EPICS channel or a NICOS device. On the
|
||||
hardware side we may have devices with several channels, like a typical temperature controller,
|
||||
which will be represented individual SECoP modules.
|
||||
On the other hand a SECoP channel might be linked with several hardware devices, for example if
|
||||
you imagine a superconducting magnet controller built of separate electronic devices like a power
|
||||
supply, switch heater and coil temperature monitor. The latter case does not mean that we have
|
||||
to hide the details in the SECoP interface. For an expert it might be useful to give at least
|
||||
read access to hardware specific data by providing them as separate SECoP modules. But the
|
||||
magnet module should be usable without knowledge of all the inner details.
|
||||
|
||||
A SECoP module has:
|
||||
|
||||
* **properties**: static information describing the module, for example a human readable
|
||||
*description* of the module or information about the intended *visibility*.
|
||||
* **parameters**: changing information about the state of a module (for example the *status*
|
||||
containing information about the state of the module) or modifiable information influencing
|
||||
the measurement (for example a "ramp" rate).
|
||||
* **commands**: actions, for example *stop*.
|
||||
|
||||
A SECoP module belongs to an interface class, mainly *Readable* or *Drivable*. A *Readable*
|
||||
has at least the parameters *value* and *status*, a *Drivable* in addition *target*. *value* is
|
||||
the main value of the module and is read only. *status* is a tuple (status code, status text),
|
||||
and *target* is the target value. When the *target* parameter value of a *Drivable* changes,
|
||||
the status code changes normally to a busy code. As soon as the target value is reached,
|
||||
the status code changes back to an idle code, if no error occurs.
|
||||
|
||||
**Programmers Hint:** before starting to code, choose carefully the main SECoP modules you want
|
||||
to provide to the user.
|
||||
|
||||
|
||||
Programming a Driver
|
||||
--------------------
|
||||
|
||||
Programming a driver means extending one of the base classes like :class:`secop.modules.Readable`
|
||||
or :class:`secop.modules.Drivable`. The parameters are defined in the dict :py:attr:`parameters`, as a
|
||||
class attribute of the extended class, using the :class:`secop.params.Parameter` constructor, or in case
|
||||
of altering the properties of an inherited parameter, :class:`secop.params.Override`.
|
||||
|
||||
Parameters usually need a method :meth:`read_<name>()`
|
||||
implementing the code to retrieve their value from the hardware. Writeable parameters
|
||||
(with the argument ``readonly=False``) usually need a method :meth:`write_<name>(<value>)`
|
||||
implementing how they are written to the hardware. Above methods may be omitted, when
|
||||
there is no interaction with the hardware involved.
|
||||
|
77
doc/source/reference.rst
Normal file
77
doc/source/reference.rst
Normal file
@ -0,0 +1,77 @@
|
||||
Reference
|
||||
---------
|
||||
|
||||
Module Base Classes
|
||||
...................
|
||||
|
||||
.. autoclass:: secop.modules.Module
|
||||
:members: earlyInit, initModule, startModule
|
||||
|
||||
.. autoclass:: secop.modules.Readable
|
||||
:members: pollerClass, Status
|
||||
|
||||
.. autoclass:: secop.modules.Writable
|
||||
|
||||
.. autoclass:: secop.modules.Drivable
|
||||
:members: Status, isBusy, isDriving, do_stop
|
||||
|
||||
|
||||
Parameters, Commands and Properties
|
||||
...................................
|
||||
|
||||
.. autoclass:: secop.params.Parameter
|
||||
.. autoclass:: secop.params.Command
|
||||
.. autoclass:: secop.params.Override
|
||||
.. autoclass:: secop.properties.Property
|
||||
.. autoclass:: secop.modules.Attached
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
|
||||
Datatypes
|
||||
.........
|
||||
|
||||
.. autoclass:: secop.datatypes.FloatRange
|
||||
.. autoclass:: secop.datatypes.IntRange
|
||||
.. autoclass:: secop.datatypes.BoolType
|
||||
.. autoclass:: secop.datatypes.ScaledInteger
|
||||
.. autoclass:: secop.datatypes.EnumType
|
||||
.. autoclass:: secop.datatypes.StringType
|
||||
.. autoclass:: secop.datatypes.TupleOf
|
||||
.. autoclass:: secop.datatypes.ArrayOf
|
||||
.. autoclass:: secop.datatypes.StructOf
|
||||
.. autoclass:: secop.datatypes.BLOBType
|
||||
|
||||
|
||||
|
||||
Communication
|
||||
.............
|
||||
|
||||
.. autoclass:: secop.modules.Communicator
|
||||
:show-inheritance:
|
||||
:members: do_communicate
|
||||
|
||||
.. autoclass:: secop.stringio.StringIO
|
||||
:show-inheritance:
|
||||
:members: do_communicate, do_multicomm
|
||||
|
||||
.. autoclass:: secop.stringio.HasIodev
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: secop.iohandler.IOHandlerBase
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
||||
.. autoclass:: secop.iohandler.IOHandler
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
||||
|
||||
Exception classes
|
||||
.....................--
|
||||
|
||||
.. automodule:: secop.errors
|
||||
:members:
|
||||
|
||||
.. include:: server.rst
|
||||
|
10
doc/source/secop_demo.rst
Normal file
10
doc/source/secop_demo.rst
Normal file
@ -0,0 +1,10 @@
|
||||
Demo
|
||||
====
|
||||
|
||||
.. automodule:: secop_demo.cryo
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
||||
.. automodule:: secop_demo.test
|
||||
:show-inheritance:
|
||||
:members:
|
@ -1,6 +1,9 @@
|
||||
EPICS modules
|
||||
=============
|
||||
ESS
|
||||
---
|
||||
|
||||
EPICS
|
||||
.....
|
||||
|
||||
.. automodule:: secop_ess.epics
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
19
doc/source/secop_mlz.rst
Normal file
19
doc/source/secop_mlz.rst
Normal file
@ -0,0 +1,19 @@
|
||||
MLZ
|
||||
---
|
||||
|
||||
Amagnet (Garfield)
|
||||
..................
|
||||
|
||||
.. automodule:: secop_mlz.amagnet
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
||||
|
||||
Entangle Framework
|
||||
..................
|
||||
|
||||
.. automodule:: secop_mlz.entangle
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
||||
|
19
doc/source/secop_psi.rst
Normal file
19
doc/source/secop_psi.rst
Normal file
@ -0,0 +1,19 @@
|
||||
PSI (SINQ)
|
||||
----------
|
||||
|
||||
PPMS
|
||||
....
|
||||
|
||||
.. automodule:: secop_psi.ppms
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
||||
LakeShore 370
|
||||
.............
|
||||
|
||||
Calibrated sensors and control loop not yet supported.
|
||||
|
||||
.. automodule:: secop_psi.ls370res
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
@ -1,8 +1,5 @@
|
||||
Configuring and Starting
|
||||
========================
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
.............
|
||||
|
||||
The configuration consists of a **NODE** section, an **INTERFACE** section and one
|
||||
section per SECoP module.
|
||||
@ -51,7 +48,7 @@ the SECoP interface.
|
||||
|
||||
|
||||
Starting
|
||||
--------
|
||||
........
|
||||
|
||||
The Frappy server can be started via the **bin/secop-server** script.
|
||||
|
||||
@ -73,5 +70,3 @@ The Frappy server can be started via the **bin/secop-server** script.
|
||||
-q, --quiet suppress non-error messages
|
||||
-d, --daemonize run as daemon
|
||||
-t, --test check cfg files only
|
||||
|
||||
|
||||
|
7
doc/source/tutorial.rst
Normal file
7
doc/source/tutorial.rst
Normal file
@ -0,0 +1,7 @@
|
||||
Tutorial
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
tutorial_helevel
|
@ -1,64 +1,10 @@
|
||||
Frappy Programming Guide
|
||||
========================
|
||||
HeLevel - a Simple Driver
|
||||
=========================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
*Frappy* is a Python framework for creating Sample Environment Control Nodes (SEC Node) with
|
||||
a SECoP interface. A *SEC Node* is a service, running usually a computer or microcomputer,
|
||||
which accesses the hardware over the interfaces given by the manufacturer of the used
|
||||
electronic devices. It provides access to the data in an abstracted form over the SECoP interface.
|
||||
`SECoP <https://github.com/SampleEnvironment/SECoP/tree/master/protocol>`_ is a protocol for
|
||||
communicating with Sample Environment and other mobile devices, specified by a committee of
|
||||
the `ISSE <https://sampleenvironment.org>`_.
|
||||
|
||||
The Frappy framework deals with all the details of the SECoP protocol, so the programmer
|
||||
can concentrate on the details of accessing the hardware with support for different types
|
||||
of interfaces (TCP or Serial, ASCII or binary). However, the programmer should be aware of
|
||||
the basic principle of the SECoP protocol: the hardware abstraction.
|
||||
|
||||
Hardware Abstraction
|
||||
--------------------
|
||||
|
||||
The idea of hardware abstraction is to hide the details of hardware access from the SECoP interface.
|
||||
A SECoP module is a logical component of an abstract view of the sample environment.
|
||||
It is one independent value of measurement like a temperature or physical output like a current or voltage.
|
||||
This corresponds roughly to an EPICS channel or a NICOS device. On the hardware side we may have devices
|
||||
with several channels, like a typical temperature controller, which will be represented individual SECoP modules.
|
||||
On the other hand a SECoP channel might be linked with several hardware devices, for example if you imagine
|
||||
a superconducting magnet controller built of seperate electronic devices like a power supply, switch heater
|
||||
and coil temperature monitor. The latter case does not mean that we have to hide complete the details in the
|
||||
SECoP interface. For an expert it might be useful to give at least read access to hardware specific data
|
||||
by providing them as seperate SECoP modules. But the magnet module should be usable without knowledge of
|
||||
all the inner details.
|
||||
|
||||
A SECoP module has:
|
||||
|
||||
* **properties**: static information describing the module, for example a human readable *description* of
|
||||
the module or information about the intended *visibiliy*.
|
||||
* **parameters**: changing information about the state of a module (for example the *status* containing
|
||||
information about the state of the module )or modifiable information influencing the measurement
|
||||
(for example a "ramp" rate)
|
||||
* **commands**: actions, for example *stop*
|
||||
|
||||
A SECoP module belongs to an interface class, mainly *Readable* or *Drivable*. A *Readable* has at least the
|
||||
parameters *value* and *status*, a *Drivable* in addition *target*. *value* is the main value of the module
|
||||
and is read only. *status* is a tuple (status code, status text), and *target* is the target value.
|
||||
When the *target* parameter value of a *Drivable* changes, the status code changes normally to a busy code.
|
||||
As soon as the target value is reached, the status code changes back to an idle code, if no error occurs.
|
||||
|
||||
**Programmers Hint:** before starting to code, choose carefully the main SECoP modules you have to provide
|
||||
to the user.
|
||||
|
||||
|
||||
Tutorial Example
|
||||
----------------
|
||||
For this tutorial we choose as an example a cryostat with a LakeShore 336 temperature controller, a level
|
||||
meter and a motorized needle value. Let us start with the level meter, as this is the simplest module.
|
||||
|
||||
|
||||
Coding the HeLevel Driver
|
||||
-------------------------
|
||||
Coding the Driver
|
||||
-----------------
|
||||
For this tutorial we choose as an example a cryostat. Let us start with the helium level meter,
|
||||
as this is the simplest module.
|
||||
As mentioned in the introduction, we have to code the access to the hardware (driver), and the Frappy
|
||||
framework will deal with the SECoP interface. The code for the driver is located in a subdirectory
|
||||
named after the facility or institute programming the driver in our case *secop_psi*.
|
||||
@ -79,11 +25,12 @@ CCU4 luckily has a very simple and logical protocol:
|
||||
StringIO, HasIodev
|
||||
|
||||
|
||||
# the class used for communication
|
||||
class CCU4IO(StringIO):
|
||||
"""communication with CCU4"""
|
||||
# for completeness: (not needed, as it is the default)
|
||||
end_of_line = '\n'
|
||||
# on connect, we send 'cid' and expect a reply starting with 'CCU4'
|
||||
identification = [('cid', r'CCU4.*')]
|
||||
end_of_line = '\n'
|
||||
|
||||
|
||||
# inheriting the HasIodev mixin creates us the things needed for talking
|
||||
@ -108,7 +55,11 @@ CCU4 luckily has a very simple and logical protocol:
|
||||
assert name == 'h' # check that we got a reply to our command
|
||||
return txtvalue # the framework will automatically convert the string to a float
|
||||
|
||||
This is already a very simple working He Level meter driver. For a next step, we want to improve it:
|
||||
The class :class:`CCU4`, an extension of (:class:`secop.stringio.StringIO`) serves as
|
||||
communication class.
|
||||
|
||||
Above is already the code for a very simple working He Level meter driver. For a next step,
|
||||
we want to improve it:
|
||||
|
||||
* We should inform the client about errors. That is what the *status* parameter is for.
|
||||
* We want to be able to configure the He Level sensor.
|
||||
@ -254,3 +205,4 @@ the parameters *empty* and *full* from the client by defining:
|
||||
|
||||
However, we do not do this here, as it is nice to try out chaning parameters for a test!
|
||||
|
||||
**name** *(x)*
|
Reference in New Issue
Block a user