Livebook and Kino tools for EtherCAT.
kino_ethercat is built around three use cases:
- discover and configure an EtherCAT bus from Livebook
- inspect and control a running master with focused runtime renders
- teach EtherCAT with a simulator-first workflow and low setup friction
If you want the shortest path to a first useful result, start with the example notebook:
That notebook uses the built-in simulator, walks through Setup and Master, and ends with a simple outputs.ch1 -> inputs.ch1 interaction.
The broader teaching direction lives in examples/README.md.
Add kino_ethercat to a Livebook notebook:
Mix.install([
{:kino_ethercat, "~> 0.3.0"}
])For local development against this repo:
Mix.install([
{:kino_ethercat, path: "~/path/to/kino_ethercat"}
])When developing this repo itself against a sibling ../ethercat checkout, set:
export KINO_ETHERCAT_USE_LOCAL_ETHERCAT=1KinoEtherCAT registers Smart Cells in Livebook under + Smart.
Discovers the current bus or simulator and generates a static EtherCAT.start/1 cell.
- auto-scans when added
- supports raw socket or UDP transport
- lets you name slaves, choose drivers, assign domains, and tune DC
- generates a notebook cell that ends with Master and diagnostics tabs
Builds a small virtual ring for teaching and testing.
- starts with
coupler -> inputs -> outputs - defaults to one loopback path:
outputs.ch1 -> inputs.ch1 - simple mode keeps the workflow minimal
Expert modeexposes device ordering and connection editing- simple mode generates
Introduction,Simulator, andFaultstabs - expert mode keeps the simulator workspace focused on
SimulatorandFaults
Builds a compact signal dashboard from the running bus.
- pick signals with checkboxes grouped by slave
- reorder the selected signal list
- generate focused signal widgets like
led/3,switch/3, andvalue/3
Combines low-level workflows for a selected slave:
- ESC registers
- CoE SDO
- SII EEPROM
The main runtime API returns renderable EtherCAT resources:
KinoEtherCAT.master()
KinoEtherCAT.slave(:io_1)
KinoEtherCAT.domain(:main)
KinoEtherCAT.bus()
KinoEtherCAT.dc()In Livebook, these render as interactive views through Kino.Render.
Use them when you want a resource-oriented runtime surface instead of a generated Smart Cell workflow.
KinoEtherCAT.diagnostics()
KinoEtherCAT.introduction()
KinoEtherCAT.simulator()
KinoEtherCAT.simulator_faults()diagnostics/0is the broad Task Manager style overviewintroduction/0is the reduced teaching surfacesimulator/0is the simulator topology and status viewsimulator_faults/0is the fault injection console
Signal-level and slave-panel widgets live under KinoEtherCAT.Widgets.
KinoEtherCAT.Widgets.led(:inputs, :ch1, label: "Input 1")
KinoEtherCAT.Widgets.switch(:outputs, :ch1, label: "Output 1")
KinoEtherCAT.Widgets.value(:analog, :temperature, label: "Temperature")led/3is a read-only 1-bit input indicatorswitch/3writes a 1-bit outputvalue/3displays multi-bit values
KinoEtherCAT.Widgets.panel(:inputs)
KinoEtherCAT.Widgets.dashboard([:left_io, :right_io], columns: 2)Use these when you want a compact operator-facing view without the full runtime panels.
KinoEtherCAT ships built-in drivers for a small Beckhoff-focused teaching and bring-up set:
| Module | Device | Description |
|---|---|---|
KinoEtherCAT.Driver.EK1100 |
EK1100 | EtherCAT coupler |
KinoEtherCAT.Driver.EL1809 |
EL1809 | 16-channel digital input |
KinoEtherCAT.Driver.EL2809 |
EL2809 | 16-channel digital output |
KinoEtherCAT.Driver.EL3202 |
EL3202 | 2-channel PT100 RTD input |
Driver lookup:
KinoEtherCAT.Driver.all()
KinoEtherCAT.Driver.lookup(%{vendor_id: 2, product_code: 0x07113052})Drivers that should work with the simulator also need a companion MyDriver.Simulator module implementing EtherCAT.Simulator.DriverAdapter.
At minimum, a custom driver needs to implement EtherCAT.Slave.Driver and provide identity, signal layout, and signal encoding/decoding:
defmodule MyApp.MyDriver do
@behaviour EtherCAT.Slave.Driver
@impl true
def identity do
%{vendor_id: 0x0000_0002, product_code: 0x1234_5678}
end
@impl true
def signal_model(_config), do: [ch1: 0x1A00]
@impl true
def encode_signal(_signal, _config, _value), do: <<>>
@impl true
def decode_signal(_signal, _config, <<_::7, bit::1>>), do: bit
def decode_signal(_signal, _config, _raw), do: 0
endApache 2.0. See LICENSE.