1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3# 4# (c) Copyright 2003-2015 HP Development Company, L.P. 5# 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2 of the License, or 9# (at your option) any later version. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License 17# along with this program; if not, write to the Free Software 18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19# 20# Author: Don Welch, Narla Naga Samrat Chowdary, Yashwant Kumar Sahu 21# 22 23 24 25# Std Lib 26import struct 27import io 28from .sixext import BytesIO, to_bytes_utf8, to_bytes_latin, to_string_latin, to_long 29 30from .g import * 31import xml.parsers.expat as expat 32import re 33import cupsext 34 35try: 36 from xml.etree import ElementTree 37 etree_loaded = True 38except ImportError: 39 try: 40 from elementtree.ElementTree import XML 41 elementtree_loaded = True 42 except ImportError: 43 elementtree_loaded = False 44 etree_loaded = False 45 46# Local 47from .g import * 48from .codes import * 49from . import pml, utils 50import hpmudext 51""" 52status dict structure: 53 { 'revision' : STATUS_REV_00 .. STATUS_REV_04, 54 'agents' : [ list of pens/agents/supplies (dicts) ], 55 'top-door' : TOP_DOOR_NOT_PRESENT | TOP_DOOR_CLOSED | TOP_DOOR_OPEN, 56 'status-code' : STATUS_..., 57 'supply-door' : SUPPLY_DOOR_NOT_PRESENT | SUPPLY_DOOR_CLOSED | SUPPLY_DOOR_OPEN. 58 'duplexer' : DUPLEXER_NOT_PRESENT | DUPLEXER_DOOR_CLOSED | DUPLEXER_DOOR_OPEN, 59 'photo_tray' : PHOTO_TRAY_NOT_PRESENT | PHOTO_TRAY_ENGAGED | PHOTO_TRAY_NOT_ENGAGED, 60 'in-tray1' : IN_TRAY_NOT_PRESENT | IN_TRAY_CLOSED | IN_TRAY_OPEN (| IN_TRAY_DEFAULT | IN_TRAY_LOCKED)*, 61 'in-tray2' : IN_TRAY_NOT_PRESENT | IN_TRAY_CLOSED | IN_TRAY_OPEN (| IN_TRAY_DEFAULT | IN_TRAY_LOCKED)*, 62 'media-path' : MEDIA_PATH_NOT_PRESENT | MEDIA_PATH_CUT_SHEET | MEDIA_PATH_BANNER | MEDIA_PATH_PHOTO, 63 } 64 65 * S:02 only 66 67agent dict structure: (pens/supplies/agents/etc) 68 { 'kind' : AGENT_KIND_NONE ... AGENT_KIND_ADF_KIT, 69 'type' : TYPE_BLACK ... AGENT_TYPE_UNSPECIFIED, # aka color 70 'health' : AGENT_HEALTH_OK ... AGENT_HEALTH_UNKNOWN, 71 'level' : 0 ... 100, 72 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0 ... AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT, 73 } 74""" 75 76 77 78# 'revision' 79STATUS_REV_00 = 0x00 80STATUS_REV_01 = 0x01 81STATUS_REV_02 = 0x02 82STATUS_REV_03 = 0x03 83STATUS_REV_04 = 0x04 84STATUS_REV_V = 0xff 85STATUS_REV_UNKNOWN = 0xfe 86 87vstatus_xlate = {'busy' : STATUS_PRINTER_BUSY, 88 'idle' : STATUS_PRINTER_IDLE, 89 'prnt' : STATUS_PRINTER_PRINTING, 90 'offf' : STATUS_PRINTER_TURNING_OFF, 91 'rprt' : STATUS_PRINTER_REPORT_PRINTING, 92 'cncl' : STATUS_PRINTER_CANCELING, 93 'iost' : STATUS_PRINTER_IO_STALL, 94 'dryw' : STATUS_PRINTER_DRY_WAIT_TIME, 95 'penc' : STATUS_PRINTER_PEN_CHANGE, 96 'oopa' : STATUS_PRINTER_OUT_OF_PAPER, 97 'bnej' : STATUS_PRINTER_BANNER_EJECT, 98 'bnmz' : STATUS_PRINTER_BANNER_MISMATCH, 99 'phmz' : STATUS_PRINTER_PHOTO_MISMATCH, 100 'dpmz' : STATUS_PRINTER_DUPLEX_MISMATCH, 101 'pajm' : STATUS_PRINTER_MEDIA_JAM, 102 'cars' : STATUS_PRINTER_CARRIAGE_STALL, 103 'paps' : STATUS_PRINTER_PAPER_STALL, 104 'penf' : STATUS_PRINTER_PEN_FAILURE, 105 'erro' : STATUS_PRINTER_HARD_ERROR, 106 'pwdn' : STATUS_PRINTER_POWER_DOWN, 107 'fpts' : STATUS_PRINTER_FRONT_PANEL_TEST, 108 'clno' : STATUS_PRINTER_CLEAN_OUT_TRAY_MISSING} 109 110REVISION_2_TYPE_MAP = {0 : AGENT_TYPE_NONE, 111 1 : AGENT_TYPE_BLACK, 112 2 : AGENT_TYPE_CYAN, 113 3 : AGENT_TYPE_MAGENTA, 114 4 : AGENT_TYPE_YELLOW, 115 5 : AGENT_TYPE_BLACK, 116 6 : AGENT_TYPE_CYAN, 117 7 : AGENT_TYPE_MAGENTA, 118 8 : AGENT_TYPE_YELLOW, 119 } 120 121STATUS_BLOCK_UNKNOWN = {'revision' : STATUS_REV_UNKNOWN, 122 'agents' : [], 123 'status-code' : STATUS_UNKNOWN, 124 } 125 126NUM_PEN_POS = {STATUS_REV_00 : 16, 127 STATUS_REV_01 : 16, 128 STATUS_REV_02 : 16, 129 STATUS_REV_03 : 18, 130 STATUS_REV_04 : 22} 131 132PEN_DATA_SIZE = {STATUS_REV_00 : 8, 133 STATUS_REV_01 : 8, 134 STATUS_REV_02 : 4, 135 STATUS_REV_03 : 8, 136 STATUS_REV_04 : 8} 137 138STATUS_POS = {STATUS_REV_00 : 14, 139 STATUS_REV_01 : 14, 140 STATUS_REV_02 : 14, 141 STATUS_REV_03 : 16, 142 STATUS_REV_04 : 20} 143 144def parseSStatus(s, z=''): 145 revision = '' 146 pens = [] 147 top_door = TOP_DOOR_NOT_PRESENT 148 stat = STATUS_UNKNOWN 149 supply_door = SUPPLY_DOOR_NOT_PRESENT 150 duplexer = DUPLEXER_NOT_PRESENT 151 photo_tray = PHOTO_TRAY_NOT_PRESENT 152 in_tray1 = IN_TRAY_NOT_PRESENT 153 in_tray2 = IN_TRAY_NOT_PRESENT 154 media_path = MEDIA_PATH_NOT_PRESENT 155 Z_SIZE = 6 156 157 try: 158 z1 = [] 159 if len(z) > 0: 160 z_fields = z.split(',') 161 162 for z_field in z_fields: 163 164 if len(z_field) > 2 and z_field[:2] == '05': 165 z1s = z_field[2:] 166 z1 = [int(x, 16) for x in z1s] 167 168 s1 = [int(x, 16) for x in s] 169 170 revision = s1[1] 171 172 assert STATUS_REV_00 <= revision <= STATUS_REV_04 173 174 top_door = bool(s1[2] & to_long(0x8)) + s1[2] & to_long(0x1) 175 supply_door = bool(s1[3] & to_long(0x8)) + s1[3] & to_long(0x1) 176 duplexer = bool(s1[4] & to_long(0xc)) + s1[4] & to_long(0x1) 177 photo_tray = bool(s1[5] & 0x8) + s1[5] & 0x1 178 179 if revision == STATUS_REV_02: 180 in_tray1 = bool(s1[6] & to_long(0x8)) + s1[6] & to_long(0x1) 181 in_tray2 = bool(s1[7] & to_long(0x8)) + s1[7] & to_long(0x1) 182 else: 183 in_tray1 = bool(s1[6] & to_long(0x8)) 184 in_tray2 = bool(s1[7] & to_long(0x8)) 185 186 media_path = bool(s1[8] & to_long(0x8)) + (s1[8] & to_long(0x1)) + ((bool(s1[18] & to_long(0x2)))<<1) 187 status_pos = STATUS_POS[revision] 188 status_byte = s1[status_pos]<<4 189 if status_byte != 48: 190 status_byte = (s1[status_pos]<<4) + s1[status_pos + 1] 191 stat = status_byte + STATUS_PRINTER_BASE 192 193 pen, c, d = {}, NUM_PEN_POS[revision]+1, 0 194 num_pens = s1[NUM_PEN_POS[revision]] 195 index = 0 196 pen_data_size = PEN_DATA_SIZE[revision] 197 198 log.debug("num_pens = %d" % num_pens) 199 for p in range(num_pens): 200 info = int(s[c : c + pen_data_size], 16) 201 202 pen['index'] = index 203 204 if pen_data_size == 4: 205 pen['type'] = REVISION_2_TYPE_MAP.get(int((info & to_long(0xf000)) >> to_long(12)), 0) 206 207 if index < (num_pens / 2): 208 pen['kind'] = AGENT_KIND_HEAD 209 else: 210 pen['kind'] = AGENT_KIND_SUPPLY 211 212 pen['level-trigger'] = int ((info & to_long(0x0e00)) >> to_long(9)) 213 pen['health'] = int((info & to_long(0x0180)) >> to_long(7)) 214 pen['level'] = int(info & to_long(0x007f)) 215 pen['id'] = 0x1f 216 217 elif pen_data_size == 8: 218 pen['kind'] = bool(info & to_long(0x80000000)) + ((bool(info & to_long(0x40000000)))<<to_long(1)) 219 pen['type'] = int((info & to_long(0x3f000000)) >> to_long(24)) 220 pen['id'] = int((info & 0xf80000) >> to_long(19)) 221 pen['level-trigger'] = int((info & to_long(0x70000)) >> to_long(16)) 222 pen['health'] = int((info & to_long(0xc000)) >> to_long(14)) 223 pen['level'] = int(info & to_long(0xff)) 224 225 else: 226 log.error("Pen data size error") 227 228 if len(z1) > 0: 229 # TODO: Determine cause of IndexError for C6100 (defect #1111) 230 try: 231 pen['dvc'] = int(z1s[d+1:d+5], 16) 232 pen['virgin'] = bool(z1[d+5] & to_long(0x8)) 233 pen['hp-ink'] = bool(z1[d+5] & to_long(0x4)) 234 pen['known'] = bool(z1[d+5] & to_long(0x2)) 235 pen['ack'] = bool(z1[d+5] & to_long(0x1)) 236 except IndexError: 237 pen['dvc'] = 0 238 pen['virgin'] = 0 239 pen['hp-ink'] = 0 240 pen['known'] = 0 241 pen['ack'] = 0 242 243 log.debug("pen %d %s" % (index, pen)) 244 245 index += 1 246 pens.append(pen) 247 pen = {} 248 c += pen_data_size 249 d += Z_SIZE 250 251 except (IndexError, ValueError, TypeError) as e: 252 log.warn("Status parsing error: %s" % str(e)) 253 254 return {'revision' : revision, 255 'agents' : pens, 256 'top-door' : top_door, 257 'status-code' : stat, 258 'supply-door' : supply_door, 259 'duplexer' : duplexer, 260 'photo-tray' : photo_tray, 261 'in-tray1' : in_tray1, 262 'in-tray2' : in_tray2, 263 'media-path' : media_path, 264 } 265 266 267 268# $HB0$NC0,ff,DN,IDLE,CUT,K0,C0,DP,NR,KP092,CP041 269# 0 1 2 3 4 5 6 7 8 9 10 270def parseVStatus(s): 271 pens, pen, c = [], {}, 0 272 fields = s.split(',') 273 log.debug(fields) 274 f0 = fields[0] 275 276 if len(f0) == 20: 277 # TODO: $H00000000$M00000000 style (OJ Pro 1150/70) 278 # Need spec 279 pass 280 elif len(f0) == 8: 281 for p in f0: 282 if c == 0: 283 #assert p == '$' 284 c += 1 285 elif c == 1: 286 if p in ('a', 'A'): 287 pen['type'], pen['kind'] = AGENT_TYPE_NONE, AGENT_KIND_NONE 288 c += 1 289 elif c == 2: 290 pen['health'] = AGENT_HEALTH_OK 291 pen['kind'] = AGENT_KIND_HEAD_AND_SUPPLY 292 if p in ('b', 'B'): pen['type'] = AGENT_TYPE_BLACK 293 elif p in ('c', 'C'): pen['type'] = AGENT_TYPE_CMY 294 elif p in ('d', 'D'): pen['type'] = AGENT_TYPE_KCM 295 elif p in ('u', 'U'): pen['type'], pen['health'] = AGENT_TYPE_NONE, AGENT_HEALTH_MISINSTALLED 296 c += 1 297 elif c == 3: 298 if p == '0': pen['state'] = 1 299 else: pen['state'] = 0 300 301 pen['level'] = 0 302 i = 8 303 304 while True: 305 try: 306 f = fields[i] 307 except IndexError: 308 break 309 else: 310 if f[:2] == 'KP' and pen['type'] == AGENT_TYPE_BLACK: 311 pen['level'] = int(f[2:]) 312 elif f[:2] == 'CP' and pen['type'] == AGENT_TYPE_CMY: 313 pen['level'] = int(f[2:]) 314 i += 1 315 316 pens.append(pen) 317 pen = {} 318 c = 0 319 else: 320 pass 321 322 try: 323 fields[2] 324 except IndexError: 325 top_lid = 1 # something went wrong! 326 else: 327 if fields[2] == 'DN': 328 top_lid = 1 329 else: 330 top_lid = 2 331 332 try: 333 stat = vstatus_xlate.get(fields[3].lower(), STATUS_PRINTER_IDLE) 334 except IndexError: 335 stat = STATUS_PRINTER_IDLE # something went wrong! 336 337 return {'revision' : STATUS_REV_V, 338 'agents' : pens, 339 'top-door' : top_lid, 340 'status-code': stat, 341 'supply-door': SUPPLY_DOOR_NOT_PRESENT, 342 'duplexer' : DUPLEXER_NOT_PRESENT, 343 'photo-tray' : PHOTO_TRAY_NOT_PRESENT, 344 'in-tray1' : IN_TRAY_NOT_PRESENT, 345 'in-tray2' : IN_TRAY_NOT_PRESENT, 346 'media-path' : MEDIA_PATH_CUT_SHEET, # ? 347 } 348 349 350def parseStatus(DeviceID): 351 if 'VSTATUS' in DeviceID: 352 return parseVStatus(DeviceID['VSTATUS']) 353 elif 'S' in DeviceID: 354 return parseSStatus(DeviceID['S'], DeviceID.get('Z', '')) 355 else: 356 return STATUS_BLOCK_UNKNOWN 357 358def LaserJetDeviceStatusToPrinterStatus(device_status, printer_status, detected_error_state): 359 stat = STATUS_PRINTER_IDLE 360 361 if device_status in (pml.DEVICE_STATUS_WARNING, pml.DEVICE_STATUS_DOWN): 362 363 if detected_error_state & pml.DETECTED_ERROR_STATE_LOW_PAPER_MASK and \ 364 not (detected_error_state & pml.DETECTED_ERROR_STATE_NO_PAPER_MASK): 365 stat = STATUS_PRINTER_LOW_PAPER 366 367 elif detected_error_state & pml.DETECTED_ERROR_STATE_NO_PAPER_MASK: 368 stat = STATUS_PRINTER_OUT_OF_PAPER 369 370 elif detected_error_state & pml.DETECTED_ERROR_STATE_DOOR_OPEN_MASK: 371 stat = STATUS_PRINTER_DOOR_OPEN 372 373 elif detected_error_state & pml.DETECTED_ERROR_STATE_JAMMED_MASK: 374 stat = STATUS_PRINTER_MEDIA_JAM 375 376 elif detected_error_state & pml.DETECTED_ERROR_STATE_OUT_CART_MASK: 377 stat = STATUS_PRINTER_NO_TONER 378 379 elif detected_error_state & pml.DETECTED_ERROR_STATE_LOW_CART_MASK: 380 stat = STATUS_PRINTER_LOW_TONER 381 382 elif detected_error_state == pml.DETECTED_ERROR_STATE_SERVICE_REQUEST_MASK: 383 stat = STATUS_PRINTER_SERVICE_REQUEST 384 385 elif detected_error_state & pml.DETECTED_ERROR_STATE_OFFLINE_MASK: 386 stat = STATUS_PRINTER_OFFLINE 387 388 else: 389 390 if printer_status == pml.PRINTER_STATUS_IDLE: 391 stat = STATUS_PRINTER_IDLE 392 393 elif printer_status == pml.PRINTER_STATUS_PRINTING: 394 stat = STATUS_PRINTER_PRINTING 395 396 elif printer_status == pml.PRINTER_STATUS_WARMUP: 397 stat = STATUS_PRINTER_WARMING_UP 398 399 return stat 400 401# Map from ISO 10175/10180 to HPLIP types 402COLORANT_INDEX_TO_AGENT_TYPE_MAP = { 403 'other' : AGENT_TYPE_UNSPECIFIED, 404 'unknown' : AGENT_TYPE_UNSPECIFIED, 405 'blue' : AGENT_TYPE_BLUE, 406 'cyan' : AGENT_TYPE_CYAN, 407 'magenta': AGENT_TYPE_MAGENTA, 408 'yellow' : AGENT_TYPE_YELLOW, 409 'black' : AGENT_TYPE_BLACK, 410 'photoblack': AGENT_TYPE_PHOTO_BLACK, 411 'matteblack' : AGENT_TYPE_MATTE_BLACK, 412 'lightgray' : AGENT_TYPE_LG, 413 'gray': AGENT_TYPE_G, 414 'darkgray': AGENT_TYPE_DG, 415 'lightcyan': AGENT_TYPE_LC, 416 'lightmagenta': AGENT_TYPE_LM, 417 'red' : AGENT_TYPE_RED, 418 } 419 420MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP = { 421 pml.OID_MARKER_SUPPLIES_TYPE_OTHER : AGENT_KIND_UNKNOWN, 422 pml.OID_MARKER_SUPPLIES_TYPE_UNKNOWN : AGENT_KIND_UNKNOWN, 423 pml.OID_MARKER_SUPPLIES_TYPE_TONER : AGENT_KIND_TONER_CARTRIDGE, 424 pml.OID_MARKER_SUPPLIES_TYPE_WASTE_TONER : AGENT_KIND_UNKNOWN, 425 pml.OID_MARKER_SUPPLIES_TYPE_INK : AGENT_KIND_SUPPLY, 426 pml.OID_MARKER_SUPPLIES_TYPE_INK_CART : AGENT_KIND_HEAD_AND_SUPPLY, 427 pml.OID_MARKER_SUPPLIES_TYPE_INK_RIBBON : AGENT_KIND_HEAD_AND_SUPPLY, 428 pml.OID_MARKER_SUPPLIES_TYPE_WASTE_INK : AGENT_KIND_UNKNOWN, 429 pml.OID_MARKER_SUPPLIES_TYPE_OPC : AGENT_KIND_DRUM_KIT, 430 pml.OID_MARKER_SUPPLIES_TYPE_DEVELOPER : AGENT_KIND_UNKNOWN, 431 pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OIL : AGENT_KIND_UNKNOWN, 432 pml.OID_MARKER_SUPPLIES_TYPE_SOLID_WAX : AGENT_KIND_UNKNOWN, 433 pml.OID_MARKER_SUPPLIES_TYPE_RIBBON_WAX : AGENT_KIND_UNKNOWN, 434 pml.OID_MARKER_SUPPLIES_TYPE_WASTE_WAX : AGENT_KIND_UNKNOWN, 435 pml.OID_MARKER_SUPPLIES_TYPE_FUSER : AGENT_KIND_MAINT_KIT, 436 pml.OID_MARKER_SUPPLIES_TYPE_CORONA_WIRE : AGENT_KIND_UNKNOWN, 437 pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OIL_WICK : AGENT_KIND_UNKNOWN, 438 pml.OID_MARKER_SUPPLIES_TYPE_CLEANER_UNIT : AGENT_KIND_UNKNOWN, 439 pml.OID_MARKER_SUPPLIES_TYPE_FUSER_CLEANING_PAD : AGENT_KIND_UNKNOWN, 440 pml.OID_MARKER_SUPPLIES_TYPE_TRANSFER_UNIT : AGENT_KIND_TRANSFER_KIT, 441 pml.OID_MARKER_SUPPLIES_TYPE_TONER_CART : AGENT_KIND_TONER_CARTRIDGE, 442 pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OILER : AGENT_KIND_UNKNOWN, 443 pml.OID_MARKER_SUPPLIES_TYPE_ADF_MAINT_KIT : AGENT_KIND_ADF_KIT, 444} 445 446 447def StatusType3( dev, parsedID ): # LaserJet Status (PML/SNMP) 448 try: 449 dev.openPML() 450 #result_code, on_off_line = dev.getPML( pml.OID_ON_OFF_LINE, pml.INT_SIZE_BYTE ) 451 #result_code, sleep_mode = dev.getPML( pml.OID_SLEEP_MODE, pml.INT_SIZE_BYTE ) 452 result_code, printer_status = dev.getPML( pml.OID_PRINTER_STATUS, pml.INT_SIZE_BYTE ) 453 result_code, device_status = dev.getPML( pml.OID_DEVICE_STATUS, pml.INT_SIZE_BYTE ) 454 result_code, cover_status = dev.getPML( pml.OID_COVER_STATUS, pml.INT_SIZE_BYTE ) 455 result_code, value = dev.getPML( pml.OID_DETECTED_ERROR_STATE ) 456 except Error: 457 dev.closePML() 458 459 return {'revision' : STATUS_REV_UNKNOWN, 460 'agents' : [], 461 'top-door' : 0, 462 'status-code' : STATUS_UNKNOWN, 463 'supply-door' : 0, 464 'duplexer' : 1, 465 'photo-tray' : 0, 466 'in-tray1' : 0, 467 'in-tray2' : 0, 468 'media-path' : 0, 469 } 470 471 try: 472 detected_error_state = struct.unpack( 'B', to_bytes_latin(value[0]))[0] 473 except (IndexError, TypeError): 474 detected_error_state = pml.DETECTED_ERROR_STATE_OFFLINE_MASK 475 476 agents, x = [], 1 477 478 while True: 479 log.debug( "%s Agent: %d %s" % ("*"*10, x, "*"*10)) 480 log.debug("OID_MARKER_SUPPLIES_TYPE_%d:" % x) 481 oid = ( pml.OID_MARKER_SUPPLIES_TYPE_x % x, pml.OID_MARKER_SUPPLIES_TYPE_x_TYPE ) 482 result_code, value = dev.getPML( oid, pml.INT_SIZE_BYTE ) 483 484 if result_code != ERROR_SUCCESS or value is None: 485 log.debug("End of supply information.") 486 break 487 488 for a in MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP: 489 if value == a: 490 agent_kind = MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP[a] 491 break 492 else: 493 agent_kind = AGENT_KIND_UNKNOWN 494 495 # TODO: Deal with printers that return -1 and -2 for level and max (LJ3380) 496 497 log.debug("OID_MARKER_SUPPLIES_LEVEL_%d:" % x) 498 oid = ( pml.OID_MARKER_SUPPLIES_LEVEL_x % x, pml.OID_MARKER_SUPPLIES_LEVEL_x_TYPE ) 499 result_code, agent_level = dev.getPML( oid ) 500 501 if result_code != ERROR_SUCCESS: 502 log.debug("Failed") 503 break 504 505 log.debug( 'agent%d-level: %d' % ( x, agent_level ) ) 506 log.debug("OID_MARKER_SUPPLIES_MAX_%d:" % x) 507 oid = ( pml.OID_MARKER_SUPPLIES_MAX_x % x, pml.OID_MARKER_SUPPLIES_MAX_x_TYPE ) 508 result_code, agent_max = dev.getPML( oid ) 509 510 if agent_max == 0: agent_max = 1 511 512 if result_code != ERROR_SUCCESS: 513 log.debug("Failed") 514 break 515 516 log.debug( 'agent%d-max: %d' % ( x, agent_max ) ) 517 log.debug("OID_MARKER_SUPPLIES_COLORANT_INDEX_%d:" % x) 518 oid = ( pml.OID_MARKER_SUPPLIES_COLORANT_INDEX_x % x, pml.OID_MARKER_SUPPLIES_COLORANT_INDEX_x_TYPE ) 519 result_code, colorant_index = dev.getPML( oid ) 520 521 if result_code != ERROR_SUCCESS: # 3080, 3055 will fail here 522 log.debug("Failed") 523 agent_type = AGENT_TYPE_BLACK 524 #break 525 else: 526 log.debug("Colorant index: %d" % colorant_index) 527 528 log.debug("OID_MARKER_COLORANT_VALUE_%d" % x) 529 oid = ( pml.OID_MARKER_COLORANT_VALUE_x % colorant_index, pml.OID_MARKER_COLORANT_VALUE_x_TYPE ) 530 result_code, colorant_value = dev.getPML( oid ) 531 532 if result_code != ERROR_SUCCESS: 533 log.debug("Failed. Defaulting to black.") 534 agent_type = AGENT_TYPE_BLACK 535 #else: 536 if 1: 537 if agent_kind in (AGENT_KIND_MAINT_KIT, AGENT_KIND_ADF_KIT, 538 AGENT_KIND_DRUM_KIT, AGENT_KIND_TRANSFER_KIT): 539 540 agent_type = AGENT_TYPE_UNSPECIFIED 541 542 else: 543 agent_type = AGENT_TYPE_BLACK 544 545 if result_code != ERROR_SUCCESS: 546 log.debug("OID_MARKER_SUPPLIES_DESCRIPTION_%d:" % x) 547 oid = (pml.OID_MARKER_SUPPLIES_DESCRIPTION_x % x, pml.OID_MARKER_SUPPLIES_DESCRIPTION_x_TYPE) 548 result_code, colorant_value = dev.getPML( oid ) 549 550 if result_code != ERROR_SUCCESS: 551 log.debug("Failed") 552 break 553 554 if colorant_value is not None: 555 log.debug("colorant value: %s" % colorant_value) 556 colorant_value = colorant_value.lower().strip() 557 558 for c in COLORANT_INDEX_TO_AGENT_TYPE_MAP: 559 if colorant_value.find(c) >= 0: 560 agent_type = COLORANT_INDEX_TO_AGENT_TYPE_MAP[c] 561 break 562 else: 563 agent_type = AGENT_TYPE_BLACK 564 565 else: # SUCCESS 566 if colorant_value is not None: 567 log.debug("colorant value: %s" % colorant_value) 568 colorant_value = colorant_value.lower().strip() 569 agent_type = COLORANT_INDEX_TO_AGENT_TYPE_MAP.get( colorant_value, AGENT_TYPE_BLACK ) 570 571 if agent_type == AGENT_TYPE_NONE: 572 if agent_kind == AGENT_KIND_TONER_CARTRIDGE: 573 agent_type = AGENT_TYPE_BLACK 574 else: 575 agent_type = AGENT_TYPE_UNSPECIFIED 576 577 log.debug("OID_MARKER_STATUS_%d:" % x) 578 oid = ( pml.OID_MARKER_STATUS_x % x, pml.OID_MARKER_STATUS_x_TYPE ) 579 result_code, agent_status = dev.getPML( oid ) 580 581 if result_code != ERROR_SUCCESS: 582 log.debug("Failed") 583 agent_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0 584 agent_health = AGENT_HEALTH_OK 585 else: 586 agent_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0 587 588 if agent_status is None: 589 agent_health = AGENT_HEALTH_OK 590 591 elif agent_status == pml.OID_MARKER_STATUS_OK: 592 agent_health = AGENT_HEALTH_OK 593 594 elif agent_status == pml.OID_MARKER_STATUS_MISINSTALLED: 595 agent_health = AGENT_HEALTH_MISINSTALLED 596 597 elif agent_status in ( pml.OID_MARKER_STATUS_LOW_TONER_CONT, 598 pml.OID_MARKER_STATUS_LOW_TONER_STOP ): 599 600 agent_health = AGENT_HEALTH_OK 601 agent_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW 602 603 else: 604 agent_health = AGENT_HEALTH_OK 605 606 agent_level = int(float(agent_level)/agent_max * 100) 607 608 609 log.debug("agent%d: kind=%d, type=%d, health=%d, level=%d, level-trigger=%d" % \ 610 (x, agent_kind, agent_type, agent_health, agent_level, agent_trigger)) 611 612 613 agents.append({'kind' : agent_kind, 614 'type' : agent_type, 615 'health' : agent_health, 616 'level' : agent_level, 617 'level-trigger' : agent_trigger,}) 618 619 x += 1 620 621 if x > 20: 622 break 623 624 625 printer_status = printer_status or STATUS_PRINTER_IDLE 626 log.debug("printer_status=%d" % printer_status) 627 device_status = device_status or pml.DEVICE_STATUS_RUNNING 628 log.debug("device_status=%d" % device_status) 629 cover_status = cover_status or pml.COVER_STATUS_CLOSED 630 log.debug("cover_status=%d" % cover_status) 631 detected_error_state = detected_error_state or pml.DETECTED_ERROR_STATE_NO_ERROR 632 log.debug("detected_error_state=%d (0x%x)" % (detected_error_state, detected_error_state)) 633 634 stat = LaserJetDeviceStatusToPrinterStatus(device_status, printer_status, detected_error_state) 635 636 log.debug("Printer status=%d" % stat) 637 638 if stat == STATUS_PRINTER_DOOR_OPEN: 639 supply_door = 0 640 else: 641 supply_door = 1 642 643 return {'revision' : STATUS_REV_UNKNOWN, 644 'agents' : agents, 645 'top-door' : cover_status, 646 'status-code' : stat, 647 'supply-door' : supply_door, 648 'duplexer' : 1, 649 'photo-tray' : 0, 650 'in-tray1' : 1, 651 'in-tray2' : 1, 652 'media-path' : 1, 653 } 654 655def setup_panel_translator(): 656 printables = list( 657"""0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 658!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~""") 659 660 map = {} 661 for x in [chr(x) for x in range(0,256)]: 662 if x in printables: 663 map[x] = x 664 else: 665 map[x] = '\x20' 666 667 map.update({'\x10' : '\xab', 668 '\x11' : '\xbb', 669 '\x12' : '\xa3', 670 '\x13' : '\xbb', 671 '\x80' : '\xab', 672 '\x81' : '\xbb', 673 '\x82' : '\x2a', 674 '\x83' : '\x2a', 675 '\x85' : '\x2a', 676 '\xa0' : '\xab', 677 '\x1f' : '\x3f', 678 '=' : '\x20', 679 }) 680 681 frm, to = to_bytes_latin(''), to_bytes_latin('') 682 map_keys = list(map.keys()) 683 map_keys.sort() 684 for x in map_keys: 685 frm = to_bytes_latin('').join([frm, to_bytes_latin(x)]) 686 to = to_bytes_latin('').join([to, to_bytes_latin(map[x])]) 687 688 global PANEL_TRANSLATOR_FUNC 689 PANEL_TRANSLATOR_FUNC = utils.Translator(frm, to) 690 691PANEL_TRANSLATOR_FUNC = None 692setup_panel_translator() 693 694 695def PanelCheck(dev): 696 line1, line2 = to_bytes_utf8(''), ('') 697 698 if dev.io_mode not in (IO_MODE_RAW, IO_MODE_UNI): 699 700 try: 701 dev.openPML() 702 except Error: 703 pass 704 else: 705 706 oids = [(pml.OID_HP_LINE1, pml.OID_HP_LINE2), 707 (pml.OID_SPM_LINE1, pml.OID_SPM_LINE2)] 708 709 for oid1, oid2 in oids: 710 result, line1 = dev.getPML(oid1) 711 712 if result < pml.ERROR_MAX_OK: 713 line1 = PANEL_TRANSLATOR_FUNC(line1.encode('utf-8')).rstrip() 714 715 if to_bytes_utf8('\x0a') in line1: 716 line1, line2 = line1.split(to_bytes_utf8('\x0a'), 1) 717 break 718 719 result, line2 = dev.getPML(oid2) 720 721 if result < pml.ERROR_MAX_OK: 722 line2 = PANEL_TRANSLATOR_FUNC(line2.encode('utf-8')).rstrip() 723 break 724 725 return bool(line1 or line2), line1 or to_bytes_utf8(''), line2 or to_bytes_utf8('') 726 727 728BATTERY_HEALTH_MAP = {0 : AGENT_HEALTH_OK, 729 1 : AGENT_HEALTH_OVERTEMP, 730 2 : AGENT_HEALTH_CHARGING, 731 3 : AGENT_HEALTH_MISINSTALLED, 732 4 : AGENT_HEALTH_FAILED, 733 } 734 735 736BATTERY_TRIGGER_MAP = {0 : AGENT_LEVEL_TRIGGER_SUFFICIENT_0, 737 1 : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT, 738 2 : AGENT_LEVEL_TRIGGER_PROBABLY_OUT, 739 3 : AGENT_LEVEL_TRIGGER_SUFFICIENT_4, 740 4 : AGENT_LEVEL_TRIGGER_SUFFICIENT_2, 741 5 : AGENT_LEVEL_TRIGGER_SUFFICIENT_0, 742 } 743 744BATTERY_PML_TRIGGER_MAP = { 745 (100, 80) : AGENT_LEVEL_TRIGGER_SUFFICIENT_0, 746 (79, 60) : AGENT_LEVEL_TRIGGER_SUFFICIENT_1, 747 (59, 40) : AGENT_LEVEL_TRIGGER_SUFFICIENT_2, 748 (39, 30) : AGENT_LEVEL_TRIGGER_SUFFICIENT_3, 749 (29, 20) : AGENT_LEVEL_TRIGGER_SUFFICIENT_4, 750 (19, 10) : AGENT_LEVEL_TRIGGER_MAY_BE_LOW, 751 (9, 5) : AGENT_LEVEL_TRIGGER_PROBABLY_OUT, 752 (4, -1) : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT, 753 } 754 755 756def BatteryCheck(dev, status_block, battery_check): 757 try_dynamic_counters = False 758 759 try: 760 try: 761 dev.openPML() 762 except Error: 763 if battery_check == STATUS_BATTERY_CHECK_STD: 764 log.debug("PML channel open failed. Trying dynamic counters...") 765 try_dynamic_counters = True 766 else: 767 if battery_check == STATUS_BATTERY_CHECK_PML: 768 result, battery_level = dev.getPML(pml.OID_BATTERY_LEVEL_2) 769 770 if result > pml.ERROR_MAX_OK: 771 status_block['agents'].append({ 772 'kind' : AGENT_KIND_INT_BATTERY, 773 'type' : AGENT_TYPE_UNSPECIFIED, 774 'health' : AGENT_HEALTH_UNKNOWN, 775 'level' : 0, 776 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0, 777 }) 778 return 779 780 else: 781 status_block['agents'].append({ 782 'kind' : AGENT_KIND_INT_BATTERY, 783 'type' : AGENT_TYPE_UNSPECIFIED, 784 'health' : AGENT_HEALTH_OK, 785 'level' : battery_level, 786 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0, 787 }) 788 return 789 790 else: # STATUS_BATTERY_CHECK_STD 791 result, battery_level = dev.getPML(pml.OID_BATTERY_LEVEL) 792 result, power_mode = dev.getPML(pml.OID_POWER_MODE) 793 794 if battery_level is not None and \ 795 power_mode is not None: 796 797 if power_mode & pml.POWER_MODE_BATTERY_LEVEL_KNOWN and \ 798 battery_level >= 0: 799 800 for x in BATTERY_PML_TRIGGER_MAP: 801 if x[0] >= battery_level > x[1]: 802 battery_trigger_level = BATTERY_PML_TRIGGER_MAP[x] 803 break 804 805 if power_mode & pml.POWER_MODE_CHARGING: 806 agent_health = AGENT_HEALTH_CHARGING 807 808 elif power_mode & pml.POWER_MODE_DISCHARGING: 809 agent_health = AGENT_HEALTH_DISCHARGING 810 811 else: 812 agent_health = AGENT_HEALTH_OK 813 814 status_block['agents'].append({ 815 'kind' : AGENT_KIND_INT_BATTERY, 816 'type' : AGENT_TYPE_UNSPECIFIED, 817 'health' : agent_health, 818 'level' : battery_level, 819 'level-trigger' : battery_trigger_level, 820 }) 821 return 822 823 else: 824 status_block['agents'].append({ 825 'kind' : AGENT_KIND_INT_BATTERY, 826 'type' : AGENT_TYPE_UNSPECIFIED, 827 'health' : AGENT_HEALTH_UNKNOWN, 828 'level' : 0, 829 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0, 830 }) 831 return 832 833 else: 834 try_dynamic_counters = True 835 836 finally: 837 dev.closePML() 838 839 840 if battery_check == STATUS_BATTERY_CHECK_STD and \ 841 try_dynamic_counters: 842 843 try: 844 try: 845 battery_health = dev.getDynamicCounter(200) 846 battery_trigger_level = dev.getDynamicCounter(201) 847 battery_level = dev.getDynamicCounter(202) 848 849 status_block['agents'].append({ 850 'kind' : AGENT_KIND_INT_BATTERY, 851 'type' : AGENT_TYPE_UNSPECIFIED, 852 'health' : BATTERY_HEALTH_MAP[battery_health], 853 'level' : battery_level, 854 'level-trigger' : BATTERY_TRIGGER_MAP[battery_trigger_level], 855 }) 856 except Error: 857 status_block['agents'].append({ 858 'kind' : AGENT_KIND_INT_BATTERY, 859 'type' : AGENT_TYPE_UNSPECIFIED, 860 'health' : AGENT_HEALTH_UNKNOWN, 861 'level' : 0, 862 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0, 863 }) 864 finally: 865 dev.closePrint() 866 867 else: 868 status_block['agents'].append({ 869 'kind' : AGENT_KIND_INT_BATTERY, 870 'type' : AGENT_TYPE_UNSPECIFIED, 871 'health' : AGENT_HEALTH_UNKNOWN, 872 'level' : 0, 873 'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0, 874 }) 875 876 877 878# this works for 2 pen products that allow 1 or 2 pens inserted 879# from: k, kcm, cmy, ggk 880def getPenConfiguration(s): # s=status dict from parsed device ID 881 pens = [p['type'] for p in s['agents']] 882 883 if utils.all(pens, lambda x : x==AGENT_TYPE_NONE): 884 return AGENT_CONFIG_NONE 885 886 if AGENT_TYPE_NONE in pens: 887 888 if AGENT_TYPE_BLACK in pens: 889 return AGENT_CONFIG_BLACK_ONLY 890 891 elif AGENT_TYPE_CMY in pens: 892 return AGENT_CONFIG_COLOR_ONLY 893 894 elif AGENT_TYPE_KCM in pens: 895 return AGENT_CONFIG_PHOTO_ONLY 896 897 elif AGENT_TYPE_GGK in pens: 898 return AGENT_CONFIG_GREY_ONLY 899 900 else: 901 return AGENT_CONFIG_INVALID 902 903 else: 904 if AGENT_TYPE_BLACK in pens and AGENT_TYPE_CMY in pens: 905 return AGENT_CONFIG_COLOR_AND_BLACK 906 907 elif AGENT_TYPE_CMY in pens and AGENT_TYPE_KCM in pens: 908 return AGENT_CONFIG_COLOR_AND_PHOTO 909 910 elif AGENT_TYPE_CMY in pens and AGENT_TYPE_GGK in pens: 911 return AGENT_CONFIG_COLOR_AND_GREY 912 913 else: 914 return AGENT_CONFIG_INVALID 915 916 917def getFaxStatus(dev): 918 tx_active, rx_active = False, False 919 920 if dev.io_mode not in (IO_MODE_UNI, IO_MODE_RAW): 921 try: 922 dev.openPML() 923 924 result_code, tx_state = dev.getPML(pml.OID_FAXJOB_TX_STATUS) 925 926 if result_code == ERROR_SUCCESS and tx_state: 927 if tx_state not in (pml.FAXJOB_TX_STATUS_IDLE, pml.FAXJOB_TX_STATUS_DONE): 928 tx_active = True 929 930 result_code, rx_state = dev.getPML(pml.OID_FAXJOB_RX_STATUS) 931 932 if result_code == ERROR_SUCCESS and rx_state: 933 if rx_state not in (pml.FAXJOB_RX_STATUS_IDLE, pml.FAXJOB_RX_STATUS_DONE): 934 rx_active = True 935 936 finally: 937 dev.closePML() 938 939 return tx_active, rx_active 940 941 942TYPE6_STATUS_CODE_MAP = { 943 0 : STATUS_PRINTER_IDLE, #</DevStatusUnknown> 944 -19928: STATUS_PRINTER_IDLE, 945 -18995: STATUS_PRINTER_CANCELING, 946 -17974: STATUS_PRINTER_WARMING_UP, 947 -17973: STATUS_PRINTER_PEN_CLEANING, # sic 948 -18993: STATUS_PRINTER_BUSY, 949 -17949: STATUS_PRINTER_BUSY, 950 -19720: STATUS_PRINTER_MANUAL_DUPLEX_BLOCK, 951 -19678: STATUS_PRINTER_BUSY, 952 -19695: STATUS_PRINTER_OUT_OF_PAPER, 953 -17985: STATUS_PRINTER_MEDIA_JAM, 954 -19731: STATUS_PRINTER_OUT_OF_PAPER, 955 -18974: STATUS_PRINTER_BUSY, #? 956 -19730: STATUS_PRINTER_OUT_OF_PAPER, 957 -19729: STATUS_PRINTER_OUT_OF_PAPER, 958 -19933: STATUS_PRINTER_HARD_ERROR, # out of memory 959 -17984: STATUS_PRINTER_DOOR_OPEN, 960 -19694: STATUS_PRINTER_DOOR_OPEN, 961 -18992: STATUS_PRINTER_MANUAL_FEED_BLOCKED, # ? 962 -19690: STATUS_PRINTER_MEDIA_JAM, # tray 1 963 -19689: STATUS_PRINTER_MEDIA_JAM, # tray 2 964 -19611: STATUS_PRINTER_MEDIA_JAM, # tray 3 965 -19686: STATUS_PRINTER_MEDIA_JAM, 966 -19688: STATUS_PRINTER_MEDIA_JAM, # paper path 967 -19685: STATUS_PRINTER_MEDIA_JAM, # cart area 968 -19684: STATUS_PRINTER_MEDIA_JAM, # output bin 969 -18848: STATUS_PRINTER_MEDIA_JAM, # duplexer 970 -18847: STATUS_PRINTER_MEDIA_JAM, # door open 971 -18846: STATUS_PRINTER_MEDIA_JAM, # tray 2 972 -19687: STATUS_PRINTER_MEDIA_JAM, # open door 973 -17992: STATUS_PRINTER_MEDIA_JAM, # mispick 974 -19700: STATUS_PRINTER_HARD_ERROR, # invalid driver 975 -17996: STATUS_PRINTER_FUSER_ERROR, # fuser error 976 -17983: STATUS_PRINTER_FUSER_ERROR, 977 -17982: STATUS_PRINTER_FUSER_ERROR, 978 -17981: STATUS_PRINTER_FUSER_ERROR, 979 -17971: STATUS_PRINTER_FUSER_ERROR, 980 -17995: STATUS_PRINTER_HARD_ERROR, # beam error 981 -17994: STATUS_PRINTER_HARD_ERROR, # scanner error 982 -17993: STATUS_PRINTER_HARD_ERROR, # fan error 983 -18994: STATUS_PRINTER_HARD_ERROR, 984 -17986: STATUS_PRINTER_HARD_ERROR, 985 -19904: STATUS_PRINTER_HARD_ERROR, 986 -19701: STATUS_PRINTER_NON_HP_INK, # [sic] 987 -19613: STATUS_PRINTER_IDLE, # HP 988 -19654: STATUS_PRINTER_NON_HP_INK, # [sic] 989 -19682: STATUS_PRINTER_HARD_ERROR, # resinstall 990 -19693: STATUS_PRINTER_IDLE, # ?? To Accept 991 -19752: STATUS_PRINTER_LOW_TONER, 992 -19723: STATUS_PRINTER_BUSY, 993 -19703: STATUS_PRINTER_BUSY, 994 -19739: STATUS_PRINTER_NO_TONER, 995 -19927: STATUS_PRINTER_BUSY, 996 -19932: STATUS_PRINTER_BUSY, 997 -19931: STATUS_PRINTER_BUSY, 998 -11989: STATUS_PRINTER_BUSY, 999 -11995: STATUS_PRINTER_BUSY, # ADF loaded 1000 -19954: STATUS_PRINTER_CANCELING, 1001 -19955: STATUS_PRINTER_REPORT_PRINTING, 1002 -19956: STATUS_PRINTER_REPORT_PRINTING, 1003 -19934: STATUS_PRINTER_HARD_ERROR, 1004 -19930: STATUS_PRINTER_BUSY, 1005 -11990: STATUS_PRINTER_DOOR_OPEN, 1006 -11999: STATUS_PRINTER_MEDIA_JAM, # ADF 1007 -12000: STATUS_PRINTER_MEDIA_JAM, # ADF 1008 -11998: STATUS_PRINTER_MEDIA_JAM, # ADF 1009 -11986: STATUS_PRINTER_HARD_ERROR, # scanner 1010 -11994: STATUS_PRINTER_BUSY, 1011 -14967: STATUS_PRINTER_BUSY, 1012 -19912: STATUS_PRINTER_HARD_ERROR, 1013 -14962: STATUS_PRINTER_BUSY, # copy pending 1014 -14971: STATUS_PRINTER_BUSY, # copying 1015 -14973: STATUS_PRINTER_BUSY, # copying being canceled 1016 -14972: STATUS_PRINTER_BUSY, # copying canceled 1017 -14966: STATUS_PRINTER_DOOR_OPEN, 1018 -14974: STATUS_PRINTER_MEDIA_JAM, 1019 -14969: STATUS_PRINTER_HARD_ERROR, 1020 -14968: STATUS_PRINTER_HARD_ERROR, 1021 -12996: STATUS_PRINTER_BUSY, # scan 1022 -12994: STATUS_PRINTER_BUSY, # scan 1023 -12993: STATUS_PRINTER_BUSY, # scan 1024 -12991: STATUS_PRINTER_BUSY, # scan 1025 -12995: STATUS_PRINTER_BUSY, # scan 1026 -12997: STATUS_PRINTER_HARD_ERROR, # scan 1027 -12990: STATUS_PRINTER_BUSY, 1028 -12998: STATUS_PRINTER_BUSY, 1029 -13000: STATUS_PRINTER_DOOR_OPEN, 1030 -12999: STATUS_PRINTER_MEDIA_JAM, 1031 -13859: STATUS_PRINTER_BUSY, 1032 -13858: STATUS_PRINTER_BUSY, #</DevStatusDialingOut> 1033 -13868: STATUS_PRINTER_BUSY, #</DevStatusRedialPending> 1034 -13867: STATUS_PRINTER_BUSY, #</DevStatusFaxSendCanceled> 1035 -13857: STATUS_PRINTER_BUSY, #</DevStatusConnecting> 1036 -13856: STATUS_PRINTER_BUSY, #</DevStatusSendingPage> 1037 -13855: STATUS_PRINTER_BUSY, #</DevStatusOnePageSend> 1038 -13854: STATUS_PRINTER_BUSY, #</DevStatusMultiplePagesSent> 1039 -13853: STATUS_PRINTER_BUSY, #</DevStatusSenderCancelingFax> 1040 -13839: STATUS_PRINTER_BUSY, #</DevStatusIncomingCall> 1041 -13842: STATUS_PRINTER_BUSY, #</DevStatusBlockingFax> 1042 -13838: STATUS_PRINTER_BUSY, #</DevStatusReceivingFax> 1043 -13847: STATUS_PRINTER_BUSY, #</DevStatusSinglePageReceived> 1044 -13846: STATUS_PRINTER_BUSY, #</DevStatusDoublePagesReceived> 1045 -13845: STATUS_PRINTER_BUSY, #</DevStatusTriplePagesReceived> 1046 -13844: STATUS_PRINTER_BUSY, #</DevStatusPrintingFax> 1047 -13840: STATUS_PRINTER_BUSY, #</DevStatusCancelingFaxPrint> 1048 -13843: STATUS_PRINTER_BUSY, #</DevStatusFaxCancelingReceive> 1049 -13850: STATUS_PRINTER_BUSY, #</DevStatusFaxCanceledReceive> 1050 -13851: STATUS_PRINTER_BUSY, #</DevStatusFaxDelayedSendMemoryFull> 1051 -13836: STATUS_PRINTER_BUSY, #</DevStatusNoDialTone> 1052 -13864: STATUS_PRINTER_BUSY, #</DevStatusNoFaxAnswer> 1053 -13863: STATUS_PRINTER_BUSY, #</DevStatusFaxBusy> 1054 -13865: STATUS_PRINTER_BUSY, #</DevStatusNoDocumentSent> 1055 -13862: STATUS_PRINTER_BUSY, #</DevStatusFaxSendError> 1056 -13837: STATUS_PRINTER_BUSY, #</DevStatusT30Error> 1057 -13861: STATUS_PRINTER_BUSY, #</DevStatusFaxMemoryFullSend> 1058 -13866: STATUS_PRINTER_BUSY, #</DevStatusADFNotCleared> 1059 -13841: STATUS_PRINTER_BUSY, #</DevStatusNoFaxDetected> 1060 -13848: STATUS_PRINTER_BUSY, #</DevStatusFaxMemoryFullReceive> 1061 -13849: STATUS_PRINTER_BUSY, #</DevStatusFaxReceiveError> 1062 1063} 1064 1065def StatusType6(dev): # LaserJet Status (XML) 1066 info_device_status = BytesIO() 1067 info_ssp = BytesIO() 1068 try: 1069 dev.getEWSUrl("/hp/device/info_device_status.xml", info_device_status) 1070 dev.getEWSUrl("/hp/device/info_ssp.xml", info_ssp) 1071 except: 1072 log.warn("Failed to get Device status information") 1073 pass 1074 1075 info_device_status = info_device_status.getvalue() 1076 info_ssp = info_ssp.getvalue() 1077 1078 device_status = {} 1079 ssp = {} 1080 1081 if info_device_status: 1082 try: 1083 log.debug_block("info_device_status", to_string_latin(info_device_status)) 1084 device_status = utils.XMLToDictParser().parseXML(info_device_status) 1085 log.debug(device_status) 1086 except expat.ExpatError: 1087 log.error("Device Status XML parse error") 1088 device_status = {} 1089 1090 if info_ssp: 1091 try: 1092 log.debug_block("info_spp", to_string_latin(info_ssp)) 1093 ssp = utils.XMLToDictParser().parseXML(info_ssp) 1094 log.debug(ssp) 1095 except expat.ExpatError: 1096 log.error("SSP XML parse error") 1097 ssp = {} 1098 1099 status_code = device_status.get('devicestatuspage-devicestatus-statuslist-status-code-0', 0) 1100 1101 if not status_code: 1102 status_code = ssp.get('devicestatuspage-devicestatus-statuslist-status-code-0', 0) 1103 1104 black_supply_level = device_status.get('devicestatuspage-suppliesstatus-blacksupply-percentremaining', 0) 1105 black_supply_low = ssp.get('suppliesstatuspage-blacksupply-lowreached', 0) 1106 agents = [] 1107 1108 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE, 1109 'type' : AGENT_TYPE_BLACK, 1110 'health' : 0, 1111 'level' : black_supply_level, 1112 'level-trigger' : 0, 1113 }) 1114 1115 if dev.tech_type == TECH_TYPE_COLOR_LASER: 1116 cyan_supply_level = device_status.get('devicestatuspage-suppliesstatus-cyansupply-percentremaining', 0) 1117 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE, 1118 'type' : AGENT_TYPE_CYAN, 1119 'health' : 0, 1120 'level' : cyan_supply_level, 1121 'level-trigger' : 0, 1122 }) 1123 1124 magenta_supply_level = device_status.get('devicestatuspage-suppliesstatus-magentasupply-percentremaining', 0) 1125 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE, 1126 'type' : AGENT_TYPE_MAGENTA, 1127 'health' : 0, 1128 'level' : magenta_supply_level, 1129 'level-trigger' : 0, 1130 }) 1131 1132 yellow_supply_level = device_status.get('devicestatuspage-suppliesstatus-yellowsupply-percentremaining', 0) 1133 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE, 1134 'type' : AGENT_TYPE_YELLOW, 1135 'health' : 0, 1136 'level' : yellow_supply_level, 1137 'level-trigger' : 0, 1138 }) 1139 1140 return {'revision' : STATUS_REV_UNKNOWN, 1141 'agents' : agents, 1142 'top-door' : 0, 1143 'supply-door' : 0, 1144 'duplexer' : 1, 1145 'photo-tray' : 0, 1146 'in-tray1' : 1, 1147 'in-tray2' : 1, 1148 'media-path' : 1, 1149 'status-code' : TYPE6_STATUS_CODE_MAP.get(status_code, STATUS_PRINTER_IDLE), 1150 } 1151 1152# PJL status codes 1153PJL_STATUS_MAP = { 1154 10001: STATUS_PRINTER_IDLE, # online 1155 10002: STATUS_PRINTER_OFFLINE, # offline 1156 10003: STATUS_PRINTER_WARMING_UP, 1157 10004: STATUS_PRINTER_BUSY, # self test 1158 10005: STATUS_PRINTER_BUSY, # reset 1159 10006: STATUS_PRINTER_LOW_TONER, 1160 10007: STATUS_PRINTER_CANCELING, 1161 10010: STATUS_PRINTER_SERVICE_REQUEST, 1162 10011: STATUS_PRINTER_OFFLINE, 1163 10013: STATUS_PRINTER_BUSY, 1164 10014: STATUS_PRINTER_REPORT_PRINTING, 1165 10015: STATUS_PRINTER_BUSY, 1166 10016: STATUS_PRINTER_BUSY, 1167 10017: STATUS_PRINTER_REPORT_PRINTING, 1168 10018: STATUS_PRINTER_BUSY, 1169 10019: STATUS_PRINTER_BUSY, 1170 10020: STATUS_PRINTER_BUSY, 1171 10021: STATUS_PRINTER_BUSY, 1172 10022: STATUS_PRINTER_REPORT_PRINTING, 1173 10023: STATUS_PRINTER_PRINTING, 1174 10024: STATUS_PRINTER_SERVICE_REQUEST, 1175 10025: STATUS_PRINTER_SERVICE_REQUEST, 1176 10026: STATUS_PRINTER_BUSY, 1177 10027: STATUS_PRINTER_MEDIA_JAM, 1178 10028: STATUS_PRINTER_REPORT_PRINTING, 1179 10029: STATUS_PRINTER_PRINTING, 1180 10030: STATUS_PRINTER_BUSY, 1181 10031: STATUS_PRINTER_BUSY, 1182 10032: STATUS_PRINTER_BUSY, 1183 10033: STATUS_PRINTER_SERVICE_REQUEST, 1184 10034: STATUS_PRINTER_CANCELING, 1185 10035: STATUS_PRINTER_PRINTING, 1186 10036: STATUS_PRINTER_WARMING_UP, 1187 10200: STATUS_PRINTER_LOW_BLACK_TONER, 1188 10201: STATUS_PRINTER_LOW_CYAN_TONER, 1189 10202: STATUS_PRINTER_LOW_MAGENTA_TONER, 1190 10203: STATUS_PRINTER_LOW_YELLOW_TONER, 1191 10204: STATUS_PRINTER_LOW_TONER, # order image drum 1192 10205: STATUS_PRINTER_LOW_BLACK_TONER, # order black drum 1193 10206: STATUS_PRINTER_LOW_CYAN_TONER, # order cyan drum 1194 10207: STATUS_PRINTER_LOW_MAGENTA_TONER, # order magenta drum 1195 10208: STATUS_PRINTER_LOW_YELLOW_TONER, # order yellow drum 1196 10209: STATUS_PRINTER_LOW_BLACK_TONER, 1197 10210: STATUS_PRINTER_LOW_CYAN_TONER, 1198 10211: STATUS_PRINTER_LOW_MAGENTA_TONER, 1199 10212: STATUS_PRINTER_LOW_YELLOW_TONER, 1200 10213: STATUS_PRINTER_SERVICE_REQUEST, # order transport kit 1201 10214: STATUS_PRINTER_SERVICE_REQUEST, # order cleaning kit 1202 10215: STATUS_PRINTER_SERVICE_REQUEST, # order transfer kit 1203 10216: STATUS_PRINTER_SERVICE_REQUEST, # order fuser kit 1204 10217: STATUS_PRINTER_SERVICE_REQUEST, # maintenance 1205 10218: STATUS_PRINTER_LOW_TONER, 1206 10300: STATUS_PRINTER_LOW_BLACK_TONER, # replace black toner 1207 10301: STATUS_PRINTER_LOW_CYAN_TONER, # replace cyan toner 1208 10302: STATUS_PRINTER_LOW_MAGENTA_TONER, # replace magenta toner 1209 10303: STATUS_PRINTER_LOW_YELLOW_TONER, # replace yellow toner 1210 10304: STATUS_PRINTER_SERVICE_REQUEST, # replace image drum 1211 10305: STATUS_PRINTER_SERVICE_REQUEST, # replace black drum 1212 10306: STATUS_PRINTER_SERVICE_REQUEST, # replace cyan drum 1213 10307: STATUS_PRINTER_SERVICE_REQUEST, # replace magenta drum 1214 10308: STATUS_PRINTER_SERVICE_REQUEST, # replace yellow drum 1215 10309: STATUS_PRINTER_SERVICE_REQUEST, # replace black cart 1216 10310: STATUS_PRINTER_SERVICE_REQUEST, # replace cyan cart 1217 10311: STATUS_PRINTER_SERVICE_REQUEST, # replace magenta cart 1218 10312: STATUS_PRINTER_SERVICE_REQUEST, # replace yellow cart 1219 10313: STATUS_PRINTER_SERVICE_REQUEST, # replace transport kit 1220 10314: STATUS_PRINTER_SERVICE_REQUEST, # replace cleaning kit 1221 10315: STATUS_PRINTER_SERVICE_REQUEST, # replace transfer kit 1222 10316: STATUS_PRINTER_SERVICE_REQUEST, # replace fuser kit 1223 10317: STATUS_PRINTER_SERVICE_REQUEST, 1224 10318: STATUS_PRINTER_SERVICE_REQUEST, # replace supplies 1225 10400: STATUS_PRINTER_NON_HP_INK, # [sic] 1226 10401: STATUS_PRINTER_IDLE, 1227 10402: STATUS_PRINTER_SERVICE_REQUEST, 1228 10403: STATUS_PRINTER_IDLE, 1229 # 11xyy - Background paper-loading 1230 # 12xyy - Background paper-tray status 1231 # 15xxy - Output-bin status 1232 # 20xxx - PJL parser errors 1233 # 25xxx - PJL parser warnings 1234 # 27xxx - PJL semantic errors 1235 # 30xxx - Auto continuable conditions 1236 30119: STATUS_PRINTER_MEDIA_JAM, 1237 # 32xxx - PJL file system errors 1238 # 35xxx - Potential operator intervention conditions 1239 # 40xxx - Operator intervention conditions 1240 40021: STATUS_PRINTER_DOOR_OPEN, 1241 40022: STATUS_PRINTER_MEDIA_JAM, 1242 40038: STATUS_PRINTER_LOW_TONER, 1243 40600: STATUS_PRINTER_NO_TONER, 1244 # 41xyy - Foreground paper-loading messages 1245 # 43xyy - Optional paper handling device messages 1246 # 44xyy - LJ 4xxx/5xxx paper jam messages 1247 # 50xxx - Hardware errors 1248 # 55xxx - Personality errors 1249 1250} 1251 1252MIN_PJL_ERROR_CODE = 10001 1253DEFAULT_PJL_ERROR_CODE = 10001 1254 1255def MapPJLErrorCode(error_code, str_code=None): 1256 if error_code < MIN_PJL_ERROR_CODE: 1257 return STATUS_PRINTER_BUSY 1258 1259 if str_code is None: 1260 str_code = str(error_code) 1261 1262 if len(str_code) < 5: 1263 return STATUS_PRINTER_BUSY 1264 1265 status_code = PJL_STATUS_MAP.get(error_code, None) 1266 1267 if status_code is None: 1268 status_code = STATUS_PRINTER_BUSY 1269 1270 if 10999 < error_code < 12000: # 11xyy - Background paper-loading 1271 # x = tray # 1272 # yy = media code 1273 tray = int(str_code[2]) 1274 media = int(str_code[3:]) 1275 log.debug("Background paper loading for tray #%d" % tray) 1276 log.debug("Media code = %d" % media) 1277 1278 elif 11999 < error_code < 13000: # 12xyy - Background paper-tray status 1279 # x = tray # 1280 # yy = status code 1281 tray = int(str_code[2]) 1282 status = int(str_code[3:]) 1283 log.debug("Background paper tray status for tray #%d" % tray) 1284 log.debug("Status code = %d" % status) 1285 1286 elif 14999 < error_code < 16000: # 15xxy - Output-bin status 1287 # xx = output bin 1288 # y = status code 1289 bin = int(str_code[2:4]) 1290 status = int(str_code[4]) 1291 log.debug("Output bin full for bin #%d" % bin) 1292 status_code = STATUS_PRINTER_OUTPUT_BIN_FULL 1293 1294 elif 19999 < error_code < 28000: # 20xxx, 25xxx, 27xxx PJL errors 1295 status_code = STATUS_PRINTER_SERVICE_REQUEST 1296 1297 elif 29999 < error_code < 31000: # 30xxx - Auto continuable conditions 1298 log.debug("Auto continuation condition #%d" % error_code) 1299 status_code = STATUS_PRINTER_BUSY 1300 1301 elif 34999 < error_code < 36000: # 35xxx - Potential operator intervention conditions 1302 status_code = STATUS_PRINTER_SERVICE_REQUEST 1303 1304 elif 39999 < error_code < 41000: # 40xxx - Operator intervention conditions 1305 status_code = STATUS_PRINTER_SERVICE_REQUEST 1306 1307 elif 40999 < error_code < 42000: # 41xyy - Foreground paper-loading messages 1308 # x = tray 1309 # yy = media code 1310 tray = int(str_code[2]) 1311 media = int(str_code[3:]) 1312 log.debug("Foreground paper loading for tray #%d" % tray) 1313 log.debug("Media code = %d" % media) 1314 status_code = STATUS_PRINTER_OUT_OF_PAPER 1315 1316 elif 41999 < error_code < 43000: 1317 status_code = STATUS_PRINTER_MEDIA_JAM 1318 1319 elif 42999 < error_code < 44000: # 43xyy - Optional paper handling device messages 1320 status_code = STATUS_PRINTER_SERVICE_REQUEST 1321 1322 elif 43999 < error_code < 45000: # 44xyy - LJ 4xxx/5xxx paper jam messages 1323 status_code = STATUS_PRINTER_MEDIA_JAM 1324 1325 elif 49999 < error_code < 51000: # 50xxx - Hardware errors 1326 status_code = STATUS_PRINTER_HARD_ERROR 1327 1328 elif 54999 < error_code < 56000 : # 55xxx - Personality errors 1329 status_code = STATUS_PRINTER_HARD_ERROR 1330 1331 log.debug("Mapped PJL error code %d to status code %d" % (error_code, status_code)) 1332 return status_code 1333 1334 1335pjl_code_pat = re.compile("""^CODE\s*=\s*(\d.*)$""", re.IGNORECASE) 1336 1337 1338 1339def StatusType8(dev): # LaserJet PJL (B&W only) 1340 try: 1341 # Will error if printer is busy printing... 1342 dev.openPrint() 1343 except Error as e: 1344 log.warn(e.msg) 1345 status_code = STATUS_PRINTER_BUSY 1346 else: 1347 try: 1348 try: 1349 dev.writePrint(to_bytes_utf8("\x1b%-12345X@PJL INFO STATUS \r\n\x1b%-12345X")) 1350 pjl_return = dev.readPrint(1024, timeout=5, allow_short_read=True) 1351 dev.close() 1352 1353 log.debug_block("PJL return:", to_string_latin(pjl_return)) 1354 1355 str_code = '10001' 1356 1357 for line in pjl_return.splitlines(): 1358 line = line.strip() 1359 match = pjl_code_pat.match(line.decode('utf-8')) 1360 1361 if match is not None: 1362 str_code = match.group(1) 1363 break 1364 1365 log.debug("Code = %s" % str_code) 1366 1367 try: 1368 error_code = int(str_code) 1369 except ValueError: 1370 error_code = DEFAULT_PJL_ERROR_CODE 1371 1372 log.debug("Error code = %d" % error_code) 1373 1374 status_code = MapPJLErrorCode(error_code, str_code) 1375 except Error: 1376 status_code = STATUS_PRINTER_HARD_ERROR 1377 finally: 1378 try: 1379 dev.closePrint() 1380 except Error: 1381 pass 1382 1383 agents = [] 1384 1385 # TODO: Only handles mono lasers... 1386 if status_code in (STATUS_PRINTER_LOW_TONER, STATUS_PRINTER_LOW_BLACK_TONER): 1387 health = AGENT_HEALTH_OK 1388 level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW 1389 level = 0 1390 1391 elif status_code == STATUS_PRINTER_NO_TONER: 1392 health = AGENT_HEALTH_MISINSTALLED 1393 level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW 1394 level = 0 1395 1396 else: 1397 health = AGENT_HEALTH_OK 1398 level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0 1399 level = 100 1400 1401 log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger)) 1402 1403 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE, 1404 'type' : AGENT_TYPE_BLACK, 1405 'health' : health, 1406 'level' : level, 1407 'level-trigger' : level_trigger, 1408 }) 1409 1410 if dev.tech_type == TECH_TYPE_COLOR_LASER: 1411 level = 100 1412 level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0 1413 if status_code == STATUS_PRINTER_LOW_CYAN_TONER: 1414 level = 0 1415 level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW 1416 1417 log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger)) 1418 1419 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE, 1420 'type' : AGENT_TYPE_CYAN, 1421 'health' : AGENT_HEALTH_OK, 1422 'level' : level, 1423 'level-trigger' : level_trigger, 1424 }) 1425 1426 level = 100 1427 level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0 1428 if status_code == STATUS_PRINTER_LOW_MAGENTA_TONER: 1429 level = 0 1430 level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW 1431 1432 log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger)) 1433 1434 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE, 1435 'type' : AGENT_TYPE_MAGENTA, 1436 'health' : AGENT_HEALTH_OK, 1437 'level' : level, 1438 'level-trigger' : level_trigger, 1439 }) 1440 1441 level = 100 1442 level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0 1443 if status_code == STATUS_PRINTER_LOW_YELLOW_TONER: 1444 level = 0 1445 level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW 1446 1447 log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger)) 1448 1449 agents.append({ 'kind' : AGENT_KIND_TONER_CARTRIDGE, 1450 'type' : AGENT_TYPE_YELLOW, 1451 'health' : AGENT_HEALTH_OK, 1452 'level' : level, 1453 'level-trigger' : level_trigger, 1454 }) 1455 1456 if status_code == 40021: 1457 top_door = 0 1458 else: 1459 top_door = 1 1460 1461 log.debug("Status code = %d" % status_code) 1462 1463 return { 'revision' : STATUS_REV_UNKNOWN, 1464 'agents' : agents, 1465 'top-door' : top_door, 1466 'supply-door' : top_door, 1467 'duplexer' : 0, 1468 'photo-tray' : 0, 1469 'in-tray1' : 1, 1470 'in-tray2' : 1, 1471 'media-path' : 1, 1472 'status-code' : status_code, 1473 } 1474 1475 1476element_type10_xlate = { 'ink' : AGENT_KIND_SUPPLY, 1477 'rechargeableToner' : AGENT_KIND_TONER_CARTRIDGE, 1478 'inkTank' : AGENT_KIND_SUPPLY, 1479 'inkCartridge' : AGENT_KIND_HEAD_AND_SUPPLY, 1480 'printhead' : AGENT_KIND_HEAD, 1481 'toner' : AGENT_KIND_TONER_CARTRIDGE, 1482 'tonerCartridge' : AGENT_KIND_TONER_CARTRIDGE, 1483 } 1484 1485pen_type10_xlate = { 'pK' : AGENT_TYPE_PHOTO_BLACK, 1486 'CMY' : AGENT_TYPE_CMY, 1487 'M' : AGENT_TYPE_MAGENTA, 1488 'C' : AGENT_TYPE_CYAN, 1489 'Y' : AGENT_TYPE_YELLOW, 1490 'K' : AGENT_TYPE_BLACK, 1491 'G' : AGENT_TYPE_G, 1492 'mK' : AGENT_TYPE_MATTE_BLACK, 1493 } 1494 1495pen_level10_xlate = { 'ok' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0, 1496 'low' : AGENT_LEVEL_TRIGGER_MAY_BE_LOW, 1497 'out' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT, 1498 'empty' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT, 1499 'missing' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT, 1500 'unknown' : AGENT_LEVEL_UNKNOWN, 1501 } 1502 1503pen_health10_xlate = { 'ok' : AGENT_HEALTH_OK, 1504 'misinstalled' : AGENT_HEALTH_MISINSTALLED, 1505 'missing' : AGENT_HEALTH_MISINSTALLED, 1506 'unknown' : AGENT_HEALTH_UNKNOWN, 1507 } 1508 1509 1510#ExtractXMLData will extract actual data from http response (Transfer-encoding: chunked). 1511#For unchunked response it will not do anything. 1512def ExtractXMLData(data): 1513 if data[0:1] != b'<': 1514 size = -1 1515 temp = to_bytes_utf8("") 1516 while size: 1517 index = data.find(to_bytes_utf8('\r\n')) 1518 size = int(data[0:index+1], 16) 1519 temp = temp + data[index+2:index+2+size] 1520 data = data[index+2+size+2:len(data)] 1521 data = temp 1522 return data 1523 1524def StatusType10FetchUrl(func, url, footer=""): 1525 data_fp = BytesIO() 1526 if footer: 1527 data = func(url, data_fp, footer) 1528 else: 1529 data = func(url, data_fp) 1530 if data: 1531 while data.find(to_bytes_utf8('\r\n\r\n')) != -1: 1532 data = data.split(to_bytes_utf8('\r\n\r\n'), 1)[1] 1533 if not data.startswith(to_bytes_utf8("HTTP")): 1534 break 1535 1536 if data: 1537 data = ExtractXMLData(data) 1538 return data 1539 1540def StatusType10(func): # Low End Data Model 1541 status_block = { 'revision' : STATUS_REV_UNKNOWN, 1542 'agents' : [], 1543 'top-door' : TOP_DOOR_NOT_PRESENT, 1544 'supply-door' : TOP_DOOR_NOT_PRESENT, 1545 'duplexer' : DUPLEXER_NOT_PRESENT, 1546 'photo-tray' : PHOTO_TRAY_NOT_PRESENT, 1547 'in-tray1' : IN_TRAY_NOT_PRESENT, 1548 'in-tray2' : IN_TRAY_NOT_PRESENT, 1549 'media-path' : MEDIA_PATH_NOT_PRESENT, 1550 'status-code' : STATUS_PRINTER_IDLE, 1551 } 1552 1553 if not etree_loaded and not elementtree_loaded: 1554 log.error("cannot get status for printer. please load ElementTree module") 1555 return status_block 1556 1557 status_block = StatusType10Agents(func) 1558 1559 temp_status_block = {} 1560 temp_status_block = StatusType10Media(func) 1561 status_block.update(temp_status_block) 1562 1563 temp_status_block = {} 1564 temp_status_block = StatusType10Status(func) 1565 status_block.update(temp_status_block) 1566 1567 return status_block 1568 1569 1570def StatusType10Agents(func): # Low End Data Model 1571 status_block = {} 1572 # Get the dynamic consumables configuration 1573 data = StatusType10FetchUrl(func, "/DevMgmt/ConsumableConfigDyn.xml") 1574 if not data: 1575 return status_block 1576 data = data.replace(to_bytes_utf8("ccdyn:"), to_bytes_utf8("")).replace(to_bytes_utf8("dd:"), to_bytes_utf8("")) 1577 1578 # Parse the agent status XML 1579 agents = [] 1580 try: 1581 if etree_loaded: 1582 tree = ElementTree.XML(data) 1583 if not etree_loaded and elementtree_loaded: 1584 tree = XML(data) 1585 elements = tree.findall("ConsumableInfo") 1586 for e in elements: 1587 health = AGENT_HEALTH_OK 1588 ink_level = 0 1589 agent_sku = '' 1590 try: 1591 type = e.find("ConsumableTypeEnum").text 1592 state = e.find("ConsumableLifeState/ConsumableState").text 1593 quantityState = e.find("ConsumableLifeState/MeasuredQuantityState").text 1594 1595 # level 1596 if type == "ink" or type == "inkCartridge" or type == "toner" or type == "tonerCartridge" or type == "rechargeableToner" or type == "inkTank": 1597 ink_type = e.find("ConsumableLabelCode").text 1598 if state != "missing": 1599 try: 1600 ink_level = int(e.find("ConsumablePercentageLevelRemaining").text) 1601 if ink_level == 0 and quantityState == 'unknown': 1602 state = "unknown" 1603 elif ink_level == 0: 1604 state = "empty" 1605 elif ink_level <=10: 1606 state = "low" 1607 1608 agent_sku = 'Unknown' #Initialize to unknown. IN some old devices, ConsumableSelectibilityNumber is not returned by device. 1609 except: 1610 ink_level = 0 1611 elif type == "printhead" or type == 'imageDrum': 1612 continue; #No need of adding this agent. 1613 else: 1614 ink_type = '' 1615 if state == "ok": 1616 ink_level = 100 1617 1618 try: 1619 agent_sku = e.find("ProductNumber").text 1620 except: 1621 try : 1622 agent_sku = e.find("ConsumableSelectibilityNumber").text 1623 except : 1624 pass 1625 1626 log.debug("type '%s' state '%s' ink_type '%s' ink_level %d agent_sku = %s" % (type, state, ink_type, ink_level,agent_sku)) 1627 1628 entry = { 'kind' : element_type10_xlate.get(type, AGENT_KIND_NONE), 1629 'type' : pen_type10_xlate.get(ink_type, AGENT_TYPE_NONE), 1630 'health' : pen_health10_xlate.get(state, AGENT_HEALTH_OK), 1631 'level' : int(ink_level), 1632 'level-trigger' : pen_level10_xlate.get(state, AGENT_LEVEL_TRIGGER_SUFFICIENT_0), 1633 'agent-sku' : agent_sku 1634 } 1635 1636 log.debug("%s" % entry) 1637 agents.append(entry) 1638 except AttributeError: 1639 log.debug("no value found for attribute") 1640 except (expat.ExpatError, UnboundLocalError): 1641 agents = [] 1642 status_block['agents'] = agents 1643 1644 return status_block 1645 1646def StatusType10Media(func): # Low End Data Model 1647 status_block = {} 1648 # Get the media handling configuration 1649 data = StatusType10FetchUrl(func, "/DevMgmt/MediaHandlingDyn.xml") 1650 if not data: 1651 return status_block 1652 data = data.replace(to_bytes_utf8("mhdyn:"), to_bytes_utf8("")).replace(to_bytes_utf8("dd:"), to_bytes_utf8("")) 1653 1654 # Parse the media handling XML 1655 try: 1656 if etree_loaded: 1657 tree = ElementTree.XML(data) 1658 if not etree_loaded and elementtree_loaded: 1659 tree = XML(data) 1660 elements = tree.findall("InputTray") 1661 except (expat.ExpatError, UnboundLocalError): 1662 elements = [] 1663 for e in elements: 1664 bin_name = e.find("InputBin").text 1665 if bin_name == "Tray1": 1666 status_block['in-tray1'] = IN_TRAY_PRESENT 1667 elif bin_name == "Tray2": 1668 status_block['in-tray2'] = IN_TRAY_PRESENT 1669 elif bin_name == "PhotoTray": 1670 status_block['photo-tray'] = PHOTO_TRAY_ENGAGED 1671 1672 try: 1673 elements = tree.findall("Accessories/MediaHandlingDeviceFunctionType") 1674 except UnboundLocalError: 1675 elements = [] 1676 for e in elements: 1677 if e.text == "autoDuplexor": 1678 status_block['duplexer'] = DUPLEXER_DOOR_CLOSED 1679 1680 return status_block 1681 1682def StatusType10Status(func): # Low End Data Model 1683 status_block = {} 1684 # Get the product status 1685 data = StatusType10FetchUrl(func, "/DevMgmt/ProductStatusDyn.xml") 1686 if not data: 1687 return status_block 1688 data = data.replace(to_bytes_utf8("psdyn:"), to_bytes_utf8("")).replace(to_bytes_utf8("locid:"), to_bytes_utf8("")) 1689 data = data.replace(to_bytes_utf8("pscat:"), to_bytes_utf8("")).replace(to_bytes_utf8("dd:"), to_bytes_utf8("")).replace(to_bytes_utf8("ad:"), to_bytes_utf8("")) 1690 1691 # Parse the product status XML 1692 try: 1693 if etree_loaded: 1694 tree = ElementTree.XML(data) 1695 if not etree_loaded and elementtree_loaded: 1696 tree = XML(data) 1697 elements = tree.findall("Status/StatusCategory") 1698 except (expat.ExpatError, UnboundLocalError): 1699 elements = [] 1700 1701 for e in elements: 1702 1703 if e.text == "processing": 1704 status_block['status-code'] = STATUS_PRINTER_PRINTING 1705 elif e.text == "ready": 1706 status_block['status-code'] = STATUS_PRINTER_IDLE 1707 elif e.text == "closeDoorOrCover": 1708 status_block['status-code'] = STATUS_PRINTER_DOOR_OPEN 1709 elif e.text == "shuttingDown": 1710 status_block['status-code'] = STATUS_PRINTER_TURNING_OFF 1711 elif e.text == "cancelJob": 1712 status_block['status-code'] = STATUS_PRINTER_CANCELING 1713 elif e.text == "trayEmptyOrOpen": 1714 status_block['status-code'] = STATUS_PRINTER_OUT_OF_PAPER 1715 elif e.text == "jamInPrinter": 1716 status_block['status-code'] = STATUS_PRINTER_MEDIA_JAM 1717 elif e.text == "hardError": 1718 status_block['status-code'] = STATUS_PRINTER_HARD_ERROR 1719 elif e.text == "outputBinFull": 1720 status_block['status-code'] = STATUS_PRINTER_OUTPUT_BIN_FULL 1721 elif e.text == "unexpectedSizeInTray" or e.text == "sizeMismatchInTray": 1722 status_block['status-code'] = STATUS_PRINTER_MEDIA_SIZE_MISMATCH 1723 elif e.text == "insertOrCloseTray2": 1724 status_block['status-code'] = STATUS_PRINTER_TRAY_2_MISSING 1725 elif e.text == "scannerError": 1726 status_block['status-code'] = EVENT_SCANNER_FAIL 1727 elif e.text == "scanProcessing": 1728 status_block['status-code'] = EVENT_START_SCAN_JOB 1729 elif e.text == "scannerAdfLoaded": 1730 status_block['status-code'] = EVENT_SCAN_ADF_LOADED 1731 elif e.text == "scanToDestinationNotSet": 1732 status_block['status-code'] = EVENT_SCAN_TO_DESTINATION_NOTSET 1733 elif e.text == "scanWaitingForPC": 1734 status_block['status-code'] = EVENT_SCAN_WAITING_FOR_PC 1735 elif e.text == "scannerAdfJam": 1736 status_block['status-code'] = EVENT_SCAN_ADF_JAM 1737 elif e.text == "scannerAdfDoorOpen": 1738 status_block['status-code'] = EVENT_SCAN_ADF_DOOR_OPEN 1739 elif e.text == "faxProcessing": 1740 status_block['status-code'] = EVENT_START_FAX_JOB 1741 elif e.text == "faxSending": 1742 status_block['status-code'] = STATUS_FAX_TX_ACTIVE 1743 elif e.text == "faxReceiving": 1744 status_block['status-code'] = STATUS_FAX_RX_ACTIVE 1745 elif e.text == "faxDialing": 1746 status_block['status-code'] = EVENT_FAX_DIALING 1747 elif e.text == "faxConnecting": 1748 status_block['status-code'] = EVENT_FAX_CONNECTING 1749 elif e.text == "faxSendError": 1750 status_block['status-code'] = EVENT_FAX_SEND_ERROR 1751 elif e.text == "faxErrorStorageFull": 1752 status_block['status-code'] = EVENT_FAX_ERROR_STORAGE_FULL 1753 elif e.text == "faxReceiveError": 1754 status_block['status-code'] = EVENT_FAX_RECV_ERROR 1755 elif e.text == "faxBlocking": 1756 status_block['status-code'] = EVENT_FAX_BLOCKING 1757 elif e.text == "inPowerSave": 1758 status_block['status-code'] = STATUS_PRINTER_POWER_SAVE 1759 elif e.text == "incorrectCartridge": 1760 status_block['status-code'] = STATUS_PRINTER_CARTRIDGE_WRONG 1761 elif e.text == "cartridgeMissing": 1762 status_block['status-code'] = STATUS_PRINTER_CARTRIDGE_MISSING 1763 elif e.text == "missingPrintHead": 1764 status_block['status-code'] = STATUS_PRINTER_PRINTHEAD_MISSING 1765 1766 1767 #Alert messages for Pentane products RQ 8888 1768 elif e.text == "scannerADFMispick": 1769 status_block['status-code'] = STATUS_SCANNER_ADF_MISPICK 1770 1771 elif e.text == "mediaTooShortToAutoDuplex": 1772 status_block['status-code'] = STATUS_PRINTER_PAPER_TOO_SHORT_TO_AUTODUPLEX 1773 1774 elif e.text == "insertOrCloseTray": 1775 status_block['status-code'] = STATUS_PRINTER_TRAY_2_3_DOOR_OPEN 1776 1777 elif e.text == "inkTooLowToPrime": 1778 status_block['status-code'] = STATUS_PRINTER_INK_TOO_LOW_TO_PRIME 1779 1780 elif e.text == "cartridgeVeryLow": 1781 status_block['status-code'] = STATUS_PRINTER_VERY_LOW_ON_INK 1782 1783 elif e.text == "wasteMarkerCollectorAlmostFull": 1784 status_block['status-code'] = STATUS_PRINTER_SERVICE_INK_CONTAINER_ALMOST_FULL 1785 1786 elif e.text == "wasteMarkerCollectorFull": 1787 status_block['status-code'] = STATUS_PRINTER_SERVICE_INK_CONTAINER_FULL 1788 1789 elif e.text == "wasteMarkerCollectorFullPrompt": 1790 status_block['status-code'] = STATUS_PRINTER_SERVICE_INK_CONTAINER_FULL_PROMPT 1791 1792 elif e.text == "missingDuplexer": 1793 status_block['status-code'] = STATUS_PRINTER_DUPLEX_MODULE_MISSING 1794 1795 elif e.text == "printBarStall": 1796 status_block['status-code'] = STATUS_PRINTER_PRINTHEAD_JAM 1797 1798 elif e.text == "outputBinClosed": 1799 status_block['status-code'] = STATUS_PRINTER_CLEAR_OUTPUT_AREA 1800 1801 elif e.text == "outputBinOpened": 1802 status_block['status-code'] = STATUS_PRINTER_CLEAR_OUTPUT_AREA 1803 1804 elif e.text == "reseatDuplexer": 1805 status_block['status-code'] = STATUS_PRINTER_RESEAT_DUPLEXER 1806 1807 elif e.text == "unexpectedTypeInTray": 1808 status_block['status-code'] = STATUS_PRINTER_MEDIA_TYPE_MISMATCH 1809 1810 elif e.text == "manuallyFeed": 1811 status_block['status-code'] = STATUS_MANUALLY_FEED 1812 1813 else: 1814 status_block['status-code'] = STATUS_UNKNOWN_CODE 1815 1816 return status_block 1817 1818#IPP Status Code 1819IPP_PRINTER_STATE_IDLE = 0x03 1820IPP_PRINTER_STATE_PROCESSING = 0x04 1821IPP_PRINTER_STATE_STOPPED = 0x05 1822 1823marker_kind_xlate = { 'ink' : AGENT_KIND_SUPPLY, 1824 'rechargeableToner' : AGENT_KIND_TONER_CARTRIDGE, 1825 'inkTank' : AGENT_KIND_SUPPLY, 1826 'inkCartridge' : AGENT_KIND_SUPPLY, 1827 'printhead' : AGENT_KIND_HEAD, 1828 'toner' : AGENT_KIND_TONER_CARTRIDGE, 1829 'tonerCartridge' : AGENT_KIND_TONER_CARTRIDGE, 1830 'toner-cartridge' : AGENT_KIND_TONER_CARTRIDGE, 1831 'maintenanceKit' : AGENT_KIND_MAINT_KIT, 1832 'ink-cartridge' : AGENT_KIND_SUPPLY, 1833 } 1834 1835marker_type_xlate = {'magenta ink' : AGENT_TYPE_MAGENTA, 1836 'cyan ink' : AGENT_TYPE_CYAN, 1837 'yellow ink' : AGENT_TYPE_YELLOW, 1838 'black ink' : AGENT_TYPE_BLACK, 1839 'Black Cartridge' : AGENT_TYPE_BLACK, 1840 'Magenta Cartridge' : AGENT_TYPE_MAGENTA, 1841 'Cyan Cartridge' : AGENT_TYPE_CYAN, 1842 'Yellow Cartridge' : AGENT_TYPE_YELLOW, 1843 'Maintenance Kit' : AGENT_TYPE_NONE, 1844 } 1845 1846marker_leveltrigger_xlate = { 'ok' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0, 1847 'low' : AGENT_LEVEL_TRIGGER_MAY_BE_LOW, 1848 'out' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT, 1849 'empty' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT, 1850 'missing' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT, 1851 } 1852 1853marker_state_xlate = { 'ok' : AGENT_HEALTH_OK, 1854 'misinstalled' : AGENT_HEALTH_MISINSTALLED, 1855 'missing' : AGENT_HEALTH_MISINSTALLED, 1856 } 1857 1858printer_state_reasons_xlate = { 'none' : STATUS_PRINTER_IDLE, 1859 'media-needed' : STATUS_PRINTER_OUT_OF_PAPER, 1860 'media-jam' : STATUS_PRINTER_MEDIA_JAM, 1861 'shutdown' : STATUS_PRINTER_TURNING_OFF, 1862 'toner-low' : STATUS_PRINTER_LOW_TONER, 1863 'toner-empty' : STATUS_PRINTER_EMPTY_TONER, 1864 'cover-open' : STATUS_PRINTER_DOOR_OPEN, 1865 'door-open' : STATUS_PRINTER_DOOR_OPEN, 1866 'input-tray-missing' : STATUS_PRINTER_TRAY_2_3_DOOR_OPEN, 1867 'media-low' : STATUS_PRINTER_OUT_OF_PAPER, 1868 'media-empty' : STATUS_PRINTER_MEDIA_EMPTY_ERROR, 1869 'output-tray-missing' : STATUS_PRINTER_TRAY_2_MISSING, 1870 'output-area-almost-full' : STATUS_PRINTER_CLEAR_OUTPUT_AREA, 1871 'output-area-full' : STATUS_PRINTER_CLEAR_OUTPUT_AREA, 1872 'marker-supply-low' : STATUS_PRINTER_VERY_LOW_ON_INK, 1873 'marker-supply-empty' : STATUS_PRINTER_VERY_LOW_ON_INK, 1874 'paused' : STATUS_PRINTER_PAUSED, 1875 'other' : STATUS_UNKNOWN_CODE, 1876 } 1877 1878def StatusTypeIPPStatus(attrs): 1879 1880 status_block = {} 1881 if not attrs: 1882 return status_block 1883 1884 try: 1885 printer_state = attrs['printer-state'][0] 1886 printer_state_reasons = attrs['printer-state-reasons'][0] 1887 1888 if printer_state == IPP_PRINTER_STATE_IDLE: 1889 status_block['status-code'] = STATUS_PRINTER_IDLE 1890 elif printer_state == IPP_PRINTER_STATE_PROCESSING: 1891 status_block['status-code'] = STATUS_PRINTER_PRINTING 1892 else: 1893 printer_state_reasons = printer_state_reasons.replace("-error", "") 1894 printer_state_reasons = printer_state_reasons.replace("-warning", "") 1895 printer_state_reasons = printer_state_reasons.replace("-report", "") 1896 status_block['status-code'] = printer_state_reasons_xlate.get(printer_state_reasons, STATUS_PRINTER_IDLE) 1897 1898 except Exception as e: 1899 log.debug("Exception occured while updating printer-state [%s]" %e.args[0]) 1900 status_block = {} 1901 1902 return status_block 1903 1904 1905def StatusTypeIPPAgents(attrs): 1906 1907 status_block = {} 1908 agents = [] 1909 1910 if not attrs: 1911 return status_block 1912 1913 loopcntr = 0 1914 while(True ): 1915 try: 1916 if loopcntr >= len(attrs['marker-names']): 1917 break 1918 1919 if attrs['marker-types'][loopcntr] == 'maintenanceKit': 1920 loopcntr = loopcntr + 1 1921 continue 1922 1923 if attrs['marker-levels'][loopcntr] > attrs['marker-low-levels'][loopcntr] : 1924 state = 'ok' 1925 else: 1926 state = 'low' 1927 1928 #match the type if marker-type is something like 'Black Cartridge HP XXXX' 1929 mtype = [v for k,v in marker_type_xlate.items() if attrs['marker-names'][loopcntr].startswith(k)] 1930 1931 entry = { 'kind' : marker_kind_xlate.get(attrs['marker-types'][loopcntr], AGENT_KIND_NONE), 1932 'type' : mtype[0] if len(mtype) > 0 else 0, 1933 'health' : marker_state_xlate.get(state, AGENT_HEALTH_OK), 1934 'level' : attrs['marker-levels'][loopcntr], 1935 'level-trigger' : marker_leveltrigger_xlate.get(state, AGENT_LEVEL_TRIGGER_SUFFICIENT_0), 1936 'agent-sku' : '' 1937 } 1938 1939 log.debug("%s" % entry) 1940 agents.append(entry) 1941 except AttributeError: 1942 log.error("no value found for attribute") 1943 return [] 1944 1945 loopcntr = loopcntr + 1 1946 1947 status_block['agents'] = agents 1948 1949 return status_block 1950 1951def StatusTypeIPP(device_uri): 1952 status_block = { 'revision' : STATUS_REV_UNKNOWN, 1953 'agents' : [], 1954 'top-door' : TOP_DOOR_NOT_PRESENT, 1955 'supply-door' : TOP_DOOR_NOT_PRESENT, 1956 'duplexer' : DUPLEXER_NOT_PRESENT, 1957 'photo-tray' : PHOTO_TRAY_NOT_PRESENT, 1958 'in-tray1' : IN_TRAY_NOT_PRESENT, 1959 'in-tray2' : IN_TRAY_NOT_PRESENT, 1960 'media-path' : MEDIA_PATH_NOT_PRESENT, 1961 'status-code' : STATUS_PRINTER_IDLE, 1962 } 1963 1964 status_attrs = cupsext.getStatusAttributes(device_uri) 1965 1966 if status_attrs: 1967 status_block.update(StatusTypeIPPAgents(status_attrs) ) 1968 status_block.update(StatusTypeIPPStatus (status_attrs) ) 1969 1970 return status_block 1971 1972 1973