Open JvdMaat opened 2 years ago
Thanks for the suggestion. Right now, the integration uses a simple library that parses the web interface of the printer. I've never used SNMP so I don't know about its capabilities.
If you like, you can extend the library yourself: https://github.com/kongo09/dell-printer
I just took a quick look at SNMP. Did you decode the Dell OIDs to identify, what data is the toner level and so on? I did a dump from my printer and found the toner:
iso.3.6.1.2.1.43.11.1.1.6.1.1 = STRING: "Cyan Cartridge"
iso.3.6.1.2.1.43.11.1.1.6.1.2 = STRING: "Magenta Cartridge"
iso.3.6.1.2.1.43.11.1.1.6.1.3 = STRING: "Yellow Cartridge"
iso.3.6.1.2.1.43.11.1.1.6.1.4 = STRING: "Black Cartridge"
iso.3.6.1.2.1.43.11.1.1.8.1.1 = INTEGER: 1400
iso.3.6.1.2.1.43.11.1.1.8.1.2 = INTEGER: 1400
iso.3.6.1.2.1.43.11.1.1.8.1.3 = INTEGER: 1400
iso.3.6.1.2.1.43.11.1.1.8.1.4 = INTEGER: 2000
iso.3.6.1.2.1.43.11.1.1.9.1.1 = INTEGER: 378
iso.3.6.1.2.1.43.11.1.1.9.1.2 = INTEGER: 602
iso.3.6.1.2.1.43.11.1.1.9.1.3 = INTEGER: 1064
iso.3.6.1.2.1.43.11.1.1.9.1.4 = INTEGER: 1760
Essentially, that seems to say:
which fits to what the printer says: 27%
There is a super long list of data available via SNMP at least of my printer. But I don't know how to translate the OID codes, so it's difficult to understand. Maybe we can decode that stuff together and I can change the integration so that it works more generically with more Dell printer types.
Yes, those are the OIDs I use for the toner. (At least the .8 and .9 ones for current and max level, I don't use the .6 as ) And I use these for page counts: 1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.1, 1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.34, 1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.33, 1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.7, 1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.29, 1.3.6.1.4.1.253.8.53.13.2.1.6.103.20.3, 1.3.6.1.4.1.253.8.53.13.2.1.6.103.20.25, 1.3.6.1.4.1.253.8.53.13.2.1.6.102.20.12, 1.3.6.1.4.1.253.8.53.13.2.1.6.102.20.11
I have all that working (through NodeRed, since the SNMP through HA configuration.yaml was .. sketchy at best) and get the interface I pasted up above. I was hoping to get your integration to collect more info.
I looked at your dell-printer repo, but not sure where to even begin. I'm more of a VB, (Pascal,) and C coder, not so much python or anything else. If you give me some direction, I'd be happy to flail my way through it though. If it's a web scraper, we may be able to get similar info our of other Dell printers (hoping they mostly have the same web interface. Or maybe only 2 or 3 different ones depending on what printer model). Here's what my rendered index.html looks like. Don't think there's anything personally identifiable on there except my public IPv6:
Interesting, that looks very similar to my interface. Yes, I just scrape that. SNMP would probably be more efficient.
My scraping code is in a separate library. Check my repos, you'll see it. Actually, I used this to learn python.
I guess there are two possibilities: add a second scraper for your model or rebuild the integration using SNMP. I wouldn't do anything by myself, but if you're willing to help...
I haven't been able to find things like the Waste Toner Box status, or the covers (open/closed), or general status (Ready) in SNMP. I agree that SNMP would be a nice way to collect all this, but in my searches, I was unable to come up with any good Dell printer MIBs that went into the details of what's what. So my vote is on updating the scraper code to make it generic for that version of the Dell printer website.
Check, if my scraper works for your model. You don't need HA for that, just on the command line. It should be easy to include your model in the integration then.
I also looked around for Dell printer MIBs but couldn't find anything serious.
Ok, I got git installed, and added it to my Visual Studio Code as extension, so I can see the project. Will see how I can actually run it next. I'm starting from scratch here. Also getting Python installed so I can actually run it. I see the printer_parser.py in the src folder which seems to do the most of the work.. Which file do I run to test? Also, I can't find where you set the IP: class DellPrinterParser: def init(self, session: aiohttp.ClientSession, ip: str): self.session = session self.ip = ip (Or do I set that in the README.md? I didn't think a readme file would be included in the code) Give me a nudge in the right direction so I can figure this out.
oh, you're serious :-)
This is just a library. To run it, you need your own python file that calls it. In the README.md there is an example file. You can copy that into a new file and name it whatever you like, e.g. test.py
and then you run it either from the command line with python test.py
or from inside VSC.
Lexmark_MIB_file_pack_20190502.zip
I found a pack of Lexmark MIBs. The Printer-MIB.mib
file is quite helpful to decode the OIDs. As far as I know, Dell printers used to be manufactured by Lexmark. For my printer, I can identify page count, status, and so on. Also the covers are there.
I also noticed that the HA brother
printer integration uses SNMP. Maybe we can just copy that integration and adapt it for Dell.
Yes, I'm having good luck with the Lexmark MIB as well. I've got the four covers, trays and sizes (how many sheets, and current capacity (though it's out of paper, so will need to check if that actually works)), Status message (Ready/Standby). Didn't get a chance to try your python yet.
Having said all that, if the Brother integration is all setup using SNMP, copying that and substituting Dell/Lexmark OIDs would work out. Better than the custom NodeRed flows I have going, or putting load on scraping the webpage regularly. I have a Brother printer as well, and have the Brother integration already and it is working well for me. Though a little limited on entities. I just get these six:
Nothing on open covers. But the drum life and toner remaining are percentages which is nice. Interestingly enough that status says "Sleep". I'm also using the IPP integration, and that tells me the status is "Idle" Unfortunately, even though I have IPP enabled on my Dell printer, I cannot get the IPP HA integration to recognize my Dell printer.
I've experimented quite a bit with pysnmp
and the brother
integration now. The data for the device status and the covers is available and in theory, it could all be pulled together via SNMP. Some stuff is not available, like the current firmware. But that's not really critical.
Howver, in my experiments, I kept struggling with asyncio
when I try to read an SNMP table, e.g. to flexibly read the available colors and toner levels. It should work with both, b&w and color printers, right? When I do a little test script without asyncio
the data is read correctly. But when I do the exact same code in the context of the library, I get endless errors that I don't understand.
For now, I'm giving up on this. If you adapt the HTML parser and send a pull request, I'm happy to take that in.
Is the brother integration using asyncio? Maybe you can't run SNMP async, and need to read them in serial? (Single connection). (Granted, I'm only postulating asyncio means doing multiple IOs asynchronously).
Yes, brother is using asyncio. That works for Dell as well, but not when I try to retrieve a whole table walking over the SNMP tree. Strange.
I've now overcome the async problem of SNMP by going for sync. The trays and covers are all available, so are the toner levels. I cannot identify the different page counters that you used. Which oids did you use?
If you like, you can clone https://github.com/kongo09/dell-printer-snmp and try the example.py
to read the values from your printer. Please share the output.
Don't have much time right now, but can at least give you these counters. Mine is an MFP unit, so it has scan to email, scan to USB, print, copy, etc counts in both black and color. OIDs: 1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.1, 1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.34, 1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.33, 1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.7, 1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.29, 1.3.6.1.4.1.253.8.53.13.2.1.6.103.20.3, 1.3.6.1.4.1.253.8.53.13.2.1.6.103.20.25, 1.3.6.1.4.1.253.8.53.13.2.1.6.102.20.12, 1.3.6.1.4.1.253.8.53.13.2.1.6.102.20.11 Which in order are: Total Black Color BPrint CPrint BCopy CCopy Scan2Email Scan2SMB
(Pretty sure there's also a scan to USB, but looks like I don't use that. I believe scan to USB may be 1.3.6.1.4.1.253.8.53.13.2.1.6.104.20.13 (Which returns 1 for me, cause I did use it once a few weeks ago when I had some scan2email issues. But I would need to verify that. And not sure what 1.3.6.1.4.1.253.8.53.13.2.1.6.104.20.14 is, as that returns 0 for me, but it's in the scan to XXX range, so it's potentially another scan destination, and there's also a 1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.71 in the page count range which returns 0 (Maybe that's FAX prints actually now that I think about it. Which would potentially make that 20.14 faxes sent (scan to FAX)? But again, guessing on those at the moment.))
Total is the total imprint count. Black is the total Black imprint count, which should equal the BPrint and BCopy added together. Ditto for the Color numbers. (And likewise, total copies is BCopy plus CCopy)
Hm, that's non-standard. 1.3.6.1.4
is a private section of XEROX. All my oids start with 1.3.6.1.2.1.43
which is the printer management standard.
Hi !
I have a Del H625cdw which is autodetected after installing your integration. Sadly i can't add it as i have the same error as OP of #7 . As this issue seems stalled, i thought i might revive it instead of creating a new one.
I cloned your snmp repo and launched example.py. That looks very promising:
Model: Dell Color MFP H625cdw; Controller 201809120649, Engine 02.54.00
Status: idle
Serial no: FH2022072
Page counter: 10001
Sensors data: {'model': 'Dell Color MFP H625cdw; Controller 201809120649, Engine 02.54.00', 'serial': 'FH2022072', 'printer_status': '3', 'device_status': '2', 'status': 'idle', 'printer_status_paper': 'ok', 'printer_status_toner': 'ok', 'uptime': datetime.datetime(2023, 10, 17, 8, 57, 29, tzinfo=datetime.timezone.utc), 'page_counter': 10001, 'supplies': [{'name': 'Cyan Toner Cartridge', 'color': 'cyan', 'capacity': '3100', 'level': '2480'}, {'name': 'Magenta Toner Cartridge', 'color': 'magenta', 'capacity': '2500', 'level': '2500'}, {'name': 'Yellow Toner Cartridge', 'color': 'yellow', 'capacity': '3100', 'level': '2480'}, {'name': 'Black Toner Cartridge', 'color': 'black', 'capacity': '1200', 'level': '480'}, {'name': 'Cyan Drum Cartridge', 'color': '', 'capacity': '50000', 'level': '40000'}, {'name': 'Magenta Drum Cartridge', 'color': '', 'capacity': '50000', 'level': '40000'}, {'name': 'Yellow Drum Cartridge', 'color': '', 'capacity': '50000', 'level': '40000'}, {'name': 'Black Drum Cartridge', 'color': '', 'capacity': '50000', 'level': '40000'}, {'name': 'Waste Toner Box', 'color': '', 'capacity': '30000', 'level': '30000'}], 'cover': [{'name': 'Right Side Cover', 'status': 'closed'}, {'name': 'Rear Cover', 'status': 'closed'}, {'name': 'DADF Cover', 'status': 'closed'}], 'output_tray': [{'name': 'MSI', 'type': 'manual sheet feeder', 'capacity': '50', 'status': 'idle', 'media': 'labels'}, {'name': 'TRAY 1', 'type': 'removable auto sheet feeder', 'capacity': '250', 'status': 'idle', 'media': 'stationery'}], 'input_tray': [{'name': 'CENTER TRAY', 'type': 'unremovable bin', 'capacity': '150', 'status': 'idle', 'page_delivery': 'face down'}]}
I'm pretty much just using NodeRed to get info from my Dell color printer. Here's the flow I use: https://github.com/JvdMaat/shared/blob/main/DellSNMP.json (Just update the IP of your printer and SNMP string in the two SNMP nodes) (And you'll need top add node-red-node-snmp to the palette)
Works well, thanks mate. I am relatively new to node-red. This saved me a ton of time. I just had to add the node-red companion integration from HACS (if someone reading this also wants to import JvdMaat's json).
While waiting for the author to maybe convert the integration to SNMP, i will stick with your solution !
If it's not asked too much, would you be so kind to share the dashboard with me ? Especially the ink level part ? Did you create helpers or a template variable to calculate the % ?
Oh yeah, I assumed one already had NoreRed setup to work with HA. That's of course a prerequisite. I use two custom cards to make the toner bar graphs: vertical-stack-in-card, bar-card. Here's the YAML:
type: custom:vertical-stack-in-card
title: Dell C2665dnf Ink Levels
cards:
- type: custom:bar-card
columns: 4
direction: up
entities:
- color: Grey
entity: sensor.c2665_black_percentage
- color: Cyan
entity: sensor.c2665_cyan_percentage
- color: Magenta
entity: sensor.c2665_magenta_percentage
- color: Yellow
entity: sensor.c2665_yellow_percentage
height: 200px
max: 100
min: 0
padding: 2px
target: 20
title_position: bottom
icon_position: inside
unit_of_measurement: '%'
width: 100%
And yes, I created template entries (in configuration.yaml):
sensor:
- platform: template
sensors:
c2665_black_percentage:
friendly_name: "Black Toner left"
unit_of_measurement: "%"
value_template: "{{ ((states('sensor.c2665dnf_black_level') | float / states('sensor.c2665dnf_black_total') | float ) * 100 ) | int }}"
Hope that helps.
Works like a charm. Big thanks man .... I had Node Red Addon and already working but did not yet had any needs for the companion integration. I think that one is only needed if you want to create sensors from NR in HA. I did not yet have that need.
Thanks again for your help, appreciated !
Hallo Foxi342,
could you help me please? I have your same printer (H625cdw), but I am lost. A short step by step guide would help very much.
Thank you very much in advance for any help you would give me.
Alexander
@JvdMaat , @Foxi352 & @Alex-DeIt in case you got it working yet.
I do have the same H625cdw as Foxi and Alex. I am very new to all of this, but I think I have most of it. I got HACS, Node Red, the companion app, and the two custom cards running. I did change my printer IP address in both of the host IP locations in the json file before I uploaded it to node-red. The issue is that the sensors reports that it is unavailable.
Checking the logs provides two errors:
Logger: homeassistant.components.template.template_entity
Source: components/template/template_entity.py:199
integration: Template (documentation, issues)
First occurred: 11:36:15 AM (4 occurrences)
Last logged: 11:36:15 AM
TemplateError('ValueError: Template error: float got invalid input 'unknown' when rendering template '{{ ((states('sensor.c2665dnf_black_level') | float / states('sensor.c2665dnf_black_total') | float) * 100) | int }}' but no default was specified') while processing template 'Template<template=({{ ((states('sensor.c2665dnf_black_level') | float / states('sensor.c2665dnf_black_total') | float) * 100) | int }}) renders=4>' for attribute '_attr_native_value' in entity 'sensor.c2665_black_percentage'
TemplateError('ValueError: Template error: float got invalid input 'unknown' when rendering template '{{ ((states('sensor.c2665dnf_cyan_level') | float / states('sensor.c2665dnf_cyan_total') | float) * 100) | int }}' but no default was specified') while processing template 'Template<template=({{ ((states('sensor.c2665dnf_cyan_level') | float / states('sensor.c2665dnf_cyan_total') | float) * 100) | int }}) renders=4>' for attribute '_attr_native_value' in entity 'sensor.c2665_cyan_percentage'
TemplateError('ValueError: Template error: float got invalid input 'unknown' when rendering template '{{ ((states('sensor.c2665dnf_magenta_level') | float / states('sensor.c2665dnf_magenta_total') | float) * 100) | int }}' but no default was specified') while processing template 'Template<template=({{ ((states('sensor.c2665dnf_magenta_level') | float / states('sensor.c2665dnf_magenta_total') | float) * 100) | int }}) renders=4>' for attribute '_attr_native_value' in entity 'sensor.c2665_magenta_percentage'
TemplateError('ValueError: Template error: float got invalid input 'unknown' when rendering template '{{ ((states('sensor.c2665dnf_yellow_level') | float / states('sensor.c2665dnf_yellow_total') | float) * 100) | int }}' but no default was specified') while processing template 'Template<template=({{ ((states('sensor.c2665dnf_yellow_level') | float / states('sensor.c2665dnf_yellow_total') | float) * 100) | int }}) renders=4>' for attribute '_attr_native_value' in entity 'sensor.c2665_yellow_percentage'
And:
Logger: homeassistant.helpers.event
Source: helpers/template.py:621
First occurred: 11:36:15 AM (4 occurrences)
Last logged: 11:36:15 AM
Error while processing template: Template<template=({{ ((states('sensor.c2665dnf_black_level') | float / states('sensor.c2665dnf_black_total') | float) * 100) | int }}) renders=2>
Error while processing template: Template<template=({{ ((states('sensor.c2665dnf_cyan_level') | float / states('sensor.c2665dnf_cyan_total') | float) * 100) | int }}) renders=2>
Error while processing template: Template<template=({{ ((states('sensor.c2665dnf_magenta_level') | float / states('sensor.c2665dnf_magenta_total') | float) * 100) | int }}) renders=2>
Error while processing template: Template<template=({{ ((states('sensor.c2665dnf_yellow_level') | float / states('sensor.c2665dnf_yellow_total') | float) * 100) | int }}) renders=2>
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2273, in forgiving_float_filter
return float(value)
^^^^^^^^^^^^
ValueError: could not convert string to float: 'unknown'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 619, in async_render
render_result = _render_with_context(self.template, compiled, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2654, in _render_with_context
return template.render(**kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/jinja2/environment.py", line 1304, in render
self.environment.handle_exception()
File "/usr/local/lib/python3.12/site-packages/jinja2/environment.py", line 939, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<template>", line 1, in top-level template code
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2276, in forgiving_float_filter
raise_no_default("float", value)
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1887, in raise_no_default
raise ValueError(
ValueError: Template error: float got invalid input 'unknown' when rendering template '{{ ((states('sensor.c2665dnf_black_level') | float / states('sensor.c2665dnf_black_total') | float) * 100) | int }}' but no default was specified
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 731, in async_render_to_info
render_info._result = self.async_render( # noqa: SLF001
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 621, in async_render
raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: ValueError: Template error: float got invalid input 'unknown' when rendering template '{{ ((states('sensor.c2665dnf_black_level') | float / states('sensor.c2665dnf_black_total') | float) * 100) | int }}' but no default was specified
I am not sure how to interpret these errors, or solve them.
My failed attempt: I went back into the yaml config and tried changing the sensor config to this, which in fact did work, but just told me that my ink levels were 0 because it didn't get an actual value. But, because it was returning an actual number now, the errors cleared and it thought it was happy and working properly, I should have seen that one coming.
sensor:
- platform: template
sensors:
c2665_black_percentage:
unique_id: c2665_black_percentage_id
friendly_name: "Black Toner left"
unit_of_measurement: "%"
value_template: >
{% set black_level = states('sensor.c2665dnf_black_level') | float(0) %}
{% set black_total = states('sensor.c2665dnf_black_total') | float(0) %}
{% if black_total > 0 %}
{{ (black_level / black_total * 100) | int }}
{% else %}
0
{% endif %}
How can we have this support more printers? I have a C2665dnf, and it is not working. The printer is not on my IoT VLAN (on which HA is), but I believe I gave HA full access to access the printer on any port. What port are you using? I may need to enable that on my printer. Otherwise, how are you accessing this, and what do you need to add more model support?
I am currently pulling data over SNMP using NodeRed. (page counts (black, color, totals, prints, copies, scan to email/USB) and toner levels) But it would be nice to get status, cover open, paper jam, and other data. (I haven't been able to find those in SNMP yet. Though I'm sure they're there)