Skip to content

Commit

Permalink
Merge pull request #57 from vulpes2/settings
Browse files Browse the repository at this point in the history
Power settings and TZe color info
  • Loading branch information
matmair authored Aug 6, 2024
2 parents 95bcb9d + e5bb09c commit f4c7d2b
Show file tree
Hide file tree
Showing 3 changed files with 307 additions and 56 deletions.
153 changes: 141 additions & 12 deletions brother_ql/backends/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,12 @@ def send(instructions, printer_identifier=None, backend_identifier=None, blockin

return status


def status(
def get_printer(
printer_identifier=None,
backend_identifier=None,
):
"""
Retrieve status info from the printer, including model and currently loaded media size.
Instantiate a printer object for communication. Only bidirectional transport backends are supported.
:param str printer_identifier: Identifier for the printer.
:param str backend_identifier: Can enforce the use of a specific backend.
Expand All @@ -131,21 +130,151 @@ def status(
be = backend_factory(selected_backend)
BrotherQLBackend = be["backend_class"]
printer = BrotherQLBackend(printer_identifier)
return printer

logger.info("Sending status information request to the printer.")
printer.write(b"\x1b\x69\x53") # "ESC i S" Status information request
def get_status(
printer,
receive_only=False,
target_status=None,
):
"""
Get printer status.
:param BrotherQLBackendGeneric printer: A printer instance.
:param bool receive_only: Don't send the status request command.
:param int target_status: Expected status code.
"""

if not receive_only:
printer.write(b"\x1b\x69\x53") # "ESC i S" Status information request
data = printer.read()
try:
result = interpret_response(data)
except ValueError:
logger.error("Failed to parse response data: %s", data)
if target_status is not None:
if result['status_code'] != target_status:
raise ValueError(f"Printer reported 0x{result['status_code']:02x} status instead of 0x{target_status:02x}")
return result


def get_setting(
printer,
setting,
payload=None
):
"""
Get setting from printer.
logger.info(f"Printer Series Code: 0x{result['series_code']:02x}")
logger.info(f"Printer Model Code: 0x{result['model_code']:02x}")
logger.info(f"Printer Status Type: {result['status_type']} ")
logger.info(f"Printer Phase Type: {result['phase_type']})")
logger.info(f"Printer Errors: {result['errors']}")
logger.info(f"Media Type: {result['media_type']}")
logger.info(f"Media Size: {result['media_width']} x {result['media_length']} mm")
:param BrotherQLBackendGeneric printer: A printer instance.
:param int setting: The code for the setting.
:param bytes payload: Optional additional payload, usually not required.
"""

# ensure printer is free of errors before proceeding
get_status(printer, target_status=0x0)
# switch to raster command mode
printer.write(b"\x1b\x69\x61\x01")
# send command
# 0x1b 0x69 0x55 setting
# u8 setting
# 0x01 read
# optional extra payload
command = b"\x1b\x69\x55" + setting.to_bytes(1) + b"\x01"
if payload is not None:
command += payload
printer.write(command)
result = get_status(printer, receive_only=True, target_status=0xF0)
return result


def write_setting(
printer,
setting,
payload,
):
"""
Write setting to printer.
:param BrotherQLBackendGeneric printer: A printer instance.
:param int setting: The code for the setting.
:param bytes payload: Payload for the setting.
"""

# switch to raster command mode
printer.write(b"\x1b\x69\x61\x01")
# write settings
# 0x1b 0x69 0x55 setting
# u8 setting
# 0x0 write
# payload (size dependent on setting and machine series)
command = b"\x1b\x69\x55" + setting.to_bytes(1) + b"\x00"
command += payload
printer.write(command)
# retrieve status to make sure no errors occured
result = get_status(printer)
if result['status_code'] != 0x0:
raise ValueError("Failed to modify settings")
return result


def configure(
printer_identifier=None,
backend_identifier=None,
action="get",
key=None,
value=None,
):
"""
Read or modify power settings.
:param str printer_identifier: Identifier for the printer
:param str backend_identifier: Can enforce the use of a specific backend
:param str action: Action to perform, get or set
:param str key: Key name for the settings
:param int value: Value to update for the specified key
"""

printer=get_printer(printer_identifier, backend_identifier)

if action not in ['get', 'set']:
raise ValueError(f"Invalid action '{action}'")
if key not in ['power-off-delay', 'auto-power-on']:
raise ValueError(f"Invalid key '{key}'")
if action == 'set':
if value is None:
raise ValueError(f"Specify a valid value for key '{key}'")

series_code = get_status(printer, target_status=0x0)['series_code']

if action == 'set':
if key == 'auto-power-on':
payload = value.to_bytes(1)
write_setting(printer, 0x70, payload)
get_status(printer, 0x0)
elif key == 'power-off-delay':
payload = b''
# 0x30 series needs an extra byte here
if series_code == 0x30:
payload += b"\x00"
payload += value.to_bytes(1)
write_setting(printer, 0x41, payload)
get_status(printer, 0x0)
else:
raise ValueError(f"Key {key} is invalid")

# retrieve settings
retrieved_val = None
if key == 'auto-power-on':
retrieved_val = get_setting(printer, 0x70)['setting']
elif key == 'power-off-delay':
payload = b''
# 0x30 series needs an extra byte here
if series_code == 0x30:
payload += b"\x00"
retrieved_val = get_setting(printer, 0x41, payload)['setting']
else:
raise ValueError(f"Key {key} is invalid")

logger.info(f"{key}: {retrieved_val}")
return retrieved_val
63 changes: 42 additions & 21 deletions brother_ql/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,11 @@ def discover(ctx):
if backend is None:
logger.info("Defaulting to pyusb as backend for discovery.")
backend = "pyusb"
from brother_ql.backends.helpers import discover, status
from brother_ql.backends.helpers import discover, get_printer, get_status

available_devices = discover(backend_identifier=backend)
for device in available_devices:
device_status = None
result = {"model": "unknown"}
status = None

# skip network discovery since it's not supported
if backend == "pyusb" or backend == "linux_kernel":
Expand All @@ -70,24 +69,12 @@ def discover(ctx):
continue

# send status request
device_status = status(
printer = get_printer(
printer_identifier=device["identifier"],
backend_identifier=backend,
)

# look up series code and model code
for m in ModelsManager().iter_elements():
if (
device_status["series_code"] == m.series_code
and device_status["model_code"] == m.model_code
):
result = {"model": m.identifier}
break

result.update(device)
logger.info(
"Found a label printer at: {identifier} (model: {model})".format(**result),
)
status = get_status(printer)
print(f"Found a label printer at: {device['identifier']} ({status['model']})")

def discover_and_list_available_devices(backend):
from brother_ql.backends.helpers import discover
Expand Down Expand Up @@ -210,13 +197,47 @@ def send_cmd(ctx, *args, **kwargs):
@cli.command(name="status", short_help="query printer status and the loaded media size")
@click.pass_context
def status_cmd(ctx, *args, **kwargs):
from brother_ql.backends.helpers import status
from brother_ql.backends.helpers import get_status, get_printer

printer=get_printer(ctx.meta.get("PRINTER"), ctx.meta.get("BACKEND"))
logger.debug("Sending status information request to the printer.")
result = get_status(printer)

print(f"Model: {result['model']}")
if result['model'] == "Unknown":
print("Unknown printer detected")
print(f"Series Code: 0x{result['series_code']:02x}")
print(f"Model Code: 0x{result['model_code']:02x}")
print(f"Status type: {result['status_type']}")
print(f"Phase: {result['phase_type']}")
if len(result['errors']) != 0:
print(f"Errors: {result['errors']}")
print(f"Media type: [{result['media_category']}] {result['media_type']}")
if result['media_category'] == 'TZe':
print("Note: tape color information may be incorrect for aftermarket tape cartridges.")
print(f"Tape color: {result['tape_color']}")
print(f"Text color: {result['text_color']}")
print(f"Media size: {result['media_width']} x {result['media_length']} mm")


@cli.command(name="configure", short_help="read and modify printer settings")
@click.argument('action', required=True, type=click.Choice(['get', 'set']), metavar='[ACTION]')
@click.argument('key', required=True, type=click.Choice(['power-off-delay', 'auto-power-on']), metavar='[KEY]')
@click.argument('value', type=int, metavar='[VALUE]', default=-1)
@click.pass_context
def configure_cmd(ctx, *args, **kwargs):
from brother_ql.backends.helpers import configure

status(
if kwargs.get('action') == 'set' and kwargs.get('value') == -1:
raise ValueError(f"Specify a valid value for key {kwargs.get('key')}")

configure(
printer_identifier=ctx.meta.get("PRINTER"),
backend_identifier=ctx.meta.get("BACKEND"),
action=kwargs.get('action'),
key=kwargs.get('key'),
value=kwargs.get('value')
)


if __name__ == '__main__':
cli()
Loading

0 comments on commit f4c7d2b

Please sign in to comment.