Python client library for the JBL MA-series (MA510/MA710/MA7100HP/MA9100HP) IP control protocol
Project description
jbl-ma-control
A pure-Python client library for the JBL MA-series AV receivers (MA510, MA710, MA7100HP, MA9100HP) over their IP control protocol.
It implements every command and option in Harman's IP control interface and commands for JBL MA510/MA710/MA7100HP/MA9100HP (document v1.7): power, input selection, volume, mute, surround decoding, equalization, room EQ, Dolby/DTS options, streaming status, IR passthrough, reboot, factory reset and more.
- No third-party runtime dependencies.
- Fully type-hinted (ships
py.typed). - Thorough error handling with a typed exception hierarchy.
- Framing layer is transport-independent and unit-tested; the client is tested end-to-end against an in-process mock AVR.
Installation
pip install jbl-ma-control
Quick start
from jbl_ma import JBLClient, InputSource, SurroundMode
# The AVR always listens on TCP port 50000.
with JBLClient("192.168.1.50") as avr:
model = avr.initialize() # identify ourselves; returns the Model
print("Connected to", model.name)
avr.power_on()
avr.set_input_source(InputSource.HDMI1)
avr.set_volume(35) # 0..99
avr.set_surround_mode(SurroundMode.ALL_STEREO)
avr.set_bass(4) # dB, -12..12
avr.unmute()
Async
For asyncio applications (including Home Assistant) use AsyncJBLClient, which
exposes the same method names as coroutines:
import asyncio
from jbl_ma import AsyncJBLClient, InputSource
async def main():
async with AsyncJBLClient("192.168.1.50") as avr:
await avr.initialize()
await avr.power_on()
await avr.set_input_source(InputSource.HDMI1)
await avr.set_volume(35)
asyncio.run(main())
Concurrent coroutines sharing one AsyncJBLClient are safe — transactions are
serialized internally so request/response pairs never interleave.
Manual connection management
The client is a context manager; you can also manage the connection manually:
avr = JBLClient("192.168.1.50", connect=False)
avr.connect()
try:
print(avr.get_volume())
finally:
avr.close()
Protocol notes
Every transmission uses the frame format from the PDF:
Controller -> AVR : <0x23><CmdID><DataLen><Data...><0x0D>
AVR -> Controller : <0x02 0x23><CmdID><RspCode><DataLen><Data...><0x0D>
-
After connecting you should call
initialize()so the AVR registers this controller. It returns the connectedModel. -
Call
heartbeat()periodically to keep the AVR out of its auto-standby timer;initialize()works as a heartbeat too. -
reboot()is acknowledged and then the unit restarts, dropping the connection. On the MA510 (verified on hardware) it comes back up in standby rather than powered on — callpower_on()afterwards if you need it on, and allow time for it to reboot before reconnecting. -
The AVR also emits unsolicited frames when its state changes from the front panel or IR remote. Pass an
on_eventcallback to receive them:def on_change(frame): print("state change:", frame.command, frame.data) avr = JBLClient("192.168.1.50", on_event=on_change)
API overview
| Area | Methods |
|---|---|
| System | initialize(), heartbeat(), reboot(), factory_reset(), get_software_version() |
| Power | get_power(), set_power(), power_on(), standby() |
| Display | get_display_dim(), set_display_dim() |
| Source | get_input_source(), set_input_source() |
| Volume | get_volume(), set_volume(), get_mute(), set_mute(), mute(), unmute() |
| Sound | get_surround_mode(), set_surround_mode(), get_dolby_audio_mode(), set_dolby_audio_mode(), get_dialog_enhanced(), set_dialog_enhanced(), get_drc(), set_drc() |
| EQ | get_treble(), set_treble(), get_bass(), set_bass(), get_room_eq(), set_room_eq() |
| Party mode | get_party_mode(), set_party_mode(), get_party_volume(), set_party_volume() |
| Streaming | get_streaming_state() |
| IR remote | send_ir() |
All enums (InputSource, SurroundMode, DisplayDim, RoomEQ,
DolbyAudioMode, PowerState, StreamingServer, PlayState,
SoftwareModule, Model, IRCommand) and value ranges are exported from the
top-level jbl_ma package.
Model availability: some options only exist on certain models (for example HDMI 5/6, Phono, party mode, DTS Neural:X and Dirac Live). The library exposes every documented value; sending one an attached model does not support results in the AVR replying with
ParameterNotRecognizedErrororCommandInvalidError.
Error handling
All errors derive from jbl_ma.JBLError:
from jbl_ma import JBLClient, JBLCommandError, CommandInvalidError, RoomEQ
with JBLClient("192.168.1.50") as avr:
try:
avr.set_room_eq(RoomEQ.DIRAC_LIVE)
except CommandInvalidError:
print("No room-correction filter has been uploaded yet.")
except JBLCommandError as exc:
print("AVR rejected the command, code", hex(exc.code))
| Exception | Meaning |
|---|---|
JBLConnectionError |
Socket refused / reset / closed |
JBLTimeoutError |
No complete response within the timeout |
JBLProtocolError |
A malformed frame was sent or received |
CommandNotRecognizedError |
Response code 0xC1 |
ParameterNotRecognizedError |
Response code 0xC2 |
CommandInvalidError |
Response code 0xC3 (command invalid at this time) |
InvalidDataLengthError |
Response code 0xC4 |
Low-level framing
The jbl_ma.protocol module can encode and decode frames without any I/O,
which is useful for testing or building your own transport:
from jbl_ma import encode_command, decode_responses, Command
frame = encode_command(Command.MASTER_VOLUME, b"\x28") # set volume to 40
responses, leftover = decode_responses(b"\x02\x23\x06\x00\x01\x28\x0d")
Development
pip install -e ".[dev]"
pytest
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jbl_ma_control-1.1.0.tar.gz.
File metadata
- Download URL: jbl_ma_control-1.1.0.tar.gz
- Upload date:
- Size: 22.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe28dc28fd2594fe77eae0d775359e219385c666b6eb2361688040e292f05393
|
|
| MD5 |
b072298cd1a29f7c561f3eb92672f217
|
|
| BLAKE2b-256 |
c31985b314aa6becaf930932f0713f265b32519d77a21556ff5da6e092720427
|
File details
Details for the file jbl_ma_control-1.1.0-py3-none-any.whl.
File metadata
- Download URL: jbl_ma_control-1.1.0-py3-none-any.whl
- Upload date:
- Size: 21.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
93d12b91bdb9cff6592476a7976afd3c4821236d3c39f72898626881ac1b4c4b
|
|
| MD5 |
aa60305e603b836524bc112a196a1370
|
|
| BLAKE2b-256 |
8009356ab67835cd89690f48ff7b446b54e25c3d9ec7e239d2b8b525a5f376a3
|