mirror of
https://github.com/Ircama/epson_print_conf.git
synced 2024-10-18 09:10:36 -04:00
Refinements
This commit is contained in:
parent
c8e79fe6f2
commit
388f3a7e56
2 changed files with 75 additions and 58 deletions
13
README.md
13
README.md
|
@ -28,7 +28,9 @@ Notes (at the time of writing):
|
||||||
- [before pysnmp, install pyasn1 with version 0.4.8 and not 0.5](https://github.com/etingof/pysnmp/issues/440#issuecomment-1544341598)
|
- [before pysnmp, install pyasn1 with version 0.4.8 and not 0.5](https://github.com/etingof/pysnmp/issues/440#issuecomment-1544341598)
|
||||||
- [pull pysnmp from the GitHub master branch, not from PyPI](https://stackoverflow.com/questions/54868134/snmp-reading-from-an-oid-with-three-libraries-gives-different-execution-times#comment96532761_54869361)
|
- [pull pysnmp from the GitHub master branch, not from PyPI](https://stackoverflow.com/questions/54868134/snmp-reading-from-an-oid-with-three-libraries-gives-different-execution-times#comment96532761_54869361)
|
||||||
|
|
||||||
Tested with Ubuntu / Windows Subsystem for Linux, Windows.
|
This program exploits [pysnmp](https://github.com/etingof/pysnmp), with related [documentation](https://pysnmp.readthedocs.io/).
|
||||||
|
|
||||||
|
It is tested with Ubuntu / Windows Subsystem for Linux, Windows.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
@ -65,7 +67,7 @@ optional arguments:
|
||||||
-r RETRIES, --retries RETRIES
|
-r RETRIES, --retries RETRIES
|
||||||
SNMP GET retries (floating point argument)
|
SNMP GET retries (floating point argument)
|
||||||
|
|
||||||
Epson Printer Configuration accessed via SNMP (TCP/IP)
|
Epson Printer Configuration via SNMP (TCP/IP)
|
||||||
```
|
```
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
@ -138,6 +140,13 @@ printer.brute_force_read_key()
|
||||||
printer.write_first_ti_received_time(2000, 1, 2)
|
printer.write_first_ti_received_time(2000, 1, 2)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Exception
|
||||||
|
|
||||||
|
```
|
||||||
|
TimeoutError
|
||||||
|
(pysnmp exceptions)
|
||||||
|
```
|
||||||
|
|
||||||
## Output example
|
## Output example
|
||||||
Example of advanced printer status with an XP-205 printer:
|
Example of advanced printer status with an XP-205 printer:
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import time
|
||||||
import textwrap
|
import textwrap
|
||||||
import ast
|
import ast
|
||||||
from pysnmp.hlapi.v1arch import *
|
from pysnmp.hlapi.v1arch import *
|
||||||
|
from pyasn1.type.univ import OctetString as OctetStringType
|
||||||
|
|
||||||
|
|
||||||
class EpsonPrinter:
|
class EpsonPrinter:
|
||||||
|
@ -429,28 +430,29 @@ class EpsonPrinter:
|
||||||
errorIndication, errorStatus, errorIndex, varBinds = response
|
errorIndication, errorStatus, errorIndex, varBinds = response
|
||||||
if errorIndication:
|
if errorIndication:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("snmp_mib error", errorIndication)
|
print("snmp_mib error:", errorIndication)
|
||||||
|
if " timed out" in errorIndication:
|
||||||
|
raise TimeoutError(errorIndication)
|
||||||
return False
|
return False
|
||||||
elif errorStatus:
|
elif errorStatus:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(
|
print(
|
||||||
'snmp_mib error: %s at %s' % (
|
'snmp_mib PDU error: %s at %s' % (
|
||||||
errorStatus.prettyPrint(),
|
errorStatus.prettyPrint(),
|
||||||
errorIndex and varBinds[int(errorIndex) - 1][0] or '?')
|
errorIndex and varBinds[int(errorIndex) - 1][0] or '?')
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
for varBind in varBinds:
|
for varBind in varBinds:
|
||||||
try:
|
if isinstance(varBind[1], OctetStringType):
|
||||||
return "".join(
|
return varBind[1].asOctets()
|
||||||
[chr(x) for x in varBind[1].asNumbers()])
|
else:
|
||||||
except Exception:
|
|
||||||
return varBind[1].prettyPrint()
|
return varBind[1].prettyPrint()
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("snmp_mib error: invalid multiple data")
|
print("snmp_mib value error: invalid multiple data")
|
||||||
return False
|
return False
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("snmp_mib error: invalid multiple data")
|
print("snmp_mib value error: invalid data")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def read_eeprom(
|
def read_eeprom(
|
||||||
|
@ -467,10 +469,12 @@ class EpsonPrinter:
|
||||||
)
|
)
|
||||||
response = self.snmp_mib(
|
response = self.snmp_mib(
|
||||||
self.eeprom_oid_read_address(oid, label=label))
|
self.eeprom_oid_read_address(oid, label=label))
|
||||||
|
if not response:
|
||||||
|
return None
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(f" RESPONSE: {repr(response)}")
|
print(f" RESPONSE: {repr(response)}")
|
||||||
try:
|
try:
|
||||||
response = re.findall(r"EE:[0-9A-F]{6}", response)[0][3:]
|
response = re.findall(r"EE:[0-9A-F]{6}", response.decode())[0][3:]
|
||||||
except (TypeError, IndexError):
|
except (TypeError, IndexError):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(f"Invalid read key.")
|
print(f"Invalid read key.")
|
||||||
|
@ -507,14 +511,7 @@ class EpsonPrinter:
|
||||||
response = self.read_eeprom(oid, label=label)
|
response = self.read_eeprom(oid, label=label)
|
||||||
print(f"Previous value for {label}: {response}")
|
print(f"Previous value for {label}: {response}")
|
||||||
oid_string = self.eeprom_oid_write_address(oid, value, label=label)
|
oid_string = self.eeprom_oid_write_address(oid, value, label=label)
|
||||||
response = None
|
response = self.snmp_mib(oid_string)
|
||||||
try:
|
|
||||||
response = self.get(oid_string)
|
|
||||||
except easysnmp.exceptions.EasySNMPTimeoutError as e:
|
|
||||||
if not self.dry_run:
|
|
||||||
raise TimeoutError(str(e))
|
|
||||||
except Exception as e:
|
|
||||||
raise ValueError(str(e))
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(
|
print(
|
||||||
f"EEPROM_WRITE {label}:\n"
|
f"EEPROM_WRITE {label}:\n"
|
||||||
|
@ -522,9 +519,11 @@ class EpsonPrinter:
|
||||||
f" OID: {oid}={hex(oid)}"
|
f" OID: {oid}={hex(oid)}"
|
||||||
)
|
)
|
||||||
if self.debug and response:
|
if self.debug and response:
|
||||||
print(f" RESPONSE: {repr(response.value)}")
|
print(f" RESPONSE: {repr(response)}")
|
||||||
if response and not ":OK;" in repr(response.value): # ":NA;" is an error
|
if not self.dry_run and response and not ":OK;" in repr(response):
|
||||||
return False
|
if self.debug:
|
||||||
|
print("Write error")
|
||||||
|
return False # ":NA;" is an error
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def status_parser(self, data):
|
def status_parser(self, data):
|
||||||
|
@ -690,23 +689,21 @@ class EpsonPrinter:
|
||||||
else:
|
else:
|
||||||
snmp_info = self.snmp_info
|
snmp_info = self.snmp_info
|
||||||
for name, oid in snmp_info.items():
|
for name, oid in snmp_info.items():
|
||||||
try:
|
result = self.snmp_mib(oid)
|
||||||
sys_info[name] = self.snmp_mib(oid)
|
if name == "hex_data" and result is not False:
|
||||||
except Exception as e:
|
sys_info[name] = result.hex(" ").upper()
|
||||||
|
elif name == "UpTime" and result is not False:
|
||||||
|
sys_info[name] = time.strftime(
|
||||||
|
'%H:%M:%S', time.gmtime(int(result)/100))
|
||||||
|
elif name == "MAC Address" and result is not False:
|
||||||
|
sys_info[name] = result.hex("-").upper()
|
||||||
|
elif isinstance(result, bytes):
|
||||||
|
sys_info[name] = result.decode()
|
||||||
|
elif isinstance(result, str):
|
||||||
|
sys_info[name] = result
|
||||||
|
else:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(
|
print(f"No value for SNMP OID '{name}'. MIB: {oid}.")
|
||||||
f"No value for SNMP OID '{name}'. "
|
|
||||||
f"MIB: {oid}. Error: {e}"
|
|
||||||
)
|
|
||||||
if "hex_data" in sys_info and sys_info["hex_data"] is not False:
|
|
||||||
sys_info["hex_data"] = bytes(
|
|
||||||
[ord(i) for i in sys_info["hex_data"]]).hex(" ").upper()
|
|
||||||
if "UpTime" in sys_info and sys_info["UpTime"] is not False:
|
|
||||||
sys_info["UpTime"] = time.strftime(
|
|
||||||
'%H:%M:%S', time.gmtime(int(sys_info["UpTime"])/100))
|
|
||||||
if "MAC Address" in sys_info and sys_info["MAC Address"] is not False:
|
|
||||||
sys_info["MAC Address"] = bytes(
|
|
||||||
[ord(i) for i in sys_info["MAC Address"]]).hex("-").upper()
|
|
||||||
return sys_info
|
return sys_info
|
||||||
|
|
||||||
def get_serial_number(self) -> str:
|
def get_serial_number(self) -> str:
|
||||||
|
@ -766,7 +763,8 @@ class EpsonPrinter:
|
||||||
f"{self.eeprom_link}.118.105.1.0.0")
|
f"{self.eeprom_link}.118.105.1.0.0")
|
||||||
if not firmware_string:
|
if not firmware_string:
|
||||||
return None
|
return None
|
||||||
firmware = re.sub(r".*vi:00:(.{6}).*", r'\g<1>', firmware_string)
|
firmware = re.sub(
|
||||||
|
r".*vi:00:(.{6}).*", r'\g<1>', firmware_string.decode())
|
||||||
year = ord(firmware[4:5]) + 1945
|
year = ord(firmware[4:5]) + 1945
|
||||||
month = int(firmware[5:], 16)
|
month = int(firmware[5:], 16)
|
||||||
day = int(firmware[2:4])
|
day = int(firmware[2:4])
|
||||||
|
@ -780,7 +778,10 @@ class EpsonPrinter:
|
||||||
if not cartridges_string:
|
if not cartridges_string:
|
||||||
return None
|
return None
|
||||||
cartridges = re.sub(
|
cartridges = re.sub(
|
||||||
r".*IA:00;(.*);.*", r'\g<1>', cartridges_string, flags=re.S)
|
r".*IA:00;(.*);.*", r'\g<1>',
|
||||||
|
cartridges_string.decode(),
|
||||||
|
flags=re.S
|
||||||
|
)
|
||||||
return [i.strip() for i in cartridges.split(',')]
|
return [i.strip() for i in cartridges.split(',')]
|
||||||
|
|
||||||
def get_ink_replacement_counters(self) -> str:
|
def get_ink_replacement_counters(self) -> str:
|
||||||
|
@ -810,13 +811,12 @@ class EpsonPrinter:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(
|
print(
|
||||||
textwrap.fill(
|
textwrap.fill(
|
||||||
"PRINTER_STATUS: " + bytes(
|
"PRINTER_STATUS: " + repr(result),
|
||||||
[ord(i) for i in result]).hex(" "),
|
|
||||||
initial_indent="",
|
initial_indent="",
|
||||||
subsequent_indent=" ",
|
subsequent_indent=" ",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return self.status_parser(bytes([ord(i) for i in result]))
|
return self.status_parser(result)
|
||||||
|
|
||||||
def get_waste_ink_levels(self):
|
def get_waste_ink_levels(self):
|
||||||
"""Return waste ink levels as a percentage."""
|
"""Return waste ink levels as a percentage."""
|
||||||
|
@ -892,12 +892,20 @@ class EpsonPrinter:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def list_known_keys(self, debug=False):
|
def list_known_keys(self):
|
||||||
for model, chars in self.PRINTER_CONFIG.items():
|
for model, chars in self.PRINTER_CONFIG.items():
|
||||||
if 'write_key' in chars:
|
if 'write_key' in chars:
|
||||||
print(f"{repr(model).rjust(25)}: {repr(chars['read_key']).rjust(10)} - {repr(chars['write_key'])[1:]}")
|
print(
|
||||||
|
f"{repr(model).rjust(25)}: "
|
||||||
|
f"{repr(chars['read_key']).rjust(10)} - "
|
||||||
|
f"{repr(chars['write_key'])[1:]}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
print(f"{repr(model).rjust(25)}: {repr(chars['read_key']).rjust(10)} (unknown write key)")
|
print(
|
||||||
|
f"{repr(model).rjust(25)}: "
|
||||||
|
f"{repr(chars['read_key']).rjust(10)} "
|
||||||
|
f"(unknown write key)"
|
||||||
|
)
|
||||||
|
|
||||||
def brute_force_read_key(
|
def brute_force_read_key(
|
||||||
self, minimum: int = 0x00, maximum: int = 0xFF, debug=False
|
self, minimum: int = 0x00, maximum: int = 0xFF, debug=False
|
||||||
|
@ -926,7 +934,7 @@ if __name__ == "__main__":
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
epilog='Epson Printer Configuration accessed via SNMP (TCP/IP)')
|
epilog='Epson Printer Configuration via SNMP (TCP/IP)')
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-m',
|
'-m',
|
||||||
|
@ -1056,25 +1064,25 @@ if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
if args.ws_to_string:
|
if args.ws_to_string:
|
||||||
print_opt = True
|
print_opt = True
|
||||||
print(self.write_sequence_to_string(args.ws_to_string))
|
print(printer.write_sequence_to_string(args.ws_to_string))
|
||||||
if args.reset_waste_ink:
|
if args.reset_waste_ink:
|
||||||
print_opt = True
|
print_opt = True
|
||||||
if self.reset_waste_ink_levels():
|
if printer.reset_waste_ink_levels():
|
||||||
print("Reset waste ink levels done.")
|
print("Reset waste ink levels done.")
|
||||||
else:
|
else:
|
||||||
print("Failed to reset waste ink levels. Check configuration.")
|
print("Failed to reset waste ink levels. Check configuration.")
|
||||||
if args.detect_key:
|
if args.detect_key:
|
||||||
print_opt = True
|
print_opt = True
|
||||||
read_key = self.brute_force_read_key(debug=True)
|
read_key = printer.brute_force_read_key(debug=True)
|
||||||
if read_key:
|
if read_key:
|
||||||
print(f"read_key found: {read_key}")
|
print(f"read_key found: {read_key}")
|
||||||
print("List of known keys:")
|
print("List of known keys:")
|
||||||
self.list_known_keys(debug=True)
|
printer.list_known_keys()
|
||||||
else:
|
else:
|
||||||
print(f"Cannot found read_key")
|
print(f"Cannot found read_key")
|
||||||
if args.ftrt:
|
if args.ftrt:
|
||||||
print_opt = True
|
print_opt = True
|
||||||
if self.write_first_ti_received_time(
|
if printer.write_first_ti_received_time(
|
||||||
int(args.ftrt[0]), int(args.ftrt[1]), int(args.ftrt[2])):
|
int(args.ftrt[0]), int(args.ftrt[1]), int(args.ftrt[2])):
|
||||||
print("Write first TI received time done.")
|
print("Write first TI received time done.")
|
||||||
else:
|
else:
|
||||||
|
@ -1084,7 +1092,7 @@ if __name__ == "__main__":
|
||||||
)
|
)
|
||||||
if args.dump_eeprom:
|
if args.dump_eeprom:
|
||||||
print_opt = True
|
print_opt = True
|
||||||
for addr, val in self.dump_eeprom(
|
for addr, val in printer.dump_eeprom(
|
||||||
args.dump_eeprom[0] % 256,
|
args.dump_eeprom[0] % 256,
|
||||||
int(args.dump_eeprom[1] % 256)
|
int(args.dump_eeprom[1] % 256)
|
||||||
).items():
|
).items():
|
||||||
|
@ -1093,13 +1101,13 @@ if __name__ == "__main__":
|
||||||
print_opt = True
|
print_opt = True
|
||||||
if ("stats" in printer.parm and
|
if ("stats" in printer.parm and
|
||||||
args.query[0] in printer.parm["stats"]):
|
args.query[0] in printer.parm["stats"]):
|
||||||
ret = self.get_stats(args.query[0])
|
ret = printer.get_stats(args.query[0])
|
||||||
if ret:
|
if ret:
|
||||||
pprint(ret)
|
pprint(ret)
|
||||||
else:
|
else:
|
||||||
print("No information returned. Check printer definition.")
|
print("No information returned. Check printer definition.")
|
||||||
elif args.query[0] in printer.snmp_info.keys():
|
elif args.query[0] in printer.snmp_info.keys():
|
||||||
ret = self.get_snmp_info(args.query[0])
|
ret = printer.get_snmp_info(args.query[0])
|
||||||
if ret:
|
if ret:
|
||||||
pprint(ret)
|
pprint(ret)
|
||||||
else:
|
else:
|
||||||
|
@ -1110,7 +1118,7 @@ if __name__ == "__main__":
|
||||||
else:
|
else:
|
||||||
method = "get_" + args.query[0]
|
method = "get_" + args.query[0]
|
||||||
if method in printer.list_methods:
|
if method in printer.list_methods:
|
||||||
ret = self.__getattribute__(method)()
|
ret = printer.__getattribute__(method)()
|
||||||
if ret:
|
if ret:
|
||||||
pprint(ret)
|
pprint(ret)
|
||||||
else:
|
else:
|
||||||
|
@ -1146,7 +1154,7 @@ if __name__ == "__main__":
|
||||||
read_list = re.split(',\s*', args.read_eeprom[0])
|
read_list = re.split(',\s*', args.read_eeprom[0])
|
||||||
for value in read_list:
|
for value in read_list:
|
||||||
try:
|
try:
|
||||||
val = self.read_eeprom(
|
val = printer.read_eeprom(
|
||||||
ast.literal_eval(value), label='read_eeprom')
|
ast.literal_eval(value), label='read_eeprom')
|
||||||
if val is None:
|
if val is None:
|
||||||
print("EEPROM read error.")
|
print("EEPROM read error.")
|
||||||
|
@ -1162,7 +1170,7 @@ if __name__ == "__main__":
|
||||||
key, val = re.split(':|=', key_val)
|
key, val = re.split(':|=', key_val)
|
||||||
try:
|
try:
|
||||||
val_int = ast.literal_eval(val)
|
val_int = ast.literal_eval(val)
|
||||||
if not self.write_eeprom(
|
if not printer.write_eeprom(
|
||||||
ast.literal_eval(key),
|
ast.literal_eval(key),
|
||||||
str(val_int), label='write_eeprom'
|
str(val_int), label='write_eeprom'
|
||||||
):
|
):
|
||||||
|
|
Loading…
Reference in a new issue