mirror of
https://github.com/Ircama/epson_print_conf.git
synced 2025-05-21 10:45:17 -04:00
Bug fix
This commit is contained in:
parent
f14cd91b8e
commit
4b3cdfc7e3
2 changed files with 89 additions and 39 deletions
22
README.md
22
README.md
|
@ -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:
|
||||||
|
|
106
parse_devices.py
106
parse_devices.py
|
@ -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:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue