bieniu / brother Goto Github PK
View Code? Open in Web Editor NEWPython wrapper for getting data from Brother laser and inkjet printers via snmp
License: Apache License 2.0
Python wrapper for getting data from Brother laser and inkjet printers via snmp
License: Apache License 2.0
The options for printer type don't include toner.
Is toner able to be added?
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'
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
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}
Asynctest doesn't work with Python 3.8 and above.
Asynctest upstream is aware of this breakage and recommends using the built-in AsyncMock instead.
See also Martiusweb/asynctest#144 and Martiusweb/asynctest#126
The lextudio project has taken over the pysnmp, since the original author has passed away.
etingof/pysnmp#429
https://github.com/lextudio/pysnmp/blob/v6.2.2/CHANGES.rst#revision-622-released-on-july-16-2024
Please migrate from pysnmp-lextudio back to pysnmp.
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.
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
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
Would you please change the default character set from "roman8" to "utf8"?
Because Japanese models return utf8 text as a status code.
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.
Hello.
I don't see issue in this repo from home-assistant/core#30888 from @bastshoes
I have same troubles when I use menu in Russian.
My printer is DCP-L2540DN.
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?
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.
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.
Output as at 7f0dfe4:
DEBUG:asyncio:Using selector: EpollSelector
DEBUG:brother:Using host: 192.168.1.23
noSuchName, 2
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]]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.