mirror of
				https://github.com/onyx-and-iris/xair-api-python.git
				synced 2025-11-04 08:21:44 +00: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
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							@ -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.
 | 
			
		||||
 | 
			
		||||
@ -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"
 | 
			
		||||
 | 
			
		||||
@ -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}"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user