Skip to main content

aiohpprinter

CI Status Test coverage percentage

uv black prek

PyPI Version Supported Python versions License


Source Code: https://github.com/chemelli74/aiohpprinter


Python library to get information from HP printers

aiohpprinter talks directly to an HP printer's embedded web server (EWS) - the same /DevMgmt/*.xml, /ePrint/*.xml and /IoMgmt/* endpoints the ha-hpprinter Home Assistant integration uses - and exposes the result as typed, async Python instead of raw XML. It has no Home Assistant dependency and can be used from any async Python application.

Installation

Install this via pip (or your favourite package manager):

pip install aiohpprinter

Basic usage

import asyncio

import aiohttp

from aiohpprinter import HpPrinter


async def main() -> None:
    async with aiohttp.ClientSession() as session:
        printer = HpPrinter("192.168.1.100", session)
        data = await printer.update()

        print(data.online)
        if data.device:
            print(data.device.make_and_model)
        for consumable in data.consumables.values():
            print(consumable.consumable_id, consumable.percentage_level_remaining)


asyncio.run(main())

update() is the one-call aggregate: it fetches every endpoint the printer answers and returns an HpPrinterData snapshot. Each endpoint is also available individually - printer.device(), printer.status(), printer.consumables(), printer.printer_usage(), printer.scanner_usage(), printer.copy_usage(), printer.fax_usage(), printer.adapters(), printer.eprint(), printer.wifi() - for callers that only need one piece of data, or that want failures raised instead of absorbed (see Exception handling below).

Session handling

HpPrinter requires an aiohttp.ClientSession, and the caller owns it: create it, share it between clients if you like (e.g. Home Assistant's shared session) and close it when done. HpPrinter never closes it and holds no other resources, so it needs no close() or async with.

HTTP and HTTPS

The EWS is reached over plain HTTP on port 80 by default. Pass ssl=True to use HTTPS instead; port then defaults to 443 (pass port to override either default).

Certificates are never verified, since most printers ship a self-signed one; this overrides the session's own setting (e.g. Home Assistant's verifying one). Many printers answer some endpoints over HTTP and redirect others to HTTPS: redirects are always followed.

Supported HP functionality

Data Endpoint Notes
Device identity /DevMgmt/ProductConfigDyn.xml Model, serial number, manufacturer
Status /DevMgmt/ProductStatusDyn.xml Used as the "is the printer reachable" check
Consumables (ink/toner/printhead) /DevMgmt/ConsumableConfigDyn.xml Life state, warranty, capacity
Consumable usage /DevMgmt/ProductUsageDyn.xml Merged into the same consumable, by label code
Printer engine usage /DevMgmt/ProductUsageDyn.xml Page counters
Scanner engine usage /DevMgmt/ProductUsageDyn.xml Page counters
Copy application usage /DevMgmt/ProductUsageDyn.xml Page counters
Fax application usage /DevMgmt/ProductUsageDyn.xml Page counters
Network adapters /IoMgmt/Adapters May reply as JSON instead of XML on some models
HP ePrint / cloud printing /ePrint/ePrintConfigDyn.xml Registration and cloud services state
Wireless Direct /DevMgmt/NetAppsSecureDyn.xml SSID prefix, connection method

Only the status endpoint is treated as required (it is what is_online() and update() use to decide whether the printer is reachable at all). Every other endpoint is optional: not every HP printer supports scanning, copying, faxing, cloud printing or Wireless Direct, and update() leaves the corresponding field None (or an empty list) instead of failing when one is missing.

Exception handling

HpPrinterError
├── HpPrinterConnectionError   # network/transport failure
│   └── HpPrinterSslError      # TLS handshake failed, e.g. port without HTTPS
├── HpPrinterTimeoutError      # request exceeded the client timeout
├── HpPrinterHttpError         # non-2xx HTTP status (`.status` holds it)
├── HpPrinterParseError        # response body was not valid XML/JSON
└── HpPrinterUnsupportedError  # reserved for a required feature genuinely absent

The single-endpoint methods (device(), status(), consumables(), ...) raise these normally, so a caller that wants to distinguish "printer is unreachable" from "printer sent garbage" can catch the specific subclass it cares about, or HpPrinterError to catch anything.

update() and is_online() are the exception to that: they are explicitly designed to tolerate a printer that only partially answers (see Supported HP functionality above), so they catch every HpPrinterError from the optional endpoints internally and never raise for that reason. update() still lets a failure while checking is_online() be represented as online=False rather than an exception, since that is the question it exists to answer.

Adding a New Printer Model

aiohpprinter's test suite is fixture-driven: every directory under tests/fixtures/ is picked up automatically by both the parser suite (tests/test_parsers.py) and an end-to-end update() test that serves the fixture's files from a local HTTP server (test_update_fixture in tests/test_client.py). No new test function is required.

  1. Capture the printer with the fixture script, giving its IP address or hostname:

    python scripts/capture_fixture.py 192.168.1.100
    

    The model name, and so the fixture directory, is taken from the printer's ProductConfigDyn.xml: when it only reports its family (MakeAndModel "HP OfficeJet Pro 9020 series"), the variant from SKUIdentifier ("9022e") replaces the series number. Pass --model "..." to override it.

    This creates e.g. tests/fixtures/hp_officejet_pro_9022e/ with:

    • every endpoint aiohpprinter reads (ProductStatusDyn.xml is required; any other endpoint answering 404 is skipped, since that model doesn't support that feature). Adapters is saved as Adapters.json when the printer answers it as JSON;
    • every other resource the printer lists in /DevMgmt/DiscoveryTree.xml (pass --no-discovery to skip these);
    • expected.json, generated from what the current parsers return;
    • a README.md recording the fixture's provenance.

    Serial numbers, IDs, MAC/IP addresses, hostnames, SSIDs, e-mail addresses and credentials are replaced with REDACTED. Use --port / --ssl for a non-default EWS, and --force to recapture over an existing directory.

  2. Review the captured files for anything identifying the redaction missed, and check expected.json: it records what the parsers return today, so a wrong or missing value there is a parser bug to fix, not a value to keep.

  3. Fix the relevant parser in src/aiohpprinter/parsers/ if a field is missing or wrong, correct expected.json to match, then run the suite: uv run pytest (or uv run pytest -k <model> for just the new fixture).

Known limitations

  • Full captures (every endpoint aiohpprinter reads plus every DiscoveryTree.xml resource) exist for three models: HP OfficeJet Pro 9022e, HP ENVY Photo 7830 All-in-One Printer and HP Color LaserJet MFP M476dw. An HP Color LaserJet M255dw is covered by the endpoints aiohpprinter reads only, and an HP LaserJet 200 color M251nw by ProductUsageDyn.xml only. None of them reports an ePrint PrinterID, so that field is only covered by a unit test. If you have another printer, contributing a capture per Adding a New Printer Model above is very welcome.
  • A field is looked up at one fixed XML path per printer generation (tolerant of a PEID attribute appearing or not, see aiohpprinter.parsers.common.text), but not of a field moving to a different element entirely on some model; that would need a fixture demonstrating the variation and a parser update.

Manual testing against a real printer

library_test.py connects to a real printer and prints an update() snapshot:

python library_test.py --host 192.168.1.100

Contributors ✨

Thanks goes to these wonderful people (emoji key):

chemelli74
Simone Chemelli
tr4nt0r
Manu
neyzm
neyzm

This project follows the all-contributors specification. Contributions of any kind welcome!

Credits

This package was created with Copier and the browniebroke/pypackage-template project template.

Metadata

Release files for aiohpprinter 3.1.1

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

Source distribution (sdist)

Source distribution for aiohpprinter 3.1.1
File Size Uploaded Provenance Actions
aiohpprinter-3.1.1.tar.gz 35.3 kB With provenance Details for aiohpprinter-3.1.1.tar.gz

Built distribution (wheel)

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

Total release size: 63.4 kB

Release files / aiohpprinter-3.1.1.tar.gz

Download URL aiohpprinter-3.1.1.tar.gz
Size 35.3 kB
Tags Source
SHA-256 checksum
How to use checksums
25d4d0390aa3dd7f1694a0822476ee80e869009d1e7f73f4e39dbe72e92f71f2
BLAKE2b-256 checksum
How to use checksums
d05dcfcd28e84a04935b850e42c171eef2bddbb40b091c206b318bf42271b1f5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Nov 2, 2026.

Transparency log

Release files / aiohpprinter-3.1.1-py3-none-any.whl

Download URL aiohpprinter-3.1.1-py3-none-any.whl
Size 28.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4a511e8346006c4c99eb126333d5fbd5cd44e0859fc695efe235e3bfeabc306e
BLAKE2b-256 checksum
How to use checksums
8a13d19d21fadf5f3d5f2213bb86f4a6e01136dde23af2d7465e0a4fc3e08499
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Nov 2, 2026.

Transparency log

Security for aiohpprinter 3.1.1

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.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for aiohpprinter-3.1.1.tar.gz

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 Nov 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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