Skip to content

Commit 0104bf9

Browse files
committed
- adds recognition of acaia ISP
- end weight source, estimate by scheduler vs measured, is remembered and persisted with each roast - lib updates
1 parent 316fdf1 commit 0104bf9

14 files changed

Lines changed: 498 additions & 270 deletions

File tree

src/artisanlib/acaia.py

Lines changed: 202 additions & 117 deletions
Large diffs are not rendered by default.

src/artisanlib/async_comm.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,11 @@ async def handle_writes(self, writer: asyncio.StreamWriter, queue: 'asyncio.Queu
392392
# if serial settings are given, the host/port settings are ignored and communication is handled by the given serial port
393393
async def connect(self, connect_timeout:float=5) -> None:
394394
writer:asyncio.StreamWriter|None = None
395+
was_connected:bool = False # set by successful connection and used to report ONE disconnect message
395396
while self._running:
396397
try:
397398
if self._serial is not None:
398-
_log.debug('connecting to serial port: %s ...', self._serial['port'])
399+
# _log.debug('connecting to serial port: %s ...', self._serial['port'])
399400
connect = self.open_serial_connection(
400401
url = self._serial['port'],
401402
baudrate = self._serial['baudrate'],
@@ -415,6 +416,7 @@ async def connect(self, connect_timeout:float=5) -> None:
415416
read_handler = asyncio.create_task(self.handle_reads(reader))
416417
self._ACK_received = asyncio.Event()
417418
_log.debug('connected')
419+
was_connected = True
418420
if self._connected_handler is not None:
419421
try:
420422
self._connected_handler()
@@ -441,14 +443,15 @@ async def connect(self, connect_timeout:float=5) -> None:
441443

442444
except TimeoutError:
443445
_log.debug('connection timeout')
444-
except SerialException as e:
445-
_log.debug('serial exception: %s',e)
446+
except SerialException:
447+
#_log.debug('serial exception: %s',e)
448+
pass
446449
except Exception as e: # pylint: disable=broad-except
447450
_log.error(e)
448451
finally:
449452
self._ACK_received = None
450453
self.reset_readings()
451-
if self._disconnected_handler is not None:
454+
if was_connected and self._disconnected_handler is not None:
452455
try:
453456
self._disconnected_handler()
454457
except Exception as e: # pylint: disable=broad-except
@@ -461,7 +464,7 @@ async def connect(self, connect_timeout:float=5) -> None:
461464
_log.debug('serial exception: %s',e)
462465
except Exception as e: # pylint: disable=broad-except
463466
_log.error(e)
464-
await asyncio.sleep(0.5)
467+
await asyncio.sleep(1)
465468

466469
def send(self, message:bytes) -> None:
467470
if self._asyncLoopThread is not None and self._write_queue is not None:

src/artisanlib/atypes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class ProfileData(TypedDict, total=False):
155155
plus_blend_spec_labels: list[str]
156156
beans: str
157157
weight: list[float|str] # NOTE: internally weight is a typed tuple
158+
end_weight_est: int
158159
volume: list[float|str] # NOTE: internally volume is a typed tuple
159160
density: list[float|str] # NOTE: internally density is a typed tuple
160161
density_roasted: list[float|str] # NOTE: internally density_roasted is a typed tuple

src/artisanlib/canvas.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ class tgraphcanvas(QObject):
303303
'patheffects', 'graphstyle', 'graphfont', 'buttonvisibility', 'buttonactions', 'buttonactionstrings', 'extrabuttonactions', 'extrabuttonactionstrings',
304304
'xextrabuttonactions', 'xextrabuttonactionstrings', 'chargeTimerFlag', 'autoChargeFlag', 'autoDropFlag', 'autoChargeMode', 'autoDropMode', 'autoChargeIdx', 'autoDropIdx', 'markTPflag',
305305
'autoDRYflag', 'autoFCsFlag', 'autoCHARGEenabled', 'autoDRYenabled', 'autoFCsenabled', 'autoDROPenabled', 'projectionconstant',
306-
'projectionmode', 'transMappingMode', 'weight', 'roasted_defects_weight', 'volume', 'density', 'roasted_defects_mode', 'density_roasted', 'volumeCalcUnit', 'volumeCalcWeightInStr',
306+
'projectionmode', 'transMappingMode', 'weight', 'end_weight_est', 'roasted_defects_weight', 'volume', 'density', 'roasted_defects_mode', 'density_roasted', 'volumeCalcUnit', 'volumeCalcWeightInStr',
307307
'volumeCalcWeightOutStr', 'container_names', 'container_weights', 'specialevents', 'etypes', 'etypesdefault',
308308
'alt_etypesdefault', 'default_etypes_set', 'specialeventstype',
309309
'specialeventsStrings', 'specialeventsvalue', 'eventsGraphflag', 'clampEvents', 'renderEventsDescr', 'eventslabelschars', 'eventsshowflag',
@@ -1746,6 +1746,7 @@ def __init__(self, parent:QWidget, dpi:int, locale:str, aw:'ApplicationWindow')
17461746

17471747
#[0]weight in, [1]weight out, [2]units (string)
17481748
self.weight:tuple[float,float,str] = (0, 0, weight_units[1])
1749+
self.end_weight_est:int = 0 # 1: weight out in self.weight[1] is an estimate an not measured or manuel set; 0: otherwise
17491750

17501751
self.roasted_defects_weight:float = 0.0 # weight of defects sorted from roasted weight in unit self.weight[2] (should always be positive and less than self.weight[1])
17511752

@@ -1762,7 +1763,7 @@ def __init__(self, parent:QWidget, dpi:int, locale:str, aw:'ApplicationWindow')
17621763

17631764

17641765
if platform.system() == 'Darwin':
1765-
# try to "guess" the users preferred temperature unit
1766+
# try to "guess" the users preferred weight unit
17661767
try:
17671768
if not QSettings().value('AppleMetricUnits'):
17681769
self.weight = (0, 0, weight_units[2])
@@ -8056,6 +8057,8 @@ def reset(self,redraw:bool = True, soundOn:bool = True, keepProperties:bool = Fa
80568057
self.aw.recording_revision = str(__revision__)
80578058
self.aw.recording_build = str(__build__)
80588059

8060+
self.end_weight_est = 0
8061+
80598062
# if we are in KeepON mode, the reset triggered by ON should respect the roastpropertiesflag ("Delete Properties on Reset")
80608063
if self.roastpropertiesflag and (self.flagKeepON or not keepProperties):
80618064
self.title = QApplication.translate('Scope Title', 'Roaster Scope')
@@ -8306,7 +8309,6 @@ def reset(self,redraw:bool = True, soundOn:bool = True, keepProperties:bool = Fa
83068309

83078310
self.aw.updatePlusStatus()
83088311

8309-
self.aw.set_ui_mode(self.aw.ui_mode)
83108312
self.aw.announce_current_ui_mode()
83118313

83128314
### REDRAW ##

src/artisanlib/main.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5619,6 +5619,7 @@ def setRecentRoast(self, rr:'RecentRoast') -> None:
56195619
if not self.qmc.flagstart or self.qmc.title_show_always:
56205620
self.qmc.setProfileTitle(self.qmc.title,updatebackground=True)
56215621
self.qmc.weight = (rr['weightIn'],self.qmc.weight[1],rr['weightUnit'])
5622+
self.qmc.end_weight_est = 0
56225623
if 'weightOut' in rr:
56235624
self.qmc.weight = (self.qmc.weight[0],rr['weightOut'],rr['weightUnit'])
56245625
else:
@@ -6079,6 +6080,7 @@ def openMachineSettings(self, _checked:bool = False) -> None:
60796080
weight_unit = self.qmc.weight[2]
60806081
self.qmc.last_batchsize = convertWeight(self.qmc.roastersize_setup,1,0) # nominal batch size in g
60816082
nominal_batch_size = convertWeight(self.qmc.roastersize_setup,1,weight_units.index(weight_unit))
6083+
self.qmc.end_weight_est = 0
60826084
self.qmc.weight = (nominal_batch_size,0,weight_unit)
60836085
# size set, ask for heating
60846086
resi:int|None
@@ -6162,6 +6164,7 @@ def openMachineSettings(self, _checked:bool = False) -> None:
61626164
self.sendmessage(QApplication.translate('Message','Action canceled'))
61636165
else:
61646166
# setup not canceled, we establish the last_batchsize
6167+
self.qmc.end_weight_est = 0
61656168
self.qmc.weight = (convertWeight(self.qmc.last_batchsize,0,weight_units.index(self.qmc.weight[2])),0,self.qmc.weight[2])
61666169
self.establish_etypes()
61676170
self.qmc.redraw(False,False)
@@ -7638,7 +7641,7 @@ def curveSimilarity(self) -> tuple[float|None, float|None]: # pylint: disable=no
76387641
try:
76397642
# we masked the -1 error values
76407643
np_etb_masked = numpy.ma.masked_equal(np_etb, -1)
7641-
np_timeB_etb_masked = numpy.ma.masked_array(np_timeB, np_etb_masked.mask) # type:ignore[operator,unused-ignore] # ty:ignore[call-non-callable] # pylint:disable=no-member
7644+
np_timeB_etb_masked = numpy.ma.masked_array(np_timeB, np_etb_masked.mask) # type:ignore[operator,unused-ignore] # pylint:disable=no-member
76427645
# ignore the masked error values on computing the interpolation and fill (especially on the left) with -1 values
76437646
interp_np_etb = numpy.interp(np_timex,np_timeB_etb_masked.compressed(),np_etb_masked.compressed(),left=-1,right=-1) # pyright:ignore[reportUnknownArgumentType] # pylint:disable=no-member
76447647

@@ -7663,7 +7666,7 @@ def curveSimilarity(self) -> tuple[float|None, float|None]: # pylint: disable=no
76637666
try:
76647667
# we masked the -1 error values
76657668
np_btb_masked = numpy.ma.masked_equal(np_btb, -1)
7666-
np_timeB_btb_masked = numpy.ma.masked_array(np_timeB, np_btb_masked.mask) # type:ignore[operator,unused-ignore] # ty:ignore[call-non-callable] # pylint:disable=no-member
7669+
np_timeB_btb_masked = numpy.ma.masked_array(np_timeB, np_btb_masked.mask) # type:ignore[operator,unused-ignore] # pylint:disable=no-member
76677670
# ignore the masked error values on computing the interpolation and fill (especially on the left) with -1 values
76687671
interp_np_btb = numpy.interp(np_timex,np_timeB_btb_masked.compressed(),np_btb_masked.compressed(),left=-1,right=-1) # pyright:ignore[reportUnknownArgumentType] # pylint:disable=no-member
76697672

@@ -14529,6 +14532,7 @@ def loadbackground(self, filename:str, quiet:bool = True) -> None: # pyright: ig
1452914532
# - scheduler is not active
1453014533
if self.qmc.setBatchSizeFromBackground and (self.qmc.flagon or not self.curFile) and self.schedule_window is None:
1453114534
self.qmc.weight = (profile['weight'][0],self.qmc.weight[1],profile['weight'][2])
14535+
self.qmc.end_weight_est = 1 # this weight out is an estimate as it was not measure nor manual set
1453214536

1453314537

1453414538
message = QApplication.translate('Message', 'Background {0} loaded successfully {1}').format(filename, '')
@@ -16001,8 +16005,10 @@ def setProfile(self, filename:str|None, profile:'ProfileData', quiet:bool = Fals
1600116005
convertWeight(float(weight[0]), weight_unit_idx, current_weight_unit_idx),
1600216006
convertWeight(float(weight[1]), weight_unit_idx, current_weight_unit_idx),
1600316007
self.qmc.weight[2])
16008+
self.qmc.end_weight_est = profile.get('end_weight_est', 0)
1600416009
else:
1600516010
self.qmc.weight = (0., 0., self.qmc.weight[2])
16011+
self.qmc.end_weight_est = 0
1600616012
#
1600716013
if 'defects_weight' in profile:
1600816014
defects = profile['defects_weight']
@@ -17028,6 +17034,7 @@ def getProfile(self) -> 'ProfileData':
1702817034

1702917035
profile['beans'] = encodeLocalStrict(self.qmc.beans)
1703017036
profile['weight'] = [self.qmc.weight[0],self.qmc.weight[1],encodeLocalStrict(self.qmc.weight[2], 'g')]
17037+
profile['end_weight_est'] = self.qmc.end_weight_est
1703117038
profile['defects_weight'] = self.qmc.roasted_defects_weight
1703217039
profile['volume'] = [self.qmc.volume[0],self.qmc.volume[1],encodeLocalStrict(self.qmc.volume[2], 'l')]
1703317040
profile['density'] = [self.qmc.density[0],encodeLocalStrict(self.qmc.density[1], 'g'),self.qmc.density[2],encodeLocalStrict(self.qmc.density[3], 'l')]
@@ -18437,6 +18444,7 @@ def settingsLoad(self, filename:str|None = None, theme:bool = False, machine:boo
1843718444
self.qmc.AUCshowFlag = toBool(settings.value('AUCshowFlag',self.qmc.AUCshowFlag))
1843818445
self.keyboardmoveflag = toInt(settings.value('keyboardmoveflag',int(self.keyboardmoveflag)))
1843918446
self.ui_mode = UI_MODE(toInt(settings.value('UI_mode',int(self.ui_mode))))
18447+
self.set_ui_mode(self.ui_mode)
1844018448
self.qmc.ambientTempSource = toInt(settings.value('AmbientTempSource',int(self.qmc.ambientTempSource)))
1844118449
self.qmc.ambientHumiditySource = toInt(settings.value('AmbientHumiditySource',int(self.qmc.ambientHumiditySource)))
1844218450
self.qmc.ambientPressureSource = toInt(settings.value('AmbientPressureSource',int(self.qmc.ambientPressureSource)))

0 commit comments

Comments
 (0)