Python

With dbus-next

pip install dbus-next
import asyncio
from dbus_next.aio import MessageBus


async def main() -> None:
    bus = await MessageBus().connect()
    intro = await bus.introspect("xyz.horchd.Daemon", "/xyz/horchd/Daemon")
    proxy = bus.get_proxy_object("xyz.horchd.Daemon", "/xyz/horchd/Daemon", intro)
    iface = proxy.get_interface("xyz.horchd.Daemon1")

    def on_detected(name: str, score: float, timestamp_us: int) -> None:
        print(f"{name}\tscore={score:.4f}\tts={timestamp_us}")

    iface.on_detected(on_detected)
    print("subscribed; waiting for fires (Ctrl-C to exit)")
    await asyncio.Event().wait()


if __name__ == "__main__":
    asyncio.run(main())

With jeepney (synchronous)

from jeepney import DBusAddress, MatchRule, message_bus, new_method_call
from jeepney.io.blocking import open_dbus_connection

addr = DBusAddress(
    "/xyz/horchd/Daemon",
    bus_name="xyz.horchd.Daemon",
    interface="xyz.horchd.Daemon1",
)
conn = open_dbus_connection(bus="SESSION")
rule = MatchRule(
    type="signal", interface="xyz.horchd.Daemon1", member="Detected"
)
conn.send_and_get_reply(message_bus.AddMatch(rule))
print("subscribed")

while True:
    msg = conn.receive()
    if msg.header.message_type.name != "signal":
        continue
    name, score, ts = msg.body
    print(f"{name}\tscore={score:.4f}\tts={ts}")

Polling state via horchctl status

If you only want a periodic health pulse, shelling out to horchctl status is the lowest-friction way:

import json, subprocess

def horchd_status() -> dict:
    raw = subprocess.check_output(["horchctl", "status", "--json"])
    return json.loads(raw)
Found a bug? Improve a section?

These docs live at codeberg.org/NewtTheWolf/docs.horchd.xyz. File an issue or send a pull request — even a typo fix is welcome.

For bugs and feature requests against the daemon itself, head to the horchd issue tracker.