Skip to content

Commit

Permalink
- updates pymodbus
Browse files Browse the repository at this point in the history
- adds support for Digi-Sense 20250-07 and the Extech 42570
- adds C/F conversion for the drop duplicates limit and the RoR limits
- fixes regression which failed to apply RoR smoothing properly
- fixes some pyinstaller warnings for Windows builds
  • Loading branch information
MAKOMO committed Feb 14, 2024
1 parent 8fd14c3 commit 8807ac1
Show file tree
Hide file tree
Showing 41 changed files with 42,934 additions and 41,826 deletions.
12 changes: 6 additions & 6 deletions src/artisan-win.spec
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,9 @@ if not ARTISAN_LEGACY=='True':
#remove_dir(TARGET + 'mpl-data\sample_data',False)

# YOCTO HACK BEGIN: manually copy over the dlls
make_dir(TARGET + '_internal\yoctopuce\cdll')
copy_file(YOCTO_BIN + r'\yapi.dll', TARGET + '_internal\yoctopuce\cdll')
copy_file(YOCTO_BIN + r'\yapi64.dll', TARGET + '_internal\yoctopuce\cdll')
make_dir(TARGET + r'_internal\yoctopuce\cdll')
copy_file(YOCTO_BIN + r'\yapi.dll', TARGET + r'_internal\yoctopuce\cdll')
copy_file(YOCTO_BIN + r'\yapi64.dll', TARGET + r'_internal\yoctopuce\cdll')
# YOCTO HACK END

# copy Snap7 lib
Expand Down Expand Up @@ -277,10 +277,10 @@ for fn in [
copy_file(fn, TARGET)

make_dir(TARGET + 'Machines')
xcopy_files('includes\Machines', TARGET + 'Machines')
xcopy_files(r'includes\Machines', TARGET + 'Machines')

make_dir(TARGET + 'Themes')
xcopy_files('includes\Themes', TARGET + 'Themes')
xcopy_files(r'includes\Themes', TARGET + 'Themes')

make_dir(TARGET + 'Icons')
xcopy_files('includes\Icons', TARGET + 'Icons')
xcopy_files(r'includes\Icons', TARGET + 'Icons')
2 changes: 1 addition & 1 deletion src/artisanlib/async_comm.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from contextlib import suppress
from threading import Thread
from pymodbus.transport.transport_serial import create_serial_connection # patched pyserial-asyncio
from pymodbus.transport.serialtransport import create_serial_connection # patched pyserial-asyncio
from typing import Final, Optional, Union, Tuple, Callable, TYPE_CHECKING

if TYPE_CHECKING:
Expand Down
14 changes: 11 additions & 3 deletions src/artisanlib/canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,9 @@ def __init__(self, parent:QWidget, dpi:int, locale:str, aw:'ApplicationWindow')
'+Phidget DAQ1301 45', #158
'+Phidget DAQ1301 67', #159
f'+IKAWA {deltaLabelUTF8}Humidity/{deltaLabelUTF8}Humidity Dir.' #160
'+Omega HH309 34', #161
'Digi-Sense 20250-07', #162
'Extech 42570' #163
]

# ADD DEVICE:
Expand Down Expand Up @@ -1952,7 +1955,7 @@ def __init__(self, parent:QWidget, dpi:int, locale:str, aw:'ApplicationWindow')
self.minmaxLimits:bool = False
self.dropSpikes:bool = False
self.dropDuplicates:bool = False
self.dropDuplicatesLimit:float = 0.3
self.dropDuplicatesLimit:float = 0.54

# self.median_filter_factor: factor used for MedianFilter on both, temperature and RoR curves
self.median_filter_factor:Final[int] = 5 # k=3 is conservative seems not to catch all spikes in all cases; k=5 and k=7 seems to be ok; 13 might be the maximum; k must be odd!
Expand Down Expand Up @@ -6836,7 +6839,6 @@ def smooth_slice(self, a:'npt.NDArray[numpy.double]', b:'npt.NDArray[numpy.float
window_len:int = 7, window:str = 'hanning', decay_weights:Optional[List[int]] = None, decay_smoothing:bool = False,
re_sample:bool = True, back_sample:bool = True, a_lin:Optional['npt.NDArray[numpy.double]'] = None,
delta:bool=False) -> 'npt.NDArray[numpy.double]':

# 1. re-sample
if re_sample:
if a_lin is None or len(a_lin) != len(a):
Expand Down Expand Up @@ -6885,7 +6887,7 @@ def smooth_slice(self, a:'npt.NDArray[numpy.double]', b:'npt.NDArray[numpy.float
result.append(v)
else:
result.append(numpy.average(seq,axis=0,weights=w)) # works only if len(seq) = len(w)
res = numpy.array(res)
res = numpy.array(result)
# postCond: len(res) = len(b)
else:
# optimal smoothing (the default)
Expand Down Expand Up @@ -10608,6 +10610,9 @@ def fahrenheitMode(self, setdefaultaxes:bool = True) -> None:
if self.step100temp is not None:
self.step100temp = int(round(fromCtoFstrict(self.step100temp)))
self.AUCbase = int(round(fromCtoFstrict(self.AUCbase)))
self.dropDuplicatesLimit = fromCtoFstrict(100 + self.dropDuplicatesLimit) - fromCtoFstrict(100)
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:
Expand Down Expand Up @@ -10642,6 +10647,9 @@ def celsiusMode(self, setdefaultaxes:bool = True) -> None:
if self.step100temp is not None:
self.step100temp = int(round(fromFtoCstrict(self.step100temp)))
self.AUCbase = int(round(fromFtoCstrict(self.AUCbase)))
self.dropDuplicatesLimit = fromFtoCstrict(212 + self.dropDuplicatesLimit) - fromFtoCstrict(212)
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()
Expand Down
25 changes: 23 additions & 2 deletions src/artisanlib/comm.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,10 @@ def __init__(self, aw:'ApplicationWindow') -> None:
self.PHIDGET_DAQ1301_23, #157
self.PHIDGET_DAQ1301_45, #158
self.PHIDGET_DAQ1301_67, #159
self.Ikawa_MROR #160
self.Ikawa_MROR, #160
self.HH309_34, #161
self.Digi_Sense_20250_07, #162
self.Extech42570 #163
]
#string with the name of the program for device #27
self.externalprogram:str = 'test.py'
Expand Down Expand Up @@ -1283,6 +1286,20 @@ def HH309(self) -> Tuple[float,float,float]:
t2,t1 = self.CENTER309temperature()
return tx,t2,t1

def HH309_34(self) -> Tuple[float,float,float]:
#return saved readings collected at self.CENTER309temperature()
return self.aw.qmc.extra309TX,self.aw.qmc.extra309T4,self.aw.qmc.extra309T3

def Digi_Sense_20250_07(self) -> Tuple[float,float,float]:
tx = self.aw.qmc.timeclock.elapsedMilli()
t2,t1 = self.CENTER309temperature()
return tx,t2,t1

def Extech42570(self) -> Tuple[float,float,float]:
tx = self.aw.qmc.timeclock.elapsedMilli()
t2,t1 = self.CENTER309temperature()
return tx,t2,t1

def CENTER309(self) -> Tuple[float,float,float]:
tx = self.aw.qmc.timeclock.elapsedMilli()
t2,t1 = self.CENTER309temperature()
Expand Down Expand Up @@ -2093,6 +2110,8 @@ def confport(self) -> None:
self.SP.parity = self.parity
self.SP.stopbits = self.stopbits
self.SP.timeout = self.timeout
if self.platf != 'Windows':
self.SP.exclusive = True

def closeport(self) -> None:
try:
Expand Down Expand Up @@ -6159,7 +6178,7 @@ def ARDUINOTC4temperature(self, chan:Optional[str] = None) -> Tuple[float, float
self.SP.flush()
libtime.sleep(.1)
rl = self.SP.readline().decode('utf-8', 'ignore')[:-2]
res = rl.rsplit(',')
res = [('-1' if el.strip() == '' else el) for el in rl.rsplit(',')]

if self.aw.seriallogflag:
self.aw.addserial('ArduinoTC4: Tx = ' + str(command) + ' || Rx = ' + str(rl))
Expand Down Expand Up @@ -6637,6 +6656,8 @@ def confport(self) -> None:
self.SP.parity = self.parity
self.SP.stopbits = self.stopbits
self.SP.timeout = self.timeout
if platform.system() != 'Windows':
self.SP.exclusive = True

def openport(self) -> None:
try:
Expand Down
26 changes: 25 additions & 1 deletion src/artisanlib/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -3069,6 +3069,27 @@ def okEvent(self) -> None: # pyright: ignore [reportGeneralTypeIssues] # Code is
##########################
#### DEVICE 160 is +IKAWA \Delta Humidity / Humidity direction but +DEVICE cannot be set as main device
##########################
##########################
#### DEVICE 161 is +Omega HH309 34 but +DEVICE cannot be set as main device
##########################
elif meter == 'Digi-Sense 20250-07' and self.aw.qmc.device != 161:
self.aw.qmc.device = 17
#self.aw.ser.comport = "COM4"
self.aw.ser.baudrate = 9600
self.aw.ser.bytesize = 8
self.aw.ser.parity= 'N'
self.aw.ser.stopbits = 1
self.aw.ser.timeout = 0.7
message = QApplication.translate('Message','Device set to {0}. Now, choose serial port').format(meter)
elif meter == 'Extech 42570' and self.aw.qmc.device != 162:
self.aw.qmc.device = 17
#self.aw.ser.comport = "COM4"
self.aw.ser.baudrate = 9600
self.aw.ser.bytesize = 8
self.aw.ser.parity= 'N'
self.aw.ser.stopbits = 1
self.aw.ser.timeout = 0.7
message = QApplication.translate('Message','Device set to {0}. Now, choose serial port').format(meter)

# ADD DEVICE:

Expand Down Expand Up @@ -3248,7 +3269,10 @@ def okEvent(self) -> None: # pyright: ignore [reportGeneralTypeIssues] # Code is
1, # 157
1, # 158
1, # 159
9 # 160
9, # 160
3, # 161
3, # 162
3 # 163
]
#init serial settings of extra devices
for i, _ in enumerate(self.aw.qmc.extradevices):
Expand Down
3 changes: 1 addition & 2 deletions src/artisanlib/kaleido.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
import websockets.client
from contextlib import suppress
from threading import Thread
#from pymodbus.client.serial_asyncio import open_serial_connection # patched pyserial-asyncio
from pymodbus.transport.transport_serial import create_serial_connection # patched pyserial-asyncio
from pymodbus.transport.serialtransport import create_serial_connection # patched pyserial-asyncio

import logging
from typing import Final, Optional, TypedDict, Union, Callable, Dict, Tuple #for Python >= 3.9: can remove 'List' since type hints can now use the generic 'list'
Expand Down
4 changes: 2 additions & 2 deletions src/artisanlib/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16569,7 +16569,7 @@ def settingsLoad(self, filename:Optional[str] = None, theme:bool = False, machin
self.modbus.bytesize = toInt(settings.value('bytesize',self.modbus.bytesize))
self.modbus.stopbits = toInt(settings.value('stopbits',self.modbus.stopbits))
self.modbus.parity = s2a(toString(settings.value('parity',self.modbus.parity)))
self.modbus.timeout = self.float2float(toFloat(settings.value('timeout',self.modbus.timeout)))
self.modbus.timeout = max(0.3, self.float2float(toFloat(settings.value('timeout',self.modbus.timeout)))) # min serial MODBUS timeout is 300ms
self.modbus.modbus_serial_extra_read_delay = toFloat(settings.value('modbus_serial_extra_read_delay',self.modbus.modbus_serial_extra_read_delay))
self.modbus.serial_readRetries = toInt(settings.value('serial_readRetries',self.modbus.serial_readRetries))
self.modbus.IP_timeout = self.float2float(toFloat(settings.value('IP_timeout',self.modbus.IP_timeout)))
Expand Down Expand Up @@ -22216,7 +22216,7 @@ def setcommport(self, _:bool = False) -> None:
self.modbus.bytesize = int(str(dialog.modbus_bytesizeComboBox.currentText()))
self.modbus.stopbits = int(str(dialog.modbus_stopbitsComboBox.currentText()))
self.modbus.parity = str(dialog.modbus_parityComboBox.currentText())
self.modbus.timeout = self.float2float(toFloat(str(dialog.modbus_timeoutEdit.text())))
self.modbus.timeout = max(0.3, self.float2float(toFloat(str(dialog.modbus_timeoutEdit.text())))) # minimum serial timeout should be 300ms
try:
self.modbus.modbus_serial_extra_read_delay = toInt(dialog.modbus_Serial_delayEdit.text()) / 1000
except Exception: # pylint: disable=broad-except
Expand Down
7 changes: 4 additions & 3 deletions src/artisanlib/modbusport.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

if TYPE_CHECKING:
from artisanlib.main import ApplicationWindow # pylint: disable=unused-import
from pymodbus.client.base import ModbusBaseSyncClient # pylint: disable=unused-import
from pymodbus.client import ModbusSerialClient, ModbusTcpClient, ModbusUdpClient # pylint: disable=unused-import
from pymodbus.payload import BinaryPayloadBuilder # pylint: disable=unused-import
from pymodbus.payload import BinaryPayloadDecoder # pylint: disable=unused-import
from pymodbus.pdu import ModbusResponse # pylint: disable=unused-import
Expand Down Expand Up @@ -170,7 +170,8 @@ def __init__(self, aw:'ApplicationWindow') -> None:
self.PIDmultiplier:int = 0 # 0:no, 1:10x, 2:100x # :Literal[0,1,2]
self.byteorderLittle:bool = False
self.wordorderLittle:bool = True
self.master:Optional['ModbusBaseSyncClient'] = None
# self.master:Optional['ModbusBaseSyncClient'] = None
self.master:Union[None, 'ModbusSerialClient', 'ModbusTcpClient', 'ModbusUdpClient'] = None
self.COMsemaphore:QSemaphore = QSemaphore(1)
self.default_host:Final[str] = '127.0.0.1'
self.host:str = self.default_host # the TCP/UDP host
Expand Down Expand Up @@ -213,7 +214,7 @@ def disconnect(self) -> None:
try:
if self.master is not None:
_log.debug('disconnect()')
self.master.close()
self.master.close() # type:ignore[no-untyped-call]
self.clearReadingsCache()
self.aw.sendmessage(QApplication.translate('Message', 'MODBUS disconnected'))
del self.master
Expand Down
13 changes: 8 additions & 5 deletions src/requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
types-openpyxl==3.1.0.20240106
types-protobuf==4.24.0.20240106
types-psutil==5.9.5.20240106
types-pyserial==3.5.0.20240106
types-openpyxl==3.1.0.20240205
types-protobuf==4.24.0.20240129
types-psutil==5.9.5.20240205
types-pyserial==3.5.0.20240205
types-python-dateutil==2.8.19.20240106
types-PyYAML==6.0.12.12
types-requests==2.31.0.20240125
types-setuptools==69.0.0.20240125
types-urllib3==1.26.25.14
lxml-stubs==0.5.1
mypy==1.8.0
pyright==1.1.349
pyright==1.1.350
ruff>=0.1.15
pylint==3.0.3
pre-commit>=3.6.0
Expand All @@ -26,3 +26,6 @@ hypothesis>=6.96.2
coverage==7.4.1
coverage-badge==1.1.0
codespell==2.2.6
# the following 2 packages are not installed along aiohttp on Python3.12 and make mypy complain
async_timeout==4.0.3; python_version >= '3.12'
cycler==0.12.1; python_version >= '3.12'
14 changes: 7 additions & 7 deletions src/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,22 @@
######
# the following commented package versions are read by appveyor.yml and downloaded outside of pip.
#
# pyinstaller==6.3.0; platform_system='Windows'
# pyinstaller==6.4.0; platform_system='Windows'
# libusb==1.0.26; platform_system='Linux'
#
######
# packages that are required on all platforms
#
setuptools==69.0.3
setuptools==69.1.0
wheel==0.42.0
pyserial==3.5
pymodbus==3.6.3
pymodbus==3.6.4
python-snap7==1.3
Phidget22==1.18.20240123
Unidecode==1.3.8
qrcode==7.4.2
requests==2.31.0
requests-file==1.5.1
requests-file==2.0.0
pyusb==1.2.1
persist-queue==0.8.1
portalocker==2.8.2
Expand All @@ -46,7 +46,7 @@ psutil==5.9.8
typing-extensions==4.9.0; python_version < '3.8' # required for supporting Final and TypeDict on Python <3.8
protobuf==4.25.2
numpy==1.24.3; python_version < '3.9' # last Python 3.8 release
numpy==1.26.3; python_version >= '3.9'
numpy==1.26.4; python_version >= '3.9'
scipy==1.10.1; python_version < '3.9' # last Python 3.8 release
scipy==1.12.0; python_version >= '3.9'
wquantiles==0.6
Expand Down Expand Up @@ -82,7 +82,7 @@ PyQtWebEngine==5.15.6; (sys_platform=='darwin' and platform_release<'20.0') or (
PyQt6==6.6.1; (sys_platform=='darwin' and platform_release>='20.0') or (platform_system=='Windows' and python_version>'3.10') or (platform_system=='Linux' and platform_machine!='aarch64')
PyQt6-WebEngine==6.6.0; (sys_platform=='darwin' and platform_release>='20.0') or (platform_system=='Windows' and python_version>'3.10') or (platform_system=='Linux' and platform_machine!='aarch64')
###
pyinstaller==6.3.0; platform_system=='Linux' # on Windows pyinstaller is separately installed (see above)
pyinstaller==6.4.0; platform_system=='Linux' # on Windows pyinstaller is separately installed (see above)
###
### Qt build tools not part of PyQt but required by build-derived
qt5-tools==5.15.2.1.3; (platform_system=='Windows' and python_version<'3.9')
Expand All @@ -91,7 +91,7 @@ qt6-tools==6.5.0.1.3; (sys_platform=='darwin' and platform_release>='20.0') or (
########
### macOS specific packages
###
appnope==0.1.3; sys_platform=='darwin'
appnope==0.1.4; sys_platform=='darwin'
pyobjc-core==10.1; sys_platform=='darwin'
pyobjc-framework-Cocoa==10.1; sys_platform=='darwin'
py2app==0.28.7; sys_platform=='darwin'
Expand Down
Loading

0 comments on commit 8807ac1

Please sign in to comment.