Skip to content

Commit

Permalink
- fixes mode-dependent SV temperature persistency (Issue #1631)
Browse files Browse the repository at this point in the history
- fixes scheduler imports for PyQt5
- supports drag-and-drop on PyQt5
- adds setWindowFilePath to show loaded profile in titlebar on macOS (maybe on Linux as well)
- remember zoom on CHARGE
- avoid JSON decode errors on empty responses
- fixes potential index error in calcBBPMetrics
- disable QtWebEngine spell checker and cache to get rid of warning related to qtwebengine_dictionaries path
- DE translation updates
  • Loading branch information
MAKOMO committed Jul 24, 2024
1 parent 95fbe10 commit 4ca8c3a
Show file tree
Hide file tree
Showing 13 changed files with 14,286 additions and 14,211 deletions.
16 changes: 11 additions & 5 deletions src/artisanlib/canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,8 @@ def __init__(self, parent:QWidget, dpi:int, locale:str, aw:'ApplicationWindow')

#F = Fahrenheit; C = Celsius
self.mode:str = 'F'

# default mode on platforms we can detect it like macOS:
if platform.system() == 'Darwin':
# try to "guess" the users preferred temperature unit
try:
Expand Down Expand Up @@ -11113,9 +11115,6 @@ def fahrenheitMode(self, setdefaultaxes:bool = True) -> None:
self.RoRlimitm = int(round(fromCtoFstrict(self.RoRlimitm)))
self.RoRlimit = int(round(fromCtoFstrict(self.RoRlimit)))
self.alarmtemperature = [(fromCtoFstrict(t) if t != 500 else t) for t in self.alarmtemperature]
# # conv Arduino mode
# if self.aw:
# self.aw.pidcontrol.conv2fahrenheit()
if self.ax is not None:
self.ax.set_ylabel('F',size=16,color = self.palette['ylabel']) #Write "F" on Y axis
self.mode = 'F'
Expand Down Expand Up @@ -11150,8 +11149,6 @@ def celsiusMode(self, setdefaultaxes:bool = True) -> None:
self.RoRlimitm = int(round(fromFtoCstrict(self.RoRlimitm)))
self.RoRlimit = int(round(fromFtoCstrict(self.RoRlimit)))
self.alarmtemperature = [(fromFtoCstrict(t) if t != 500 else t) for t in self.alarmtemperature]
# # conv Arduino mode
# self.aw.pidcontrol.conv2celsius()
if self.ax is not None:
self.ax.set_ylabel('C',size=16,color = self.palette['ylabel']) #Write "C" on Y axis
self.mode = 'C'
Expand Down Expand Up @@ -12782,6 +12779,11 @@ def markChargeTrigger(self) -> None:
# if noaction is True, the button event action is not triggered
@pyqtSlot(bool)
def markCharge(self, noaction:bool = False) -> None:
try:
if self.aw.ntb._nav_stack(): # pylint: disable=protected-access # if ZOOMED in we push state on stack
self.aw.ntb.push_current() # remember current canvas ZOOM/POSITION on stack
except Exception: # pylint: disable=broad-except
pass
removed = False
try:
self.profileDataSemaphore.acquire(1)
Expand Down Expand Up @@ -12927,6 +12929,10 @@ def markCharge(self, noaction:bool = False) -> None:
if self.roastpropertiesAutoOpenFlag:
self.aw.openPropertiesSignal.emit()
self.aw.onMarkMoveToNext(self.aw.buttonCHARGE)
try:
self.aw.ntb._update_view() # type:ignore[has-type] # pylint: disable=protected-access # recallcanvas ZOOM/POSITION from stack
except Exception: # pylint: disable=broad-except
pass

# called via markTPSignal (queued), triggered by external device
# does directly call markTP()
Expand Down
65 changes: 46 additions & 19 deletions src/artisanlib/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
#QtWebEngineWidgets must be imported before a QCoreApplication instance is created
try:
from PyQt6.QtWebEngineWidgets import QWebEngineView # @Reimport @UnresolvedImport @UnusedImport # pylint: disable=import-error,no-name-in-module
from PyQt6.QtWebEngineCore import QWebEngineProfile
QtWebEngineSupport = True
except ImportError:
# on the RPi platform there is no native package PyQt-WebEngine nor PyQt6-WebEngine for Raspebarry 32bit
Expand All @@ -153,7 +154,8 @@
from PyQt5.QtNetwork import QLocalSocket # type: ignore # @Reimport @UnresolvedImport @UnusedImport
#QtWebEngineWidgets must be imported before a QCoreApplication instance is created
try:
from PyQt5.QtWebEngineWidgets import QWebEngineView # type: ignore # @Reimport @UnresolvedImport @UnusedImport # pylint: disable=import-error,no-name-in-module
from PyQt5.QtWebEngineWidgets import QWebEngineView # type: ignore[import-not-found, no-redef] # @Reimport @UnresolvedImport @UnusedImport # pylint: disable=import-error,no-name-in-module
from PyQt5.QtWebEngineCore import QWebEngineProfile # type: ignore[import-not-found, no-redef]
QtWebEngineSupport = True
except ImportError:
# on the RPi platform there is no native package PyQt-WebEngine nor PyQt6-WebEngine for Raspebarry 32bit
Expand Down Expand Up @@ -4480,11 +4482,16 @@ def updateWindowTitle(self) -> None:
elif self.curFile:
# profile loaded
self.setWindowTitle(f'{dirtySign}{self.strippedName(self.curFile)} – {appTitle}')
# if not Simulator, Comparator, Designer, WheelGraph
if self.comparator is None and not self.qmc.designerflag and not self.qmc.wheelflag and self.qmc.ax is not None:
self.setWindowFilePath(self.curFile)
# no profile loaded
elif __release_sponsor_name__:
self.setWindowTitle(f"{dirtySign}{appTitle} – {__release_sponsor_name__} ({QApplication.translate('About','Release Sponsor')})")
self.setWindowFilePath('')
else:
self.setWindowTitle(f'{dirtySign}{appTitle}')
self.setWindowFilePath('')
except Exception as e: # pylint: disable=broad-except
_log.exception(e)

Expand Down Expand Up @@ -12480,7 +12487,7 @@ def loadFile(self, filename:str, quiet:bool = False) -> None:
if self.qmc.statssummary and self.summarystats_startup and self.qmc.autotimex:
# allow only once, at startup
self.summarystats_startup = False
self.qmc.redraw(False)
self.qmc.redraw(recomputeAllDeltas = False, re_smooth_foreground = False)


self.qmc.redraw()
Expand Down Expand Up @@ -15422,7 +15429,8 @@ def calcBBPMetrics(self,checkCache:bool=False) -> None:
_log.debug('clearing bbpCache')
# now calculate all the bbp data
# does the current profile have the minimum time for bbp?
if (len(self.qmc.timeindex) > 0) and (self.qmc.timex[self.qmc.timeindex[0]] > 0) and (self.qmc.timex[self.qmc.timeindex[0]] - self.qmc.timex[0] >= minBbpTime):
if (len(self.qmc.timeindex) > 0 and len(self.qmc.timex) > self.qmc.timeindex[0] > -1 and (self.qmc.timex[self.qmc.timeindex[0]] > 0) and
(self.qmc.timex[self.qmc.timeindex[0]] - self.qmc.timex[0] >= minBbpTime)):
self.bbp_total_time = self.qmc.timex[self.qmc.timeindex[0]] - self.qmc.timex[0] + self.bbp_time_added_from_prev
# fake the events to use with findTPint
bbp_timeindex = [0, 0, self.qmc.timeindex[0], 0, 0, 0, self.qmc.timeindex[0], 0]
Expand Down Expand Up @@ -21694,7 +21702,13 @@ def renderingTerminated(_terminationStatus:'QWebEnginePage.RenderProcessTerminat
libtime.sleep(0.001)
self.pdf_rendering = True
if self.html_loader is None:
self.html_loader = QWebEngineView() # pyright:ignore[reportPossiblyUnboundVariable]
try:
profile = QWebEngineProfile() # pyright:ignore[reportPossiblyUnboundVariable]
profile.setSpellCheckEnabled(False) # disable spell checker
profile.setHttpCacheType(QWebEngineProfile.HttpCacheType.NoCache) # pyright:ignore[reportPossiblyUnboundVariable]
self.html_loader = QWebEngineView(profile) # pyright:ignore[reportPossiblyUnboundVariable]
except: # pylint: disable=broad-except
self.html_loader = QWebEngineView() # pyright:ignore[reportPossiblyUnboundVariable]
self.html_loader.setZoomFactor(1)
if self.pdf_page_layout is None:
# lazy imports
Expand Down Expand Up @@ -22689,24 +22703,35 @@ def helpHelp(self, _:bool = False) -> None: # pylint: disable=no-self-use # use
def checkUpdate(self, _:bool = False) -> None:
update_url = '<a href="https://artisan-scope.org">https://artisan-scope.org</a>'
update_str = QApplication.translate('About', 'There was a problem retrieving the latest version information. Please check your Internet connection, try again later, or check manually.')
import json
try:
import requests
r = requests.get('https://api.github.com/repos/artisan-roaster-scope/artisan/releases/latest', timeout=(2,4))
tag_name = r.json()['tag_name']
match = re.search(r'[\d\.]+',tag_name)
if match is not None:
latest = match.group(0)
if latest > __version__:
update_str = QApplication.translate('About', 'A new release is available.')
update_str += '<br/><a href="https://github.com/artisan-roaster-scope/artisan/blob/master/wiki/ReleaseHistory.md">'
update_str += QApplication.translate('About', 'Show Change list')
update_str += '<br/><a href="https://github.com/artisan-roaster-scope/artisan/releases/tag/' + str(tag_name) + '">'
update_str += QApplication.translate('About', 'Download Release') + ' ' + str(tag_name)
elif latest == __version__ :
update_str = QApplication.translate('About', 'You are using the latest release.')
elif latest < __version__:
update_str = QApplication.translate('About', 'You are using a beta continuous build.')
update_str += '<br/><br/>' + QApplication.translate('About', 'You will see a notice here once a new official release is available.')
if r.status_code != 204 and r.headers['content-type'].strip().startswith('application/json'):
response = r.json()
if 'tag_name' in response:
tag_name = r.json()['tag_name']
match = re.search(r'[\d\.]+',tag_name)
if match is not None:
latest = match.group(0)
if latest > __version__:
update_str = QApplication.translate('About', 'A new release is available.')
update_str += '<br/><a href="https://github.com/artisan-roaster-scope/artisan/blob/master/wiki/ReleaseHistory.md">'
update_str += QApplication.translate('About', 'Show Change list')
update_str += '<br/><a href="https://github.com/artisan-roaster-scope/artisan/releases/tag/' + str(tag_name) + '">'
update_str += QApplication.translate('About', 'Download Release') + ' ' + str(tag_name)
elif latest == __version__ :
update_str = QApplication.translate('About', 'You are using the latest release.')
elif latest < __version__:
update_str = QApplication.translate('About', 'You are using a beta continuous build.')
update_str += '<br/><br/>' + QApplication.translate('About', 'You will see a notice here once a new official release is available.')
except json.decoder.JSONDecodeError as e:
if not e.doc:
_log.error('Empty response in checkUpdate.')
else:
_log.error("Decoding error at char %s (line %s, col %s): '%s'", e.pos, e.lineno, e.colno, e.doc)
except ValueError:
_log.error('checkUpdate response content is not valid JSON')
except Exception as ex: # pylint: disable=broad-except
_log.exception(ex)
_a, _b, exc_tb = sys.exc_info()
Expand Down Expand Up @@ -25958,6 +25983,8 @@ def main() -> None:
start_time = libtime.process_time() # begin of settings load
# fill self.defaultSettings with default app QSettings values before loading app settings from system via settingsLoad()
appWindow.saveAllSettings(QSettings(), appWindow.defaultSettings, read_defaults=True) # don't save any settings, but just read in the defaults

# now load the app settings
appWindow.settingsLoad(redraw=False) # redraw is triggered later in the startup process again
appWindow.restoreExtraDeviceSettingsBackup() # load settings backup if it exists (like on RESET)
_log.info('loaded %s settings in %.2fs', len(QSettings().allKeys()), libtime.process_time() - start_time)
Expand Down
10 changes: 5 additions & 5 deletions src/artisanlib/pid_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -1177,8 +1177,8 @@ def __init__(self, aw:'ApplicationWindow') -> None:
self.svMode:int = 0 # 0: manual, 1: Ramp/Soak, 2: Follow (background profile)
self.svLookahead:int = 0
self.svSliderMin:int = 0
self.svSliderMax:int = 230
self.svValue:float = 180 # the value in the setSV textinput box of the PID dialog
self.svSliderMax:int = (230 if self.aw.qmc.mode == 'C' else 446) # 446F / 230C
self.svValue:float = (180 if self.aw.qmc.mode == 'C' else 356) # 356F / 180C # the value in the setSV textinput box of the PID dialog
self.dutySteps:int = 1
self.dutyMin:int = -100
self.dutyMax:int = 100
Expand All @@ -1189,9 +1189,9 @@ def __init__(self, aw:'ApplicationWindow') -> None:
self.negativeTargetMin:int = 0
self.negativeTargetMax:int = 100
self.derivative_filter:int = 0 # 0: off, 1: on
self.pidKp:float = 15.0
self.pidKi:float = 0.01
self.pidKd:float = 20.0
self.pidKp:float = (15.0 if self.aw.qmc.mode == 'C' else 8.3334) # 15.0 in C
self.pidKi:float = (0.01 if self.aw.qmc.mode == 'C' else 0.00556) # 0.01 in C
self.pidKd:float = (20.0 if self.aw.qmc.mode == 'C' else 11.1111) # 20.0 in C
# Proposional on Measurement mode see: http://brettbeauregard.com/blog/2017/06/introducing-proportional-on-measurement/
self.pOnE:bool = True # True for Proposional on Error mode, False for Proposional on Measurement Mode
# pidSource
Expand Down
File renamed without changes.
Loading

0 comments on commit 4ca8c3a

Please sign in to comment.