Skip to content

Commit 81e4413

Browse files
committed
makes synchronization of main events with Kaleido and Santoker roasting machines configurable (disabled by default)
1 parent bde0400 commit 81e4413

7 files changed

Lines changed: 101 additions & 34 deletions

File tree

src/artisanlib/canvas.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13118,11 +13118,11 @@ def OnMonitor(self) -> None:
1311813118
disconnected_handler=lambda : self.aw.sendmessageSignal.emit(QApplication.translate('Message', '{} disconnected').format('Santoker'),True,None),
1311913119
# CHARGE handler disactivated to not trigger CHARGE after CHARGE is signalled to the machine by START
1312013120
# NOTE: only after CHARGE the heater
13121-
# charge_handler=lambda : (self.markChargeDelaySignal.emit(0) if (self.timeindex[0] == -1) else None),
13122-
dry_handler=lambda : (self.markDRYSignal.emit(False) if (self.timeindex[1] == 0) else None),
13123-
fcs_handler=lambda : (self.markFCsSignal.emit(False) if (self.timeindex[2] == 0) else None),
13124-
scs_handler=lambda : (self.markSCsSignal.emit(False) if (self.timeindex[4] == 0) else None),
13125-
drop_handler=lambda : (self.markDropSignal.emit(False) if (self.timeindex[6] == 0) else None))
13121+
charge_handler=lambda : (self.markChargeDelaySignal.emit(0) if (len(self.aw.santokerEventFlags)>0 and self.aw.santokerEventFlags[0] and self.timeindex[0] == -1) else None),
13122+
dry_handler=lambda : (self.markDRYSignal.emit(False) if (len(self.aw.santokerEventFlags)>1 and self.aw.santokerEventFlags[1] and self.timeindex[1] == 0) else None),
13123+
fcs_handler=lambda : (self.markFCsSignal.emit(False) if (len(self.aw.santokerEventFlags)>2 and self.aw.santokerEventFlags[2] and self.timeindex[2] == 0) else None),
13124+
scs_handler=lambda : (self.markSCsSignal.emit(False) if (len(self.aw.santokerEventFlags)>4 and self.aw.santokerEventFlags[4] and self.timeindex[4] == 0) else None),
13125+
drop_handler=lambda : (self.markDropSignal.emit(False) if (len(self.aw.santokerEventFlags)>6 and self.aw.santokerEventFlags[6] and self.timeindex[6] == 0) else None))
1312613126
self.aw.santoker.setLogging(self.device_logging)
1312713127
self.aw.santoker.start()
1312813128
elif self.device == 171:

src/artisanlib/comm.py

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,34 +1827,37 @@ def Kaleido_BTET(self) -> Tuple[float,float,float]:
18271827
if self.aw.kaleido is not None:
18281828
t1, t2, _sid = self.aw.kaleido.getBTET()
18291829
# it remains unclear what those machine exactly report and when. In some cases processingn this event flag can lead to unfavorable situations so we do not process them at all
1830-
# try:
1831-
# event_flag:int = _sid & 15 # last 4 bits of the sid
1832-
# if event_flag == 1 and self.aw.qmc.timeindex[0] == -1:
1833-
# self.aw.qmc.markChargeSignal.emit(True) # CHARGE
1830+
# now the syncing of those event flags can be user configurable and is by default OFF
1831+
try:
1832+
event_flag:int = _sid & 15 # last 4 bits of the sid
1833+
if len(self.aw.kaleidoEventFlags)>0 and self.aw.kaleidoEventFlags[0] and event_flag == 1 and self.aw.qmc.timeindex[0] == -1:
1834+
self.aw.qmc.markChargeSignal.emit(True) # CHARGE
18341835
# elif event_flag == 2 and self.aw.qmc.TPalarmtimeindex is None:
18351836
# self.aw.qmc.markTPSignal.emit() # TP
1836-
# elif event_flag == 3 and self.aw.qmc.timeindex[1] == 0:
1837-
# self.aw.qmc.markDRYSignal.emit(True) # DRY
1838-
# elif event_flag == 4 and self.aw.qmc.timeindex[2] == 0:
1839-
# self.aw.qmc.markFCsSignal.emit(True) # FCs
1840-
# elif event_flag == 5 and self.aw.qmc.timeindex[3] == 0:
1841-
# self.aw.qmc.markFCeSignal.emit(True) # FCe
1842-
# elif event_flag == 6 and self.aw.qmc.timeindex[4] == 0:
1843-
# self.aw.qmc.markSCsSignal.emit(True) # SCs
1844-
# elif event_flag == 7 and self.aw.qmc.timeindex[5] == 0:
1845-
# self.aw.qmc.markSCeSignal.emit(True) # SCe
1846-
# elif (event_flag == 8 and self.aw.qmc.timeindex[6] == 0 and
1847-
# self.aw.qmc.timeindex[0] > -1 and self.aw.qmc.autoDropIdx == 0 and
1848-
# (self.aw.qmc.timex[-1] - self.aw.qmc.timex[self.aw.qmc.timeindex[0]]) > 7*60):
1849-
# # only after 7min into the roast and if CHARGE is marked
1850-
# self.aw.qmc.autoDropIdx = len(self.aw.qmc.timex) - 2
1851-
# self.aw.qmc.markDropSignal.emit(True) # DROP
1837+
elif len(self.aw.kaleidoEventFlags)>1 and self.aw.kaleidoEventFlags[1] and event_flag == 3 and self.aw.qmc.timeindex[1] == 0:
1838+
self.aw.qmc.markDRYSignal.emit(True) # DRY
1839+
elif len(self.aw.kaleidoEventFlags)>2 and self.aw.kaleidoEventFlags[2] and event_flag == 4 and self.aw.qmc.timeindex[2] == 0:
1840+
self.aw.qmc.markFCsSignal.emit(True) # FCs
1841+
elif len(self.aw.kaleidoEventFlags)>3 and self.aw.kaleidoEventFlags[3] and event_flag == 5 and self.aw.qmc.timeindex[3] == 0:
1842+
self.aw.qmc.markFCeSignal.emit(True) # FCe
1843+
elif len(self.aw.kaleidoEventFlags)>4 and self.aw.kaleidoEventFlags[4] and event_flag == 6 and self.aw.qmc.timeindex[4] == 0:
1844+
self.aw.qmc.markSCsSignal.emit(True) # SCs
1845+
elif len(self.aw.kaleidoEventFlags)>5 and self.aw.kaleidoEventFlags[5] and event_flag == 7 and self.aw.qmc.timeindex[5] == 0:
1846+
self.aw.qmc.markSCeSignal.emit(True) # SCe
1847+
elif len(self.aw.kaleidoEventFlags)>6 and self.aw.kaleidoEventFlags[6] and (event_flag == 8 and self.aw.qmc.timeindex[6] == 0 and
1848+
self.aw.qmc.timeindex[0] > -1 and self.aw.qmc.autoDropIdx == 0 and
1849+
(self.aw.qmc.timex[-1] - self.aw.qmc.timex[self.aw.qmc.timeindex[0]]) > 7*60):
1850+
# only after 7min into the roast and if CHARGE is marked
1851+
self.aw.qmc.autoDropIdx = len(self.aw.qmc.timex) - 2
1852+
self.aw.qmc.markDropSignal.emit(True) # DROP
18521853
# elif event_flag == 9 and self.aw.qmc.timeindex[7] == 0:
18531854
# self.aw.qmc.markCoolSignal.emit(True) # COOL
1854-
# except Exception as e: # pylint: disable=broad-except
1855-
# _log.error(e)
1855+
except Exception as e: # pylint: disable=broad-except
1856+
_log.error(e)
18561857
return tx,t2,t1 # time, ET (chan2), BT (chan1)
18571858

1859+
1860+
18581861
def Kaleido_SVAT(self) -> Tuple[float,float,float]:
18591862
tx = self.aw.qmc.timeclock.elapsedMilli()
18601863
if self.aw.kaleido is not None:

src/artisanlib/devices.py

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,24 @@ def __init__(self, parent:QWidget, aw:'ApplicationWindow', activeTab:int = 0) ->
11501150
self.santokerPort.setValidator(QIntValidator(1, 65535,self.santokerPort))
11511151
self.santokerPort.setEnabled(not self.aw.santokerSerial)
11521152

1153+
eventFlagLabels = [
1154+
QApplication.translate('Label','CHARGE'),
1155+
QApplication.translate('Label','DRY'),
1156+
QApplication.translate('Label','FCs'),
1157+
QApplication.translate('Label','FCe'),
1158+
QApplication.translate('Label','SCs'),
1159+
QApplication.translate('Label','SCe'),
1160+
QApplication.translate('Label','DROP')
1161+
]
1162+
self.santokerEventFlags:List[QCheckBox] = [QCheckBox(l) for l in eventFlagLabels]
1163+
self.santokerEventFlags[3].setEnabled(False) # not available
1164+
self.santokerEventFlags[5].setEnabled(False) # not available
1165+
for i, cb in enumerate(self.santokerEventFlags):
1166+
cb.setToolTip(QApplication.translate('Tooltip','Receive {} event from machine').format(cb.text()))
1167+
if len(self.aw.santokerEventFlags) > i:
1168+
cb.setChecked(self.aw.santokerEventFlags[i])
1169+
1170+
11531171
self.santokerSerialFlag = QCheckBox(QApplication.translate('Label','Serial'))
11541172
self.santokerSerialFlag.setChecked(self.aw.santokerSerial and not self.aw.santokerBLE)
11551173
self.santokerSerialFlag.stateChanged.connect(self.santokerSerialStateChanged)
@@ -1187,6 +1205,12 @@ def __init__(self, parent:QWidget, aw:'ApplicationWindow', activeTab:int = 0) ->
11871205
# self.kaleidoPIDFlag = QCheckBox()
11881206
# self.kaleidoPIDFlag.setChecked(self.aw.kaleidoPID)
11891207

1208+
self.kaleidoEventFlags:List[QCheckBox] = [QCheckBox(l) for l in eventFlagLabels]
1209+
for i, cb in enumerate(self.kaleidoEventFlags):
1210+
cb.setToolTip(QApplication.translate('Tooltip','Receive {} event from machine').format(cb.text()))
1211+
if len(self.aw.kaleidoEventFlags) > i:
1212+
cb.setChecked(self.aw.kaleidoEventFlags[i])
1213+
11901214
mugmaHostLabel = QLabel(QApplication.translate('Label','Host'))
11911215
self.mugmaHost = QLineEdit(self.aw.mugmaHost)
11921216
self.mugmaHost.setAlignment(Qt.AlignmentFlag.AlignRight)
@@ -1226,12 +1250,25 @@ def __init__(self, parent:QWidget, aw:'ApplicationWindow', activeTab:int = 0) ->
12261250
santokerHBox.addStretch()
12271251
santokerHBox.addLayout(santokerNetworkGrid)
12281252
santokerHBox.addStretch()
1253+
1254+
santokerEventFlagHBox = QHBoxLayout()
1255+
santokerEventFlagHBox.setSpacing(17)
1256+
santokerEventFlagHBox.addStretch()
1257+
santokerSerialHBox.addSpacing(20)
1258+
for cb in self.santokerEventFlags:
1259+
santokerEventFlagHBox.addWidget(cb)
1260+
santokerSerialHBox.addSpacing(20)
1261+
santokerEventFlagHBox.addStretch()
1262+
12291263
santokerVBox = QVBoxLayout()
12301264
santokerVBox.addLayout(santokerSerialHBox)
1265+
santokerVBox.addSpacing(15)
12311266
santokerVBox.addLayout(santokerHBox)
1267+
santokerVBox.addSpacing(15)
1268+
santokerVBox.addLayout(santokerEventFlagHBox)
12321269
santokerVBox.addStretch()
12331270
santokerVBox.setSpacing(5)
1234-
santokerVBox.setContentsMargins(0,0,0,0)
1271+
santokerVBox.setContentsMargins(7,5,7,5) # left, top, right, bottom
12351272

12361273
santokerNetworkGroupBox = QGroupBox('Santoker')
12371274
santokerNetworkGroupBox.setLayout(santokerVBox)
@@ -1245,16 +1282,30 @@ def __init__(self, parent:QWidget, aw:'ApplicationWindow', activeTab:int = 0) ->
12451282
# kaleidoNetworkGrid.addWidget(self.kaleidoPIDFlag,2,0)
12461283
# kaleidoNetworkGrid.addWidget(kaleidoPIDLabel,2,1)
12471284
kaleidoNetworkGrid.setSpacing(20)
1248-
kaleidoNetworkGroupBox = QGroupBox('Kaleido')
1249-
kaleidoNetworkGroupBox.setLayout(kaleidoNetworkGrid)
12501285
kaleidoHBox = QHBoxLayout()
1251-
kaleidoHBox.addWidget(kaleidoNetworkGroupBox)
1286+
kaleidoHBox.addLayout(kaleidoNetworkGrid)
12521287
kaleidoHBox.addStretch()
1288+
1289+
kaleidoEventFlagHBox = QHBoxLayout()
1290+
kaleidoEventFlagHBox.setSpacing(17)
1291+
kaleidoEventFlagHBox.addStretch()
1292+
kaleidoEventFlagHBox.addSpacing(20)
1293+
for cb in self.kaleidoEventFlags:
1294+
kaleidoEventFlagHBox.addWidget(cb)
1295+
kaleidoEventFlagHBox.addSpacing(20)
1296+
kaleidoEventFlagHBox.addStretch()
1297+
12531298
kaleidoVBox = QVBoxLayout()
12541299
kaleidoVBox.addLayout(kaleidoHBox)
1300+
kaleidoVBox.addSpacing(15)
1301+
kaleidoVBox.addLayout(kaleidoEventFlagHBox)
12551302
kaleidoVBox.addStretch()
12561303
kaleidoVBox.setSpacing(5)
1257-
kaleidoVBox.setContentsMargins(0,0,0,0)
1304+
kaleidoVBox.setContentsMargins(7,5,7,5) # left, top, right, bottom
1305+
1306+
kaleidoNetworkGroupBox = QGroupBox('Kaleido')
1307+
kaleidoNetworkGroupBox.setLayout(kaleidoVBox)
1308+
12581309

12591310
mugmaNetworkGrid = QGridLayout()
12601311
mugmaNetworkGrid.addWidget(mugmaHostLabel,0,1)
@@ -1437,7 +1488,7 @@ def __init__(self, parent:QWidget, aw:'ApplicationWindow', activeTab:int = 0) ->
14371488
#LAYOUT TAB 7 (Santoker)
14381489
tab7VLayout = QVBoxLayout()
14391490
tab7VLayout.addWidget(santokerNetworkGroupBox)
1440-
tab7VLayout.addLayout(kaleidoVBox)
1491+
tab7VLayout.addWidget(kaleidoNetworkGroupBox)
14411492
tab7VLayout.addStretch()
14421493
tab7V2Layout = QVBoxLayout()
14431494
tab7V2Layout.addLayout(mugmaVBox)
@@ -3272,6 +3323,9 @@ def okEvent(self) -> None: # pyright: ignore [reportGeneralTypeIssues] # Code is
32723323
self.aw.ser.externalprogram = self.programedit.text()
32733324
self.aw.ser.externaloutprogram = self.outprogramedit.text()
32743325

3326+
self.aw.santokerEventFlags = [cb.isChecked() for cb in self.santokerEventFlags]
3327+
self.aw.kaleidoEventFlags = [cb.isChecked() for cb in self.kaleidoEventFlags]
3328+
32753329
self.aw.two_bucket_mode = self.dual_bucket_mode.isChecked()
32763330
self.aw.green_task_precision = self.greenTaskPrecision.value()
32773331

src/artisanlib/main.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,6 +1857,7 @@ def __init__(self, parent:Optional[QWidget] = None, *, locale:str, WebEngineSupp
18571857
# santokerSerial and santokerBLE should never be True at the same time (BLE will have preceedence)
18581858
self.santokerSerial:bool = False # if True connection is via the main serial port
18591859
self.santokerBLE:bool = False # if True connection is via the main serial port
1860+
self.santokerEventFlags:List[bool] = [False, False, False, False, False, False, False ] # CHARGE, DRY, FCs, FCe, SCs, SCe, DROP
18601861
self.santoker:Optional[Santoker] = None # holds the Santoker instance created on connect; reset to None on disconnect
18611862

18621863
# Santoker R
@@ -1882,6 +1883,7 @@ def __init__(self, parent:Optional[QWidget] = None, *, locale:str, WebEngineSupp
18821883
self.kaleidoSerial:bool = False # if True connection is via the main serial port
18831884
self.kaleidoPID:bool = True # if True the external Kaleido PID is operated, otherwise the internal Artisan PID is active
18841885
self.kaleido:Optional[KaleidoPort] = None # holds the Kaleido instance created on connect; reset to None on disconnect
1886+
self.kaleidoEventFlags:List[bool] = [False, False, False, False, False, False, False ] # CHARGE, DRY, FCs, FCe, SCs, SCe, DROP
18851887

18861888
# Ikawa BLE
18871889
self.ikawa:'Optional[IKAWA_BLE]' = None # noqa: UP037
@@ -17687,10 +17689,14 @@ def settingsLoad(self, filename:Optional[str] = None, theme:bool = False, machin
1768717689
self.santokerPort = toInt(settings.value('santokerPort',self.santokerPort))
1768817690
self.santokerSerial = toBool(settings.value('santokerSerial',self.santokerSerial))
1768917691
self.santokerBLE = toBool(settings.value('santokerBLE',self.santokerBLE))
17692+
if settings.contains('santokerEventFlags'):
17693+
self.santokerEventFlags = [toBool(x) for x in toList(settings.value('santokerEventFlags',self.santokerEventFlags))]
1769017694
self.kaleidoHost = toString(settings.value('kaleidoHost',self.kaleidoHost))
1769117695
self.kaleidoPort = toInt(settings.value('kaleidoPort',self.kaleidoPort))
1769217696
self.kaleidoSerial = toBool(settings.value('kaleidoSerial',self.kaleidoSerial))
1769317697
self.kaleidoPID = toBool(settings.value('kaleidoPID',self.kaleidoPID))
17698+
if settings.contains('kaleidoEventFlags'):
17699+
self.kaleidoEventFlags = [toBool(x) for x in toList(settings.value('kaleidoEventFlags',self.kaleidoEventFlags))]
1769417700
self.mugmaHost = toString(settings.value('mugmaHost',self.mugmaHost))
1769517701
self.mugmaPort = toInt(settings.value('mugmaPort',self.mugmaPort))
1769617702
self.colorTrack_mean_window_size = toInt(settings.value('ctMean',self.colorTrack_mean_window_size))
@@ -19717,10 +19723,12 @@ def saveAllSettings(self, settings:QSettings, default_settings:Optional[Dict[str
1971719723
self.settingsSetValue(settings, default_settings, 'santokerPort',self.santokerPort, read_defaults)
1971819724
self.settingsSetValue(settings, default_settings, 'santokerSerial',self.santokerSerial, read_defaults)
1971919725
self.settingsSetValue(settings, default_settings, 'santokerBLE',self.santokerBLE, read_defaults)
19726+
self.settingsSetValue(settings, default_settings, 'santokerEventFlags',self.santokerEventFlags, read_defaults)
1972019727
self.settingsSetValue(settings, default_settings, 'kaleidoHost',self.kaleidoHost, read_defaults)
1972119728
self.settingsSetValue(settings, default_settings, 'kaleidoPort',self.kaleidoPort, read_defaults)
1972219729
self.settingsSetValue(settings, default_settings, 'kaleidoSerial',self.kaleidoSerial, read_defaults)
1972319730
self.settingsSetValue(settings, default_settings, 'kaleidoPID',self.kaleidoPID, read_defaults)
19731+
self.settingsSetValue(settings, default_settings, 'kaleidoEventFlags',self.kaleidoEventFlags, read_defaults)
1972419732
self.settingsSetValue(settings, default_settings, 'mugmaHost',self.mugmaHost, read_defaults)
1972519733
self.settingsSetValue(settings, default_settings, 'mugmaPort',self.mugmaPort, read_defaults)
1972619734
self.settingsSetValue(settings, default_settings, 'ctMean',self.colorTrack_mean_window_size, read_defaults)

src/artisanlib/util.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ def stringfromseconds(seconds_raw:float, leadingzero:bool = True) -> str:
139139

140140
#Converts a string into a seconds integer. Use for example to interpret times from Roaster Properties Dlg inputs
141141
#accepted formats: "00:00","-00:00"
142+
# returns -1 on invalid inputs
142143
def stringtoseconds(string:str) -> int:
143144
timeparts = string.split(':')
144145
if len(timeparts) != 2:

src/requirements-dev.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ types-docutils>=0.21.0.20250715
1313
lxml-stubs>=0.5.1
1414
mypy==1.17.0
1515
pyright==1.1.403
16-
ruff>=0.12.3
16+
ruff>=0.12.4
1717
pylint==3.3.7
1818
pre-commit>=4.2.0
1919
pytest>=8.4.1

wiki/ReleaseHistory.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ v3.2.1
2323
- unlimited number of buttons can be created while display is limited to maximum 10 rows with maximum 50 buttons each
2424
- palette load uses and updates the user selected profile path
2525
- increases the maximum number of recent roast entries from 25 to 40
26+
- makes synchronization of main events with Kaleido and Santoker roasting machines configurable (disabled by default)
2627

2728
* FIXES
2829
- fixes regression which broke the designer such that points could not be moved ([Discussion #1905](../../../discussions/1905) and [Issue #1916](../../../issues/1916))

0 commit comments

Comments
 (0)