Skip to content

Add async_set_datetime and async_get_datetime methods#761

Merged
bieniu merged 9 commits intobieniu:masterfrom
lorek123:feature/set-datetime
Apr 9, 2026
Merged

Add async_set_datetime and async_get_datetime methods#761
bieniu merged 9 commits intobieniu:masterfrom
lorek123:feature/set-datetime

Conversation

@lorek123
Copy link
Copy Markdown
Contributor

@lorek123 lorek123 commented Mar 26, 2026

Closes #28

Summary

Many Brother printers (especially older inkjet models like the DCP-J552DW) lose their clock after a power outage, which breaks scanning functionality until the date/time is manually reset on the control panel.

This PR adds SNMP-based methods to read and set the printer's date/time via the standard hrSystemDate.0 OID (1.3.6.1.2.1.25.1.2.0), enabling automated clock restoration (e.g. via Home Assistant).

New API

  • Brother(write_community=...) — optional parameter for the SNMP write community string (defaults to "internal", which is the standard Brother write community)
  • async_get_datetime() -> datetime | None — reads the printer's current clock as a naive datetime (printer has no timezone concept)
  • async_set_datetime(dt=None) — sets the printer's clock; defaults to the host's local time if no datetime is provided

Changes

  • brother/__init__.py — added set_cmd import, write_community parameter, async_get_datetime, async_set_datetime, _build_dateandtime, _parse_dateandtime
  • brother/const.py — added OID_DATETIME, DATEANDTIME_MIN_LENGTH, DEFAULT_WRITE_COMMUNITY constants
  • tests/test_datetime.py — 14 new tests covering set/get, error paths, DateAndTime encoding/decoding, and community string configuration

Background

Tested live on a Brother DCP-J552DW. The hrSystemDate.0 OID is a standard HOST-RESOURCES-MIB OID supported across Brother models. The write community "internal" is the default Brother SNMP write community string, discovered via SNMP reconnaissance and firmware analysis of BroSNMP.dll.

Test plan

  • All 70 tests pass (14 new + 56 existing, 0 regressions)
  • ruff check passes with no errors
  • Verified async_set_datetime() and async_get_datetime() against a real DCP-J552DW printer
  • Confirmed correct local timezone handling (tested from CET/Poland timezone)

Made with Cursor

Summary by CodeRabbit

  • New Features

    • View the device's current date and time.
    • Set the device's date and time, including an option to use the system time.
    • Configure a custom SNMP write community for write operations.
  • Tests

    • Added comprehensive unit tests covering datetime get/set flows, error mappings, and encoding/decoding edge cases.

Many Brother printers (especially older inkjet models like the
DCP-J552DW) lose their clock after a power outage, which breaks
scanning functionality. This adds SNMP-based methods to read and
set the printer's date/time via the standard hrSystemDate.0 OID
(1.3.6.1.2.1.25.1.2.0) using a configurable write community string
(default: "internal").

New API:
  - Brother(write_community=...) parameter
  - async_get_datetime() -> datetime | None
  - async_set_datetime(dt=None) sets clock (defaults to local time)

Made-with: Cursor
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds SNMP DateAndTime support: new constants and utilities to encode/decode RFC 2579 DateAndTime, plus Brother.async_get_datetime, Brother.async_set_datetime, and an optional write_community parameter with tests and helper to build SNMP SET request args.

Changes

Cohort / File(s) Summary
Constants
brother/const.py
Added OID_DATETIME, DATEANDTIME_MIN_LENGTH, and DEFAULT_WRITE_COMMUNITY.
Brother core
brother/__init__.py
Added optional write_community param to constructor/create; implemented async_get_datetime, async_set_datetime, and _request_args_for; updated SNMP imports for set_cmd and OctetString/date-time helpers; error mappings for PySnmp errors and SNMP error-status handling.
Utilities
brother/utils.py
Added build_dateandtime(dt: datetime) -> bytes and `parse_dateandtime(raw: bytes) -> datetime
Tests — fixtures
tests/conftest.py
Added brother_with_request_args fixture that populates Brother._request_args with mocked SnmpEngine, CommunityData, and ContextData for testing.
Tests — behavior & unit
tests/test_init.py
Extensive tests for GET/SET flows (success, SNMP error-status mapping, connection errors), DateAndTime encode/decode, default and custom write community behavior, and async SNMP call mocking.

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant Brother
    participant SNMP_Engine as SNMP Engine
    participant Device
    Client->>Brother: async_get_datetime()
    Brother->>SNMP_Engine: get_cmd(OID_DATETIME, request_args)
    SNMP_Engine->>Device: SNMP GET request
    Device-->>SNMP_Engine: DateAndTime octets / error
    SNMP_Engine-->>Brother: response / errindication
    Brother->>Brother: parse_dateandtime(octets) or map error
    Brother-->>Client: datetime | None | SnmpError | ConnectionError
Loading
sequenceDiagram
    actor Client
    participant Brother
    participant SNMP_Engine as SNMP Engine
    participant Device
    Client->>Brother: async_set_datetime(dt?)
    Brother->>Brother: build_dateandtime(dt or now)
    Brother->>Brother: _request_args_for(write_community)
    Brother->>SNMP_Engine: set_cmd(OID_DATETIME, OctetString(encoded), request_args)
    SNMP_Engine->>Device: SNMP SET request
    Device-->>SNMP_Engine: confirmation or error-status
    SNMP_Engine-->>Brother: response / errindication
    alt Success
        Brother-->>Client: None
    else Error
        Brother-->>Client: SnmpError | ConnectionError
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nibbled bytes of time and date,

Built octets neat, and parsed them straight.
A hop, a set, a gentle get—
Brother's clock is snug and set.
Hooray for sync; no more late!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: adding two new async methods (async_set_datetime and async_get_datetime) for managing printer date/time via SNMP.
Linked Issues check ✅ Passed The PR fully addresses issue #28 by implementing SNMP-based read/write of date/time via async_get_datetime and async_set_datetime methods, allowing automated clock restoration after power outages as requested.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the datetime SNMP functionality: parameter additions, method implementations, constants, utilities, and comprehensive tests—no unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 96.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@brother/__init__.py`:
- Around line 382-387: The DateAndTime parser can raise ValueError for invalid
month/day/etc and should fail gracefully; in the function that parses the
DateAndTime payload (using DATEANDTIME_MIN_LENGTH and the raw byte slice and
constructing datetime(...)), validate the extracted fields or wrap the
datetime(...) call in a try/except that catches ValueError (and TypeError if
needed) and returns None on failure so Brother.async_get_datetime() never leaks
an undocumented exception; reference the code that reads year =
int.from_bytes(raw[0:2], "big") and the subsequent datetime(...) construction
and ensure invalid/zeroed month/day/hour/minute/second values are handled by
returning None.
- Line 104: The assignment uses truthiness so an empty string becomes
DEFAULT_WRITE_COMMUNITY; change it to preserve explicit empty values by only
defaulting when the argument is None: in the constructor where
self._write_community is set (symbol: self._write_community and
DEFAULT_WRITE_COMMUNITY), replace the `write_community or
DEFAULT_WRITE_COMMUNITY` logic with an explicit None check (e.g., set to
DEFAULT_WRITE_COMMUNITY only if write_community is None), leaving
blank/empty-string values intact.
- Around line 304-313: The current logic treats any errstatus as "None" which
hides real agent errors; update the error handling in the block around get_cmd
so that: if errindication is set raise SnmpError with its message; if errstatus
is set, inspect the error code/text and only return None when it indicates an
unsupported/missing OID (e.g., noSuchName/noSuchObject/noSuchInstance depending
on SNMP version); for any other errstatus raise SnmpError (include errstatus and
restable details). Refer to get_cmd, errindication, errstatus, restable, and
SnmpError to locate and modify the logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 07fad32d-82a0-4f46-afc9-bdc53be2e9ae

📥 Commits

Reviewing files that changed from the base of the PR and between 006af16 and 87afe52.

📒 Files selected for processing (3)
  • brother/__init__.py
  • brother/const.py
  • tests/test_datetime.py

Comment thread brother/__init__.py Outdated
Comment thread brother/__init__.py Outdated
Comment thread brother/__init__.py Outdated
- Use explicit `is None` check for write_community to preserve empty strings
- Only return None for noSuchName in async_get_datetime; raise SnmpError for
  other SNMP errors (e.g. genErr) instead of silently hiding them
- Wrap datetime construction in _parse_dateandtime with try/except ValueError
  to handle malformed DateAndTime payloads from the printer gracefully
- Add tests for genErr handling and invalid DateAndTime values

Made-with: Cursor
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
brother/__init__.py (1)

148-150: Reduce the order-dependent argument wiring.

create() now forwards seven positional constructor args, and async_set_datetime() rebuilds _request_args via tuple indexes. Both are easy to break on the next signature or tuple-shape change. A small helper / keyword-based call would make this path less brittle.

♻️ One way to make the forwarding explicit
-        instance = cls(
-            host, port, community, printer_type, model, snmp_engine, write_community
-        )
+        instance = cls(
+            host=host,
+            port=port,
+            community=community,
+            printer_type=printer_type,
+            model=model,
+            snmp_engine=snmp_engine,
+            write_community=write_community,
+        )
def _request_args_for(self, community: str) -> tuple[
    SnmpEngine, CommunityData, UdpTransportTarget, ContextData
]:
    return (
        self._request_args[0],
        CommunityData(community, mpModel=0),
        self._request_args[2],
        self._request_args[3],
    )

Also applies to: 354-359

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@brother/__init__.py` around lines 148 - 150, The constructor-forwarding in
create() and the tuple-index rebuild in async_set_datetime() are order-dependent
and brittle; add a small helper method (e.g., _request_args_for(self, community:
str) or build_request_args) that returns the four request args as named
components (SnmpEngine, CommunityData(...), UdpTransportTarget, ContextData)
instead of slicing by tuple indexes, update async_set_datetime() (and the other
site around the same pattern) to call that helper, and change create() to
construct the instance using explicit keyword arguments or by passing the
helper-produced values so the wiring is explicit and resilient to
signature/tuple-shape changes (reference symbols: create, async_set_datetime,
and the new _request_args_for/build_request_args).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@brother/__init__.py`:
- Around line 148-150: The constructor-forwarding in create() and the
tuple-index rebuild in async_set_datetime() are order-dependent and brittle; add
a small helper method (e.g., _request_args_for(self, community: str) or
build_request_args) that returns the four request args as named components
(SnmpEngine, CommunityData(...), UdpTransportTarget, ContextData) instead of
slicing by tuple indexes, update async_set_datetime() (and the other site around
the same pattern) to call that helper, and change create() to construct the
instance using explicit keyword arguments or by passing the helper-produced
values so the wiring is explicit and resilient to signature/tuple-shape changes
(reference symbols: create, async_set_datetime, and the new
_request_args_for/build_request_args).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 58c8c89c-8b79-4dfa-beeb-9ce5a06902a8

📥 Commits

Reviewing files that changed from the base of the PR and between 87afe52 and a241882.

📒 Files selected for processing (2)
  • brother/__init__.py
  • tests/test_datetime.py
✅ Files skipped from review due to trivial changes (1)
  • tests/test_datetime.py

Reduces order-dependent positional forwarding in create() and
eliminates tuple-index slicing in async_set_datetime().

Made-with: Cursor
Copy link
Copy Markdown
Owner

@bieniu bieniu left a comment

Choose a reason for hiding this comment

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

Thanks for your PR. I didn't have time to thoroughly review the code, so here are a few comments that caught my eye.

Comment thread tests/test_datetime.py Outdated
@@ -0,0 +1,189 @@
"""Tests for datetime get/set functionality."""
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The test file should match the code file. There is no datetime.py file in the Brother library.

Comment thread brother/__init__.py Outdated
)

@staticmethod
def _parse_dateandtime(raw: bytes) -> datetime | None:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This function should be moved to the utils module.

Comment thread brother/__init__.py Outdated
)

@staticmethod
def _build_dateandtime(dt: datetime) -> bytes:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This function should be moved to the utils module.

Comment thread tests/test_datetime.py Outdated
HOST = "localhost"


def _setup_request_args(brother: Brother) -> None:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This should be a fixture.

@bieniu bieniu added the new-feature A new feature label Mar 26, 2026
- Move build_dateandtime and parse_dateandtime to utils module
- Merge datetime tests into test_init.py (match code file convention)
- Use pytest fixture for fake _request_args setup

Made-with: Cursor
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.65%. Comparing base (006af16) to head (8a74964).
⚠️ Report is 8 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #761      +/-   ##
==========================================
+ Coverage   97.29%   97.65%   +0.36%     
==========================================
  Files           5        5              
  Lines         370      427      +57     
==========================================
+ Hits          360      417      +57     
  Misses         10       10              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Format brother/__init__.py and brother/utils.py (fixes CI ruff format --check).
- Add tests for async_get_datetime when get_cmd returns errindication or raises
  PySnmpError (improves patch coverage for Codecov).

Made-with: Cursor
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/test_init.py (1)

773-775: Avoid asserting through _ObjectType__args.

Line 775 uses a private Python field, making the test brittle to PySNMP refactoring. The ObjectType class exposes a public sequence protocol (per RFC 1902) supporting tuple unpacking and index access.

♻️ Use public interface
     args = mock_set.call_args
     oid_arg = args[0][-1]
-    val = oid_arg._ObjectType__args[1]
+    _, val = oid_arg
     expected = b"\x07\xea\x03\x1a\x0e\x1e\x00\x00"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_init.py` around lines 773 - 775, The test is accessing a private
attribute on ObjectType (oid_arg._ObjectType__args[1]) which is brittle; instead
use the public sequence protocol on ObjectType (tuple-unpacking or index
access). Replace the private access with something like val = tuple(oid_arg)[1]
or val = oid_arg[1] after locating the variables set in tests/test_init.py
(refs: mock_set.call_args, oid_arg = args[0][-1]) so the test reads the second
element via the public API rather than _ObjectType__args.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@brother/__init__.py`:
- Around line 348-350: The docstring incorrectly states that an unreachable
printer raises ConnectionError; update the Raises section to document that SNMP
timeouts and errindication values are raised as SnmpError (per the errindication
handling in the code around the block that routes SNMP timeouts/errindication to
SnmpError at lines analogous to 369–373), and only mention ConnectionError if
there are other network-level connection failures actually raised elsewhere;
ensure the Raises lists SnmpError (for SNMP timeouts/errindication) and
ConnectionError only when applicable.

In `@tests/test_init.py`:
- Around line 781-790: The test test_set_datetime_default_uses_now currently
only asserts set_cmd was called; update it to freeze time (e.g., via freezegun
or monkeypatching datetime) before calling
brother_with_request_args.async_set_datetime(), then inspect the
mock_set.call_args to extract the DateAndTime octets sent by async_set_datetime
and assert they match the frozen UTC/local instant and expected timezone
encoding; ensure you still use AsyncMock for set_cmd and keep the same call but
replace the single assert_called_once() with assertions that the emitted octet
sequence equals the expected bytes derived from the frozen time and timezone.

---

Nitpick comments:
In `@tests/test_init.py`:
- Around line 773-775: The test is accessing a private attribute on ObjectType
(oid_arg._ObjectType__args[1]) which is brittle; instead use the public sequence
protocol on ObjectType (tuple-unpacking or index access). Replace the private
access with something like val = tuple(oid_arg)[1] or val = oid_arg[1] after
locating the variables set in tests/test_init.py (refs: mock_set.call_args,
oid_arg = args[0][-1]) so the test reads the second element via the public API
rather than _ObjectType__args.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: de6806f1-6b1e-45f9-9ad2-5e41abee8b2c

📥 Commits

Reviewing files that changed from the base of the PR and between 769d7ec and ea125c9.

📒 Files selected for processing (3)
  • brother/__init__.py
  • brother/utils.py
  • tests/test_init.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • brother/utils.py

Comment thread brother/__init__.py Outdated
Comment thread tests/test_init.py
- Clarify async_set_datetime Raises (SnmpError vs ConnectionError).
- Strengthen test_set_datetime_default_uses_now with freeze_time, TZ=UTC, and
  octet assertion vs build_dateandtime(now).
- Document why tests read ObjectType via _ObjectType__args (mocked varbind is
  not unpackable; __getitem__ raises SmiError).

Made-with: Cursor
@lorek123
Copy link
Copy Markdown
Contributor Author

@bieniu I think all requested changes are now solved, please take a look

@bieniu
Copy link
Copy Markdown
Owner

bieniu commented Mar 29, 2026

The code looks good.
Unfortunately, setting the time doesn't work for my printer. SNMP doesn't return an error, but the time isn't set and the printer always returns 2000-01-01 00:00:00.

Therefore, I'd like to ask how you plan to use these two new methods. Do you intend to implement the Brother integration change in the HA repository? If so, I'd like you to open a draft PR so we can analyze how it will work.

@lorek123
Copy link
Copy Markdown
Contributor Author

@bieniu I can work on broader support, I'll just need few more details. If you want we can catch up on Discord: lorek123.

Comment thread brother/__init__.py Outdated
LCD.unconfigure(self._snmp_engine, None)

async def async_get_datetime(self) -> datetime | None:
"""Read the printer's current date and time via SNMP.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

We don't need such an extended docstring here.

Comment thread brother/__init__.py Outdated
return parse_dateandtime(raw)

async def async_set_datetime(self, dt: datetime | None = None) -> None:
"""Set the printer's date and time via SNMP.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

We don't need such an extended docstring here.

Comment thread brother/__init__.py Outdated

_LOGGER.debug("Printer datetime set to %s", dt.isoformat())

def _request_args_for(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The function name is misleading.

Comment thread brother/__init__.py
raw: bytes = restable[0][-1].asOctets()
return parse_dateandtime(raw)

async def async_set_datetime(self, dt: datetime | None = None) -> None:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

We know that setting the date doesn't work on all printer models. Therefore, we need to maintain a list of printers that support this feature and raise an exception when attempting to use this method on a printer model that isn't on the list.

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.

Added an allowlist, do we want to have a way to test for users if their printer has this option?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

yeah, good idea

Comment thread brother/__init__.py Outdated
printer_type: str = "laser",
model: str | None = None,
snmp_engine: SnmpEngine | None = None,
write_community: str | None = None,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Suggested change
write_community: str | None = None,
write_community: str = DEFAULT_WRITE_COMMUNITY,

lorek123 and others added 2 commits April 6, 2026 22:29
- Add DATETIME_SET_SUPPORTED_MODELS allowlist (dcp-j552dw); async_set_datetime
  raises UnsupportedModelError for unlisted or unknown models
- Change write_community param default to DEFAULT_WRITE_COMMUNITY (drop None)
- Rename _request_args_for -> _write_request_args; absorb community internally
- Simplify docstrings on async_get_datetime and async_set_datetime
- Replace _ObjectType__args private access with OctetString patch in tests
- Add tests for unsupported model and unknown model (pre-async_update) cases

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Sort DATETIME_SET_SUPPORTED_MODELS import alphabetically (I001)
- Assign f-string to variable before raising UnsupportedModelError (EM102)
- Shorten two test docstrings to fit within 88-char line limit (E501)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread brother/__init__.py Outdated
m in model.lower() for m in DATETIME_SET_SUPPORTED_MODELS
):
msg = f"Setting datetime is not supported on model {model}"
raise UnsupportedModelError(msg)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Let's add a new exception for this purpose, e.g. MethodNotSupportedError. UnsupportedModelError doesn't suit here

class UnsupportedModelError(BrotherError):
"""Raised when no model, serial no, firmware data."""

Comment thread brother/__init__.py Outdated

async def async_set_datetime(self, dt: datetime | None = None) -> None:
"""Set the printer's date and time via SNMP."""
model = getattr(self, "model", None)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The printer model is available as self.model, we don't need to use getattr()

Comment thread brother/__init__.py Outdated
async def async_set_datetime(self, dt: datetime | None = None) -> None:
"""Set the printer's date and time via SNMP."""
model = getattr(self, "model", None)
if model is None or not any(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

self.model is a string, no need to check if it is None

- Add MethodNotSupportedError exception for method-level capability checks
- Add is_datetime_set_supported property so callers can probe support before SET
- async_set_datetime raises MethodNotSupportedError (not UnsupportedModelError)
  for models outside DATETIME_SET_SUPPORTED_MODELS
- Use self.model directly in check; remove getattr/None guard
- Update snapshots and tests accordingly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Owner

@bieniu bieniu left a comment

Choose a reason for hiding this comment

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

Looks good, thanks @lorek123 👍

@bieniu bieniu merged commit 2d3d695 into bieniu:master Apr 9, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new-feature A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Set time and date via SNMP

2 participants