Show
Ignore:
Timestamp:
10/04/06 00:21:34 (18 years ago)
Author:
jerome
Message:

Added the 'noprintingmaxdelay' directive to workaround printers
which don't conform to RFC3805.
Improved the reliability of SNMP and PJL hardware accounting.
PJL still needs some work though...

Location:
pykota/trunk/pykota/accounters
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/pykota/accounters/pjl.py

    r2830 r3025  
    131131    def waitPrinting(self) : 
    132132        """Waits for printer status being 'printing'.""" 
     133        try : 
     134            noprintingmaxdelay = int(self.parent.filter.config.getNoPrintingMaxDelay(self.parent.filter.PrinterName)) 
     135        except (TypeError, AttributeError) : # NB : AttributeError in testing mode because I'm lazy ! 
     136            noprintingmaxdelay = NOPRINTINGMAXDELAY 
     137            self.parent.filter.logdebug("No max delay defined for printer %s, using %i seconds." % (self.parent.filter.PrinterName, noprintingmaxdelay)) 
     138        if not noprintingmaxdelay : 
     139            self.parent.filter.logdebug("Will wait indefinitely until printer %s is in 'printing' state." % self.parent.filter.PrinterName) 
     140        else :     
     141            self.parent.filter.logdebug("Will wait until printer %s is in 'printing' state or %i seconds have elapsed." % (self.parent.filter.PrinterName, noprintingmaxdelay)) 
    133142        previousValue = self.parent.getLastPageCounter() 
    134143        timebefore = time.time() 
     
    151160                        self.parent.filter.printInfo("Printer %s is lying to us !!!" % self.parent.filter.PrinterName, "warn") 
    152161                        break 
    153                     elif (time.time() - timebefore) > NOPRINTINGMAXDELAY : 
     162                    elif noprintingmaxdelay and ((time.time() - timebefore) > noprintingmaxdelay) : 
    154163                        # More than X seconds without the printer being in 'printing' mode 
    155164                        # We can safely assume this won't change if printer is now 'idle' 
  • pykota/trunk/pykota/accounters/snmp.py

    r2877 r3025  
    2222# 
    2323# 
     24 
     25"""This module is used to extract printer's internal page counter 
     26and status informations using SNMP queries. 
     27 
     28The values extracted are defined at least in RFC3805 and RFC2970. 
     29""" 
    2430 
    2531ITERATIONDELAY = 1.5   # 1.5 Second 
     
    6571                     }   
    6672hrPrinterDetectedErrorStateOID = "1.3.6.1.2.1.25.3.5.1.2.1" # SNMPv2-SMI::mib-2.25.3.5.1.2.1 
     73printerDetectedErrorStateValues = [ { 128 : 'Low Paper', 
     74                                       64 : 'No Paper', 
     75                                       32 : 'Low Toner', 
     76                                       16 : 'No Toner', 
     77                                        8 : 'Door Open', 
     78                                        4 : 'Jammed', 
     79                                        2 : 'Offline', 
     80                                        1 : 'Service Requested', 
     81                                    }, 
     82                                    { 128 : 'Input Tray Missing', 
     83                                       64 : 'Output Tray Missing', 
     84                                       32 : 'Marker Supply Missing', 
     85                                       16 : 'Output Near Full', 
     86                                        8 : 'Output Full', 
     87                                        4 : 'Input Tray Empty', 
     88                                        2 : 'Overdue Preventive Maintainance', 
     89                                        1 : 'Not Assigned in RFC3805', 
     90                                    }, 
     91                                  ]   
     92errorConditions = [ 'No Paper', 
     93                    # 'No Toner', 
     94                    'Door Open', 
     95                    'Jammed', 
     96                    'Offline', 
     97                    'Service Requested', 
     98                    'Input Tray Missing', 
     99                    'Output Tray Missing', 
     100                    # 'Marker Supply Missing', 
     101                    'Output Full', 
     102                    'Input Tray Empty', 
     103                  ] 
    67104prtConsoleDisplayBufferTextOID = "1.3.6.1.2.1.43.16.5.1.2.1.1" # SNMPv2-SMI::mib-2.43.16.5.1.2.1.1 
     105 
    68106class BaseHandler : 
    69107    """A class for SNMP print accounting.""" 
     
    76114            self.community = "public" 
    77115        self.port = 161 
     116        self.initValues() 
     117         
     118    def initValues(self) :     
     119        """Initializes SNMP values.""" 
    78120        self.printerInternalPageCounter = None 
    79121        self.printerStatus = None 
    80122        self.deviceStatus = None 
     123        self.printerDetectedErrorState = None 
     124        self.consoleDisplayBufferText = None 
     125        self.timebefore = time.time()   # resets timer also in case of error 
    81126         
    82127    def retrieveSNMPValues(self) :     
     
    84129        raise RuntimeError, "You have to overload this method." 
    85130         
     131    def extractErrorStates(self, value) :     
     132        """Returns a list of textual error states from a binary value.""" 
     133        states = [] 
     134        for i in range(min(len(value), len(printerDetectedErrorStateValues))) : 
     135            byte = ord(value[i]) 
     136            bytedescription = printerDetectedErrorStateValues[i] 
     137            for (k, v) in bytedescription.items() : 
     138                if byte & k : 
     139                    states.append(v) 
     140        return states             
     141         
     142    def checkIfError(self, errorstates) :     
     143        """Checks if any error state is fatal or not.""" 
     144        for err in errorstates : 
     145            if err in errorConditions : 
     146                return True 
     147        return False     
     148         
    86149    def waitPrinting(self) : 
    87150        """Waits for printer status being 'printing'.""" 
     151        try : 
     152            noprintingmaxdelay = int(self.parent.filter.config.getNoPrintingMaxDelay(self.parent.filter.PrinterName)) 
     153        except (TypeError, AttributeError) : # NB : AttributeError in testing mode because I'm lazy ! 
     154            noprintingmaxdelay = NOPRINTINGMAXDELAY 
     155            self.parent.filter.logdebug("No max delay defined for printer %s, using %i seconds." % (self.parent.filter.PrinterName, noprintingmaxdelay)) 
     156        if not noprintingmaxdelay : 
     157            self.parent.filter.logdebug("Will wait indefinitely until printer %s is in 'printing' state." % self.parent.filter.PrinterName) 
     158        else :     
     159            self.parent.filter.logdebug("Will wait until printer %s is in 'printing' state or %i seconds have elapsed." % (self.parent.filter.PrinterName, noprintingmaxdelay)) 
    88160        previousValue = self.parent.getLastPageCounter() 
    89         timebefore = time.time() 
    90161        firstvalue = None 
    91162        while 1: 
     
    107178                        self.parent.filter.printInfo("Printer %s is lying to us !!!" % self.parent.filter.PrinterName, "warn") 
    108179                        break 
    109                     elif (time.time() - timebefore) > NOPRINTINGMAXDELAY : 
     180                    elif noprintingmaxdelay \ 
     181                         and ((time.time() - self.timebefore) > noprintingmaxdelay) \ 
     182                         and not self.checkIfError(self.printerDetectedErrorState) : 
    110183                        # More than X seconds without the printer being in 'printing' mode 
    111184                        # We can safely assume this won't change if printer is now 'idle' 
     
    135208            dstatusAsString = deviceStatusValues.get(self.deviceStatus) 
    136209            idle_flag = 0 
    137             if (pstatusAsString == 'idle') or \ 
    138                ((pstatusAsString == 'other') and \ 
    139                 (dstatusAsString == 'running')) : 
     210            if (not self.checkIfError(self.printerDetectedErrorState)) \ 
     211               and ((pstatusAsString == 'idle') or \ 
     212                         ((pstatusAsString == 'other') and \ 
     213                          (dstatusAsString == 'running'))) : 
    140214                idle_flag = 1       # Standby / Powersave is considered idle 
    141215            if idle_flag :     
     
    173247                                                  tuple([int(i) for i in pageCounterOID.split('.')]), \ 
    174248                                                  tuple([int(i) for i in hrPrinterStatusOID.split('.')]), \ 
    175                                                   tuple([int(i) for i in hrDeviceStatusOID.split('.')])) 
     249                                                  tuple([int(i) for i in hrDeviceStatusOID.split('.')]), \ 
     250                                                  tuple([int(i) for i in hrPrinterDetectedErrorStateOID.split('.')]), \ 
     251                                                  tuple([int(i) for i in prtConsoleDisplayBufferTextOID.split('.')])) 
    176252            if errorIndication :                                                   
    177253                self.parent.filter.printInfo("SNMP Error : %s" % errorIndication, "error") 
     254                self.initValues() 
    178255            elif errorStatus :     
    179256                self.parent.filter.printInfo("SNMP Error : %s at %s" % (errorStatus.prettyPrint(), \ 
     
    184261                self.printerStatus = int(varBinds[1][1].prettyPrint()) 
    185262                self.deviceStatus = int(varBinds[2][1].prettyPrint()) 
    186                 self.parent.filter.logdebug("SNMP answer decoded : PageCounter : %s  PrinterStatus : '%s'  DeviceStatus : '%s'" \ 
     263                self.printerDetectedErrorState = self.extractErrorStates(str(varBinds[3][1])) 
     264                self.consoleDisplayBufferText = varBinds[4][1].prettyPrint() 
     265                self.parent.filter.logdebug("SNMP answer decoded : PageCounter : %s  PrinterStatus : '%s'  DeviceStatus : '%s'  PrinterErrorState : '%s'  ConsoleDisplayBuffer : '%s'" \ 
    187266                     % (self.printerInternalPageCounter, \ 
    188267                        printerStatusValues.get(self.printerStatus), \ 
    189                         deviceStatusValues.get(self.deviceStatus))) 
     268                        deviceStatusValues.get(self.deviceStatus), \ 
     269                        self.printerDetectedErrorState, \ 
     270                        self.consoleDisplayBufferText)) 
    190271else : 
    191272    class Handler(BaseHandler) : 
     
    199280            req.apiAlphaGetPdu().apiAlphaSetVarBindList((pageCounterOID, ver.Null()), \ 
    200281                                                        (hrPrinterStatusOID, ver.Null()), \ 
    201                                                         (hrDeviceStatusOID, ver.Null())) 
     282                                                        (hrDeviceStatusOID, ver.Null()), \ 
     283                                                        (hrPrinterDetectedErrorStateOID, ver.Null()), \ 
     284                                                        (prtConsoleDisplayBufferTextOID, ver.Null())) 
    202285            tsp = Manager() 
    203286            try : 
     
    211294        def handleAnswer(self, wholeMsg, notusedhere, req): 
    212295            """Decodes and handles the SNMP answer.""" 
    213             self.parent.filter.logdebug("SNMP answer : '%s'" % repr(wholeMsg)) 
    214296            ver = alpha.protoVersions[alpha.protoVersionId1] 
    215297            rsp = ver.Message() 
     
    232314                            self.printerStatus = self.values[1] 
    233315                            self.deviceStatus = self.values[2] 
    234                             self.parent.filter.logdebug("SNMP answer decoded : PageCounter : %s  PrinterStatus : '%s'  DeviceStatus : '%s'" \ 
     316                            self.printerDetectedErrorState = self.extractErrorStates(self.values[3]) 
     317                            self.consoleDisplayBufferText = self.values[4] 
     318                            self.parent.filter.logdebug("SNMP answer decoded : PageCounter : %s  PrinterStatus : '%s'  DeviceStatus : '%s'  PrinterErrorState : '%s'  ConsoleDisplayBuffer : '%s'" \ 
    235319                                 % (self.printerInternalPageCounter, \ 
    236320                                    printerStatusValues.get(self.printerStatus), \ 
    237                                     deviceStatusValues.get(self.deviceStatus))) 
     321                                    deviceStatusValues.get(self.deviceStatus), \ 
     322                                    self.printerDetectedErrorState, \ 
     323                                    self.consoleDisplayBufferText)) 
    238324                        except IndexError :     
    239325                            self.parent.filter.logdebug("SNMP answer is incomplete : %s" % str(self.values))