#!/usr/bin/env python3 """ Generate Zabbix SNMP Item Configuration Creates Zabbix item definitions for printer monitoring Includes: Toner, Maintenance Kit, Fuser, Drums, Waste """ import json import uuid import yaml # Zabbix SNMP items configuration for HP & Xerox printers ZABBIX_ITEMS = { "printer_info": [ { "name": "Printer Model", "key": "printer.model", "oid": "1.3.6.1.2.1.25.3.2.1.3.1", "type": "text", "description": "Device model information" }, { "name": "Printer Hostname", "key": "printer.hostname", "oid": "1.3.6.1.2.1.1.5.0", "type": "text", "description": "System hostname" }, { "name": "Printer Serial Number", "key": "printer.serial", "oid": "1.3.6.1.2.1.43.5.1.1.17.1", "type": "text", "description": "Printer serial number" }, { "name": "System Location", "key": "printer.location", "oid": "1.3.6.1.2.1.1.6.0", "type": "text", "description": "Physical location" }, { "name": "MAC Address", "key": "printer.macaddress", "oid": "1.3.6.1.2.1.2.2.1.6.2", "type": "text", "description": "Primary network interface MAC address" } ], "toner_levels": [ { "name": "Black Toner Current", "key": "printer.toner.black.current", "oid": "1.3.6.1.2.1.43.11.1.1.9.1.1", "type": "numeric_unsigned", "units": "", "description": "Black toner current level (raw value)" }, { "name": "Black Toner Max", "key": "printer.toner.black.max", "oid": "1.3.6.1.2.1.43.11.1.1.8.1.1", "type": "numeric_unsigned", "units": "", "description": "Black toner maximum capacity" }, { "name": "Black Toner Level", "key": "printer.toner.black", "type": "calculated", "formula": "round((last(//printer.toner.black.current)/last(//printer.toner.black.max))*100,0)", "units": "%", "description": "Black toner percentage", "color": "black", "is_percentage": True, "triggers": [ {"severity": "warning", "threshold": 20, "expression": "<"}, {"severity": "high", "threshold": 10, "expression": "<"} ] }, { "name": "Cyan Toner Current", "key": "printer.toner.cyan.current", "oid": "1.3.6.1.2.1.43.11.1.1.9.1.2", "type": "numeric_unsigned", "units": "", "description": "Cyan toner current level (raw value)" }, { "name": "Cyan Toner Max", "key": "printer.toner.cyan.max", "oid": "1.3.6.1.2.1.43.11.1.1.8.1.2", "type": "numeric_unsigned", "units": "", "description": "Cyan toner maximum capacity" }, { "name": "Cyan Toner Level", "key": "printer.toner.cyan", "type": "calculated", "formula": "round((last(//printer.toner.cyan.current)/last(//printer.toner.cyan.max))*100,0)", "units": "%", "description": "Cyan toner percentage", "color": "cyan", "is_percentage": True, "triggers": [ {"severity": "warning", "threshold": 20, "expression": "<"}, {"severity": "high", "threshold": 10, "expression": "<"} ] }, { "name": "Magenta Toner Current", "key": "printer.toner.magenta.current", "oid": "1.3.6.1.2.1.43.11.1.1.9.1.3", "type": "numeric_unsigned", "units": "", "description": "Magenta toner current level (raw value)" }, { "name": "Magenta Toner Max", "key": "printer.toner.magenta.max", "oid": "1.3.6.1.2.1.43.11.1.1.8.1.3", "type": "numeric_unsigned", "units": "", "description": "Magenta toner maximum capacity" }, { "name": "Magenta Toner Level", "key": "printer.toner.magenta", "type": "calculated", "formula": "round((last(//printer.toner.magenta.current)/last(//printer.toner.magenta.max))*100,0)", "units": "%", "description": "Magenta toner percentage", "color": "magenta", "is_percentage": True, "triggers": [ {"severity": "warning", "threshold": 20, "expression": "<"}, {"severity": "high", "threshold": 10, "expression": "<"} ] }, { "name": "Yellow Toner Current", "key": "printer.toner.yellow.current", "oid": "1.3.6.1.2.1.43.11.1.1.9.1.4", "type": "numeric_unsigned", "units": "", "description": "Yellow toner current level (raw value)" }, { "name": "Yellow Toner Max", "key": "printer.toner.yellow.max", "oid": "1.3.6.1.2.1.43.11.1.1.8.1.4", "type": "numeric_unsigned", "units": "", "description": "Yellow toner maximum capacity" }, { "name": "Yellow Toner Level", "key": "printer.toner.yellow", "type": "calculated", "formula": "round((last(//printer.toner.yellow.current)/last(//printer.toner.yellow.max))*100,0)", "units": "%", "description": "Yellow toner percentage", "color": "yellow", "is_percentage": True, "triggers": [ {"severity": "warning", "threshold": 20, "expression": "<"}, {"severity": "high", "threshold": 10, "expression": "<"} ] } ], "cartridge_info": [ { "name": "Black Cartridge Part Number", "key": "printer.cartridge.black", "oid": "1.3.6.1.2.1.43.11.1.1.6.1.1", "type": "text", "description": "Black toner cartridge model/part number" }, { "name": "Cyan Cartridge Part Number", "key": "printer.cartridge.cyan", "oid": "1.3.6.1.2.1.43.11.1.1.6.1.2", "type": "text", "description": "Cyan toner cartridge model/part number" }, { "name": "Magenta Cartridge Part Number", "key": "printer.cartridge.magenta", "oid": "1.3.6.1.2.1.43.11.1.1.6.1.3", "type": "text", "description": "Magenta toner cartridge model/part number" }, { "name": "Yellow Cartridge Part Number", "key": "printer.cartridge.yellow", "oid": "1.3.6.1.2.1.43.11.1.1.6.1.4", "type": "text", "description": "Yellow toner cartridge model/part number" } ], "other_supplies": [ # Drum Cartridge R1 { "name": "Drum Cartridge R1 Part Number", "key": "printer.drum.r1", "oid": "1.3.6.1.2.1.43.11.1.1.6.1.5", "type": "text", "description": "Drum cartridge R1 part number" }, { "name": "Drum Cartridge R1 Level", "key": "printer.drum.r1.level", "oid": "1.3.6.1.2.1.43.11.1.1.9.1.5", "type": "numeric_unsigned", "units": "%", "description": "Drum cartridge R1 remaining life percentage", "part_number_item": "printer.drum.r1", "triggers": [ {"severity": "warning", "threshold": 20, "expression": "<"}, {"severity": "high", "threshold": 10, "expression": "<"} ] }, # Drum Cartridge R2 { "name": "Drum Cartridge R2 Part Number", "key": "printer.drum.r2", "oid": "1.3.6.1.2.1.43.11.1.1.6.1.6", "type": "text", "description": "Drum cartridge R2 part number" }, { "name": "Drum Cartridge R2 Level", "key": "printer.drum.r2.level", "oid": "1.3.6.1.2.1.43.11.1.1.9.1.6", "type": "numeric_unsigned", "units": "%", "description": "Drum cartridge R2 remaining life percentage", "part_number_item": "printer.drum.r2", "triggers": [ {"severity": "warning", "threshold": 20, "expression": "<"}, {"severity": "high", "threshold": 10, "expression": "<"} ] }, # Drum Cartridge R3 { "name": "Drum Cartridge R3 Part Number", "key": "printer.drum.r3", "oid": "1.3.6.1.2.1.43.11.1.1.6.1.7", "type": "text", "description": "Drum cartridge R3 part number" }, { "name": "Drum Cartridge R3 Level", "key": "printer.drum.r3.level", "oid": "1.3.6.1.2.1.43.11.1.1.9.1.7", "type": "numeric_unsigned", "units": "%", "description": "Drum cartridge R3 remaining life percentage", "part_number_item": "printer.drum.r3", "triggers": [ {"severity": "warning", "threshold": 20, "expression": "<"}, {"severity": "high", "threshold": 10, "expression": "<"} ] }, # Drum Cartridge R4 { "name": "Drum Cartridge R4 Part Number", "key": "printer.drum.r4", "oid": "1.3.6.1.2.1.43.11.1.1.6.1.8", "type": "text", "description": "Drum cartridge R4 part number" }, { "name": "Drum Cartridge R4 Level", "key": "printer.drum.r4.level", "oid": "1.3.6.1.2.1.43.11.1.1.9.1.8", "type": "numeric_unsigned", "units": "%", "description": "Drum cartridge R4 remaining life percentage", "part_number_item": "printer.drum.r4", "triggers": [ {"severity": "warning", "threshold": 20, "expression": "<"}, {"severity": "high", "threshold": 10, "expression": "<"} ] }, # Waste Toner Container { "name": "Waste Toner Container Part Number", "key": "printer.waste.partnumber", "oid": "1.3.6.1.2.1.43.11.1.1.6.1.9", "type": "text", "description": "Waste toner container part number" }, { "name": "Waste Toner Container Level", "key": "printer.waste.level", "oid": "1.3.6.1.2.1.43.11.1.1.9.1.9", "type": "numeric_unsigned", "units": "%", "description": "Waste toner container fill level (higher is more full)", "part_number_item": "printer.waste.partnumber", "triggers": [ {"severity": "warning", "threshold": 80, "expression": ">"}, {"severity": "high", "threshold": 90, "expression": ">"} ] }, # Transfer Belt Cleaner { "name": "Transfer Belt Cleaner Part Number", "key": "printer.transfer.belt", "oid": "1.3.6.1.2.1.43.11.1.1.6.1.10", "type": "text", "description": "Transfer belt cleaner part number" }, { "name": "Transfer Belt Cleaner Level", "key": "printer.transfer.belt.level", "oid": "1.3.6.1.2.1.43.11.1.1.9.1.10", "type": "numeric_unsigned", "units": "%", "description": "Transfer belt cleaner remaining life percentage", "part_number_item": "printer.transfer.belt", "triggers": [ {"severity": "warning", "threshold": 20, "expression": "<"}, {"severity": "high", "threshold": 10, "expression": "<"} ] }, # Second Bias Transfer Roll { "name": "Second Bias Transfer Roll Part Number", "key": "printer.transfer.roller", "oid": "1.3.6.1.2.1.43.11.1.1.6.1.11", "type": "text", "description": "Second bias transfer roll part number" }, { "name": "Second Bias Transfer Roll Level", "key": "printer.transfer.roller.level", "oid": "1.3.6.1.2.1.43.11.1.1.9.1.11", "type": "numeric_unsigned", "units": "%", "description": "Second bias transfer roll remaining life percentage", "part_number_item": "printer.transfer.roller", "triggers": [ {"severity": "warning", "threshold": 20, "expression": "<"}, {"severity": "high", "threshold": 10, "expression": "<"} ] } ], "maintenance_kit_hp": [ { "name": "Maintenance Kit Model (HP)", "key": "printer.maintenance.model", "oid": "1.3.6.1.4.1.11.2.3.9.4.2.1.1.3.3.0", "type": "text", "description": "HP maintenance kit model/serial number" }, { "name": "Maintenance Kit Remaining (HP)", "key": "printer.maintenance.remaining", "oid": "1.3.6.1.4.1.11.2.3.9.4.2.1.4.1.2.0", "type": "numeric_unsigned", "units": "pages", "description": "HP maintenance kit remaining pages", "part_number_item": "printer.maintenance.model", "triggers": [ {"severity": "warning", "threshold": 10000, "expression": "<"}, {"severity": "high", "threshold": 5000, "expression": "<"} ] }, { "name": "Printer Model (HP MIB)", "key": "printer.maintenance.printer_model", "oid": "1.3.6.1.4.1.11.2.3.9.4.2.1.1.3.2.0", "type": "text", "description": "Printer model from HP maintenance MIB" } ], "supply_capacity": [ { "name": "Supply 1 Max Capacity", "key": "printer.supply.1.max", "oid": "1.3.6.1.2.1.43.10.2.1.4.1.1", "type": "numeric_unsigned", "description": "Maximum capacity for supply index 1 (usually black)" }, { "name": "Supply 1 Current Level", "key": "printer.supply.1.current", "oid": "1.3.6.1.2.1.43.10.2.1.9.1.1", "type": "numeric_unsigned", "description": "Current level for supply index 1 (usually black)" } ] } def generate_zabbix_cli_commands(): """ Generate Zabbix CLI commands for adding SNMP items """ print("=" * 80) print("ZABBIX SNMP ITEM CONFIGURATION") print("=" * 80) print("\nThese commands can be used in Zabbix CLI or adapted for the web interface.\n") for category, items in ZABBIX_ITEMS.items(): print(f"\n## {category.replace('_', ' ').title()}") print("-" * 80) for item in items: print(f"\n### {item['name']}") if 'oid' in item: print(f"OID: {item['oid']}") if 'formula' in item: print(f"Formula: {item['formula']}") print(f"Key: {item['key']}") print(f"Type: {item['type']}") if 'units' in item: print(f"Units: {item['units']}") print(f"Description: {item['description']}") if 'triggers' in item: print(f"\nRecommended Triggers:") for trigger in item['triggers']: print(f" - {trigger['severity'].upper()}: " f"{item['name']} {trigger['expression']} {trigger['threshold']}{item.get('units', '')}") print() def generate_zabbix_import_json(): """ Generate a Zabbix 7.4 importable JSON template Note: Zabbix requires UUIDs to be 32 characters without hyphens """ template = { "zabbix_export": { "version": "7.4", "template_groups": [ { "uuid": "3cd4e8d0b828464e8f4b3becf13a9dbd", "name": "Printers" } ], "templates": [ { "uuid": uuid.uuid4().hex, "template": "Printer SNMP Monitor", "name": "Printer SNMP Monitor", "groups": [ { "name": "Printers" } ], "items": [] } ] } } # Build items list with Zabbix 7.4 format for category, items in ZABBIX_ITEMS.items(): for item in items: # Handle calculated items differently if item['type'] == 'calculated': # Only add component:toner and color tags if this is a percentage item is_percentage = item.get('is_percentage', False) zabbix_item = { "uuid": uuid.uuid4().hex, "name": item['name'], "type": "CALCULATED", "key": item['key'], "delay": "1h", "history": "90d", "trends": "365d", "value_type": "FLOAT", "params": item['formula'], "description": item['description'], "tags": [ { "tag": "component", "value": "toner" if is_percentage else "printer" }, { "tag": "category", "value": category } ] } # Add color tag only for toner percentage items if is_percentage and 'color' in item: zabbix_item['tags'].append({ "tag": "color", "value": item['color'] }) else: # Use get[OID] for better performance in Zabbix 7.4 snmp_oid = f"get[{item['oid']}]" zabbix_item = { "uuid": uuid.uuid4().hex, "name": item['name'], "type": "SNMP_AGENT", "snmp_oid": snmp_oid, "key": item['key'], "delay": "1h", "history": "90d", "trends": "365d" if item['type'] != 'text' else "0d", "value_type": "TEXT" if item['type'] == 'text' else "FLOAT", "description": item['description'], "tags": [ { "tag": "component", "value": "printer" }, { "tag": "category", "value": category } ] } # Add inventory mapping for specific items if item['key'] == 'printer.model': zabbix_item['inventory_link'] = 'MODEL' elif item['key'] == 'printer.serial': zabbix_item['inventory_link'] = 'SERIALNO_A' elif item['key'] == 'printer.hostname': zabbix_item['inventory_link'] = 'NAME' elif item['key'] == 'printer.macaddress': zabbix_item['inventory_link'] = 'MACADDRESS_A' # Add preprocessing for text items to handle hex-encoded strings # Some SNMP values come as hex strings like "FD E8 48 50 20 4C 61..." # or as binary with control chars like "ýèHP LaserJet" if item['type'] == 'text': zabbix_item['preprocessing'] = [ { "type": "JAVASCRIPT", "parameters": [ "// Handle hex-encoded SNMP strings\n// Try multiple approaches to convert hex to ASCII\n\n// First, check if it looks like hex (with spaces, newlines, or other separators)\nvar hexPattern = /^[0-9A-Fa-f\\s]+$/;\nif (hexPattern.test(value) && value.length > 4) {\n // Extract all hex pairs (2 characters)\n var hexBytes = value.match(/[0-9A-Fa-f]{2}/g);\n if (hexBytes && hexBytes.length > 0) {\n var result = '';\n for (var i = 0; i < hexBytes.length; i++) {\n var code = parseInt(hexBytes[i], 16);\n // Only keep printable ASCII (0x20-0x7E)\n if (code >= 32 && code <= 126) {\n result += String.fromCharCode(code);\n }\n }\n if (result.length > 0) {\n return result;\n }\n }\n}\n\n// Fallback: Remove non-printable characters\nreturn value.replace(/[^\\x20-\\x7E]/g, '');" ] } ] if 'units' in item: zabbix_item['units'] = item['units'] # Add triggers if defined - nested inside the item if 'triggers' in item: zabbix_item['triggers'] = [] for trigger_def in item['triggers']: severity_map = { "warning": "WARNING", "high": "HIGH", "average": "AVERAGE" } template_name = template['zabbix_export']['templates'][0]['template'] # Build description and expression with part number reference description = f"{item['name']} has dropped below {trigger_def['threshold']}{item.get('units', '')}" # Build base expression expression = f"last(/{template_name}/{item['key']}){trigger_def['expression']}{trigger_def['threshold']}" # Add replacement part reference for toner items # We need to add the part number item to the expression so we can reference it with {ITEM.LASTVALUE2} if 'color' in item and category == "toner_levels": color = item['color'].lower() part_key = f"printer.cartridge.{color}" # Add the part number item to the expression using "and" so it's evaluated but doesn't affect trigger logic expression = f"last(/{template_name}/{item['key']}){trigger_def['expression']}{trigger_def['threshold']} and length(last(/{template_name}/{part_key}))>0" description += ". Replacement part: {ITEM.LASTVALUE2}" # Add replacement part reference for other items with part_number_item elif 'part_number_item' in item: part_key = item['part_number_item'] # Add the part number item to the expression using "and" so it's evaluated but doesn't affect trigger logic expression = f"last(/{template_name}/{item['key']}){trigger_def['expression']}{trigger_def['threshold']} and length(last(/{template_name}/{part_key}))>0" description += ". Replacement part: {ITEM.LASTVALUE2}" trigger = { "uuid": uuid.uuid4().hex, "expression": expression, "name": f"{item['name']} is low on {{{{HOST.NAME}}}}", "priority": severity_map.get(trigger_def['severity'], "WARNING"), "description": description, "tags": [ { "tag": "scope", "value": "availability" } ] } zabbix_item['triggers'].append(trigger) template["zabbix_export"]["templates"][0]["items"].append(zabbix_item) return template def main(): """ Main function """ print("\n" + "=" * 80) print("ZABBIX CONFIGURATION GENERATOR FOR PRINTER SNMP MONITORING") print("Includes: Toner, Maintenance Kit, Fuser, Drums, Waste, Transfer components") print("=" * 80) # Generate CLI-friendly output generate_zabbix_cli_commands() # Generate importable template print("\n" + "=" * 80) print("ZABBIX IMPORT TEMPLATE") print("=" * 80) print("\nSave this template to a file and import it into Zabbix:") print("Configuration -> Templates -> Import\n") template_data = generate_zabbix_import_json() # Save as YAML (like the working example) # Use default_flow_style=None to let PyYAML choose when to quote yaml_output = yaml.dump(template_data, default_flow_style=False, sort_keys=False, allow_unicode=True, width=1000) print(yaml_output) with open('zabbix_printer_template.yaml', 'w') as f: f.write(yaml_output) # Also save JSON version json_output = json.dumps(template_data, indent=2) with open('zabbix_printer_template.json', 'w') as f: f.write(json_output) print("\n" + "=" * 80) print(f"✓ Zabbix template saved to: zabbix_printer_template.yaml (YAML)") print(f"✓ Zabbix template saved to: zabbix_printer_template.json (JSON)") print("=" * 80) print("\n## Quick Setup Instructions:") print("1. Import zabbix_printer_template.json into Zabbix") print("2. Create/Edit a host for each printer") print("3. Set the SNMP interface with:") print(" - IP address: [printer IP]") print(" - Port: 161") print(f" - SNMP community: WestJeff2025") print(" - SNMP version: SNMPv2") print("4. Link the 'SNMP Printer Template (HP & Xerox) - Complete' to each host") print("5. Wait 1 hour for data collection to begin (or trigger manual check)") print("\n## What Gets Monitored:") print("✓ Toner levels (Black, Cyan, Magenta, Yellow)") print("✓ Cartridge part numbers for ordering") print("✓ Maintenance kit status (HP printers)") print("✓ Fuser assembly part number") print("✓ Drum cartridge part numbers (all colors)") print("✓ Waste cartridge part number") print("✓ Transfer belt/roller part numbers") print("✓ Supply capacity data for percentage calculations") print("\n## Triggers Configured:") print("- Warning: Toner < 20%") print("- Critical: Toner < 10%") print("- Warning: Maintenance kit < 10,000 pages") print("- Critical: Maintenance kit < 5,000 pages") print("\n## Notes:") print("- Not all OIDs exist on all printers (e.g., drums on HP, maintenance on Xerox)") print("- Color toner OIDs only exist on color printers") print("- HP-specific MIB items only work on HP printers") print("- Check interval is 1 hour (supplies don't change rapidly)") print() if __name__ == "__main__": main()