Compare commits

...

6 Commits

Author SHA1 Message Date
caaf2689ff upd docstring 2024-02-16 12:53:34 +00:00
7e7aa1b4de 2.3.2 section added to CHANGELOG
patch bump
2024-02-16 12:50:54 +00:00
2dc096e306 connect_timeout kwarg added to README
Errors section added to README
2024-02-16 12:37:15 +00:00
ed397e57aa XAirRemoteConnectionTimeoutError added to errors 2024-02-16 12:26:24 +00:00
718ecbd982 timeout decorator func added to util 2024-02-16 12:26:00 +00:00
69cabb3db0 add configurable kwarg connect_timeout 2024-02-16 12:25:41 +00:00
6 changed files with 78 additions and 14 deletions

View File

@ -11,6 +11,14 @@ Before any major/minor/patch bump all unit tests will be run to verify they pass
- [ ]
## [2.3.2] - 2024-02-16
### Added
- Configurable kwarg `connect_timeout` added. Defaults to 2 seconds.
- New error class `XAirRemoteConnectionTimeoutError`. Raised if a connection validation times out.
- timeout kwarg + Errors section added to README.
## [2.3.1] - 2024-02-15
### Changed

View File

@ -55,7 +55,7 @@ if __name__ == "__main__":
main()
```
#### `xair_api.connect(kind_id, ip=ip, delay=delay)`
#### `xair_api.connect(kind_id, ip=ip, delay=0.02, connect_timeout=2)`
Currently the following devices are supported:
@ -72,6 +72,7 @@ The following keyword arguments may be passed:
- `port`: mixer port, defaults to 10023 for x32 and 10024 for xair
- `delay`: a delay between each command (applies to the getters). Defaults to 20ms.
- a note about delay, stability may rely on network connection. For wired connections the delay can be safely reduced.
- `connect_timeout`: amount of time to wait for a validated connection. Defaults to 2s.
## API
@ -317,6 +318,14 @@ for example:
print(mixer.query("/ch/01/mix/on"))
```
### Errors
- `errors.XAirRemoteError`: Base error class for XAIR Remote.
- `errors.XAirRemoteConnectionTimeoutError`:Exception raised when a connection attempt times out.
- The following attributes are available:
- `ip`: IP of the mixer.
- `port`: Port of the mixer.
### `Tests`
Unplug any expensive equipment before running tests.

View File

@ -1,6 +1,6 @@
[tool.poetry]
name = "xair-api"
version = "2.3.1"
version = "2.3.2"
description = "Remote control Behringer X-Air | Midas MR mixers through OSC"
authors = ["onyx-and-iris <code@onyxandiris.online>"]
license = "MIT"

View File

@ -1,2 +1,14 @@
class XAirRemoteError(Exception):
"""Base error class for XAIR Remote."""
class XAirRemoteConnectionTimeoutError(XAirRemoteError):
"""Exception raised when a connection attempt times out"""
def __init__(self, ip, port):
self.ip = ip
self.port = port
super().__init__(
f"Timeout attempting to connect to mixer at {self.ip}:{self.port}"
)

View File

@ -1,6 +1,35 @@
import functools
import time
from math import exp, log
from .errors import XAirRemoteConnectionTimeoutError
def timeout(func):
"""
Times out the validate_connection function once time elapsed exceeds remote.connect_timeout.
"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
remote, *_ = args
err = None
start = time.time()
while time.time() < start + remote.connect_timeout:
try:
func(*args, **kwargs)
remote.logger.debug(f"login time: {round(time.time() - start, 2)}")
err = None
break
except XAirRemoteConnectionTimeoutError as e:
err = e
continue
if err:
raise err
return wrapper
def lin_get(min, max, val):
return min + (max - min) * val

View File

@ -14,11 +14,11 @@ from pythonosc.dispatcher import Dispatcher
from pythonosc.osc_message_builder import OscMessageBuilder
from pythonosc.osc_server import BlockingOSCUDPServer
from . import adapter, kinds
from . import adapter, kinds, util
from .bus import Bus
from .config import Config
from .dca import DCA
from .errors import XAirRemoteError
from .errors import XAirRemoteConnectionTimeoutError, XAirRemoteError
from .fx import FX, FXSend
from .kinds import KindMap
from .lr import LR
@ -47,8 +47,6 @@ class OSCClientServer(BlockingOSCUDPServer):
class XAirRemote(abc.ABC):
"""Handles the communication with the mixer via the OSC protocol"""
_CONNECT_TIMEOUT = 0.5
_info_response = []
def __init__(self, **kwargs):
@ -57,6 +55,7 @@ class XAirRemote(abc.ABC):
self.xair_ip = kwargs["ip"] or self._ip_from_toml()
self.xair_port = kwargs["port"]
self._delay = kwargs["delay"]
self.connect_timeout = kwargs["connect_timeout"]
self.logger = logger.getChild(self.__class__.__name__)
if not self.xair_ip:
raise XAirRemoteError("No valid ip detected")
@ -74,13 +73,10 @@ class XAirRemote(abc.ABC):
conn = tomllib.load(f)
return conn["connection"].get("ip")
@util.timeout
def validate_connection(self):
self.send("/xinfo")
time.sleep(self._CONNECT_TIMEOUT)
if not self.info_response:
raise XAirRemoteError(
"Failed to setup OSC connection to mixer. Please check for correct ip address."
)
if not self.query("/xinfo"):
raise XAirRemoteConnectionTimeoutError(self.xair_ip, self.xair_port)
self.logger.info(
f"Successfully connected to {self.info_response[2]} at {self.info_response[0]}."
)
@ -117,7 +113,12 @@ def _make_remote(kind: KindMap) -> XAirRemote:
"""
def init_x32(self, *args, **kwargs):
defaultkwargs = {"ip": None, "port": 10023, "delay": 0.02}
defaultkwargs = {
"ip": None,
"port": 10023,
"delay": 0.02,
"connect_timeout": 2,
}
kwargs = defaultkwargs | kwargs
XAirRemote.__init__(self, *args, **kwargs)
self.kind = kind
@ -135,7 +136,12 @@ def _make_remote(kind: KindMap) -> XAirRemote:
self.config = Config.make(self)
def init_xair(self, *args, **kwargs):
defaultkwargs = {"ip": None, "port": 10024, "delay": 0.02}
defaultkwargs = {
"ip": None,
"port": 10024,
"delay": 0.02,
"connect_timeout": 2,
}
kwargs = defaultkwargs | kwargs
XAirRemote.__init__(self, *args, **kwargs)
self.kind = kind