# API
The package exports GrblStreamer and State.
# Methods
| Method | Description |
|---|---|
connect() / disconnect() |
open/close the session; safe to call repeatedly |
stream(commands, total=None, ...) |
stream any iterable of commands |
send_file(path, ...) |
stream a file lazily; same options as stream() |
command(cmd) |
send one command interactively, wait for ok/error |
pause() / resume() / stop() |
real-time job control |
unlock() / home() |
$X / $H |
reconnect(retries, delay, reset=...) |
explicitly retry connection after a disconnect |
sync(timeout=2) |
query the controller and update local state |
reset(unlock=True) |
soft reset, optionally unlock, then synchronize |
Parameters and failure handling are on Connections and Streaming.
# Callbacks
Assign callbacks as attributes or override them in a subclass. They run on a
dedicated dispatcher thread. Keep them short: a slow callback delays later
callbacks, although serial reading continues separately. If a callback raises,
the exception is reported through log_callback instead of being silently
swallowed.
| Callback | Signature | Fires on |
|---|---|---|
progress_callback |
(percent, command) |
acknowledged command progress (-1 for unbounded streams) |
state_callback |
(state) |
state machine transitions |
alarm_callback |
(line) |
GRBL ALARM:n |
error_callback |
(line) |
GRBL error:n or internal errors |
send_callback / receive_callback |
(data) |
raw serial traffic |
disconnect_callback |
(reason) |
physical disconnection |
log_callback |
(level, message) |
internal diagnostics ('debug'/'info'/'warning') |
# Logging integration
The library imposes no logging framework. Wire the callbacks to Python's
standard logging in the application:
import logging
from pygrbl_streamer import GrblStreamer
log = logging.getLogger('laser1')
laser = GrblStreamer("/dev/ttyUSB0")
laser.log_callback = lambda level, message: getattr(log, level)(message)
laser.error_callback = lambda line: log.warning('GRBL error: %s', line)
laser.alarm_callback = lambda line: log.error('ALARM: %s', line)
laser.disconnect_callback = lambda reason: log.critical('disconnected: %s', reason)
laser.receive_callback = lambda line: log.debug('<< %s', line)
laser.send_callback = lambda data: log.debug('>> %s', data.strip())
# State and recovery
State contains DISCONNECTED, CONNECTING, IDLE, STREAMING, PAUSED
and ALARM. is_connected is true for states other than DISCONNECTED and
CONNECTING; it does not guarantee that a job can start. stream() requires
local state IDLE.
last_status holds the latest parsed status report: state is the firmware
state string, raw is the complete report and time is its reception time.
A previously received report can be stale. Firmware state and the streamer's
local state are different: a local IDLE is not itself fresh evidence that
physical motion has finished.
sync(timeout=2) requests a fresh status. Alarm, Hold and Door map to local
ALARM; other firmware states, including Run, Jog and Home, map to local
IDLE. During a local stream or pause it returns the existing state without
querying. On an unresponsive controller it reports disconnection. Use the raw
status when the distinction between physically idle and moving matters.
An ALARM message aborts a running stream; it is never automatically cleared
mid-job. unlock() explicitly sends $X. The default connect() and
reset(unlock=True) also request unlock, as part of their startup and recovery
sequence. Set auto_unlock=False for a connection that must preserve alarms.
reset() aborts streaming, sends a soft reset and synchronizes after optional
unlock. Its boolean result reflects the mapped local state, not a restored
position or a resumable job. Homing is separate; see
Homing for acknowledgement plus fresh-Idle
confirmation.
# Troubleshooting
- No connection: check port ownership, baud rate, DTR/RTS and the initialization sequence. Log received lines and connection errors before changing options.
- Connected but unable to stream: inspect local state and
last_status; do not clear an alarm solely to suppress an error message. - Homing returns
False: inspect alarm and error callbacks and distinguish a missing acknowledgement from a missing final Idle. It does not retry or stop itself.