This commit is contained in:
Ircama 2024-08-01 01:08:37 +02:00
parent f14cd91b8e
commit 4b3cdfc7e3
2 changed files with 89 additions and 39 deletions

View file

@ -185,7 +185,7 @@ An alternative way to create the executable file named *epson_print_conf.exe* fr
pyinstaller --onefile ui.py --name epson_print_conf --hidden-import babel.numbers --windowed pyinstaller --onefile ui.py --name epson_print_conf --hidden-import babel.numbers --windowed
``` ```
A file named *gui.py* is also included (similar to *ui.py*), which automatically loads a previously created configuration file that has to be named *printer_conf.pickle*, merging it with the program configuration. To build the executable program with this file instead of the default *ui.py*, run the following command: A file named *gui.py* is also included (similar to *ui.py*), which automatically loads a previously created configuration file that has to be named *printer_conf.pickle*, merging it with the program configuration. (See below the *parse_devices.py* utility.) To build the executable program with this file instead of the default *ui.py*, run the following command:
```bash ```bash
pip install pyinstaller # if not yet installed pip install pyinstaller # if not yet installed
@ -200,7 +200,7 @@ When the build operation is completed, you can run the *epson_print_conf.exe* fi
### parse_devices.py ### parse_devices.py
Within an [issue](https://codeberg.org/atufi/reinkpy/issues/12#issue-716809) in repo https://codeberg.org/atufi/reinkpy there is an interesting [attachment](https://codeberg.org/attachments/147f41a3-a6ea-45f6-8c2a-25bac4495a1d) which reports an extensive XML database of Epson model features. Within a [report](https://codeberg.org/atufi/reinkpy/issues/12#issue-716809) in repo https://codeberg.org/atufi/reinkpy there is an interesting [attachment](https://codeberg.org/attachments/147f41a3-a6ea-45f6-8c2a-25bac4495a1d) which includes an extensive XML database of Epson model features.
The program *parse_devices.py* transforms this XML DB into the dictionary that *epson_print_conf.py* can use. The program *parse_devices.py* transforms this XML DB into the dictionary that *epson_print_conf.py* can use.
@ -211,7 +211,7 @@ curl -o devices.xml https://codeberg.org/attachments/147f41a3-a6ea-45f6-8c2a-25b
python3 parse_devices.py -i -m XP-205 python3 parse_devices.py -i -m XP-205
``` ```
After generating the related printer configuration, *epson_print_conf.py* shall be manually edited to copy/paste the output of *parse_devices.py* within its PRINTER_CONFIG dictionary. Alternatively, the program is able to create a *pickle* configuration file, which the other programs can load. After generating the related printer configuration, *epson_print_conf.py* shall be manually edited to copy/paste the output of *parse_devices.py* within its PRINTER_CONFIG dictionary. Alternatively, the program is able to create a *pickle* configuration file (check the `-p` lowercase option), which the other programs can load (with the `-P` uppercase option and in addition with the optional `-O` flag).
The `-m` option is optional and is used to filter the printer model in scope. If the produced output is not referred to the target model, use part of the model name as a filter (e.g., only the digits, like `parse_devices.py -i -m 315`) and select the appropriate model from the output. The `-m` option is optional and is used to filter the printer model in scope. If the produced output is not referred to the target model, use part of the model name as a filter (e.g., only the digits, like `parse_devices.py -i -m 315`) and select the appropriate model from the output.
@ -264,9 +264,9 @@ Output example:
### Other utilities ### Other utilities
``` ```
import epson_print_conf from epson_print_conf import EpsonPrinter
import pprint import pprint
printer = epson_print_conf.EpsonPrinter() printer = EpsonPrinter()
# Decode write_key: # Decode write_key:
printer.reverse_caesar(bytes.fromhex("48 62 7B 62 6F 6A 62 2B")) # last 8 bytes printer.reverse_caesar(bytes.fromhex("48 62 7B 62 6F 6A 62 2B")) # last 8 bytes
@ -288,12 +288,12 @@ ink_level = int("".join(reversed(byte_sequence.split())), 16)
waste_percent = round(ink_level / divider, 2) waste_percent = round(ink_level / divider, 2)
# Print the read key sequence in byte and hex formats: # Print the read key sequence in byte and hex formats:
printer = epson_print_conf.EpsonPrinter(model="ET-2700") printer = EpsonPrinter(model="ET-2700")
'.'.join(str(x) for x in printer.parm['read_key']) '.'.join(str(x) for x in printer.parm['read_key'])
" ".join('{0:02x}'.format(x) for x in printer.parm['read_key']) " ".join('{0:02x}'.format(x) for x in printer.parm['read_key'])
# Print the write key sequence in byte and hex formats: # Print the write key sequence in byte and hex formats:
printer = epson_print_conf.EpsonPrinter(model="ET-2700") printer = EpsonPrinter(model="ET-2700")
printer.caesar(printer.parm['write_key']) printer.caesar(printer.parm['write_key'])
printer.caesar(printer.parm['write_key'], hex=True).upper() printer.caesar(printer.parm['write_key'], hex=True).upper()
@ -311,9 +311,9 @@ for key, value in printer.parm["raw_waste_reset"].items():
Generic query of the status of the printer (regardless of the model): Generic query of the status of the printer (regardless of the model):
``` ```
import epson_print_conf from epson_print_conf import EpsonPrinter
import pprint import pprint
printer = epson_print_conf.EpsonPrinter(hostname="192.168.1.87") printer = EpsonPrinter(hostname="192.168.1.87")
pprint.pprint(printer.status_parser(printer.snmp_mib("1.3.6.1.4.1.1248.1.2.2.1.1.1.4.1")[1])) pprint.pprint(printer.status_parser(printer.snmp_mib("1.3.6.1.4.1.1248.1.2.2.1.1.1.4.1")[1]))
``` ```
@ -393,12 +393,12 @@ ValueError
### Sample ### Sample
```python ```python
import epson_print_conf from epson_print_conf import EpsonPrinter
import logging import logging
logging.basicConfig(level=logging.DEBUG, format="%(message)s") # if logging is needed logging.basicConfig(level=logging.DEBUG, format="%(message)s") # if logging is needed
printer = epson_print_conf.EpsonPrinter( printer = EpsonPrinter(
model="XP-205", hostname="192.168.1.87") model="XP-205", hostname="192.168.1.87")
if not printer.parm: if not printer.parm:

View file

@ -7,6 +7,11 @@ import textwrap
from ui import get_printer_models from ui import get_printer_models
WASTE_LABELS = [
"main_waste", "borderless_waste", "third_waste", "fourth_waste",
"fifth_waste", "sixth_waste"
]
def to_ranges(iterable): def to_ranges(iterable):
iterable = sorted(set(iterable)) iterable = sorted(set(iterable))
for key, group in itertools.groupby(enumerate(iterable), for key, group in itertools.groupby(enumerate(iterable),
@ -46,10 +51,6 @@ def traverse_data(element, depth=0):
def generate_config(config, traverse, add_fatal_errors, full, printer_model): def generate_config(config, traverse, add_fatal_errors, full, printer_model):
waste_string = [
"main_waste", "borderless_waste", "third_waste", "fourth_waste",
"fifth_waste", "sixth_waste"
]
irc_pattern = [ irc_pattern = [
r'Ink replacement counter %-% (\w+) % \((\w+)\)' r'Ink replacement counter %-% (\w+) % \((\w+)\)'
] ]
@ -183,7 +184,7 @@ def generate_config(config, traverse, add_fatal_errors, full, printer_model):
waste["oids"] += text_to_bytes(counter.text) waste["oids"] += text_to_bytes(counter.text)
else: else:
waste["oids"] = text_to_bytes(counter.text) waste["oids"] = text_to_bytes(counter.text)
chars[waste_string[count]] = waste chars[WASTE_LABELS[count]] = waste
count += 1 count += 1
if item.tag == "serial": if item.tag == "serial":
chars["serial_number"] = text_to_bytes(item.text) chars["serial_number"] = text_to_bytes(item.text)
@ -223,8 +224,10 @@ def normalize_config(
remove_invalid, remove_invalid,
expand_names, expand_names,
add_alias, add_alias,
aggregate_alias,
add_same_as, add_same_as,
): ):
logging.info("Number of configuration entries before removing invalid ones: %s", len(config))
# Remove printers without write_key or without read_key # Remove printers without write_key or without read_key
if remove_invalid: if remove_invalid:
for base_key, base_items in config.copy().items(): for base_key, base_items in config.copy().items():
@ -236,6 +239,7 @@ def normalize_config(
continue continue
# Replace original names with converted names and add printers for all optional names # Replace original names with converted names and add printers for all optional names
logging.info("Number of configuration entries before adding optional names: %s", len(config))
if expand_names: if expand_names:
for key, items in config.copy().items(): for key, items in config.copy().items():
printer_list = get_printer_models(key) printer_list = get_printer_models(key)
@ -247,6 +251,7 @@ def normalize_config(
config[i] = items config[i] = items
# Add aliases for same printer with different names and remove aliased printers # Add aliases for same printer with different names and remove aliased printers
logging.info("Number of configuration entries before removing aliases: %s", len(config))
if add_alias: if add_alias:
for base_key, base_items in config.copy().items(): for base_key, base_items in config.copy().items():
found = False found = False
@ -263,9 +268,9 @@ def normalize_config(
config[base_key]["alias"].append(i) config[base_key]["alias"].append(i)
del config[key] del config[key]
# Add "same-as" for almost same printer (IGNORED_KEYS) with different names # Aggregate aliases
if add_same_as: logging.info("Number of configuration entries before aggregating aliases: %s", len(config))
IGNORED_KEYS = ['write_key', 'read_key', 'alias', 'main_waste', 'borderless_waste'] if aggregate_alias:
for base_key, base_items in config.copy().items(): for base_key, base_items in config.copy().items():
found = False found = False
for key, items in config.copy().items(): for key, items in config.copy().items():
@ -273,27 +278,59 @@ def normalize_config(
if base_key == key and base_key in config: if base_key == key and base_key in config:
found = True found = True
continue continue
if base_key != key: if base_key != key and equal_dicts(base_items, items, ["alias"]): # everything but the alias is the same
if equal_dicts(base_items, items, IGNORED_KEYS): # everything but the IGNORED_KEYS is the same base_items["alias"] = sorted(list(set(
# Get the IGNORED_KEYS from the printer (base_items["alias"] if "alias" in base_items else [])
write_key = base_items['write_key'] + (items["alias"] if "alias" in items else [])
read_key = base_items['read_key'] + [key]
alias = base_items['alias'] if 'alias' in base_items else [] )))
main_waste = base_items['main_waste'] if 'main_waste' in base_items else [] del config[key]
borderless_waste = base_items['borderless_waste'] if 'borderless_waste' in base_items else []
# Rebuild the printer with only the IGNORED_KEYS, then add the 'same-as'
del config[base_key]
config[base_key] = {}
config[base_key]['write_key'] = write_key
config[base_key]['read_key'] = read_key
if alias:
config[base_key]['alias'] = alias
if main_waste:
config[base_key]['main_waste'] = main_waste
if borderless_waste:
config[base_key]['borderless_waste'] = borderless_waste
config[base_key]['same-as'] = key
# Add "same-as" for almost same printer (IGNORED_KEYS) with different names
if add_same_as:
IGNORED_KEYS = [ # 'alias' must always be present
['write_key', 'read_key', 'alias'],
['write_key', 'read_key', 'alias'] + WASTE_LABELS,
]
for ignored_keys in IGNORED_KEYS:
same_as_counter = 0
for base_key, base_items in config.copy().items():
found = False
for key, items in config.copy().items():
if not found:
if base_key == key and base_key in config:
found = True
continue
if base_key != key and 'same-as' not in base_key:
if equal_dicts(base_items, items, ignored_keys): # everything but the ignored keys is the same
# Rebuild the printer with only the ignored keys, then add the 'same-as'
config[base_key] = {}
for i in ignored_keys:
if i in base_items:
config[base_key][i] = base_items[i]
config[base_key]['same-as'] = key
same_as_counter += 1
logging.info("Number of added 'same-as' entries with %s: %s", ignored_keys, same_as_counter)
# Aggregate aliases
logging.info("Number of configuration entries before aggregating aliases: %s", len(config))
if aggregate_alias:
for base_key, base_items in config.copy().items():
found = False
for key, items in config.copy().items():
if not found:
if base_key == key and base_key in config:
found = True
continue
if base_key != key and equal_dicts(base_items, items, ["alias"]): # everything but the alias is the same
base_items["alias"] = sorted(list(set(
(base_items["alias"] if "alias" in base_items else [])
+ (items["alias"] if "alias" in items else [])
+ [key]
)))
del config[key]
logging.info("Number of obtained configuration entries: %s", len(config))
return config return config
def equal_dicts(a, b, ignore_keys): def equal_dicts(a, b, ignore_keys):
@ -421,6 +458,13 @@ if __name__ == "__main__":
action='store_true', action='store_true',
help='Do not add aliases for same printer with different names and remove aliased printers' help='Do not add aliases for same printer with different names and remove aliased printers'
) )
parser.add_argument(
'-G',
'--no_aggregate_alias',
dest='no_aggregate_alias',
action='store_true',
help='Do not aggregate aliases of printers with same configuration'
)
parser.add_argument( parser.add_argument(
'-S', '-S',
'--no_same_as', '--no_same_as',
@ -456,8 +500,10 @@ if __name__ == "__main__":
remove_invalid=not args.keep_invalid, remove_invalid=not args.keep_invalid,
expand_names=not args.keep_names, expand_names=not args.keep_names,
add_alias=not args.no_alias, add_alias=not args.no_alias,
aggregate_alias=not args.no_aggregate_alias,
add_same_as=not args.no_same_as, add_same_as=not args.no_same_as,
) )
if args.default_model: if args.default_model:
if "internal_data" not in normalized_config: if "internal_data" not in normalized_config:
normalized_config["internal_data"] = {} normalized_config["internal_data"] = {}
@ -469,6 +515,10 @@ if __name__ == "__main__":
if args.pickle: if args.pickle:
pickle.dump(normalized_config, args.pickle[0]) # serialize the list pickle.dump(normalized_config, args.pickle[0]) # serialize the list
args.pickle[0].close() args.pickle[0].close()
from epson_print_conf import EpsonPrinter
ep = EpsonPrinter(conf_dict=normalized_config, replace_conf=True)
logging.info("Number of expanded configuration entries: %s", len(ep.PRINTER_CONFIG))
quit() quit()
try: try: