Giter Site home page Giter Site logo

bieniu / brother Goto Github PK

View Code? Open in Web Editor NEW
12.0 4.0 8.0 570 KB

Python wrapper for getting data from Brother laser and inkjet printers via snmp

License: Apache License 2.0

Python 98.28% Shell 0.99% Dockerfile 0.73%
brother snmp python laser-printer inkjet-printer printer hacktoberfest

brother's Issues

Toner type missing

The options for printer type don't include toner.

Is toner able to be added?

Getting Printer IpAddress

Works great but trying to add some extra OIDs. All work fine except ipAddress which returns 7 octets instead of expected 4. Works fine with snmp-walk. My guess it is related to the snmp library reading the ipaddress incorrectly. I have tried different ways but unable to get ipAddress returned correctly:

init.py

from .const import (
....
ATTR_TCPIP,
...
)
....
self.tcpip = None
....
        try:
           self.tcpip = raw_data[OIDS[ATTR_TCPIP]].format('utf')
           data[ATTR_TCPIP] = self.tcpip
        except:
           _LOGGER.debug("Incomplete Network data from printer")
.....

const.py

...
OIDS_WITHOUT_COUNTERS: Final[dict[str, str]] = {

....
ATTR_TCPIP: "1.3.6.1.4.1.2435.2.4.3.1240.5.2.3.0"
...
}

print(f"Printer TCPIP: {(data.tcpip)}")
Printer TCPIP: ˬ

print(f"Printer TCPIP: {ipaddress.IPv4Address(data.tcpip)}")
ipaddress.AddressValueError: Expected 4 octets in 'ˬ\xad\x14'

Brother HL-5350DN: noSuchName, 2

Hi,

I'm trying to integrate a Brother HL-5350DN into Home Assistant. Since it wouldn't connect, I used the test script provided here. The script reports the following:

DEBUG:asyncio:Using selector: EpollSelector
DEBUG:brother:Using host: brn001ba9e7ce21.lan
noSuchName, 2
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending name='Task-3' coro=<handle_timeout() running at <string>:4> wait_for=<Future pending cb=[Task.task_wakeup()]>>

Is it one of the older, unsupported printers?
What can I do to add support for it?

Thanks

encoding issue with Dutch status

I get: 'status': 'stap. kopieín:01'. This should be 'status': 'stap. kopieën:01'. After some digging, it turns out the encoding the printer uses is hp_roman8. The chardet call (visible in the diff below) detects the string as ISO-8859-9 which is wrong (but I can see how it could not do any better).

This diff makes things work for me:

diff --git a/brother/__init__.py b/brother/__init__.py
index 8fc37b3..ee1932c 100644
--- a/brother/__init__.py
+++ b/brother/__init__.py
@@ -65,9 +65,10 @@ class Brother:  # pylint:disable=too-many-instance-attributes
         try:
             self.firmware = raw_data[OIDS[ATTR_FIRMWARE]]
             data[ATTR_FIRMWARE] = self.firmware
-            code_page = chardet.detect(raw_data[OIDS[ATTR_STATUS]].encode("latin1"))[
-                "encoding"
-            ]
+            code_page = 'hp_roman8'
+            # code_page = chardet.detect(raw_data[OIDS[ATTR_STATUS]].encode("latin1"))[
+            #     "encoding"
+            # ]
             # chardet detects Polish as ISO-8859-1 but Polish should use ISO-8859-2
             if code_page == "ISO-8859-1":
                 data[ATTR_STATUS] = (

but of course that is not a patch that would be good for everybody. I'm unsure what the right fix is; I understand from the existing code that some printers in fact use ISO-8559-1? I'm also confused about the .encode('latin1') step, why is that happening?

And, unrelated, why is the status string lowercased?

Full status output from unpatched code:

Data available: True
Model: DCP-7070DW
Firmware: U1307022128VER.J
Status: stap. kopieín:01
Serial no: E69767E2N930019
Sensors data: {'model': 'DCP-7070DW', 'serial': 'E69767E2N930019', 'firmware': 'U1307022128VER.J', 'status': 'stap. kopieín:01', 'page_counter': 2652, 'uptime': 346, 'drum_status': 1, 'drum_counter': 1603, 'drum_remaining_life': 88, 'black_toner_status': 1, 'black_toner_remaining': 72, 'drum_remaining_pages': 10397}

SNMP setings for Brother integration

Printers, as well as other devices, have the option of both setting a different community name and using their own v3 configuration. Integration does not have the ability to configure its own SNMP settings.

object tuple can't be used in 'await' expression

2023-02-25 23:18:15.010 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry Drucker9120 for brother
Traceback (most recent call last):
File "/srv/homeassistant/lib/python3.11/site-packages/homeassistant/config_entries.py", line 382, in async_setup
result = await component.async_setup_entry(hass, self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/srv/homeassistant/lib/python3.11/site-packages/homeassistant/components/brother/init.py", line 33, in async_setup_entry
brother = await Brother.create(
^^^^^^^^^^^^^^^^^^^^^
File "/srv/homeassistant/lib/python3.11/site-packages/brother/init.py", line 95, in create
await instance.initialize()
File "/srv/homeassistant/lib/python3.11/site-packages/brother/init.py", line 121, in initialize
_, errstatus, errindex, _ = await get_result
^^^^^^^^^^^^^^^^
TypeError: object tuple can't be used in 'await' expression

python 3.10 AttributeError

Everything was fine but with the python update to 3.10 this happens:

loop = asyncio.get_event_loop()
Traceback (most recent call last):
; File "/usr/lib/python3.10/site-packages/pysnmp/carrier/asyncio/dgram/base.py", line 93, in openClientMode
self._lport = getattr(asyncio, 'async')(c)
;AttributeError: module 'asyncio' has no attribute 'async'
caused by <class 'AttributeError'>: module 'asyncio' has no attribute 'async'
/home/pepe/bin/Brother/brother.py:15: RuntimeWarning: coroutine 'BaseEventLoop.create_datagram_endpoint' was never awaited
return
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

Default charset

Would you please change the default character set from "roman8" to "utf8"?
Because Japanese models return utf8 text as a status code.

RuntimeError: await wasn't used with future

Running the example.py script (or using this lib via a home assistant integration) results in an immediate error (I'm not really familiar with python asyncio to try to fix this myself):

$ python example.py 172.17.2.17
DEBUG:asyncio:Using selector: EpollSelector
DEBUG:brother:Initializing device 172.17.2.17
Traceback (most recent call last):
  File "/srv/homeassistant/example.py", line 50, in <module>
    loop.run_until_complete(main())
  File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/srv/homeassistant/example.py", line 31, in main
    brother = await Brother.create(
  File "/srv/homeassistant/lib/python3.9/site-packages/brother/__init__.py", line 95, in create
    await instance.initialize()
  File "/srv/homeassistant/lib/python3.9/site-packages/brother/__init__.py", line 120, in initialize
    _, errstatus, errindex, _ = await hlapi.getCmd(*request_args, *tuple(oids))
RuntimeError: await wasn't used with future
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending name='Task-2' coro=<BaseEventLoop.create_datagram_endpoint() running at /usr/lib/python3.9/asyncio/base_events.py:1380> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7fbb365fa0>()]>>
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending name='Task-3' coro=<AsyncioDispatcher.handle_timeout() running at /srv/homeassistant/lib/python3.9/site-packages/pysnmp/carrier/asyncio/dispatch.py:55> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7fbb365f10>()]>>
Exception ignored in: <coroutine object BaseEventLoop.create_datagram_endpoint at 0x7fbb472340>
Traceback (most recent call last):
  File "/usr/lib/python3.9/asyncio/base_events.py", line 1382, in create_datagram_endpoint
  File "/usr/lib/python3.9/asyncio/selector_events.py", line 700, in close
  File "/usr/lib/python3.9/asyncio/base_events.py", line 746, in call_soon
  File "/usr/lib/python3.9/asyncio/base_events.py", line 510, in _check_closed
RuntimeError: Event loop is closed

I tried both 2.0.0 and current git with python 3.9 in home assistant virtual environment and 3.11 in a clean Fedora 37 installation, the error is always the same.

pysnmplib?

Hi,

I believe migrationg to pysnmplib is a bad idea.
Just tried to compile the required sub-libraries (asn1 & smi), which all have lots of file conflicts with the according libraries supporting pysnmp, all in different versions.

On my HA production box:

dev-python/pyasn1-0.4.8-r1 pulled in by:
dev-python/adb-shell-0.4.2 requires dev-python/pyasn1[python_targets_python3_9(-)]
dev-python/google-auth-2.6.0 requires >=dev-python/pyasn1-0.1.7[python_targets_python3_9(-)]
dev-python/oauth2client-4.1.3-r1 requires >=dev-python/pyasn1-0.1.7[python_targets_python3_9(-)]
dev-python/paramiko-2.10.2 requires >=dev-python/pyasn1-0.1.7[python_targets_python3_9(-)]
dev-python/pyasn1-modules-0.2.8-r1 requires >=dev-python/pyasn1-0.4.6[python_targets_python3_9(-)]
dev-python/pysnmp-4.4.12-r1 requires >=dev-python/pyasn1-0.2.3[python_targets_python3_9(-)]
dev-python/python-jose-3.3.0 requires dev-python/pyasn1[python_targets_python3_9(-)]
dev-python/rsa-4.8 requires >=dev-python/pyasn1-0.1.3[python_targets_python3_9(-)]
dev-python/service_identity-21.1.0 requires dev-python/pyasn1[python_targets_python3_9(-)]
dev-python/slixmpp-1.8.0.1 requires dev-python/pyasn1[python_targets_python3_9(-)]

dev-python/pysmi-0.3.4 pulled in by:
dev-python/pysnmp-4.4.12-r1 requires dev-python/pysmi[python_targets_python3_9(-)]

What benefits do you expect from pysnmplib?

Set time and date via SNMP

On my DCP-J552DW each time there is power outage I need to setup time and date for scan uploads. Is it possible to do this via SNMP and to add it here? It could be a nice feature to recover time and date each time it recovers from HA.

Support for models without ATTR_COUNTERS

Hi, thanks for the great module! I have an older Brother printer, model HL-2270DW, which does not play nicely with this module. This model does not support the ATTR_COUNTERS OID and raises SnmpError noSuchName, 2 if it is requested.

I've tested this by modifying the code so that the OID is not requested, and afterwards the example code starts working without issue. Included below is a diff of the quick edits I made to get it working, however I just removed the request for it entirely so it will break support for this in newer models. I'm not yet familiar with the code to make a proper PR.

Before

Output as at 7f0dfe4:

DEBUG:asyncio:Using selector: EpollSelector
DEBUG:brother:Using host: 192.168.1.23
noSuchName, 2

After

Output:

DEBUG:asyncio:Using selector: EpollSelector
DEBUG:brother:Using host: 192.168.1.23
DEBUG:brother:RAW data: {'1.3.6.1.2.1.43.7.1.1.4.1.1': '2004', '1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.17.0': '1.16', '1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.8.0': ['...'], '1.3.6.1.4.1.2435.2.3.9.1.1.7.0': 'MFG:Brother;CMD:PJL,PCL,PCLXL;MDL:HL-2270DW series;CLS:PRINTER;CID:Brother Laser Type1;', '1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.11.0': ['82010400001e81'], '1.3.6.1.2.1.43.10.2.1.4.1.1': '4191', '1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.1.0': '...', '1.3.6.1.4.1.2435.2.3.9.4.2.1.5.4.5.2.0': 'SLEEP           ', '1.3.6.1.2.1.1.3.0': '720555'}
DEBUG:brother:Data: {'model': 'HL-2270DW', 'serial': '...', 'firmware': '1.16', 'status': 'sleep', 'uptime': 0, 'drum_counter': 4191, 'black_toner_remaining': 93, 'black_toner_status': 21037316, 'drum_remaining_pages': 7809, 'page_counter': 4191}
Data available: True
Model: HL-2270DW
Firmware: 1.16
Status: sleep
Serial no: ...
Sensors data: {'model': 'HL-2270DW', 'serial': '...', 'firmware': '1.16', 'status': 'sleep', 'uptime': 0, 'drum_counter': 4191, 'black_toner_remaining': 93, 'black_toner_status': 21037316, 'drum_remaining_pages': 7809, 'page_counter': 4191}

Code diff:

diff --git a/brother/__init__.py b/brother/__init__.py
index 4060f83..470bbd7 100644
--- a/brother/__init__.py
+++ b/brother/__init__.py
@@ -112,7 +112,7 @@ class Brother:  # pylint:disable=too-many-instance-attributes
                         self._iterate_data(
                             raw_data[OIDS[ATTR_COUNTERS]], VALUES_COUNTERS
                         )
-                    )
+                    ) if ATTR_COUNTERS in OIDS else {}
                 )
                 data.update(
                     dict(
@@ -134,7 +134,7 @@ class Brother:  # pylint:disable=too-many-instance-attributes
                         self._iterate_data(
                             raw_data[OIDS[ATTR_COUNTERS]], VALUES_COUNTERS
                         )
-                    )
+                    ) if ATTR_COUNTERS in OIDS else {}
                 )
                 data.update(
                     dict(
diff --git a/brother/const.py b/brother/const.py
index cc92455..c324b17 100644
--- a/brother/const.py
+++ b/brother/const.py
@@ -73,7 +73,6 @@ KINDS = ["ink", "laser"]

 OIDS = {
     ATTR_CHARSET: "1.3.6.1.2.1.43.7.1.1.4.1.1",
-    ATTR_COUNTERS: "1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.10.0",
     ATTR_FIRMWARE: "1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.17.0",
     ATTR_MAINTENANCE: "1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.8.0",
     ATTR_MODEL: "1.3.6.1.4.1.2435.2.3.9.1.1.7.0",
@@ -181,4 +180,4 @@ PERCENT_VALUES = [
     VAL_YELLOW_TONER_REMAIN,
 ]

-OIDS_HEX = [OIDS[ATTR_COUNTERS], OIDS[ATTR_MAINTENANCE], OIDS[ATTR_NEXTCARE]]
+OIDS_HEX = [OIDS[ATTR_MAINTENANCE], OIDS[ATTR_NEXTCARE]]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.