mirror of
https://github.com/onyx-and-iris/xair-api-python.git
synced 2025-04-20 04:03:53 +01:00
Compare commits
6 Commits
6a2df6352d
...
caaf2689ff
Author | SHA1 | Date | |
---|---|---|---|
caaf2689ff | |||
7e7aa1b4de | |||
2dc096e306 | |||
ed397e57aa | |||
718ecbd982 | |||
69cabb3db0 |
@ -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
|
## [2.3.1] - 2024-02-15
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
11
README.md
11
README.md
@ -55,7 +55,7 @@ if __name__ == "__main__":
|
|||||||
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:
|
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
|
- `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.
|
- `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.
|
- 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
|
## API
|
||||||
|
|
||||||
@ -317,6 +318,14 @@ for example:
|
|||||||
print(mixer.query("/ch/01/mix/on"))
|
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`
|
### `Tests`
|
||||||
|
|
||||||
Unplug any expensive equipment before running tests.
|
Unplug any expensive equipment before running tests.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "xair-api"
|
name = "xair-api"
|
||||||
version = "2.3.1"
|
version = "2.3.2"
|
||||||
description = "Remote control Behringer X-Air | Midas MR mixers through OSC"
|
description = "Remote control Behringer X-Air | Midas MR mixers through OSC"
|
||||||
authors = ["onyx-and-iris <code@onyxandiris.online>"]
|
authors = ["onyx-and-iris <code@onyxandiris.online>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -1,2 +1,14 @@
|
|||||||
class XAirRemoteError(Exception):
|
class XAirRemoteError(Exception):
|
||||||
"""Base error class for XAIR Remote."""
|
"""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}"
|
||||||
|
)
|
||||||
|
@ -1,6 +1,35 @@
|
|||||||
import functools
|
import functools
|
||||||
|
import time
|
||||||
from math import exp, log
|
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):
|
def lin_get(min, max, val):
|
||||||
return min + (max - min) * val
|
return min + (max - min) * val
|
||||||
|
@ -14,11 +14,11 @@ from pythonosc.dispatcher import Dispatcher
|
|||||||
from pythonosc.osc_message_builder import OscMessageBuilder
|
from pythonosc.osc_message_builder import OscMessageBuilder
|
||||||
from pythonosc.osc_server import BlockingOSCUDPServer
|
from pythonosc.osc_server import BlockingOSCUDPServer
|
||||||
|
|
||||||
from . import adapter, kinds
|
from . import adapter, kinds, util
|
||||||
from .bus import Bus
|
from .bus import Bus
|
||||||
from .config import Config
|
from .config import Config
|
||||||
from .dca import DCA
|
from .dca import DCA
|
||||||
from .errors import XAirRemoteError
|
from .errors import XAirRemoteConnectionTimeoutError, XAirRemoteError
|
||||||
from .fx import FX, FXSend
|
from .fx import FX, FXSend
|
||||||
from .kinds import KindMap
|
from .kinds import KindMap
|
||||||
from .lr import LR
|
from .lr import LR
|
||||||
@ -47,8 +47,6 @@ class OSCClientServer(BlockingOSCUDPServer):
|
|||||||
class XAirRemote(abc.ABC):
|
class XAirRemote(abc.ABC):
|
||||||
"""Handles the communication with the mixer via the OSC protocol"""
|
"""Handles the communication with the mixer via the OSC protocol"""
|
||||||
|
|
||||||
_CONNECT_TIMEOUT = 0.5
|
|
||||||
|
|
||||||
_info_response = []
|
_info_response = []
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
@ -57,6 +55,7 @@ class XAirRemote(abc.ABC):
|
|||||||
self.xair_ip = kwargs["ip"] or self._ip_from_toml()
|
self.xair_ip = kwargs["ip"] or self._ip_from_toml()
|
||||||
self.xair_port = kwargs["port"]
|
self.xair_port = kwargs["port"]
|
||||||
self._delay = kwargs["delay"]
|
self._delay = kwargs["delay"]
|
||||||
|
self.connect_timeout = kwargs["connect_timeout"]
|
||||||
self.logger = logger.getChild(self.__class__.__name__)
|
self.logger = logger.getChild(self.__class__.__name__)
|
||||||
if not self.xair_ip:
|
if not self.xair_ip:
|
||||||
raise XAirRemoteError("No valid ip detected")
|
raise XAirRemoteError("No valid ip detected")
|
||||||
@ -74,13 +73,10 @@ class XAirRemote(abc.ABC):
|
|||||||
conn = tomllib.load(f)
|
conn = tomllib.load(f)
|
||||||
return conn["connection"].get("ip")
|
return conn["connection"].get("ip")
|
||||||
|
|
||||||
|
@util.timeout
|
||||||
def validate_connection(self):
|
def validate_connection(self):
|
||||||
self.send("/xinfo")
|
if not self.query("/xinfo"):
|
||||||
time.sleep(self._CONNECT_TIMEOUT)
|
raise XAirRemoteConnectionTimeoutError(self.xair_ip, self.xair_port)
|
||||||
if not self.info_response:
|
|
||||||
raise XAirRemoteError(
|
|
||||||
"Failed to setup OSC connection to mixer. Please check for correct ip address."
|
|
||||||
)
|
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
f"Successfully connected to {self.info_response[2]} at {self.info_response[0]}."
|
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):
|
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
|
kwargs = defaultkwargs | kwargs
|
||||||
XAirRemote.__init__(self, *args, **kwargs)
|
XAirRemote.__init__(self, *args, **kwargs)
|
||||||
self.kind = kind
|
self.kind = kind
|
||||||
@ -135,7 +136,12 @@ def _make_remote(kind: KindMap) -> XAirRemote:
|
|||||||
self.config = Config.make(self)
|
self.config = Config.make(self)
|
||||||
|
|
||||||
def init_xair(self, *args, **kwargs):
|
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
|
kwargs = defaultkwargs | kwargs
|
||||||
XAirRemote.__init__(self, *args, **kwargs)
|
XAirRemote.__init__(self, *args, **kwargs)
|
||||||
self.kind = kind
|
self.kind = kind
|
||||||
|
Loading…
x
Reference in New Issue
Block a user