Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion ocflib/printing/printers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import puresnmp

PRINTERS = ['logjam', 'pagefault', 'papercut']
PRINTERS = ['logjam', 'pagefault', 'papercut', 'fishpaper']

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we query ldap and get printers in prod env

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that would be nice but probably not realistic right now as we'd also need to tell the difference between hp printers and not


OID_TONER_MAX = '1.3.6.1.2.1.43.11.1.1.8.1.1'
OID_TONER_CUR = '1.3.6.1.2.1.43.11.1.1.9.1.1'
Expand All @@ -13,6 +13,12 @@

OID_LIFETIME_PAGES_PRINTED = '1.3.6.1.2.1.43.10.2.1.4.1.1'

OID_STATUS = '1.3.6.1.2.1.43.16.5.1.2.1'

OID_TRAY_MAX = '1.3.6.1.2.1.43.8.2.1.9.1'
OID_TRAY_CUR = '1.3.6.1.2.1.43.8.2.1.10.1'
OID_TRAY_NAME = '1.3.6.1.2.1.43.8.2.1.13.1'


def _snmp(host, oid):
try:
Expand All @@ -22,6 +28,18 @@ def _snmp(host, oid):
raise IOError('Device {} returned SNMP error: {}'.format(host, e)) from e


def _snmp_walk(host, oid):
try:
client = puresnmp.PyWrapper(puresnmp.Client(host, puresnmp.V2C('public')))

async def _collect():
return [item async for item in client.walk(oid)]

return asyncio.run(_collect())
except Exception as e:
raise IOError('Device {} returned SNMP error: {}'.format(host, e)) from e


def get_toner(printer):
"""Returns (cur, max) toner tuple for the given printer."""
return tuple(
Expand All @@ -41,3 +59,38 @@ def get_maintkit(printer):
def get_lifetime_pages(printer):
"""Returns lifetime pages printed for the given printer."""
return int(_snmp(printer, OID_LIFETIME_PAGES_PRINTED))


def get_paper_trays(printer):
"""Returns a list of (name, cur, max) tuples for each input tray.

cur and max are sheet counts. Tray 1 (manual/multipurpose feed) and trays
where the current level is not sensed by the printer (negative value) are
excluded.
"""
def _decode(v):
return v.decode() if isinstance(v, bytes) else str(v)

names_raw = _snmp_walk(printer, OID_TRAY_NAME)
maxes_raw = _snmp_walk(printer, OID_TRAY_MAX)
curs_raw = _snmp_walk(printer, OID_TRAY_CUR)

trays = []
for (_, name), (_, max_val), (_, cur_val) in zip(names_raw, maxes_raw, curs_raw):
name = _decode(name)
max_val = int(max_val)
cur_val = int(cur_val)
if name == 'Tray 1' or max_val <= 0 or cur_val < 0:
continue
trays.append((name, cur_val, max_val))
return trays


def get_status(printer):
"""Returns a list of non-empty status strings for the given printer.

Status messages are read from the printer's display/alert table
(SNMPv2-SMI::mib-2.43.16.5.1.2.1). Empty entries are omitted.
"""
results = _snmp_walk(printer, OID_STATUS)
return [value.decode() if isinstance(value, bytes) else str(value) for _, value in results if value]
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "ocflib"
version = "2026.05.05"
version = "2026.05.05-1"
description = "libraries for account and server management"
authors = ["Open Computing Facility <help@ocf.berkeley.edu>"]
readme = "README.md"
Expand Down