Skip to content

Commit ffb39b7

Browse files
committed
- event replay is OFF by default for all event types
- reset CM ET/BT device calculation on background profile horizontal re-alignment - clean up
1 parent efcdb1e commit ffb39b7

6 files changed

Lines changed: 61 additions & 58 deletions

File tree

.appveyor.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# the GNU General Public License for more details.
1414
#
1515
# AUTHOR
16-
# Dave Baxter, Marko Luther 2025
16+
# Dave Baxter, Marko Luther 2026
1717

1818
# Include "skip ci" in the commit message to prevent this build process from running
1919
environment:
@@ -24,10 +24,10 @@ environment:
2424
#PYUPGRADE_MACOS_V: 3.12.1 # when upgrading see the notes in the deploy phase
2525

2626
matrix:
27-
# - job_name: windows
28-
# appveyor_build_worker_image: Visual Studio 2022
29-
# - job_name: macos
30-
# appveyor_build_worker_image: macos-ventura
27+
- job_name: windows
28+
appveyor_build_worker_image: Visual Studio 2022
29+
- job_name: macos
30+
appveyor_build_worker_image: macos-ventura
3131
- job_name: linux
3232
appveyor_build_worker_image: Ubuntu2204
3333

src/artisan-linux.spec

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@ BINARIES.extend([(os.path.join(yocto_lib_path, fn),'yoctopuce/cdll') for fn in o
1414
phidgets_lib_path = os.path.join(get_package_paths('Phidget22')[1], '.libs')
1515
BINARIES.extend([(os.path.join(phidgets_lib_path, fn),'Phidget22/.libs') for fn in os.listdir(phidgets_lib_path) if fn.endswith('.so')])
1616

17-
## add missing QtWebEngine shared libs
18-
#BINARIES.append((os.path.join(get_package_paths('PyQt6')[1], 'Qt6/lib/libQt6QmlMeta.so.6'), 'PyQt6/Qt6/lib'))
19-
#BINARIES.append((os.path.join(get_package_paths('PyQt6')[1], 'Qt6/lib/libQt6QmlWorkerScript.so.6'), 'PyQt6/Qt6/lib'))
20-
21-
2217
path=os.environ['HOME'] + '/artisan-master/src'
2318
if not os.path.isdir(path):
2419
path=os.environ['HOME'] + '/artisan/src'
@@ -29,9 +24,6 @@ if not os.path.isdir(path):
2924
hiddenimports_list=[
3025
'matplotlib.backends.backend_pdf',
3126
'matplotlib.backends.backend_svg',
32-
# 'PyQt6.QtPositioning',
33-
# 'PyQt6.QtWebChannel', ## Win incl., but did not help
34-
# 'PyQt6.QtWebEngineCore', ## Win incl.
3527
'babel.numbers' # should not be needed as it got fixed in pyinstaller 6.11
3628
] + collect_submodules('dbus_fast')
3729

@@ -69,7 +61,7 @@ a = Analysis(['artisan.py'],
6961
datas=DATA_FILES,
7062
hookspath=[],
7163
runtime_hooks=['./pyinstaller_hooks/rthooks/pyi_rth_mplconfig.py'], # overwrites default MPL runtime hook which keeps loading font cache from (new) temp directory
72-
# excludes=EXCLUDES,
64+
excludes=EXCLUDES,
7365
hiddenimports=hiddenimports_list,
7466
win_no_prefer_redirects=False,
7567
win_private_assemblies=False,

src/artisanlib/canvas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1820,7 +1820,7 @@ def __init__(self, parent:QWidget, dpi:int, locale:str, aw:'ApplicationWindow')
18201820
self.specialeventannotations:list[str] = ['','','','']
18211821
self.specialeventannovisibilities:list[int] = [0,0,0,0]
18221822
self.specialeventplaybackaid:list[bool] = [True, True, True, True] # per event type decides if playback aid is active (note that eventtype 4 "--" is not replayed)
1823-
self.specialeventplayback:list[bool] = [True, True, True, True] # per event type decides if background events are play-backed or not
1823+
self.specialeventplayback:list[bool] = [False, False, False, False] # per event type decides if background events are play-backed or not
18241824
self.specialeventplaybackramp:list[bool] = [False, False, False, False] # per event type decides if playback ramping is applied or not
18251825
self.ramp_lookahead:int = 0 # lookahead of ramping event replay in seconds
18261826
self.overlappct:int = 100

src/artisanlib/comm.py

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ class serialport:
247247
'YOCTOthread','YOCTOvoltageOutputs','YOCTOcurrentOutputs','YOCTOrelays','YOCTOservos','YOCTOpwmOutputs','HH506RAid','MS6514PrevTemp1','MS6514PrevTemp2','DT301PrevTemp','EXTECH755PrevTemp',\
248248
'controlETpid','readBTpid','useModbusPort','showFujiLCDs','arduinoETChannel','arduinoBTChannel','arduinoATChannel',\
249249
'ArduinoIsInitialized','ArduinoFILT','HH806Winitflag','R1','devicefunctionlist','externalprogram',\
250-
'externaloutprogram','externaloutprogramFlag','PhidgetHUMtemp','PhidgetHUMhum','PhidgetPREpre','TMP1000temp', 'colorTrackSerial', 'colorTrackBT', 'CM_ET_readings_count', 'CM_BT_readings_count', 'CM_ET_sum_of_squared_differences', 'CM_BT_sum_of_squared_differences' ]
250+
'externaloutprogram','externaloutprogramFlag','PhidgetHUMtemp','PhidgetHUMhum','PhidgetPREpre','TMP1000temp', 'colorTrackSerial', 'colorTrackBT',
251+
'CM_reference_timeb', 'CM_ET_readings_count', 'CM_BT_readings_count', 'CM_ET_sum_of_squared_differences', 'CM_BT_sum_of_squared_differences' ]
251252

252253
def __init__(self, aw:'ApplicationWindow') -> None:
253254

@@ -333,6 +334,7 @@ def __init__(self, aw:'ApplicationWindow') -> None:
333334
self.colorTrackSerial:ColorTrack|None = None
334335
self.colorTrackBT:ColorTrackBLE|None = None
335336

337+
self.CM_reference_timeb:float|None = None # set on adding first reading to detect updated horizontal background profile alignment which resets calculation
336338
self.CM_ET_readings_count:int = 0
337339
self.CM_BT_readings_count:int = 0
338340
self.CM_ET_sum_of_squared_differences:float = 0
@@ -1018,39 +1020,45 @@ def slider_23(self) -> tuple[float,float,float]:
10181020
def CM_ETBT(self) -> tuple[float,float,float]:
10191021
tx = self.aw.qmc.timeclock.elapsedMilli()
10201022
try:
1021-
t1 = -1
1022-
t2 = -1
1023-
# update counts and sum_of_squared_differences
1024-
BTlimit = self.aw.qmc.phases[1]
1025-
BT = (self.aw.qmc.temp2[-1] if len(self.aw.qmc.temp2)>0 else -1)
1026-
if (BTlimit < BT and self.aw.qmc.timeindex[0] > -1 and
1027-
(tx - self.aw.qmc.timex[self.aw.qmc.timeindex[0]] > 90) and
1028-
self.aw.qmc.timeindex[6] == 0):
1029-
# BT above DRY END as specified in Phased dialog, at least 1:30m after CHARGE and before DROP is registered
1030-
ET = (self.aw.qmc.temp1[-1] if len(self.aw.qmc.temp1)>0 else -1)
1031-
nowB = self.aw.qmc.backgroundtime2index(tx) # points to the last entry if tx > all elements in btimex
1032-
ETB = (self.aw.qmc.temp1B[nowB] if len(self.aw.qmc.temp1B)>nowB>-1 else -1)
1033-
BTB = (self.aw.qmc.temp2B[nowB] if len(self.aw.qmc.temp2B)>nowB>-1 else -1)
1034-
if ET > -1 and ETB > -1:
1035-
self.CM_ET_readings_count += 1
1036-
ET_squared_diff = (ET - ETB)**2
1037-
self.CM_ET_sum_of_squared_differences += ET_squared_diff
1038-
if BT > -1 and BTB > -1:
1039-
self.CM_BT_readings_count += 1
1040-
BT_squared_diff = (BT - BTB)**2
1041-
self.CM_BT_sum_of_squared_differences += BT_squared_diff
1042-
elif self.aw.qmc.timeindex[0] == 0:
1043-
# if CHARGE is not set reset readings, keep readings otherwise (eg. after DROP)
1044-
self.CM_ET_readings_count = 0
1045-
self.CM_ET_sum_of_squared_differences = 0
1046-
self.CM_BT_readings_count = 0
1047-
self.CM_BT_sum_of_squared_differences = 0
1048-
# calc results
1049-
if self.CM_ET_readings_count > 0:
1050-
t1 = numpy.sqrt(self.CM_ET_sum_of_squared_differences / self.CM_ET_readings_count)
1051-
if self.CM_BT_readings_count > 0:
1052-
t2 = numpy.sqrt(self.CM_BT_sum_of_squared_differences / self.CM_BT_readings_count)
1053-
return tx,t2,t1
1023+
if self.aw.qmc.backgroundprofile is not None and len(self.aw.qmc.timeB)>0: # a non-empty background profile is loaded
1024+
# set CM reference timeb to first reading of the background profile, if any
1025+
first_timeb:float = self.aw.qmc.timeB[0]
1026+
t1 = -1
1027+
t2 = -1
1028+
# update counts and sum_of_squared_differences
1029+
BTlimit = self.aw.qmc.phases[1]
1030+
BT = (self.aw.qmc.temp2[-1] if len(self.aw.qmc.temp2)>0 else -1)
1031+
if (BTlimit < BT and self.aw.qmc.timeindex[0] > -1 and
1032+
(self.CM_reference_timeb is None or self.CM_reference_timeb == first_timeb) and
1033+
(tx - self.aw.qmc.timex[self.aw.qmc.timeindex[0]] > 90) and
1034+
self.aw.qmc.timeindex[6] == 0):
1035+
# BT above DRY END as specified in Phased dialog, at least 1:30m after CHARGE and before DROP is registered
1036+
ET = (self.aw.qmc.temp1[-1] if len(self.aw.qmc.temp1)>0 else -1)
1037+
nowB = self.aw.qmc.backgroundtime2index(tx) # points to the last entry if tx > all elements in btimex (-1 if btime is empty!)
1038+
ETB = (self.aw.qmc.temp1B[nowB] if len(self.aw.qmc.temp1B)>nowB>-1 else -1)
1039+
BTB = (self.aw.qmc.temp2B[nowB] if len(self.aw.qmc.temp2B)>nowB>-1 else -1)
1040+
if ET > -1 and ETB > -1:
1041+
self.CM_ET_readings_count += 1
1042+
ET_squared_diff = (ET - ETB)**2
1043+
self.CM_ET_sum_of_squared_differences += ET_squared_diff
1044+
if BT > -1 and BTB > -1:
1045+
self.CM_BT_readings_count += 1
1046+
BT_squared_diff = (BT - BTB)**2
1047+
self.CM_BT_sum_of_squared_differences += BT_squared_diff
1048+
self.CM_reference_timeb = first_timeb
1049+
elif self.aw.qmc.timeindex[0] == 0 or (self.CM_reference_timeb is not None and self.CM_reference_timeb != first_timeb):
1050+
# if CHARGE is not set reset readings, keep readings otherwise (eg. after DROP)
1051+
self.CM_reference_timeb = None
1052+
self.CM_ET_readings_count = 0
1053+
self.CM_ET_sum_of_squared_differences = 0
1054+
self.CM_BT_readings_count = 0
1055+
self.CM_BT_sum_of_squared_differences = 0
1056+
# calc results
1057+
if self.CM_ET_readings_count > 0:
1058+
t1 = numpy.sqrt(self.CM_ET_sum_of_squared_differences / self.CM_ET_readings_count)
1059+
if self.CM_BT_readings_count > 0:
1060+
t2 = numpy.sqrt(self.CM_BT_sum_of_squared_differences / self.CM_BT_readings_count)
1061+
return tx,t2,t1
10541062
except Exception as e: # pylint: disable=broad-except
10551063
_log.exception(e)
10561064
return tx, -1, -1

src/artisanlib/main.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -685,13 +685,6 @@ def filter(self, record:logging.LogRecord) -> bool:
685685
_log.info('QtWebEngine found => PDF report rendering enabled')
686686
else:
687687
_log.info('QtWebEngine not found => PDF report rendering disabled')
688-
# temp test
689-
try:
690-
from PyQt6.QtWebEngineWidgets import QWebEngineView
691-
from PyQt6.QtWebEngineCore import QWebEngineProfile
692-
except Exception as e: # pylint: disable=broad-except
693-
_log.exception(e)
694-
695688

696689
if platform.system().startswith('Windows'):
697690
# on Windows we use the Fusion style per default which supports the dark mode
@@ -27917,8 +27910,6 @@ def main() -> None:
2791727910
_log.info('loaded %s settings in %.2fs', len(QSettings().allKeys()), libtime.process_time() - start_time)
2791827911
# _log.debug("PRINT mpl.get_cachedir(): %s",mpl.get_cachedir())
2791927912

27920-
_log.debug('PRINT QLibraryInfo.LibraryPath.TranslationsPath: %s', QLibraryInfo.path(QLibraryInfo.LibraryPath.TranslationsPath))
27921-
2792227913
appWindow.set_ui_mode(appWindow.ui_mode)
2792327914

2792427915
# inform the user the debug logging is on

wiki/ReleaseHistory.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
Detailed Release History
22
========================
33

4+
----
5+
v4.0.1
6+
------------------
7+
8+
* CHANGES
9+
- event replay is OFF by default for all event types
10+
- reset CM ET/BT device calculation on background profile horizontal re-alignment
11+
12+
* FIXES
13+
- fixes regression where cut/copy/paste shortcuts are not working in file selector dialogs ([Issue #2114](../../../issues/2114))
14+
- fixes build issues which broke PDF reports on Linux and macOS ([Issue #2113](../../../issues/2113))
15+
416
----
517
v4.0.0 (Jan 28, 2026)
618
------------------

0 commit comments

Comments
 (0)