Skip to content

Commit

Permalink
- relaxed default timeouts of BLE communication
Browse files Browse the repository at this point in the history
- fixes MODBUS write errors (see pymodbus-dev/pymodbus#2368)
- (hopefully) improves speed of closing the RoastProperties dialog after using the Acaia connection
  • Loading branch information
MAKOMO committed Oct 10, 2024
1 parent 6265f5f commit fef8ba3
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 24 deletions.
23 changes: 13 additions & 10 deletions src/artisanlib/ble_port.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ def scan_and_connect(self,
blacklist:Set[str], # list of client addresses to ignore as they don't offer the required service
case_sensitive:bool=True,
disconnected_callback:Optional[Callable[[BleakClient], None]] = None,
scan_timeout:float=3,
connect_timeout:float=2) -> Tuple[Optional[BleakClient], Optional[str]]:
scan_timeout:float=5,
connect_timeout:float=4) -> Tuple[Optional[BleakClient], Optional[str]]:
if self._asyncLoopThread is None:
self._asyncLoopThread = AsyncLoopThread()
fut = asyncio.run_coroutine_threadsafe(
Expand All @@ -145,16 +145,19 @@ def scan_and_connect(self,
self._asyncLoopThread.loop)
try:
return fut.result()
except Exception as e: # pylint: disable=broad-except
raise fut.exception() from e # type: ignore[misc]
except Exception: # pylint: disable=broad-except
#raise fut.exception() from e # type: ignore[misc]
_log.error('exception in scan_and_connect: %s', fut.exception())
return None, None

def disconnect(self, client:'BleakClient') -> bool:
if self._asyncLoopThread is not None:
fut = asyncio.run_coroutine_threadsafe(client.disconnect(), self._asyncLoopThread.loop)
try:
return fut.result()
except Exception as e: # pylint: disable=broad-except
raise fut.exception() from e # type: ignore[misc]
except Exception: # pylint: disable=broad-except
#raise fut.exception() from e # type: ignore[misc]
_log.error('exception in disconnect: %s', fut.exception())
return False

def start_notify(self, client:BleakClient, uuid:str, callback: 'Callable[[BleakGATTCharacteristic, bytearray], Union[None, Awaitable[None]]]') -> None:
Expand Down Expand Up @@ -256,7 +259,7 @@ def connected(self) -> Optional[str]:


# connect and re-connect while self._running to BLE
async def _connect(self, case_sensitive:bool=True, scan_timeout:float=3, connect_timeout:float=2) -> None:
async def _connect(self, case_sensitive:bool=True, scan_timeout:float=5, connect_timeout:float=4) -> None:
blacklist:Set[str] = set()
while self._running:
# scan and connect
Expand Down Expand Up @@ -308,22 +311,22 @@ def disconnected_callback(self, _client:BleakClient) -> None:
asyncio.run_coroutine_threadsafe(self.set_event(), self._async_loop_thread.loop)

def send(self, message:bytes) -> None:
_log.debug('send: %s', message)
if self._ble_client is not None and self._connected_service_uuid is not None and self._connected_service_uuid in self._writers:
_log.debug('send: %s', message)
ble.write(self._ble_client, self._writers[self._connected_service_uuid], message)

async def _keep_alive(self) -> None:
while self._heartbeat_frequency > 0:
await asyncio.sleep(self._heartbeat_frequency)
self.heartbeat()

async def _connect_and_keep_alive(self,case_sensitive:bool,scan_timeout:float=3, connect_timeout:float=2) -> None:
async def _connect_and_keep_alive(self,case_sensitive:bool,scan_timeout:float, connect_timeout:float) -> None:
await asyncio.gather(
self._connect(case_sensitive,scan_timeout,connect_timeout),
self._keep_alive())


def start(self, case_sensitive:bool=True, scan_timeout:float=3, connect_timeout:float=2) -> None:
def start(self, case_sensitive:bool=True, scan_timeout:float=5, connect_timeout:float=4) -> None:
_log.debug('start')
if self._running:
_log.error('BLE client already running')
Expand Down
5 changes: 0 additions & 5 deletions src/artisanlib/canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -6580,11 +6580,6 @@ def reset(self,redraw:bool = True, soundOn:bool = True, keepProperties:bool = Fa
except Exception as e: # pylint: disable=broad-except
_log.exception(e)


import threading
for thread in threading.enumerate():
_log.info('PRINT running thread: %s', thread.name)

if not self.checkSaved():
return False

Expand Down
13 changes: 6 additions & 7 deletions src/artisanlib/modbusport.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,11 +566,12 @@ def writeSingleRegister(self, slave:int, register:int, value:float) -> None:
self.connect()
if self._asyncLoopThread is not None and self.isConnected():
assert self._client is not None
asyncio.run_coroutine_threadsafe(self._client.write_register(int(register),int(round(value)).to_bytes(2, 'big'),slave=int(slave)), self._asyncLoopThread.loop).result()
asyncio.run_coroutine_threadsafe(self._client.write_register(int(register),int(round(value)),slave=int(slave)), self._asyncLoopThread.loop).result() # type:ignore[arg-type] # type annotation wrong in pymodbus 3.7.3
# time.sleep(.03) # avoid possible hickups on startup
except Exception as ex: # pylint: disable=broad-except
_log.info('writeSingleRegister(%d,%d,%s) failed', slave, register, value)
_log.debug(ex)
_log.exception(ex)
self.disconnectOnError()
_, _, exc_tb = sys.exc_info()
if self.aw.qmc.flagon:
Expand Down Expand Up @@ -628,12 +629,10 @@ def writeRegisters(self, slave:int, register:int, values:Union[List[int], int])
self.connect()
if self._asyncLoopThread is not None and self.isConnected():
assert self._client is not None
byte_values:List[bytes]
if isinstance(values, int):
byte_values = [values.to_bytes(2, 'big')]
else:
byte_values = [v.to_bytes(2, 'big') for v in values]
asyncio.run_coroutine_threadsafe(self._client.write_registers(int(register),byte_values,slave=int(slave)), self._asyncLoopThread.loop).result()
# byte_values:List[bytes] = ([values.to_bytes(2, 'big')] if isinstance(values, int) else [v.to_bytes(2, 'big') for v in values])
int_values:List[int] = ([values] if isinstance(values, int) else values)
# asyncio.run_coroutine_threadsafe(self._client.write_registers(int(register),byte_values,slave=int(slave)), self._asyncLoopThread.loop).result()
asyncio.run_coroutine_threadsafe(self._client.write_registers(int(register),int_values,slave=int(slave)), self._asyncLoopThread.loop).result() # type:ignore[arg-type] # type annotation wrong in pymodbus 3.7.3
# time.sleep(.03)
except Exception as ex: # pylint: disable=broad-except
_log.info('writeRegisters(%d,%d,%s) failed', slave, register, values)
Expand Down
3 changes: 2 additions & 1 deletion src/artisanlib/roast_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -2538,7 +2538,8 @@ def closeEvent(self, _:Optional['QCloseEvent'] = None) -> None:
except Exception as e: # pylint: disable=broad-except
_log.exception(e)
try:
self.acaia.stop()
#self.acaia.stop()
QTimer.singleShot(2,self.acaia.stop) # no delay on RoastProperties window close on Windows
self.updateWeightLCD('')
except Exception as e: # pylint: disable=broad-except
_log.exception(e)
Expand Down
2 changes: 1 addition & 1 deletion src/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ python-snap7==1.3; python_version < '3.10' # last Python 3.9 release
python-snap7==2.0.0; python_version >= '3.10'
Phidget22==1.20.20240911
Unidecode==1.3.8
qrcode==8.0; python_version >= '3.10'
qrcode==8.0; python_version >= '3.9'
qrcode==7.4.2; python_version < '3.9' # last Python 3.8 release
requests==2.32.3
requests-file==2.1.0
Expand Down

0 comments on commit fef8ba3

Please sign in to comment.