Skip to content

Instantly share code, notes, and snippets.

@erichiggins
Created June 28, 2022 07:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erichiggins/d808c7029d101ba728826d70e315d31b to your computer and use it in GitHub Desktop.
Save erichiggins/d808c7029d101ba728826d70e315d31b to your computer and use it in GitHub Desktop.
Boilerplate scale class for the Open Trickler. Fill out the sections labeled with TODOs.
class BasicScale:
"""Class for controlling a basic scale scale."""
# TODO(you): Update the default values, such as baudrate, to match your scale.
def __init__(self, memcache, port='/dev/ttyUSB0', baudrate=19200, timeout=0.1, _version=1, **kwargs):
"""Controller."""
self._memcache = memcache
self._serial = serial.Serial(port=port, baudrate=baudrate, timeout=timeout, **kwargs)
# Set default values, which should be overwritten quickly.
self.raw = b''
# TODO(you): Change this to match the default unit of measure of your scale.
self.unit = Units.GRAINS
# TODO(you): Change this to match the resolution of your scale.
self.resolution = decimal.Decimal(0.02)
# TODO(you): Change this to match the default weight & resolution of your scale given the default unit.
self.weight = decimal.Decimal('0.00')
atexit.register(self._graceful_exit)
def _graceful_exit(self):
"""Graceful exit, closes serial port."""
logging.debug('Closing serial port...')
self._serial.close()
def change_unit(self):
"""Changes the unit of weight on the scale."""
logging.debug('changing weight unit on scale from: %r', self.unit)
# TODO(you): Change this to match the command that you can send to your
# scale via serial connection that will change the unit of measure.
# If your scale doesn't have this capability, then you can just remove
# or comment out the self._serial.write line below. But, this could make
# things buggy. Just make sure you start on the settings you want and don't
# change the unit within the mobile app.
# Send Mode button command.
self._serial.write(b'U\r\n')
# Sleep 1s and wait for change to take effect.
time.sleep(1)
# Run update fn to set latest values.
self.update()
@property
def is_stable(self):
"""Returns True if the scale is stable, otherwise False."""
# TODO(you): Basic scales may not include a status. Change this to just return True.
return self.status == self.StatusMap.STABLE
def update(self):
"""Read from the serial port and update an instance of this class with the most recent values."""
# Note: The input buffer can fill up, causing latency. Clear it before reading.
self._serial.reset_input_buffer()
raw = self._serial.readline()
self.raw = raw
logging.debug(raw)
try:
line = raw.strip().decode('utf-8')
except UnicodeDecodeError:
logging.debug('Could not decode bytes to unicode.')
else:
self._stable_unstable(line)
def _stable_unstable(self, line):
"""Update the scale when status is stable or unstable."""
# TODO(you): Change this line to parse the weight value, with +/-.
weight = line[3:12].strip()
self.weight = decimal.Decimal(weight)
# TODO(you): Change this line to parse the unit of measure.
unit = line[12:15].strip()
self.unit = UNIT_MAP[unit]
resolution = {}
# TODO(you): Change these to match the resolutions for each unit your scale supports.
resolution[Units.GRAINS] = decimal.Decimal(0.02)
resolution[Units.GRAMS] = decimal.Decimal(0.001)
self.resolution = resolution[self.unit]
# Update memcache values.
self._memcache.set(constants.SCALE_STATUS, self.status)
self._memcache.set(constants.SCALE_WEIGHT, self.weight)
self._memcache.set(constants.SCALE_UNIT, self.unit)
self._memcache.set(constants.SCALE_RESOLUTION, self.resolution)
self._memcache.set(constants.SCALE_IS_STABLE, self.is_stable)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment