Metadata-Version: 2.5
Name: lg-bartalk
Version: 0.1.1
Summary: LG soundbar control with reliable power-state updates
Project-URL: Source, https://github.com/skynet01/lg-bartalk
Project-URL: Issues, https://github.com/skynet01/lg-bartalk/issues
License-Expression: Apache-2.0
License-File: LICENSE
License-File: LICENSE.temescal
License-File: NOTICE
Requires-Python: >=3.10
Requires-Dist: pycryptodome>=3.23.0
Provides-Extra: test
Requires-Dist: temescal==0.5; extra == 'test'
Description-Content-Type: text/markdown

# BarTalk

Talk to LG Wi-Fi soundbars without losing track of their power state.

BarTalk replaces the archived [Temescal 0.5](https://github.com/google/python-temescal)
client. It comes from a Home Assistant custom fix for an LG S95Q that could leave
HA showing on after the soundbar was switched off manually. It runs inside your
Python application, not as a separate service.

## Install

Python 3.10 or newer is required.

```sh
python -m pip install lg-bartalk
```

## Use

```python
from lg_bartalk import LGSoundbarClient

speaker = LGSoundbarClient("192.0.2.1", callback=print)
try:
    speaker.get_info()
    speaker.set_volume(17)
finally:
    speaker.close()
```

Pass a callback to receive decoded responses on the client's listener thread.
Always call `close()` when finished. Commands are synchronous; async applications
should run construction, commands and cleanup in an executor.

## Switching from Temescal

Change the import; keep your existing calls:

```python
import lg_bartalk as temescal

speaker = temescal.temescal("192.0.2.1", port=9741, callback=print, logger=None)
speaker.set_func(temescal.E_ARC)
speaker.set_eq(eq=temescal.CINEMA)
speaker.close()
```

The Temescal 0.5 constructor, public methods, keyword arguments, tables and
numeric constants are retained and tested against the original library.
`encrypt_packet()` still returns a complete wire frame. The old package is only
used by compatibility tests; it is not a runtime dependency.

Unlike Temescal's silent send failures, failed commands raise `OSError` after
one reconnect attempt, and malformed payloads raise `ValueError` when decrypted
directly. Only one listener can run at a time. Direct manipulation
of Temescal's socket/thread internals is not a supported migration path.

## When does it check?

- Normally it waits for soundbar notifications instead of polling.
- A new connection has five seconds to supply its first valid response.
- While power is on or unknown, 30 seconds without data triggers a reconnect and state request.
- After a reported shutdown, five idle seconds trigger one reconnect to restore the listener.
- Once off is confirmed on that connection, recurring state requests stop.
- Broken or unresponsive sessions reconnect with increasing retry delays, capped at 30 seconds.

A valid response resets the retry delay. Models without power-status messages use
the normal 30-second idle deadline instead of repeatedly reconnecting every five seconds.

It reads complete TCP frames, so split reads cannot silently discard an update.
Idle receive deadlines while off send no traffic; socket deadlines also bound commands.
No HA polling automation is needed. Device support follows Temescal's protocol;
the original fix was exercised on an S95Q, not every LG model.
LG's fixed protocol key is not network authentication; use this on a trusted LAN.

## Development

```sh
python -m pip install -e '.[test]'
python -m unittest discover -s tests -v
```

## License

Apache-2.0. Protocol constants and command payloads retain Google's original
attribution in [NOTICE](NOTICE).
