1 # -*- coding: utf-8 -*-
3 # (c) Copyright 2003-2007 Hewlett-Packard Development Company, L.P.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 # Author: Don Welch, Narla Naga Samrat Chowdary, Yashwant Kumar Sahu
22 from __future__ import division
27 import xml.parsers.expat as expat
31 from xml.etree import ElementTree
35 from elementtree.ElementTree import XML
36 elementtree_loaded = True
38 elementtree_loaded = False
48 status dict structure:
49 { 'revision' : STATUS_REV_00 .. STATUS_REV_04,
50 'agents' : [ list of pens/agents/supplies (dicts) ],
51 'top-door' : TOP_DOOR_NOT_PRESENT | TOP_DOOR_CLOSED | TOP_DOOR_OPEN,
52 'status-code' : STATUS_...,
53 'supply-door' : SUPPLY_DOOR_NOT_PRESENT | SUPPLY_DOOR_CLOSED | SUPPLY_DOOR_OPEN.
54 'duplexer' : DUPLEXER_NOT_PRESENT | DUPLEXER_DOOR_CLOSED | DUPLEXER_DOOR_OPEN,
55 'photo_tray' : PHOTO_TRAY_NOT_PRESENT | PHOTO_TRAY_ENGAGED | PHOTO_TRAY_NOT_ENGAGED,
56 'in-tray1' : IN_TRAY_NOT_PRESENT | IN_TRAY_CLOSED | IN_TRAY_OPEN (| IN_TRAY_DEFAULT | IN_TRAY_LOCKED)*,
57 'in-tray2' : IN_TRAY_NOT_PRESENT | IN_TRAY_CLOSED | IN_TRAY_OPEN (| IN_TRAY_DEFAULT | IN_TRAY_LOCKED)*,
58 'media-path' : MEDIA_PATH_NOT_PRESENT | MEDIA_PATH_CUT_SHEET | MEDIA_PATH_BANNER | MEDIA_PATH_PHOTO,
63 agent dict structure: (pens/supplies/agents/etc)
64 { 'kind' : AGENT_KIND_NONE ... AGENT_KIND_ADF_KIT,
65 'type' : TYPE_BLACK ... AGENT_TYPE_UNSPECIFIED, # aka color
66 'health' : AGENT_HEALTH_OK ... AGENT_HEALTH_UNKNOWN,
68 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0 ... AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
81 STATUS_REV_UNKNOWN = 0xfe
83 vstatus_xlate = {'busy' : STATUS_PRINTER_BUSY,
84 'idle' : STATUS_PRINTER_IDLE,
85 'prnt' : STATUS_PRINTER_PRINTING,
86 'offf' : STATUS_PRINTER_TURNING_OFF,
87 'rprt' : STATUS_PRINTER_REPORT_PRINTING,
88 'cncl' : STATUS_PRINTER_CANCELING,
89 'iost' : STATUS_PRINTER_IO_STALL,
90 'dryw' : STATUS_PRINTER_DRY_WAIT_TIME,
91 'penc' : STATUS_PRINTER_PEN_CHANGE,
92 'oopa' : STATUS_PRINTER_OUT_OF_PAPER,
93 'bnej' : STATUS_PRINTER_BANNER_EJECT,
94 'bnmz' : STATUS_PRINTER_BANNER_MISMATCH,
95 'phmz' : STATUS_PRINTER_PHOTO_MISMATCH,
96 'dpmz' : STATUS_PRINTER_DUPLEX_MISMATCH,
97 'pajm' : STATUS_PRINTER_MEDIA_JAM,
98 'cars' : STATUS_PRINTER_CARRIAGE_STALL,
99 'paps' : STATUS_PRINTER_PAPER_STALL,
100 'penf' : STATUS_PRINTER_PEN_FAILURE,
101 'erro' : STATUS_PRINTER_HARD_ERROR,
102 'pwdn' : STATUS_PRINTER_POWER_DOWN,
103 'fpts' : STATUS_PRINTER_FRONT_PANEL_TEST,
104 'clno' : STATUS_PRINTER_CLEAN_OUT_TRAY_MISSING}
106 REVISION_2_TYPE_MAP = {0 : AGENT_TYPE_NONE,
107 1 : AGENT_TYPE_BLACK,
109 3 : AGENT_TYPE_MAGENTA,
110 4 : AGENT_TYPE_YELLOW,
111 5 : AGENT_TYPE_BLACK,
113 7 : AGENT_TYPE_MAGENTA,
114 8 : AGENT_TYPE_YELLOW,
117 STATUS_BLOCK_UNKNOWN = {'revision' : STATUS_REV_UNKNOWN,
119 'status-code' : STATUS_UNKNOWN,
122 NUM_PEN_POS = {STATUS_REV_00 : 16,
128 PEN_DATA_SIZE = {STATUS_REV_00 : 8,
134 STATUS_POS = {STATUS_REV_00 : 14,
140 def parseSStatus(s, z=''):
143 top_door = TOP_DOOR_NOT_PRESENT
144 stat = STATUS_UNKNOWN
145 supply_door = SUPPLY_DOOR_NOT_PRESENT
146 duplexer = DUPLEXER_NOT_PRESENT
147 photo_tray = PHOTO_TRAY_NOT_PRESENT
148 in_tray1 = IN_TRAY_NOT_PRESENT
149 in_tray2 = IN_TRAY_NOT_PRESENT
150 media_path = MEDIA_PATH_NOT_PRESENT
156 z_fields = z.split(',')
158 for z_field in z_fields:
160 if len(z_field) > 2 and z_field[:2] == '05':
162 z1 = [int(x, 16) for x in z1s]
164 s1 = [int(x, 16) for x in s]
168 assert STATUS_REV_00 <= revision <= STATUS_REV_04
170 top_door = bool(s1[2] & 0x8L) + s1[2] & 0x1L
171 supply_door = bool(s1[3] & 0x8L) + s1[3] & 0x1L
172 duplexer = bool(s1[4] & 0xcL) + s1[4] & 0x1L
173 photo_tray = bool(s1[5] & 0x8L) + s1[5] & 0x1L
175 if revision == STATUS_REV_02:
176 in_tray1 = bool(s1[6] & 0x8L) + s1[6] & 0x1L
177 in_tray2 = bool(s1[7] & 0x8L) + s1[7] & 0x1L
179 in_tray1 = bool(s1[6] & 0x8L)
180 in_tray2 = bool(s1[7] & 0x8L)
182 media_path = bool(s1[8] & 0x8L) + (s1[8] & 0x1L) + ((bool(s1[18] & 0x2L))<<1)
183 status_pos = STATUS_POS[revision]
184 status_byte = s1[status_pos]<<4
185 if status_byte != 48:
186 status_byte = (s1[status_pos]<<4) + s1[status_pos + 1]
187 stat = status_byte + STATUS_PRINTER_BASE
189 pen, c, d = {}, NUM_PEN_POS[revision]+1, 0
190 num_pens = s1[NUM_PEN_POS[revision]]
192 pen_data_size = PEN_DATA_SIZE[revision]
194 log.debug("num_pens = %d" % num_pens)
195 for p in range(num_pens):
196 info = long(s[c : c + pen_data_size], 16)
200 if pen_data_size == 4:
201 pen['type'] = REVISION_2_TYPE_MAP.get(int((info & 0xf000L) >> 12L), 0)
203 if index < (num_pens / 2):
204 pen['kind'] = AGENT_KIND_HEAD
206 pen['kind'] = AGENT_KIND_SUPPLY
208 pen['level-trigger'] = int ((info & 0x0e00L) >> 9L)
209 pen['health'] = int((info & 0x0180L) >> 7L)
210 pen['level'] = int(info & 0x007fL)
213 elif pen_data_size == 8:
214 pen['kind'] = bool(info & 0x80000000L) + ((bool(info & 0x40000000L))<<1L)
215 pen['type'] = int((info & 0x3f000000L) >> 24L)
216 pen['id'] = int((info & 0xf80000) >> 19L)
217 pen['level-trigger'] = int((info & 0x70000L) >> 16L)
218 pen['health'] = int((info & 0xc000L) >> 14L)
219 pen['level'] = int(info & 0xffL)
222 log.error("Pen data size error")
225 # TODO: Determine cause of IndexError for C6100 (defect #1111)
227 pen['dvc'] = long(z1s[d+1:d+5], 16)
228 pen['virgin'] = bool(z1[d+5] & 0x8L)
229 pen['hp-ink'] = bool(z1[d+5] & 0x4L)
230 pen['known'] = bool(z1[d+5] & 0x2L)
231 pen['ack'] = bool(z1[d+5] & 0x1L)
239 log.debug("pen %d %s" % (index, pen))
247 except (IndexError, ValueError, TypeError), e:
248 log.warn("Status parsing error: %s" % str(e))
250 return {'revision' : revision,
252 'top-door' : top_door,
253 'status-code' : stat,
254 'supply-door' : supply_door,
255 'duplexer' : duplexer,
256 'photo-tray' : photo_tray,
257 'in-tray1' : in_tray1,
258 'in-tray2' : in_tray2,
259 'media-path' : media_path,
264 # $HB0$NC0,ff,DN,IDLE,CUT,K0,C0,DP,NR,KP092,CP041
265 # 0 1 2 3 4 5 6 7 8 9 10
267 pens, pen, c = [], {}, 0
268 fields = s.split(',')
273 # TODO: $H00000000$M00000000 style (OJ Pro 1150/70)
283 pen['type'], pen['kind'] = AGENT_TYPE_NONE, AGENT_KIND_NONE
286 pen['health'] = AGENT_HEALTH_OK
287 pen['kind'] = AGENT_KIND_HEAD_AND_SUPPLY
288 if p in ('b', 'B'): pen['type'] = AGENT_TYPE_BLACK
289 elif p in ('c', 'C'): pen['type'] = AGENT_TYPE_CMY
290 elif p in ('d', 'D'): pen['type'] = AGENT_TYPE_KCM
291 elif p in ('u', 'U'): pen['type'], pen['health'] = AGENT_TYPE_NONE, AGENT_HEALTH_MISINSTALLED
294 if p == '0': pen['state'] = 1
295 else: pen['state'] = 0
306 if f[:2] == 'KP' and pen['type'] == AGENT_TYPE_BLACK:
307 pen['level'] = int(f[2:])
308 elif f[:2] == 'CP' and pen['type'] == AGENT_TYPE_CMY:
309 pen['level'] = int(f[2:])
321 top_lid = 1 # something went wrong!
323 if fields[2] == 'DN':
329 stat = vstatus_xlate.get(fields[3].lower(), STATUS_PRINTER_IDLE)
331 stat = STATUS_PRINTER_IDLE # something went wrong!
333 return {'revision' : STATUS_REV_V,
335 'top-door' : top_lid,
337 'supply-door': SUPPLY_DOOR_NOT_PRESENT,
338 'duplexer' : DUPLEXER_NOT_PRESENT,
339 'photo-tray' : PHOTO_TRAY_NOT_PRESENT,
340 'in-tray1' : IN_TRAY_NOT_PRESENT,
341 'in-tray2' : IN_TRAY_NOT_PRESENT,
342 'media-path' : MEDIA_PATH_CUT_SHEET, # ?
346 def parseStatus(DeviceID):
347 if 'VSTATUS' in DeviceID:
348 return parseVStatus(DeviceID['VSTATUS'])
349 elif 'S' in DeviceID:
350 return parseSStatus(DeviceID['S'], DeviceID.get('Z', ''))
352 return STATUS_BLOCK_UNKNOWN
354 def LaserJetDeviceStatusToPrinterStatus(device_status, printer_status, detected_error_state):
355 stat = STATUS_PRINTER_IDLE
357 if device_status in (pml.DEVICE_STATUS_WARNING, pml.DEVICE_STATUS_DOWN):
359 if detected_error_state & pml.DETECTED_ERROR_STATE_LOW_PAPER_MASK and \
360 not (detected_error_state & pml.DETECTED_ERROR_STATE_NO_PAPER_MASK):
361 stat = STATUS_PRINTER_LOW_PAPER
363 elif detected_error_state & pml.DETECTED_ERROR_STATE_NO_PAPER_MASK:
364 stat = STATUS_PRINTER_OUT_OF_PAPER
366 elif detected_error_state & pml.DETECTED_ERROR_STATE_DOOR_OPEN_MASK:
367 stat = STATUS_PRINTER_DOOR_OPEN
369 elif detected_error_state & pml.DETECTED_ERROR_STATE_JAMMED_MASK:
370 stat = STATUS_PRINTER_MEDIA_JAM
372 elif detected_error_state & pml.DETECTED_ERROR_STATE_OUT_CART_MASK:
373 stat = STATUS_PRINTER_NO_TONER
375 elif detected_error_state & pml.DETECTED_ERROR_STATE_LOW_CART_MASK:
376 stat = STATUS_PRINTER_LOW_TONER
378 elif detected_error_state == pml.DETECTED_ERROR_STATE_SERVICE_REQUEST_MASK:
379 stat = STATUS_PRINTER_SERVICE_REQUEST
381 elif detected_error_state & pml.DETECTED_ERROR_STATE_OFFLINE_MASK:
382 stat = STATUS_PRINTER_OFFLINE
386 if printer_status == pml.PRINTER_STATUS_IDLE:
387 stat = STATUS_PRINTER_IDLE
389 elif printer_status == pml.PRINTER_STATUS_PRINTING:
390 stat = STATUS_PRINTER_PRINTING
392 elif printer_status == pml.PRINTER_STATUS_WARMUP:
393 stat = STATUS_PRINTER_WARMING_UP
397 # Map from ISO 10175/10180 to HPLIP types
398 COLORANT_INDEX_TO_AGENT_TYPE_MAP = {
399 'other' : AGENT_TYPE_UNSPECIFIED,
400 'unknown' : AGENT_TYPE_UNSPECIFIED,
401 'blue' : AGENT_TYPE_BLUE,
402 'cyan' : AGENT_TYPE_CYAN,
403 'magenta': AGENT_TYPE_MAGENTA,
404 'yellow' : AGENT_TYPE_YELLOW,
405 'black' : AGENT_TYPE_BLACK,
408 MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP = {
409 pml.OID_MARKER_SUPPLIES_TYPE_OTHER : AGENT_KIND_UNKNOWN,
410 pml.OID_MARKER_SUPPLIES_TYPE_UNKNOWN : AGENT_KIND_UNKNOWN,
411 pml.OID_MARKER_SUPPLIES_TYPE_TONER : AGENT_KIND_TONER_CARTRIDGE,
412 pml.OID_MARKER_SUPPLIES_TYPE_WASTE_TONER : AGENT_KIND_UNKNOWN,
413 pml.OID_MARKER_SUPPLIES_TYPE_INK : AGENT_KIND_SUPPLY,
414 pml.OID_MARKER_SUPPLIES_TYPE_INK_CART : AGENT_KIND_HEAD_AND_SUPPLY,
415 pml.OID_MARKER_SUPPLIES_TYPE_INK_RIBBON : AGENT_KIND_HEAD_AND_SUPPLY,
416 pml.OID_MARKER_SUPPLIES_TYPE_WASTE_INK : AGENT_KIND_UNKNOWN,
417 pml.OID_MARKER_SUPPLIES_TYPE_OPC : AGENT_KIND_DRUM_KIT,
418 pml.OID_MARKER_SUPPLIES_TYPE_DEVELOPER : AGENT_KIND_UNKNOWN,
419 pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OIL : AGENT_KIND_UNKNOWN,
420 pml.OID_MARKER_SUPPLIES_TYPE_SOLID_WAX : AGENT_KIND_UNKNOWN,
421 pml.OID_MARKER_SUPPLIES_TYPE_RIBBON_WAX : AGENT_KIND_UNKNOWN,
422 pml.OID_MARKER_SUPPLIES_TYPE_WASTE_WAX : AGENT_KIND_UNKNOWN,
423 pml.OID_MARKER_SUPPLIES_TYPE_FUSER : AGENT_KIND_MAINT_KIT,
424 pml.OID_MARKER_SUPPLIES_TYPE_CORONA_WIRE : AGENT_KIND_UNKNOWN,
425 pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OIL_WICK : AGENT_KIND_UNKNOWN,
426 pml.OID_MARKER_SUPPLIES_TYPE_CLEANER_UNIT : AGENT_KIND_UNKNOWN,
427 pml.OID_MARKER_SUPPLIES_TYPE_FUSER_CLEANING_PAD : AGENT_KIND_UNKNOWN,
428 pml.OID_MARKER_SUPPLIES_TYPE_TRANSFER_UNIT : AGENT_KIND_TRANSFER_KIT,
429 pml.OID_MARKER_SUPPLIES_TYPE_TONER_CART : AGENT_KIND_TONER_CARTRIDGE,
430 pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OILER : AGENT_KIND_UNKNOWN,
431 pml.OID_MARKER_SUPPLIES_TYPE_ADF_MAINT_KIT : AGENT_KIND_ADF_KIT,
435 def StatusType3( dev, parsedID ): # LaserJet Status (PML/SNMP)
438 #result_code, on_off_line = dev.getPML( pml.OID_ON_OFF_LINE, pml.INT_SIZE_BYTE )
439 #result_code, sleep_mode = dev.getPML( pml.OID_SLEEP_MODE, pml.INT_SIZE_BYTE )
440 result_code, printer_status = dev.getPML( pml.OID_PRINTER_STATUS, pml.INT_SIZE_BYTE )
441 result_code, device_status = dev.getPML( pml.OID_DEVICE_STATUS, pml.INT_SIZE_BYTE )
442 result_code, cover_status = dev.getPML( pml.OID_COVER_STATUS, pml.INT_SIZE_BYTE )
443 result_code, value = dev.getPML( pml.OID_DETECTED_ERROR_STATE )
447 return {'revision' : STATUS_REV_UNKNOWN,
450 'status-code' : STATUS_UNKNOWN,
460 detected_error_state = struct.unpack( 'B', value[0])[0]
461 except (IndexError, TypeError):
462 detected_error_state = pml.DETECTED_ERROR_STATE_OFFLINE_MASK
467 log.debug( "%s Agent: %d %s" % ("*"*10, x, "*"*10))
468 log.debug("OID_MARKER_SUPPLIES_TYPE_%d:" % x)
469 oid = ( pml.OID_MARKER_SUPPLIES_TYPE_x % x, pml.OID_MARKER_SUPPLIES_TYPE_x_TYPE )
470 result_code, value = dev.getPML( oid, pml.INT_SIZE_BYTE )
472 if result_code != ERROR_SUCCESS or value is None:
473 log.debug("End of supply information.")
476 for a in MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP:
478 agent_kind = MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP[a]
481 agent_kind = AGENT_KIND_UNKNOWN
483 # TODO: Deal with printers that return -1 and -2 for level and max (LJ3380)
485 log.debug("OID_MARKER_SUPPLIES_LEVEL_%d:" % x)
486 oid = ( pml.OID_MARKER_SUPPLIES_LEVEL_x % x, pml.OID_MARKER_SUPPLIES_LEVEL_x_TYPE )
487 result_code, agent_level = dev.getPML( oid )
489 if result_code != ERROR_SUCCESS:
493 log.debug( 'agent%d-level: %d' % ( x, agent_level ) )
494 log.debug("OID_MARKER_SUPPLIES_MAX_%d:" % x)
495 oid = ( pml.OID_MARKER_SUPPLIES_MAX_x % x, pml.OID_MARKER_SUPPLIES_MAX_x_TYPE )
496 result_code, agent_max = dev.getPML( oid )
498 if agent_max == 0: agent_max = 1
500 if result_code != ERROR_SUCCESS:
504 log.debug( 'agent%d-max: %d' % ( x, agent_max ) )
505 log.debug("OID_MARKER_SUPPLIES_COLORANT_INDEX_%d:" % x)
506 oid = ( pml.OID_MARKER_SUPPLIES_COLORANT_INDEX_x % x, pml.OID_MARKER_SUPPLIES_COLORANT_INDEX_x_TYPE )
507 result_code, colorant_index = dev.getPML( oid )
509 if result_code != ERROR_SUCCESS: # 3080, 3055 will fail here
511 agent_type = AGENT_TYPE_BLACK
514 log.debug("Colorant index: %d" % colorant_index)
516 log.debug("OID_MARKER_COLORANT_VALUE_%d" % x)
517 oid = ( pml.OID_MARKER_COLORANT_VALUE_x % colorant_index, pml.OID_MARKER_COLORANT_VALUE_x_TYPE )
518 result_code, colorant_value = dev.getPML( oid )
520 if result_code != ERROR_SUCCESS:
521 log.debug("Failed. Defaulting to black.")
522 agent_type = AGENT_TYPE_BLACK
525 if agent_kind in (AGENT_KIND_MAINT_KIT, AGENT_KIND_ADF_KIT,
526 AGENT_KIND_DRUM_KIT, AGENT_KIND_TRANSFER_KIT):
528 agent_type = AGENT_TYPE_UNSPECIFIED
531 agent_type = AGENT_TYPE_BLACK
533 if result_code != ERROR_SUCCESS:
534 log.debug("OID_MARKER_SUPPLIES_DESCRIPTION_%d:" % x)
535 oid = (pml.OID_MARKER_SUPPLIES_DESCRIPTION_x % x, pml.OID_MARKER_SUPPLIES_DESCRIPTION_x_TYPE)
536 result_code, colorant_value = dev.getPML( oid )
538 if result_code != ERROR_SUCCESS:
542 if colorant_value is not None:
543 log.debug("colorant value: %s" % colorant_value)
544 colorant_value = colorant_value.lower().strip()
546 for c in COLORANT_INDEX_TO_AGENT_TYPE_MAP:
547 if colorant_value.find(c) >= 0:
548 agent_type = COLORANT_INDEX_TO_AGENT_TYPE_MAP[c]
551 agent_type = AGENT_TYPE_BLACK
554 if colorant_value is not None:
555 log.debug("colorant value: %s" % colorant_value)
556 agent_type = COLORANT_INDEX_TO_AGENT_TYPE_MAP.get( colorant_value, AGENT_TYPE_BLACK )
558 if agent_type == AGENT_TYPE_NONE:
559 if agent_kind == AGENT_KIND_TONER_CARTRIDGE:
560 agent_type = AGENT_TYPE_BLACK
562 agent_type = AGENT_TYPE_UNSPECIFIED
564 log.debug("OID_MARKER_STATUS_%d:" % x)
565 oid = ( pml.OID_MARKER_STATUS_x % x, pml.OID_MARKER_STATUS_x_TYPE )
566 result_code, agent_status = dev.getPML( oid )
568 if result_code != ERROR_SUCCESS:
570 agent_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
571 agent_health = AGENT_HEALTH_OK
573 agent_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
575 if agent_status is None:
576 agent_health = AGENT_HEALTH_OK
578 elif agent_status == pml.OID_MARKER_STATUS_OK:
579 agent_health = AGENT_HEALTH_OK
581 elif agent_status == pml.OID_MARKER_STATUS_MISINSTALLED:
582 agent_health = AGENT_HEALTH_MISINSTALLED
584 elif agent_status in ( pml.OID_MARKER_STATUS_LOW_TONER_CONT,
585 pml.OID_MARKER_STATUS_LOW_TONER_STOP ):
587 agent_health = AGENT_HEALTH_OK
588 agent_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
591 agent_health = AGENT_HEALTH_OK
593 agent_level = int(agent_level/agent_max * 100)
595 log.debug("agent%d: kind=%d, type=%d, health=%d, level=%d, level-trigger=%d" % \
596 (x, agent_kind, agent_type, agent_health, agent_level, agent_trigger))
599 agents.append({'kind' : agent_kind,
601 'health' : agent_health,
602 'level' : agent_level,
603 'level-trigger' : agent_trigger,})
611 printer_status = printer_status or STATUS_PRINTER_IDLE
612 log.debug("printer_status=%d" % printer_status)
613 device_status = device_status or pml.DEVICE_STATUS_RUNNING
614 log.debug("device_status=%d" % device_status)
615 cover_status = cover_status or pml.COVER_STATUS_CLOSED
616 log.debug("cover_status=%d" % cover_status)
617 detected_error_state = detected_error_state or pml.DETECTED_ERROR_STATE_NO_ERROR
618 log.debug("detected_error_state=%d (0x%x)" % (detected_error_state, detected_error_state))
620 stat = LaserJetDeviceStatusToPrinterStatus(device_status, printer_status, detected_error_state)
622 log.debug("Printer status=%d" % stat)
624 if stat == STATUS_PRINTER_DOOR_OPEN:
629 return {'revision' : STATUS_REV_UNKNOWN,
631 'top-door' : cover_status,
632 'status-code' : stat,
633 'supply-door' : supply_door,
641 def setup_panel_translator():
643 """0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
644 !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~""")
647 for x in [chr(x) for x in range(0,256)]:
653 map.update({'\x10' : '\xab',
668 map_keys = map.keys()
671 frm = ''.join([frm, x])
672 to = ''.join([to, map[x]])
674 global PANEL_TRANSLATOR_FUNC
675 PANEL_TRANSLATOR_FUNC = utils.Translator(frm, to)
677 PANEL_TRANSLATOR_FUNC = None
678 setup_panel_translator()
682 line1, line2 = '', ''
684 if dev.io_mode not in (IO_MODE_RAW, IO_MODE_UNI):
692 oids = [(pml.OID_HP_LINE1, pml.OID_HP_LINE2),
693 (pml.OID_SPM_LINE1, pml.OID_SPM_LINE2)]
695 for oid1, oid2 in oids:
696 result, line1 = dev.getPML(oid1)
698 if result < pml.ERROR_MAX_OK:
699 line1 = PANEL_TRANSLATOR_FUNC(line1).rstrip()
702 line1, line2 = line1.split('\x0a', 1)
705 result, line2 = dev.getPML(oid2)
707 if result < pml.ERROR_MAX_OK:
708 line2 = PANEL_TRANSLATOR_FUNC(line2).rstrip()
711 return bool(line1 or line2), line1 or '', line2 or ''
714 BATTERY_HEALTH_MAP = {0 : AGENT_HEALTH_OK,
715 1 : AGENT_HEALTH_OVERTEMP,
716 2 : AGENT_HEALTH_CHARGING,
717 3 : AGENT_HEALTH_MISINSTALLED,
718 4 : AGENT_HEALTH_FAILED,
722 BATTERY_TRIGGER_MAP = {0 : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
723 1 : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
724 2 : AGENT_LEVEL_TRIGGER_PROBABLY_OUT,
725 3 : AGENT_LEVEL_TRIGGER_SUFFICIENT_4,
726 4 : AGENT_LEVEL_TRIGGER_SUFFICIENT_2,
727 5 : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
730 BATTERY_PML_TRIGGER_MAP = {
731 (100, 80) : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
732 (79, 60) : AGENT_LEVEL_TRIGGER_SUFFICIENT_1,
733 (59, 40) : AGENT_LEVEL_TRIGGER_SUFFICIENT_2,
734 (39, 30) : AGENT_LEVEL_TRIGGER_SUFFICIENT_3,
735 (29, 20) : AGENT_LEVEL_TRIGGER_SUFFICIENT_4,
736 (19, 10) : AGENT_LEVEL_TRIGGER_MAY_BE_LOW,
737 (9, 5) : AGENT_LEVEL_TRIGGER_PROBABLY_OUT,
738 (4, -1) : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
742 def BatteryCheck(dev, status_block, battery_check):
743 try_dynamic_counters = False
749 if battery_check == STATUS_BATTERY_CHECK_STD:
750 log.debug("PML channel open failed. Trying dynamic counters...")
751 try_dynamic_counters = True
753 if battery_check == STATUS_BATTERY_CHECK_PML:
754 result, battery_level = dev.getPML(pml.OID_BATTERY_LEVEL_2)
756 if result > pml.ERROR_MAX_OK:
757 status_block['agents'].append({
758 'kind' : AGENT_KIND_INT_BATTERY,
759 'type' : AGENT_TYPE_UNSPECIFIED,
760 'health' : AGENT_HEALTH_UNKNOWN,
762 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
767 status_block['agents'].append({
768 'kind' : AGENT_KIND_INT_BATTERY,
769 'type' : AGENT_TYPE_UNSPECIFIED,
770 'health' : AGENT_HEALTH_OK,
771 'level' : battery_level,
772 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
776 else: # STATUS_BATTERY_CHECK_STD
777 result, battery_level = dev.getPML(pml.OID_BATTERY_LEVEL)
778 result, power_mode = dev.getPML(pml.OID_POWER_MODE)
780 if battery_level is not None and \
781 power_mode is not None:
783 if power_mode & pml.POWER_MODE_BATTERY_LEVEL_KNOWN and \
786 for x in BATTERY_PML_TRIGGER_MAP:
787 if x[0] >= battery_level > x[1]:
788 battery_trigger_level = BATTERY_PML_TRIGGER_MAP[x]
791 if power_mode & pml.POWER_MODE_CHARGING:
792 agent_health = AGENT_HEALTH_CHARGING
794 elif power_mode & pml.POWER_MODE_DISCHARGING:
795 agent_health = AGENT_HEALTH_DISCHARGING
798 agent_health = AGENT_HEALTH_OK
800 status_block['agents'].append({
801 'kind' : AGENT_KIND_INT_BATTERY,
802 'type' : AGENT_TYPE_UNSPECIFIED,
803 'health' : agent_health,
804 'level' : battery_level,
805 'level-trigger' : battery_trigger_level,
810 status_block['agents'].append({
811 'kind' : AGENT_KIND_INT_BATTERY,
812 'type' : AGENT_TYPE_UNSPECIFIED,
813 'health' : AGENT_HEALTH_UNKNOWN,
815 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
820 try_dynamic_counters = True
826 if battery_check == STATUS_BATTERY_CHECK_STD and \
827 try_dynamic_counters:
831 battery_health = dev.getDynamicCounter(200)
832 battery_trigger_level = dev.getDynamicCounter(201)
833 battery_level = dev.getDynamicCounter(202)
835 status_block['agents'].append({
836 'kind' : AGENT_KIND_INT_BATTERY,
837 'type' : AGENT_TYPE_UNSPECIFIED,
838 'health' : BATTERY_HEALTH_MAP[battery_health],
839 'level' : battery_level,
840 'level-trigger' : BATTERY_TRIGGER_MAP[battery_trigger_level],
843 status_block['agents'].append({
844 'kind' : AGENT_KIND_INT_BATTERY,
845 'type' : AGENT_TYPE_UNSPECIFIED,
846 'health' : AGENT_HEALTH_UNKNOWN,
848 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
854 status_block['agents'].append({
855 'kind' : AGENT_KIND_INT_BATTERY,
856 'type' : AGENT_TYPE_UNSPECIFIED,
857 'health' : AGENT_HEALTH_UNKNOWN,
859 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
864 # this works for 2 pen products that allow 1 or 2 pens inserted
865 # from: k, kcm, cmy, ggk
866 def getPenConfiguration(s): # s=status dict from parsed device ID
867 pens = [p['type'] for p in s['agents']]
869 if utils.all(pens, lambda x : x==AGENT_TYPE_NONE):
870 return AGENT_CONFIG_NONE
872 if AGENT_TYPE_NONE in pens:
874 if AGENT_TYPE_BLACK in pens:
875 return AGENT_CONFIG_BLACK_ONLY
877 elif AGENT_TYPE_CMY in pens:
878 return AGENT_CONFIG_COLOR_ONLY
880 elif AGENT_TYPE_KCM in pens:
881 return AGENT_CONFIG_PHOTO_ONLY
883 elif AGENT_TYPE_GGK in pens:
884 return AGENT_CONFIG_GREY_ONLY
887 return AGENT_CONFIG_INVALID
890 if AGENT_TYPE_BLACK in pens and AGENT_TYPE_CMY in pens:
891 return AGENT_CONFIG_COLOR_AND_BLACK
893 elif AGENT_TYPE_CMY in pens and AGENT_TYPE_KCM in pens:
894 return AGENT_CONFIG_COLOR_AND_PHOTO
896 elif AGENT_TYPE_CMY in pens and AGENT_TYPE_GGK in pens:
897 return AGENT_CONFIG_COLOR_AND_GREY
900 return AGENT_CONFIG_INVALID
903 def getFaxStatus(dev):
904 tx_active, rx_active = False, False
906 if dev.io_mode not in (IO_MODE_UNI, IO_MODE_RAW):
910 result_code, tx_state = dev.getPML(pml.OID_FAXJOB_TX_STATUS)
912 if result_code == ERROR_SUCCESS and tx_state:
913 if tx_state not in (pml.FAXJOB_TX_STATUS_IDLE, pml.FAXJOB_TX_STATUS_DONE):
916 result_code, rx_state = dev.getPML(pml.OID_FAXJOB_RX_STATUS)
918 if result_code == ERROR_SUCCESS and rx_state:
919 if rx_state not in (pml.FAXJOB_RX_STATUS_IDLE, pml.FAXJOB_RX_STATUS_DONE):
925 return tx_active, rx_active
928 TYPE6_STATUS_CODE_MAP = {
929 0 : STATUS_PRINTER_IDLE, #</DevStatusUnknown>
930 -19928: STATUS_PRINTER_IDLE,
931 -18995: STATUS_PRINTER_CANCELING,
932 -17974: STATUS_PRINTER_WARMING_UP,
933 -17973: STATUS_PRINTER_PEN_CLEANING, # sic
934 -18993: STATUS_PRINTER_BUSY,
935 -17949: STATUS_PRINTER_BUSY,
936 -19720: STATUS_PRINTER_MANUAL_DUPLEX_BLOCK,
937 -19678: STATUS_PRINTER_BUSY,
938 -19695: STATUS_PRINTER_OUT_OF_PAPER,
939 -17985: STATUS_PRINTER_MEDIA_JAM,
940 -19731: STATUS_PRINTER_OUT_OF_PAPER,
941 -18974: STATUS_PRINTER_BUSY, #?
942 -19730: STATUS_PRINTER_OUT_OF_PAPER,
943 -19729: STATUS_PRINTER_OUT_OF_PAPER,
944 -19933: STATUS_PRINTER_HARD_ERROR, # out of memory
945 -17984: STATUS_PRINTER_DOOR_OPEN,
946 -19694: STATUS_PRINTER_DOOR_OPEN,
947 -18992: STATUS_PRINTER_MANUAL_FEED_BLOCKED, # ?
948 -19690: STATUS_PRINTER_MEDIA_JAM, # tray 1
949 -19689: STATUS_PRINTER_MEDIA_JAM, # tray 2
950 -19611: STATUS_PRINTER_MEDIA_JAM, # tray 3
951 -19686: STATUS_PRINTER_MEDIA_JAM,
952 -19688: STATUS_PRINTER_MEDIA_JAM, # paper path
953 -19685: STATUS_PRINTER_MEDIA_JAM, # cart area
954 -19684: STATUS_PRINTER_MEDIA_JAM, # output bin
955 -18848: STATUS_PRINTER_MEDIA_JAM, # duplexer
956 -18847: STATUS_PRINTER_MEDIA_JAM, # door open
957 -18846: STATUS_PRINTER_MEDIA_JAM, # tray 2
958 -19687: STATUS_PRINTER_MEDIA_JAM, # open door
959 -17992: STATUS_PRINTER_MEDIA_JAM, # mispick
960 -19700: STATUS_PRINTER_HARD_ERROR, # invalid driver
961 -17996: STATUS_PRINTER_FUSER_ERROR, # fuser error
962 -17983: STATUS_PRINTER_FUSER_ERROR,
963 -17982: STATUS_PRINTER_FUSER_ERROR,
964 -17981: STATUS_PRINTER_FUSER_ERROR,
965 -17971: STATUS_PRINTER_FUSER_ERROR,
966 -17995: STATUS_PRINTER_HARD_ERROR, # beam error
967 -17994: STATUS_PRINTER_HARD_ERROR, # scanner error
968 -17993: STATUS_PRINTER_HARD_ERROR, # fan error
969 -18994: STATUS_PRINTER_HARD_ERROR,
970 -17986: STATUS_PRINTER_HARD_ERROR,
971 -19904: STATUS_PRINTER_HARD_ERROR,
972 -19701: STATUS_PRINTER_NON_HP_INK, # [sic]
973 -19613: STATUS_PRINTER_IDLE, # HP
974 -19654: STATUS_PRINTER_NON_HP_INK, # [sic]
975 -19682: STATUS_PRINTER_HARD_ERROR, # resinstall
976 -19693: STATUS_PRINTER_IDLE, # ?? To Accept
977 -19752: STATUS_PRINTER_LOW_TONER,
978 -19723: STATUS_PRINTER_BUSY,
979 -19703: STATUS_PRINTER_BUSY,
980 -19739: STATUS_PRINTER_NO_TONER,
981 -19927: STATUS_PRINTER_BUSY,
982 -19932: STATUS_PRINTER_BUSY,
983 -19931: STATUS_PRINTER_BUSY,
984 -11989: STATUS_PRINTER_BUSY,
985 -11995: STATUS_PRINTER_BUSY, # ADF loaded
986 -19954: STATUS_PRINTER_CANCELING,
987 -19955: STATUS_PRINTER_REPORT_PRINTING,
988 -19956: STATUS_PRINTER_REPORT_PRINTING,
989 -19934: STATUS_PRINTER_HARD_ERROR,
990 -19930: STATUS_PRINTER_BUSY,
991 -11990: STATUS_PRINTER_DOOR_OPEN,
992 -11999: STATUS_PRINTER_MEDIA_JAM, # ADF
993 -12000: STATUS_PRINTER_MEDIA_JAM, # ADF
994 -11998: STATUS_PRINTER_MEDIA_JAM, # ADF
995 -11986: STATUS_PRINTER_HARD_ERROR, # scanner
996 -11994: STATUS_PRINTER_BUSY,
997 -14967: STATUS_PRINTER_BUSY,
998 -19912: STATUS_PRINTER_HARD_ERROR,
999 -14962: STATUS_PRINTER_BUSY, # copy pending
1000 -14971: STATUS_PRINTER_BUSY, # copying
1001 -14973: STATUS_PRINTER_BUSY, # copying being canceled
1002 -14972: STATUS_PRINTER_BUSY, # copying canceled
1003 -14966: STATUS_PRINTER_DOOR_OPEN,
1004 -14974: STATUS_PRINTER_MEDIA_JAM,
1005 -14969: STATUS_PRINTER_HARD_ERROR,
1006 -14968: STATUS_PRINTER_HARD_ERROR,
1007 -12996: STATUS_PRINTER_BUSY, # scan
1008 -12994: STATUS_PRINTER_BUSY, # scan
1009 -12993: STATUS_PRINTER_BUSY, # scan
1010 -12991: STATUS_PRINTER_BUSY, # scan
1011 -12995: STATUS_PRINTER_BUSY, # scan
1012 -12997: STATUS_PRINTER_HARD_ERROR, # scan
1013 -12990: STATUS_PRINTER_BUSY,
1014 -12998: STATUS_PRINTER_BUSY,
1015 -13000: STATUS_PRINTER_DOOR_OPEN,
1016 -12999: STATUS_PRINTER_MEDIA_JAM,
1017 -13859: STATUS_PRINTER_BUSY,
1018 -13858: STATUS_PRINTER_BUSY, #</DevStatusDialingOut>
1019 -13868: STATUS_PRINTER_BUSY, #</DevStatusRedialPending>
1020 -13867: STATUS_PRINTER_BUSY, #</DevStatusFaxSendCanceled>
1021 -13857: STATUS_PRINTER_BUSY, #</DevStatusConnecting>
1022 -13856: STATUS_PRINTER_BUSY, #</DevStatusSendingPage>
1023 -13855: STATUS_PRINTER_BUSY, #</DevStatusOnePageSend>
1024 -13854: STATUS_PRINTER_BUSY, #</DevStatusMultiplePagesSent>
1025 -13853: STATUS_PRINTER_BUSY, #</DevStatusSenderCancelingFax>
1026 -13839: STATUS_PRINTER_BUSY, #</DevStatusIncomingCall>
1027 -13842: STATUS_PRINTER_BUSY, #</DevStatusBlockingFax>
1028 -13838: STATUS_PRINTER_BUSY, #</DevStatusReceivingFax>
1029 -13847: STATUS_PRINTER_BUSY, #</DevStatusSinglePageReceived>
1030 -13846: STATUS_PRINTER_BUSY, #</DevStatusDoublePagesReceived>
1031 -13845: STATUS_PRINTER_BUSY, #</DevStatusTriplePagesReceived>
1032 -13844: STATUS_PRINTER_BUSY, #</DevStatusPrintingFax>
1033 -13840: STATUS_PRINTER_BUSY, #</DevStatusCancelingFaxPrint>
1034 -13843: STATUS_PRINTER_BUSY, #</DevStatusFaxCancelingReceive>
1035 -13850: STATUS_PRINTER_BUSY, #</DevStatusFaxCanceledReceive>
1036 -13851: STATUS_PRINTER_BUSY, #</DevStatusFaxDelayedSendMemoryFull>
1037 -13836: STATUS_PRINTER_BUSY, #</DevStatusNoDialTone>
1038 -13864: STATUS_PRINTER_BUSY, #</DevStatusNoFaxAnswer>
1039 -13863: STATUS_PRINTER_BUSY, #</DevStatusFaxBusy>
1040 -13865: STATUS_PRINTER_BUSY, #</DevStatusNoDocumentSent>
1041 -13862: STATUS_PRINTER_BUSY, #</DevStatusFaxSendError>
1042 -13837: STATUS_PRINTER_BUSY, #</DevStatusT30Error>
1043 -13861: STATUS_PRINTER_BUSY, #</DevStatusFaxMemoryFullSend>
1044 -13866: STATUS_PRINTER_BUSY, #</DevStatusADFNotCleared>
1045 -13841: STATUS_PRINTER_BUSY, #</DevStatusNoFaxDetected>
1046 -13848: STATUS_PRINTER_BUSY, #</DevStatusFaxMemoryFullReceive>
1047 -13849: STATUS_PRINTER_BUSY, #</DevStatusFaxReceiveError>
1051 def StatusType6(dev): # LaserJet Status (XML)
1052 info_device_status = cStringIO.StringIO()
1053 info_ssp = cStringIO.StringIO()
1056 dev.getEWSUrl("/hp/device/info_device_status.xml", info_device_status)
1057 dev.getEWSUrl("/hp/device/info_ssp.xml", info_ssp)
1061 info_device_status = info_device_status.getvalue()
1062 info_ssp = info_ssp.getvalue()
1067 if info_device_status:
1069 log.debug_block("info_device_status", info_device_status)
1070 device_status = utils.XMLToDictParser().parseXML(info_device_status)
1071 log.debug(device_status)
1072 except expat.ExpatError:
1073 log.error("Device Status XML parse error")
1078 log.debug_block("info_spp", info_ssp)
1079 ssp = utils.XMLToDictParser().parseXML(info_ssp)
1081 except expat.ExpatError:
1082 log.error("SSP XML parse error")
1085 status_code = device_status.get('devicestatuspage-devicestatus-statuslist-status-code-0', 0)
1088 status_code = ssp.get('devicestatuspage-devicestatus-statuslist-status-code-0', 0)
1090 black_supply_level = device_status.get('devicestatuspage-suppliesstatus-blacksupply-percentremaining', 0)
1091 black_supply_low = ssp.get('suppliesstatuspage-blacksupply-lowreached', 0)
1094 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE,
1095 'type' : AGENT_TYPE_BLACK,
1097 'level' : black_supply_level,
1098 'level-trigger' : 0,
1101 if dev.tech_type == TECH_TYPE_COLOR_LASER:
1102 cyan_supply_level = device_status.get('devicestatuspage-suppliesstatus-cyansupply-percentremaining', 0)
1103 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE,
1104 'type' : AGENT_TYPE_CYAN,
1106 'level' : cyan_supply_level,
1107 'level-trigger' : 0,
1110 magenta_supply_level = device_status.get('devicestatuspage-suppliesstatus-magentasupply-percentremaining', 0)
1111 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE,
1112 'type' : AGENT_TYPE_MAGENTA,
1114 'level' : magenta_supply_level,
1115 'level-trigger' : 0,
1118 yellow_supply_level = device_status.get('devicestatuspage-suppliesstatus-yellowsupply-percentremaining', 0)
1119 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE,
1120 'type' : AGENT_TYPE_YELLOW,
1122 'level' : yellow_supply_level,
1123 'level-trigger' : 0,
1126 return {'revision' : STATUS_REV_UNKNOWN,
1135 'status-code' : TYPE6_STATUS_CODE_MAP.get(status_code, STATUS_PRINTER_IDLE),
1140 10001: STATUS_PRINTER_IDLE, # online
1141 10002: STATUS_PRINTER_OFFLINE, # offline
1142 10003: STATUS_PRINTER_WARMING_UP,
1143 10004: STATUS_PRINTER_BUSY, # self test
1144 10005: STATUS_PRINTER_BUSY, # reset
1145 10006: STATUS_PRINTER_LOW_TONER,
1146 10007: STATUS_PRINTER_CANCELING,
1147 10010: STATUS_PRINTER_SERVICE_REQUEST,
1148 10011: STATUS_PRINTER_OFFLINE,
1149 10013: STATUS_PRINTER_BUSY,
1150 10014: STATUS_PRINTER_REPORT_PRINTING,
1151 10015: STATUS_PRINTER_BUSY,
1152 10016: STATUS_PRINTER_BUSY,
1153 10017: STATUS_PRINTER_REPORT_PRINTING,
1154 10018: STATUS_PRINTER_BUSY,
1155 10019: STATUS_PRINTER_BUSY,
1156 10020: STATUS_PRINTER_BUSY,
1157 10021: STATUS_PRINTER_BUSY,
1158 10022: STATUS_PRINTER_REPORT_PRINTING,
1159 10023: STATUS_PRINTER_PRINTING,
1160 10024: STATUS_PRINTER_SERVICE_REQUEST,
1161 10025: STATUS_PRINTER_SERVICE_REQUEST,
1162 10026: STATUS_PRINTER_BUSY,
1163 10027: STATUS_PRINTER_MEDIA_JAM,
1164 10028: STATUS_PRINTER_REPORT_PRINTING,
1165 10029: STATUS_PRINTER_PRINTING,
1166 10030: STATUS_PRINTER_BUSY,
1167 10031: STATUS_PRINTER_BUSY,
1168 10032: STATUS_PRINTER_BUSY,
1169 10033: STATUS_PRINTER_SERVICE_REQUEST,
1170 10034: STATUS_PRINTER_CANCELING,
1171 10035: STATUS_PRINTER_PRINTING,
1172 10036: STATUS_PRINTER_WARMING_UP,
1173 10200: STATUS_PRINTER_LOW_BLACK_TONER,
1174 10201: STATUS_PRINTER_LOW_CYAN_TONER,
1175 10202: STATUS_PRINTER_LOW_MAGENTA_TONER,
1176 10203: STATUS_PRINTER_LOW_YELLOW_TONER,
1177 10204: STATUS_PRINTER_LOW_TONER, # order image drum
1178 10205: STATUS_PRINTER_LOW_BLACK_TONER, # order black drum
1179 10206: STATUS_PRINTER_LOW_CYAN_TONER, # order cyan drum
1180 10207: STATUS_PRINTER_LOW_MAGENTA_TONER, # order magenta drum
1181 10208: STATUS_PRINTER_LOW_YELLOW_TONER, # order yellow drum
1182 10209: STATUS_PRINTER_LOW_BLACK_TONER,
1183 10210: STATUS_PRINTER_LOW_CYAN_TONER,
1184 10211: STATUS_PRINTER_LOW_MAGENTA_TONER,
1185 10212: STATUS_PRINTER_LOW_YELLOW_TONER,
1186 10213: STATUS_PRINTER_SERVICE_REQUEST, # order transport kit
1187 10214: STATUS_PRINTER_SERVICE_REQUEST, # order cleaning kit
1188 10215: STATUS_PRINTER_SERVICE_REQUEST, # order transfer kit
1189 10216: STATUS_PRINTER_SERVICE_REQUEST, # order fuser kit
1190 10217: STATUS_PRINTER_SERVICE_REQUEST, # maintenance
1191 10218: STATUS_PRINTER_LOW_TONER,
1192 10300: STATUS_PRINTER_LOW_BLACK_TONER, # replace black toner
1193 10301: STATUS_PRINTER_LOW_CYAN_TONER, # replace cyan toner
1194 10302: STATUS_PRINTER_LOW_MAGENTA_TONER, # replace magenta toner
1195 10303: STATUS_PRINTER_LOW_YELLOW_TONER, # replace yellow toner
1196 10304: STATUS_PRINTER_SERVICE_REQUEST, # replace image drum
1197 10305: STATUS_PRINTER_SERVICE_REQUEST, # replace black drum
1198 10306: STATUS_PRINTER_SERVICE_REQUEST, # replace cyan drum
1199 10307: STATUS_PRINTER_SERVICE_REQUEST, # replace magenta drum
1200 10308: STATUS_PRINTER_SERVICE_REQUEST, # replace yellow drum
1201 10309: STATUS_PRINTER_SERVICE_REQUEST, # replace black cart
1202 10310: STATUS_PRINTER_SERVICE_REQUEST, # replace cyan cart
1203 10311: STATUS_PRINTER_SERVICE_REQUEST, # replace magenta cart
1204 10312: STATUS_PRINTER_SERVICE_REQUEST, # replace yellow cart
1205 10313: STATUS_PRINTER_SERVICE_REQUEST, # replace transport kit
1206 10314: STATUS_PRINTER_SERVICE_REQUEST, # replace cleaning kit
1207 10315: STATUS_PRINTER_SERVICE_REQUEST, # replace transfer kit
1208 10316: STATUS_PRINTER_SERVICE_REQUEST, # replace fuser kit
1209 10317: STATUS_PRINTER_SERVICE_REQUEST,
1210 10318: STATUS_PRINTER_SERVICE_REQUEST, # replace supplies
1211 10400: STATUS_PRINTER_NON_HP_INK, # [sic]
1212 10401: STATUS_PRINTER_IDLE,
1213 10402: STATUS_PRINTER_SERVICE_REQUEST,
1214 10403: STATUS_PRINTER_IDLE,
1215 # 11xyy - Background paper-loading
1216 # 12xyy - Background paper-tray status
1217 # 15xxy - Output-bin status
1218 # 20xxx - PJL parser errors
1219 # 25xxx - PJL parser warnings
1220 # 27xxx - PJL semantic errors
1221 # 30xxx - Auto continuable conditions
1222 30119: STATUS_PRINTER_MEDIA_JAM,
1223 # 32xxx - PJL file system errors
1224 # 35xxx - Potential operator intervention conditions
1225 # 40xxx - Operator intervention conditions
1226 40021: STATUS_PRINTER_DOOR_OPEN,
1227 40022: STATUS_PRINTER_MEDIA_JAM,
1228 40038: STATUS_PRINTER_LOW_TONER,
1229 40600: STATUS_PRINTER_NO_TONER,
1230 # 41xyy - Foreground paper-loading messages
1231 # 43xyy - Optional paper handling device messages
1232 # 44xyy - LJ 4xxx/5xxx paper jam messages
1233 # 50xxx - Hardware errors
1234 # 55xxx - Personality errors
1238 MIN_PJL_ERROR_CODE = 10001
1239 DEFAULT_PJL_ERROR_CODE = 10001
1241 def MapPJLErrorCode(error_code, str_code=None):
1242 if error_code < MIN_PJL_ERROR_CODE:
1243 return STATUS_PRINTER_BUSY
1245 if str_code is None:
1246 str_code = str(error_code)
1248 if len(str_code) < 5:
1249 return STATUS_PRINTER_BUSY
1251 status_code = PJL_STATUS_MAP.get(error_code, None)
1253 if status_code is None:
1254 status_code = STATUS_PRINTER_BUSY
1256 if 10999 < error_code < 12000: # 11xyy - Background paper-loading
1259 tray = int(str_code[2])
1260 media = int(str_code[3:])
1261 log.debug("Background paper loading for tray #%d" % tray)
1262 log.debug("Media code = %d" % media)
1264 elif 11999 < error_code < 13000: # 12xyy - Background paper-tray status
1267 tray = int(str_code[2])
1268 status = int(str_code[3:])
1269 log.debug("Background paper tray status for tray #%d" % tray)
1270 log.debug("Status code = %d" % status)
1272 elif 14999 < error_code < 16000: # 15xxy - Output-bin status
1275 bin = int(str_code[2:4])
1276 status = int(str_code[4])
1277 log.debug("Output bin full for bin #%d" % bin)
1278 status_code = STATUS_PRINTER_OUTPUT_BIN_FULL
1280 elif 19999 < error_code < 28000: # 20xxx, 25xxx, 27xxx PJL errors
1281 status_code = STATUS_PRINTER_SERVICE_REQUEST
1283 elif 29999 < error_code < 31000: # 30xxx - Auto continuable conditions
1284 log.debug("Auto continuation condition #%d" % error_code)
1285 status_code = STATUS_PRINTER_BUSY
1287 elif 34999 < error_code < 36000: # 35xxx - Potential operator intervention conditions
1288 status_code = STATUS_PRINTER_SERVICE_REQUEST
1290 elif 39999 < error_code < 41000: # 40xxx - Operator intervention conditions
1291 status_code = STATUS_PRINTER_SERVICE_REQUEST
1293 elif 40999 < error_code < 42000: # 41xyy - Foreground paper-loading messages
1296 tray = int(str_code[2])
1297 media = int(str_code[3:])
1298 log.debug("Foreground paper loading for tray #%d" % tray)
1299 log.debug("Media code = %d" % media)
1300 status_code = STATUS_PRINTER_OUT_OF_PAPER
1302 elif 41999 < error_code < 43000:
1303 status_code = STATUS_PRINTER_MEDIA_JAM
1305 elif 42999 < error_code < 44000: # 43xyy - Optional paper handling device messages
1306 status_code = STATUS_PRINTER_SERVICE_REQUEST
1308 elif 43999 < error_code < 45000: # 44xyy - LJ 4xxx/5xxx paper jam messages
1309 status_code = STATUS_PRINTER_MEDIA_JAM
1311 elif 49999 < error_code < 51000: # 50xxx - Hardware errors
1312 status_code = STATUS_PRINTER_HARD_ERROR
1314 elif 54999 < error_code < 56000 : # 55xxx - Personality errors
1315 status_code = STATUS_PRINTER_HARD_ERROR
1317 log.debug("Mapped PJL error code %d to status code %d" % (error_code, status_code))
1321 pjl_code_pat = re.compile("""^CODE\s*=\s*(\d.*)$""", re.IGNORECASE)
1325 def StatusType8(dev): # LaserJet PJL (B&W only)
1327 # Will error if printer is busy printing...
1331 status_code = STATUS_PRINTER_BUSY
1335 dev.writePrint("\x1b%-12345X@PJL INFO STATUS \r\n\x1b%-12345X")
1336 pjl_return = dev.readPrint(1024, timeout=5, allow_short_read=True)
1339 log.debug_block("PJL return:", pjl_return)
1343 for line in pjl_return.splitlines():
1345 match = pjl_code_pat.match(line)
1347 if match is not None:
1348 str_code = match.group(1)
1351 log.debug("Code = %s" % str_code)
1354 error_code = int(str_code)
1356 error_code = DEFAULT_PJL_ERROR_CODE
1358 log.debug("Error code = %d" % error_code)
1360 status_code = MapPJLErrorCode(error_code, str_code)
1362 status_code = STATUS_PRINTER_HARD_ERROR
1371 # TODO: Only handles mono lasers...
1372 if status_code in (STATUS_PRINTER_LOW_TONER, STATUS_PRINTER_LOW_BLACK_TONER):
1373 health = AGENT_HEALTH_OK
1374 level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
1377 elif status_code == STATUS_PRINTER_NO_TONER:
1378 health = AGENT_HEALTH_MISINSTALLED
1379 level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
1383 health = AGENT_HEALTH_OK
1384 level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
1387 log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))
1389 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE,
1390 'type' : AGENT_TYPE_BLACK,
1393 'level-trigger' : level_trigger,
1396 if dev.tech_type == TECH_TYPE_COLOR_LASER:
1398 level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
1399 if status_code == STATUS_PRINTER_LOW_CYAN_TONER:
1401 level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
1403 log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))
1405 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE,
1406 'type' : AGENT_TYPE_CYAN,
1407 'health' : AGENT_HEALTH_OK,
1409 'level-trigger' : level_trigger,
1413 level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
1414 if status_code == STATUS_PRINTER_LOW_MAGENTA_TONER:
1416 level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
1418 log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))
1420 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE,
1421 'type' : AGENT_TYPE_MAGENTA,
1422 'health' : AGENT_HEALTH_OK,
1424 'level-trigger' : level_trigger,
1428 level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
1429 if status_code == STATUS_PRINTER_LOW_YELLOW_TONER:
1431 level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
1433 log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))
1435 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE,
1436 'type' : AGENT_TYPE_YELLOW,
1437 'health' : AGENT_HEALTH_OK,
1439 'level-trigger' : level_trigger,
1442 if status_code == 40021:
1447 log.debug("Status code = %d" % status_code)
1449 return { 'revision' : STATUS_REV_UNKNOWN,
1451 'top-door' : top_door,
1452 'supply-door' : top_door,
1458 'status-code' : status_code,
1462 element_type10_xlate = { 'ink' : AGENT_KIND_SUPPLY,
1463 'inkCartridge' : AGENT_KIND_HEAD_AND_SUPPLY,
1464 'printhead' : AGENT_KIND_HEAD,
1465 'toner' : AGENT_KIND_TONER_CARTRIDGE,
1466 'tonerCartridge' : AGENT_KIND_TONER_CARTRIDGE,
1469 pen_type10_xlate = { 'pK' : AGENT_TYPE_PG,
1470 'CMY' : AGENT_TYPE_CMY,
1471 'M' : AGENT_TYPE_MAGENTA,
1472 'C' : AGENT_TYPE_CYAN,
1473 'Y' : AGENT_TYPE_YELLOW,
1474 'K' : AGENT_TYPE_BLACK,
1477 pen_level10_xlate = { 'ok' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
1478 'low' : AGENT_LEVEL_TRIGGER_MAY_BE_LOW,
1479 'out' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
1480 'empty' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
1481 'missing' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
1484 pen_health10_xlate = { 'ok' : AGENT_HEALTH_OK,
1485 'misinstalled' : AGENT_HEALTH_MISINSTALLED,
1486 'missing' : AGENT_HEALTH_MISINSTALLED,
1490 if data[0] is not '<':
1494 index = data.find('\r\n')
1495 size = int(data[0:index+1], 16)
1496 temp = temp + data[index+2:index+2+size]
1497 data = data[index+2+size+2:len(data)]
1501 def StatusType10FetchUrl(func, url, footer=""):
1502 data_fp = cStringIO.StringIO()
1504 #data = dev.getEWSUrl_LEDM(url, data_fp, footer)
1505 data = func(url, data_fp, footer)
1507 #data = dev.getEWSUrl_LEDM(url, data_fp)
1508 data = func(url, data_fp)
1510 data = data.split('\r\n\r\n', 1)[1]
1515 def StatusType10(func): # Low End Data Model
1516 status_block = { 'revision' : STATUS_REV_UNKNOWN,
1518 'top-door' : TOP_DOOR_NOT_PRESENT,
1519 'supply-door' : TOP_DOOR_NOT_PRESENT,
1520 'duplexer' : DUPLEXER_NOT_PRESENT,
1521 'photo-tray' : PHOTO_TRAY_NOT_PRESENT,
1522 'in-tray1' : IN_TRAY_NOT_PRESENT,
1523 'in-tray2' : IN_TRAY_NOT_PRESENT,
1524 'media-path' : MEDIA_PATH_NOT_PRESENT,
1525 'status-code' : STATUS_PRINTER_IDLE,
1528 if not etree_loaded and not elementtree_loaded:
1529 log.error("cannot get status for printer. please load ElementTree module")
1532 # Get the dynamic consumables configuration
1533 data = StatusType10FetchUrl(func, "/DevMgmt/ConsumableConfigDyn.xml")
1536 data = data.replace("ccdyn:", "").replace("dd:", "")
1538 # Parse the agent status XML
1542 tree = ElementTree.XML(data)
1543 if not etree_loaded and elementtree_loaded:
1545 elements = tree.findall("ConsumableInfo")
1547 health = AGENT_HEALTH_OK
1550 type = e.find("ConsumableTypeEnum").text
1551 state = e.find("ConsumableLifeState/ConsumableState").text
1554 if type == "ink" or type == "inkCartridge" or type == "toner" or type == "tonerCartridge":
1555 ink_type = e.find("ConsumableLabelCode").text
1556 if state != "missing":
1558 ink_level = int(e.find("ConsumablePercentageLevelRemaining").text)
1566 log.debug("type '%s' state '%s' ink_type '%s' ink_level %d" % (type, state, ink_type, ink_level))
1568 entry = { 'kind' : element_type10_xlate.get(type, AGENT_KIND_NONE),
1569 'type' : pen_type10_xlate.get(ink_type, AGENT_TYPE_NONE),
1570 'health' : pen_health10_xlate.get(state, AGENT_HEALTH_OK),
1571 'level' : int(ink_level),
1572 'level-trigger' : pen_level10_xlate.get(state, AGENT_LEVEL_TRIGGER_SUFFICIENT_0)
1575 log.debug("%s" % entry)
1576 agents.append(entry)
1577 except AttributeError:
1578 log.debug("no value found for attribute")
1579 except (expat.ExpatError, UnboundLocalError):
1581 status_block['agents'] = agents
1583 # Get the media handling configuration
1584 data = StatusType10FetchUrl(func, "/DevMgmt/MediaHandlingDyn.xml")
1587 data = data.replace("mhdyn:", "").replace("dd:", "")
1589 # Parse the media handling XML
1592 tree = ElementTree.XML(data)
1593 if not etree_loaded and elementtree_loaded:
1595 elements = tree.findall("InputTray")
1596 except (expat.ExpatError, UnboundLocalError):
1599 bin_name = e.find("InputBin").text
1600 if bin_name == "Tray1":
1601 status_block['in-tray1'] = IN_TRAY_PRESENT
1602 elif bin_name == "Tray2":
1603 status_block['in-tray2'] = IN_TRAY_PRESENT
1604 elif bin_name == "PhotoTray":
1605 status_block['photo-tray'] = PHOTO_TRAY_ENGAGED
1607 log.error("found invalid bin name '%s'" % bin_name)
1610 elements = tree.findall("Accessories/MediaHandlingDeviceFunctionType")
1611 except UnboundLocalError:
1614 if e.text == "autoDuplexor":
1615 status_block['duplexer'] = DUPLEXER_DOOR_CLOSED
1617 # Get the product status
1618 data = StatusType10FetchUrl(func, "/DevMgmt/ProductStatusDyn.xml")
1621 data = data.replace("psdyn:", "").replace("locid:", "")
1622 data = data.replace("pscat:", "").replace("dd:", "").replace("ad:", "")
1624 # Parse the product status XML
1627 tree = ElementTree.XML(data)
1628 if not etree_loaded and elementtree_loaded:
1630 elements = tree.findall("Status/StatusCategory")
1631 except (expat.ExpatError, UnboundLocalError):
1634 if e.text == "processing":
1635 status_block['status-code'] = STATUS_PRINTER_PRINTING
1636 if e.text == "closeDoorOrCover":
1637 status_block['status-code'] = STATUS_PRINTER_DOOR_OPEN
1638 elif e.text == "shuttingDown":
1639 status_block['status-code'] = STATUS_PRINTER_TURNING_OFF
1640 elif e.text == "cancelJob":
1641 status_block['status-code'] = STATUS_PRINTER_CANCELING
1642 elif e.text == "trayEmptyOrOpen":
1643 status_block['status-code'] = STATUS_PRINTER_OUT_OF_PAPER
1644 elif e.text == "jamInPrinter":
1645 status_block['status-code'] = STATUS_PRINTER_MEDIA_JAM
1646 elif e.text == "hardError":
1647 status_block['status-code'] = STATUS_PRINTER_HARD_ERROR
1648 elif e.text == "outputBinFull":
1649 status_block['status-code'] = STATUS_PRINTER_OUTPUT_BIN_FULL
1650 elif e.text == "unexpectedSizeInTray" or e.text == "sizeMismatchInTray":
1651 status_block['status-code'] = STATUS_PRINTER_MEDIA_SIZE_MISMATCH
1652 elif e.text == "insertOrCloseTray2":
1653 status_block['status-code'] = STATUS_PRINTER_TRAY_2_MISSING
1654 elif e.text == "scannerError":
1655 status_block['status-code'] = EVENT_SCANNER_FAIL
1656 elif e.text == "scanProcessing":
1657 status_block['status-code'] = EVENT_START_SCAN_JOB
1658 elif e.text == "scannerAdfLoaded":
1659 status_block['status-code'] = EVENT_SCAN_ADF_LOADED
1660 elif e.text == "scanToDestinationNotSet":
1661 status_block['status-code'] = EVENT_SCAN_TO_DESTINATION_NOTSET
1662 elif e.text == "scanWaitingForPC":
1663 status_block['status-code'] = EVENT_SCAN_WAITING_FOR_PC
1664 elif e.text == "scannerAdfJam":
1665 status_block['status-code'] = EVENT_SCAN_ADF_JAM
1666 elif e.text == "scannerAdfDoorOpen":
1667 status_block['status-code'] = EVENT_SCAN_ADF_DOOR_OPEN
1668 elif e.text == "faxProcessing":
1669 status_block['status-code'] = EVENT_START_FAX_JOB
1670 elif e.text == "faxSending":
1671 status_block['status-code'] = STATUS_FAX_TX_ACTIVE
1672 elif e.text == "faxReceiving":
1673 status_block['status-code'] = STATUS_FAX_RX_ACTIVE
1674 elif e.text == "faxDialing":
1675 status_block['status-code'] = EVENT_FAX_DIALING
1676 elif e.text == "faxConnecting":
1677 status_block['status-code'] = EVENT_FAX_CONNECTING
1678 elif e.text == "faxSendError":
1679 status_block['status-code'] = EVENT_FAX_SEND_ERROR
1680 elif e.text == "faxErrorStorageFull":
1681 status_block['status-code'] = EVENT_FAX_ERROR_STORAGE_FULL
1682 elif e.text == "faxReceiveError":
1683 status_block['status-code'] = EVENT_FAX_RECV_ERROR
1684 elif e.text == "faxBlocking":
1685 status_block['status-code'] = EVENT_FAX_BLOCKING
1686 elif e.text == "inPowerSave":
1687 status_block['status-code'] = STATUS_PRINTER_POWER_SAVE
1688 elif e.text == "incorrectCartridge":
1689 status_block['status-code'] = STATUS_PRINTER_CARTRIDGE_WRONG
1690 elif e.text == "cartridgeMissing":
1691 status_block['status-code'] = STATUS_PRINTER_CARTRIDGE_MISSING
1692 elif e.text == "missingPrintHead":
1693 status_block['status-code'] = STATUS_PRINTER_PRINTHEAD_MISSING