ESPHome external component for integrating GRBL-based CNC controllers with Home Assistant. It provides a seamless way to send commands, monitor state, and control your CNC machine from Home Assistant using an ESP32/ESP8266 device. Furthermore it acts as telnet-UART bridge, allowing you to connect to GRBL via telnet for remote command execution and monitoring.
This component allows you to:
- Send GRBL commands
- Control machine movement (jogging)
- Monitor GRBL state and settings
- Expose GRBL as sensors, switches, numbers, and buttons in Home Assistant
- Connect to your GRBL device via telnet for remote access
It is designed for ESP32/ESP8266 devices connected to a GRBL controller via UART.
- ๐ก Remote communication with GRBL via telnet protocol
- ๐ฎ Send arbitrary G-code / GRBL commands
- ๐น๏ธ Jog control (X/Y/Z movement)
- ๐ Home Assistant buttons for common actions
- ๐ Event-driven updates (no polling)
- ๐ Exposes GRBL settings as:
sensorbinary_sensorswitchnumber
- โก Native ESPHome automations support
The component includes a built-in telnet server that allows you to connect to your GRBL controller remotely. This is especially useful for sending commands or monitoring the machine state without needing direct physical access. By default, the telnet server listens on port 23, but you can configure it to use a different port if needed.
Due to the nature of the telnet protocol, only one client can be connected at a time. When a client is connected, the component will not allow sending commands from Home Assistant to avoid conflicts. However, you can configure this behavior to allow commands even when a telnet client is connected.
Add this to your ESPHome YAML configuration:
external_components:
- source: github://macdems/ESPHome-GRBL- ESP32 / ESP8266
- GRBL controller (e.g. Arduino Uno + CNC Shield)
- UART connection:
| ESP | GRBL |
|---|---|
| TX | RX |
| RX | TX |
| GND | GND |
โ ๏ธ Ensure voltage compatibility (3.3V vs 5V)! Use level shifters if needed.
uart:
tx_pin: <your_esp_tx_pin>
rx_pin: <your_esp_rx_pin>
baud_rate: 115200
grbl:
port: 23 # Optional: Default telnet port is 23
allow_commands_when_connected: false # Optional: allow commands when telnet client is connected, default is false
The component exposes sensors for status reports and GRBL settings. You can create sensors for any GRBL parameter by specifying the param. It can be either a numeric value for a GRBL setting (e.g. 110 for $110) or a one of the following status parameters:
| Parameter | Description |
|---|---|
mpos |
Machine position (MPos) |
wpos |
Work position (WPos) |
wco |
Work coordinates offset (WCO) |
In case of mpos, wpos, and wco, you need to specify the axis to select the X/Y/Z axis or the state value:
sensor:
- platform: grbl
name: "X Machine Position"
entity_param: mpos
axis: xTo expose eg. the maximum feed rate for the X axis ($110):
sensor:
- platform: grbl
name: "X Max Rate"
entity_param: $110Binary GRBL configurations can be exposed as binary sensors. For example, you can create a binary sensor for the $21 setting (hard limits enabled):
binary_sensor:
- platform: grbl
name: "Hard Limits Enabled"
param: $21You can also expose the status of the the telnet connection, limit switches, or the probe as binary sensors:
binary_sensor:
- platform: grbl
name: "X Limit Switch"
param: limit
axis: x
- platform: grbl
name: "Probe Triggered"
param: probe
- platform: grbl
name: "GRBL Connected"
param: client_connectedThe current GRBL state (Idle, Run, Alarm, etc.) can be exposed as a text sensor:
text_sensor:
- platform: grbl
name: "GRBL State"
param: stateThe following states are reported:
idlerunholdjogalarmdoorcheckhomesleepunknown
Binary GRBL settings can also be exposed as switches to allow toggling them from Home Assistant. For example, to toggle hard limits:
switch:
- platform: grbl
name: "Hard Limits"
param: $21Similarly, numeric GRBL settings can be exposed as number entities to allow changing them from Home Assistant. For example, to change the maximum feed rate for the X axis ($110):
number:
- platform: grbl
name: "X Max Rate"
param: $110
min_value: 0
max_value: 10000
step: 1The component provides several actions to control GRBL from Home Assistant automations or scripts or eg. ESPHome button entities.
To cancel any running command and reset GRBL:
- grbl.send_resetSend any GRBL command or G-code line:
- grbl.send_command: "G28"or:
- grbl.send_command:
command: "G0 X10"Run jog commands to move the machine. You can specify relative movement (dx/dy/dz) and speed. This command uses the units set in your machine GRBL configuration (mm and mm/min or inches and in/min).
- grbl.jog:
dx: 10
speed: 2000To stop jogging:
- grbl.cancel_jogTo pause the current motion (hold) or resume it:
- grbl.hold- grbl.resumeYou may create a hold switch to toggle between hold and resume states:
- platform: template
name: Hold
icon: "mdi:pause"
lambda: return id(grbl_state).state == "hold";
turn_on_action:
- grbl.hold
turn_off_action:
- grbl.resumeIf you have limit switches set up, you can run the homing cycle:
- grbl.run_homing_cycleIf GRBL is in an alarm or error state, you repeat the homing cycle or release the machine state:
- grbl.release_stateYou may set the current position as work coordinates home for X/Y/Z axes:
- grbl.set_home:
xy: true # Set X and Y as home
z: true # Set Z as home
coords: G54 # Optional: select coordinate system (G54-G59 or G92), default is G54Run a Z probe cycle to measure the height of the tool. You can specify the distance to probe, seek_rate for the initial probing move, feed_rate for the final probing move, offset to apply to the measured height, and retract distance to move back after probing. You can also specify the coordinate system to use for the probe results.
- grbl.probe_z:
distance: auto
seek_rate: 100.0
feed_rate: 10.0
offset: 0.0
retract: 5.0
coords: G54 # Optional: select coordinate system (G54-G59 or G92), default is G54distance: auto will automatically calculate the probing distance based on the current Z position, which is useful to avoid crashing the tool into the bed. It will only work if homing is enabled and the machine has a valid position.
By default, the component listens for GRBL status reports and updates entities automatically. However, it does not send status queries (?) on its own. If you want to trigger a status update (e.g. after sending a command), you can use the grbl.update_status action:
- grbl.update_statusYou can trigger automations based on GRBL events such as alarms or errors. For example, to trigger an automation when an alarm occurs:
grbl:
on_alarm:
then:
- logger.log:
format: "Alarm: %d"
args:
- codeRight now the components provides on_alarm and on_error triggers that pass the alarm/error code. You can use these to create automations that react to specific alarms or errors.
See example.yaml for a complete example configuration.
- Parses GRBL responses (
$,?, status reports) - Maintains internal state of settings
- Uses event-driven listeners to update entities instantly
- Avoids polling โ low latency & efficient
- Assumes standard GRBL serial protocol
- Not all GRBL features are implemented yet
- No G-code streaming (yet)
- Streaming G-code support
- Status parsing improvements
- Alarm & error codes sensors
Contributions are welcome!
- Open issues for bugs / ideas
- PRs with improvements
- Feature requests encouraged
Copyright (C) 2026 Maciek Dems https://github.com/macdems
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- GRBL project โ open-source CNC firmware (GitHub)
- ESPHome โ amazing IoT framework
- Home Assistant community
If you find this useful:
- โญ Star the repo
- Share your setups
- Contribute improvements