MSHPro
The MSHPro is low-cost hotplate stirrer.
The hotplate has a RS232 9-pin connector on the rear that allows control of its functions. This package is a tool for control of these hotplates via serial interface.
A interface to all commands is provided by the Hotplates.MSHPro
class.
Commands are avilable to get information and control the hotplate’s speed and temperature.
All the formal communication structure is described by
the Hotplates.MSHProCommunication
module.
Serial communication is full duplex and this is
acheived using Hotplates.SerialThreadedDuplex.Serial
, an
extension of PySerial’s serial.Serial
.
Example usage:
>>> import Hotplates
>>> hp = Hotplates.MSHPro(port="/dev/ttyUSB0")
>>> hp.status()
{'success': True, 'stir_set': 'Off', 'stir_actual': 0, 'heat_set': 'Off', 'heat_actual': 17.5, 'stir_on': False, 'heat_on': False, 'heat_limit': 340.0}
>>> hp.stir(400) # Wait after command for hotplate to reach speed
>>> hp.status()
{'success': True, 'stir_set': 400, 'stir_actual': 399, 'heat_set': 'Off', 'heat_actual': 17.7, 'stir_on': True, 'heat_on': False, 'heat_limit': 340.0}
>>> hp.off()
>>> hp.status()
{'success': True, 'stir_set': 'Off', 'stir_actual': 0, 'heat_set': 'Off', 'heat_actual': 1.1, 'stir_on': False, 'heat_on': False, 'heat_limit': 340.0}
Logging
Logging is implemented in MSHPro
.
The handler is logging.NullHandler
.
Communicated bytes
are logged at logging.DEBUG
level.
Commands are logged at logging.INFO
level.
The logger is available through: logger = logging.getLogger("Hotplates.MSHPro")
.
- class MSHPro(port: Optional[Union[int, str]] = None, timeout: float | int = 0.5)[source]
Serial communication with a MSHPro hotplate.
- SERIAL_SETTINGS = {'baudrate': 9600, 'bytesize': 8, 'dsrdtr': False, 'parity': 'N', 'rtscts': False, 'stopbits': 1, 'xonxoff': False}
Communications settings for the MSHPro hotplate.
- HEATLIMIT_MAX: float = 340.0
Maximum settable temperature (°C).
- HEATLIMIT_MIN: float = 25.0
Minimum settable temperature (°C).
- STIRLIMIT_MAX: int = 1500
Maximum settable stir speed (rpm).
- STIRLIMIT_MIN: int = 100
Minimum settable stir speed (rpm).
- __init__(port: Optional[Union[int, str]] = None, timeout: float | int = 0.5)[source]
Create a MSHPro object.
The serial settings of the hotplate are stored in
MSHPro.SERIAL_SETTINGS
.- Parameters:
port (Optional[Union[int, str]], optional) – Serial port name. If an integer is passed it will be converted to a serial port name depending on the current system using
SerialThreadedDuplex.port_parser()
The serial port will not be opened upon creation. Defaults to None.timeout (float | int, optional) – Set the timeout for serial read. Passed into
SerialThreadedDuplex.Serial
creation. Defaults to 0.5.
- property port: Any
Serial port name.
- ping() bool [source]
Send a ping command.
- Returns:
True
if hotplate is online and responding correctly.- Return type:
bool
- _status() Dict[str, Any] [source]
Get status of the hotplate: stir_set, stir_actual, heat_set, heat_actual. See
status()
.
- _info() Dict[str, Any] [source]
Get info from the hotplate: mode, stir_on, heat_on, heat_limit and heat_alarm. See
status()
.
- status(raw_values: bool = False) Dict[str, Any] [source]
Get hotplate status. See also
_status()
and_info()
for a subset of this data.- Dictionary keys:
“success” (bool):
True
if command received correctly.“stir_set” (int | “Off”): target speed (rpm) or “Off”. Set
raw _values
to beTrue
to view value when off instead of “Off”.“stir_actual” (int): measured speed (rpm).
“heat_set” (float | “Off”): target temperature (°C) or “Off”. Set
raw _values
to beTrue
to view value when off instead of “Off”.“heat_actual” (float): measured temperature (°C). N.B. The heat_actual reading is from an internal temperature sensor that doesn’t necesserily match the display value. If a temperature probe is attached then both the display and heat_actual reading is from the probe.
“stir_on” (bool):
True
if stirring.“heat_on” (bool):
True
if heating.“heat_limit” (float): maximum set temperature (°C).
“mode” ({“A”, “B”, “C”}): default is “A”. Undocumented. Possibly related to heat rate profile.
“heat_alarm”. Undocumented. Unknown. Only returned when
raw _values
isTrue
.
- Parameters:
raw_values – bool Default behaviour [
False
] is to convert values to more readable format, specifically related to set values when off and hiding unknown values. IfTrue
then the raw values fromCOMMUNICATION.parse_response()
are returned.- Returns:
Dictionary of hotplate information.
- Return type:
dict
- heat(val: float) None [source]
Control heating.
If
val
is not truthy, heating will be turned off. If an exception is encountered, heating will be turned off.- Parameters:
val (int) – Target temperature (1 decimal place float, rounded down, °C).
- Raises:
ValueError – If
val
can not be converted tofloat
or is outside permissable range.
- stir(val: int) None [source]
Control stirring.
If
val
is not truthy, stirring will be turned off.- Parameters:
val (int) – Target stir speed (integer, rpm).
- Raises:
ValueError – If
val
can not be converted toint
or is outside permissable range.
- mode(mode: str) None [source]
Set hotplate mode. Warning: undocumented feature.
- Parameters:
mode ({"A", "B", "C"}) – Choose mode A, B or C.
- text_command(cmd: str) Any [source]
Interpret a text command. The command is one of {“PING”, “STATUS”, “OFF”, “STIR”, “HEAT”, “MODE”}. Text is not case-sensitive. Each of these will be sent to the corresponding method. i.e. for {“HEAT”, “STIR” and “MODE”} a whitespace separated value will be used for setting.
Examples:
>>> hp = Hotplates.MSHPro(0) >>> hp.text_command("STATUS") >>> hp.text_command("HEAT OFF") >>> hp.text_command("MODE B") >>> hp.text_command("stir 560") >>> hp.text_command("PING") >>> hp.text_command("OFF")
MSHPro Communication
- class COMMUNICATION(value)[source]
Utilities for serial communication with a MSHPro hotplate. Contains all information about communication protocols, including functions for encoding and decoding.
Communications available with the hotplate:
COMMUNICATION.PING
Ping command to see if the hotplate is on and responding correctly.COMMUNICATION.INFO
Get info from the hotplate: mode, stir_on, heat_on, heat_limit and heat_alarm.COMMUNICATION.STATUS
Get status of the hotplate: stir_set, stir_actual, heat_set and heat_actual. N.B. The heat_actual reading is from an internal temperature sensor that doesn’t necesserily match the display value. If a temperature probe is attached then both the display and heat_actual reading is from the probe.COMMUNICATION.STIR
Set stirring speed (rpm). Useto_bytes()
withval = stir_set
(int). Sending speed toggles on or off.COMMUNICATION.HEAT
Set temperature (°C). Useto_bytes()
withval = heat_set
(1 decimal place float, rounded down). Sending set temperature toggles on or off.
Warning
Communication values below this, prefixed with a single underscore, are undocumented. Proceed with extreme caution!
COMMUNICATION._MODE
The hotplate default mode is “A”. This command toggles between [“A”, “B”, “C”] modes. The mode is beleived to be heating profiles, i.e. “A” will get to the target temperature fastest but may overshoot, “C” will try to avoid overshooting; and “B” is a balance between the two.
Example usage:
>>> import Hotplates.MSHProCommunication >>> comm = Hotplates.MSHProCommunication.COMMUNICATION.PING >>> comm.to_bytes() b'\xfe\xa0\x00\x00\x00\xa0' >>> comm.len_rx 6
- property len_rx: int
Length of expected response.
- to_bytes(val: Optional[Any] = None) bytes [source]
Generate
bytes
for transmission to hotplate.- Parameters:
val (int | float, optional) – Value for setting where appropriate (i.e.
COMMUNICATION.STIR
,COMMUNICATION.HEAT
).- Returns:
bytes for transmission.
- Return type:
bytes
- Raises:
ValueError – When
val
is incorectly formatted or outside of allowed range.
- parse_response(b: bytes) Dict[str, Any] [source]
Process
bytes
received from serial communication with hotplate.- Parameters:
b (bytes) –
bytes
for decoding.- Returns:
Parsed reponses. All responses have a key
"success": bool
that represents the overall outcome.INFO
andSTATUS
responses have keys referencing data as described above.- Return type:
dict[str, Any]
- Raises:
IncompleteResponseException – on communications timeout.
ResponseFormatException – on error with checksum or control bytes.
HotplateException – if an error is sent from the hotplate.
ResponseParseException – if there was a problem parsing data.
SerialThreadedDuplex
- class Serial(*args: Any, **kwargs: Any)[source]
Extending PySerial
serial.Serial
to include full duplex commuication usingthreading.Thread
.Example usage:
>>> import Hotplates.SerialThreadedDuplex >>> s = Hotplates.SerialThreadedDuplex.Serial(port="/dev/ttyUSB0", timeout=1.0) >>> s.write_with_read_until(b"Hello!", expected="\n") >>> s.value # received bytes
- __init__(*args: Any, **kwargs: Any) None [source]
All paramaters are passed to PySerial’s
serial.Serial
.
- write_with_read_until(data: bytes, *, expected: str = '\n', size: Optional[int] = None) bytes [source]
Write data to the serial port using
serial.Serial.write()
while reading withserial.Serial.read_until()
.- Parameters:
data (bytes) –
data
forserial.Serial.write()
.expected (str, optional) –
expected
forserial.Serial.read_until()
. Defaults to “\n”.size (int, optional) –
size
forserial.Serial.read_until()
. Defaults toNone
.
- Returns:
received bytes. Also accessable using the
value
property.- Return type:
bytes
- write_with_read(data: bytes, size: int = 1) bytes [source]
Write data to the serial port using
serial.Serial.write()
while reading withserial.Serial.read()
.- Parameters:
data (bytes) – data for
serial.Serial.write()
.size (int, optional) –
size
forserial.Serial.read()
.
- Returns:
received bytes. Also accessable using the
value
property.- Return type:
bytes
- property value: bytes
Most recent received value.
- Raises:
Exception – If an exception was raised during operation. See
exception()
.ReadingNotCompleteException – If the read thread is still active.
NoCommunicationException – If communication was not attempted before reading value.
NoDataException – If there is no data, i.e. device timeout.
- Returns:
received value.
- Return type:
bytes
- port_parser(port: int | str, check_exists: bool = True) str [source]
Parses serial port information.
If an
int
is passed then a formattedstr
of COM{} or \dev\ttyUSB{} will be generated.If
check_exists
isTrue
the an exception will be raised if the port can not be found.- Parameters:
port (int | str) – port name for parsing.
check_exists (bool, optional) – Check if port exists. Defaults to
True
.
- Raises:
PortNotFoundException – If the port is not found.
- Returns:
parsed port name.
- Return type:
str