Source code for PyLabware.devices.mt_ms3002s

"""PyLabware driver for Mettler Toledo MS3002S balance."""

from typing import Optional, Union
import serial

# Core imports
from .. import parsers as parser
from ..controllers import LabDevice, in_simulation_device_returns
from ..exceptions import PLConnectionError, PLDeviceCommandError
from ..models import LabDeviceCommands, ConnectionParameters


[docs] class MS3002SBalanceCommands(LabDeviceCommands): """Collection of command definitions for Mettler Toledo MS3002S balances. """ # ########################## Constants ################################## # Default reply to GET_TYPE command DEFAULT_TYPE = "MS3002S/01" # Maximum allowed weight, in grams MAX_WEIGHT = 3200 # ################### Control commands ################################### # Get list of commands GET_CMD_LIST = {"name": "I0", "reply":{"type": str, "parser": str.split, "args":[" "]}} # Get command interface level and version GET_CMD_VER = {"name": "I1", "reply":{"type": str, "parser": str.split, "args":[" "]}} # Get balance info string GET_INFO = {"name": "I2", "reply":{"type": str, "parser": str.split, "args":[" "]}} # Get software version GET_SW_VER = {"name": "I3", "reply":{"type": str, "parser": str.split, "args":[" "]}} # Get serial number GET_SER_NUM = {"name": "I4", "reply":{"type": str, "parser": str.split, "args":[" "]}} # Get software id number GET_SW_ID = {"name": "I5", "reply":{"type": str, "parser": str.split, "args":[" "]}} # Get individual unit id string GET_ID = {"name": "I10", "reply":{"type": str, "parser": str.split, "args":[" "]}} # Get balance type/model GET_NAME = {"name": "I11", "reply":{"type": str, "parser": str.split, "args":[" "]}} # Set tare weight SET_TARE = {"name": "T", "reply":{"type": str}} # Set tare weight immediately SET_TARE_IMMEDIATE = {"name": "TI", "reply":{"type": str}} # Get tare weight/ set tare weight to a specified value GET_TARE = {"name": "TA", "reply":{"type": float, "parser": parser.splitter, "args":[" ", -2, -1]}} # Clear tare weight CLEAR_TARE = {"name": "TAC", "reply":{"type": str}} # Zero weight ZERO = {"name": "Z", "reply":{"type": str}} # Zero weight immediately ZERO_IMMEDIATE = {"name": "ZI", "reply":{"type": str}} # Get stable weight GET_WEIGHT = {"name": "S", "reply":{"type": float, "parser": parser.splitter, "args":[" ", -2, -1]}} # Get weight immediately GET_WEIGHT_IMMEDIATE = {"name": "SI", "reply":{"type": float, "parser": parser.splitter, "args":[" ", -2, -1]}} # Get stable weight with unit GET_WEIGHT_UNIT = {"name": "SU", "reply":{"type": str, "parser": parser.splitter, "args":[" ", -2, -1]}} # Get weight immediately GET_WEIGHT_UNIT_IMMEDIATE = {"name": "SIU", "reply":{"type": str, "parser": parser.splitter, "args":[" ", -2, -1]}} # ################### Configuration commands ############################# # Reset device RESET = {"name": "@", "reply": {"type": str}}
[docs] class MS3002SBalance(LabDevice): """ This provides a Python class for the Mettler Toledo MS3002S balance based on the original operation manual 11781259 0309/2.12. """ def __init__(self, device_name: str, connection_mode: str, address: Optional[str], port: Union[str, int]): """Default constructor """ # Load commands from helper class self.cmd = MS3002SBalanceCommands # Connection settings connection_parameters: ConnectionParameters = {} connection_parameters["port"] = port connection_parameters["address"] = address connection_parameters["baudrate"] = 9600 connection_parameters["bytesize"] = serial.EIGHTBITS connection_parameters["parity"] = serial.PARITY_NONE super().__init__(device_name, connection_mode, connection_parameters) # Protocol settings self.command_terminator = "\r\n" self.reply_terminator = "\r\n" self.args_delimiter = " "
[docs] def initialize_device(self): """Issue reset command. """ self.send(self.cmd.RESET) self.logger.info("Device initialized.")
[docs] @in_simulation_device_returns([MS3002SBalanceCommands.DEFAULT_TYPE]) def is_connected(self) -> bool: """ Check if the device is connected via GET_NAME command. """ try: reply = self.send(self.cmd.GET_NAME) except PLConnectionError: return False reply = reply[-1] return self.cmd.DEFAULT_TYPE in reply
# TODO Maybe put power on/off in start/stop ?
[docs] def start(self): """Not supported on this device. """
[docs] def stop(self) -> bool: """Not supported on this device. """
[docs] def is_idle(self) -> bool: """Not supported on this device. """ return self.is_connected()
[docs] def get_status(self): """Not supported on this device. """
[docs] def check_errors(self): """Not supported on this device. """
[docs] def clear_errors(self): """Not supported on this device. """
[docs] def set_tare(self, weight:float = None): """Sets tare weight to the currently measured or the specified value Args: weight (float, optional): Desired tare weight. Defaults to None. """ if weight is not None: # FIXME can be checked later in check_value when f-strings are supported if (weight < 0 or weight > self.cmd.MAX_WEIGHT): raise PLDeviceCommandError(f"Illegal tare weight {weight} (min - 0 max - {self.cmd.MAX_WEIGHT})") self.send(self.cmd.GET_TARE, f"{weight} g") else: self.send(self.cmd.SET_TARE)
[docs] def get_tare_weight(self) -> float: """Gets currently stored tare weight Returns: float: tare weight in grams """ return self.send(self.cmd.GET_TARE)
[docs] def clear_tare_weight(self): """Clears currently stored tare weight """ self.send(self.cmd.CLEAR_TARE)
[docs] def zero_weight(self, stabilize=True): """Zeros current balance reading. Args: stabilize (bool, optional): Whether to wait for the reading to stabilize. Defaults to True. """ if stabilize is True: self.send(self.cmd.ZERO) else: self.send(self.cmd.ZERO_IMMEDIATE)
[docs] @in_simulation_device_returns(42) def get_weight(self, stabilize=True) -> float: """Gets current weight reading. Args: stabilize (bool, optional): Whether to wait for the reading to stabilize. Defaults to True. Returns: float: current weight reading. """ if stabilize is True: return self.send(self.cmd.GET_WEIGHT) else: return self.send(self.cmd.GET_WEIGHT_IMMEDIATE)