Skip to main content

aioharmony

Codecov

Python library for programmatically using a Logitech Harmony Link or Ultimate Hub.

This library originated from iandday/pyharmony which was a fork of bkanuka/pyharmony with the intent to:

  • Make the harmony library asyncio

  • Ability to provide one’s own custom callbacks to be called

  • Automatic reconnect, even if re-connection cannot be established for a time

  • More easily get the HUB configuration through API call

  • Additional callbacks: connect, disconnect, HUB configuration updated

  • Using unique msgid’s ensuring that responses from the HUB are correctly managed.

Protocol

As the harmony protocol is being worked out, notes will be in PROTOCOL.md.

Status

  • Retrieving current activity

  • Querying for entire device information

  • Querying for activity information only

  • Querying for current activity

  • Starting Activity

  • Sending Command

  • Changing channels

  • Custom callbacks.

Installation

pip install aioharmony

Python API usage

aioharmony is an asyncio library, so every method that talks to the Hub is a coroutine and must be await-ed from inside an event loop. The public entry point is the HarmonyAPI class.

Connecting to a Hub

import asyncio

from aioharmony.harmonyapi import HarmonyAPI


async def main() -> None:
    client = HarmonyAPI(ip_address="192.168.1.203", protocol="WEBSOCKETS")
    await client.connect()
    try:
        print(f"Connected to {client.name} (firmware {client.fw_version})")
    finally:
        await client.close()


asyncio.run(main())

protocol accepts "WEBSOCKETS" (default for modern firmware) or "XMPP" (legacy hubs that still have XMPP enabled). Always pair connect() with close() — typically inside a try/finally — so the background reconnect loop and the WebSocket session shut down cleanly.

Starting an activity

start_activity() takes an activity ID, not a name. Use get_activity_id() to look the ID up:

async def start_watch_tv(client: HarmonyAPI) -> None:
    activity_id = client.get_activity_id("Watch TV")
    if activity_id is None:
        raise ValueError("Activity 'Watch TV' is not configured on this hub")
    success, message = await client.start_activity(activity_id)
    if not success:
        raise RuntimeError(f"Failed to start activity: {message}")

Showing the current activity / powering off

async def show_and_power_off(client: HarmonyAPI) -> None:
    activity_id, activity_name = client.current_activity
    print(f"Current activity: {activity_name} ({activity_id})")
    await client.power_off()

Sending a device command

send_commands() takes a SendCommandDevice (or a list of them, optionally interleaved with float delays in seconds). device is the device ID — look it up with get_device_id():

from aioharmony.const import SendCommandDevice


async def volume_up(client: HarmonyAPI, device_name: str) -> None:
    device_id = client.get_device_id(device_name)
    if device_id is None:
        raise ValueError(f"Device {device_name!r} not found")
    command = SendCommandDevice(device=device_id, command="VolumeUp", delay=0.2)
    # send_commands returns an empty list on success, or a list of
    # SendCommandResponse entries describing the failures.
    errors = await client.send_commands(command)
    for err in errors:
        print(f"{err.command.command} failed: {err.msg} (code {err.code})")

Reacting to hub events with callbacks

ClientCallbackType is a NamedTuple with five slots (connect, disconnect, new_activity_starting, new_activity, config_updated). Each slot accepts a plain callable, an asyncio.Future, an asyncio.Event, or None:

from aioharmony.const import ClientCallbackType


def on_new_activity(info: tuple[int, str]) -> None:
    activity_id, activity_name = info
    print(f"Now running: {activity_name} ({activity_id})")


callbacks = ClientCallbackType(
    connect=None,
    disconnect=None,
    new_activity_starting=None,
    new_activity=on_new_activity,
    config_updated=None,
)
client = HarmonyAPI(
    ip_address="192.168.1.203", protocol="WEBSOCKETS", callbacks=callbacks
)

See the examples/ directory in the source tree for runnable versions of each snippet above.

Command-line usage

usage: __main__.py [-h] (--harmony_ip HARMONY_IP | --discover)
                   [--protocol {WEBSOCKETS,XMPP}]
                   [--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
                   [--logmodules LOGMODULES]
                   [--show_responses | --no-show_responses] [--wait WAIT]
                   {show_config,show_detailed_config,show_current_activity,start_activity,power_off,sync,listen,activity_monitor,send_command,change_channel}
                   ...

aioharmony - Harmony device control

positional arguments:
  {show_config,show_detailed_config,show_current_activity,start_activity,power_off,sync,listen,activity_monitor,send_command,change_channel}
    show_config         Print the Harmony device configuration.
    show_detailed_config
                        Print the detailed Harmony device configuration.
    show_current_activity
                        Print the current activity config.
    start_activity      Switch to a different activity.
    power_off           Stop the activity.
    sync                Sync the harmony.
    listen              Output everything HUB sends out. Use in combination
                        with --wait.
    activity_monitor    Monitor and show when an activity is changing. Use in
                        combination with --wait to keep monitoring
                        foractivities otherwise only current activity will be
                        shown.
    send_command        Send a simple command.
    send_commands       Send a series of simple commands separated by spaces.
    change_channel      Change the channel

optional arguments:
  -h, --help            show this help message and exit
  --harmony_ip HARMONY_IP
                        IP Address of the Harmony device, multiple IPs can be
                        specified as a comma separated list without spaces.
                        (default: None)
  --discover            Scan for Harmony devices. (default: False)
  --protocol {WEBSOCKETS,XMPP}
                        Protocol to use to connect to HUB. Note for XMPP one
                        has to ensure that XMPP is enabledon the hub.
                        (default: None)
  --loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}
                        Logging level for all components to print to the
                        console. (default: ERROR)
  --logmodules LOGMODULES
                        Restrict logging to modules specified. Multiple can be
                        provided as a comma separated list without any spaces.
                        Use * to include any further submodules. (default:
                        None)
  --show_responses      Print out responses coming from HUB. (default: False)
  --no-show_responses   Do not print responses coming from HUB. (default:
                        False)
  --wait WAIT           How long to wait in seconds after completion, useful
                        in combination with --show-responses. Use -1 to wait
                        infinite, otherwise has to be a positive number.
                        (default: 0)

Release Notes

See changelog <https://github.com/Harmony-Libs/aioharmony/blob/main/CHANGELOG.md> for release notes

TODO

  • Redo discovery for asyncio. This will be done once XMPP is re-implemented by Logitech

  • More items can be done from the Harmony iOS app; determining what could be done within the library as well

  • Is it possible to update device configuration?

Metadata

Release files for aioharmony 1.0.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aioharmony 1.0.9
File Size Uploaded
aioharmony-1.0.9.tar.gz 63.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aioharmony 1.0.9
File Interpreter ABI Platform
aioharmony-1.0.9-py3-none-any.whl Python 3 none any Details

Total release size: 104.6 kB

Release files / aioharmony-1.0.9.tar.gz

Download URL aioharmony-1.0.9.tar.gz
Size 63.3 kB
Tags Source
SHA-256 checksum
How to use checksums
9882a404376e14acfa68ab515ef3c7fa39abcd4d36955c59ecff24f9c55e2dc6
BLAKE2b-256 checksum
How to use checksums
edb21bf4fec9d7b6d0b797550983cd967e51a5c86adedadb7d77c3557107453b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Release files / aioharmony-1.0.9-py3-none-any.whl

Download URL aioharmony-1.0.9-py3-none-any.whl
Size 41.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d280834c9ee27703744e8696641a68dbee57f10755dbb80eb99d8bf7a0116a13
BLAKE2b-256 checksum
How to use checksums
b410f90c0aa182679089fb363237002cd5c3707f0168b638bd48ff9e0f23823f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Release history Release notifications | RSS feed

1.0.10

2 release files

This release

1.0.9 This release

2 release files

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.14

2 release files

0.2.13

2 release files

0.2.12

2 release files

0.2.11

2 release files

0.2.10

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.12

2 release files

0.1.11

2 release files

0.1.10

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page