Building a Web HMI
HMI Overview
Every AutoCore project includes a www/ directory that contains a React + TypeScript web application. This web app connects to the server via WebSocket and can:
- Display live variable values
- Send commands (write variables, trigger actions)
- Show logs and status information
The web HMI is served directly by the AutoCore server. After deploying, you open it in any web browser.
The AutoCore React Library
The @adcops/autocore-react library provides React hooks for connecting to the AutoCore server and working with variables. The project template includes this library pre-configured.
Key hooks:
| Hook | Purpose |
|---|---|
useAutoCoreConnection() | Connect to the server WebSocket |
useVariable(name) | Subscribe to a variable and get its live value |
useCommand() | Send commands to the server |
Creating a Simple Dashboard
Here is a basic HMI that shows the motor speed and provides start/stop controls. Edit www/src/App.tsx:
import React from 'react';
import { useVariable, useCommand } from './AutoCore';
import { Button } from 'primereact/button';
import { Knob } from 'primereact/knob';
function App() {
// Subscribe to live variable values
const motorRunning = useVariable<boolean>('machine_running');
const speedActual = useVariable<number>('motor_speed_actual');
const speedSetpoint = useVariable<number>('motor_speed_setpoint');
// Command hook for writing variables
const sendCommand = useCommand();
const handleStart = () => {
sendCommand('gm.write', { name: 'machine_running', value: true });
};
const handleStop = () => {
sendCommand('gm.write', { name: 'machine_running', value: false });
};
const handleSpeedChange = (rpm: number) => {
sendCommand('gm.write', { name: 'motor_speed_setpoint', value: rpm });
};
return (
<div style={{ padding: '2rem' }}>
<h1>Motor Control</h1>
<div style={{ display: 'flex', gap: '2rem', alignItems: 'center' }}>
<div>
<h3>Speed</h3>
<Knob
value={speedActual?.value ?? 0}
max={2000}
readOnly
valueTemplate="{value} RPM"
size={150}
/>
</div>
<div>
<h3>Setpoint</h3>
<Knob
value={speedSetpoint?.value ?? 0}
max={2000}
onChange={(e) => handleSpeedChange(e.value)}
valueTemplate="{value} RPM"
size={150}
/>
</div>
<div>
<h3>Controls</h3>
<Button
label="Start"
icon="pi pi-play"
onClick={handleStart}
disabled={motorRunning?.value === true}
severity="success"
style={{ marginRight: '1rem' }}
/>
<Button
label="Stop"
icon="pi pi-stop"
onClick={handleStop}
disabled={motorRunning?.value !== true}
severity="danger"
/>
</div>
</div>
<p>
Status: {motorRunning?.value ? 'RUNNING' : 'STOPPED'}
</p>
</div>
);
}
export default App;
Subscribing to Live Variable Updates
When you use useVariable(name), the library automatically subscribes to that variable via WebSocket. The value updates in real time whenever the control program changes it — there is no polling.
Under the hood, this sends a subscribe message to the server:
{ "domain": "gm", "fname": "subscribe", "args": { "name": "motor_speed_actual" } }
The server then pushes updates whenever the value changes:
{ "domain": "gm", "fname": "broadcast", "args": { "name": "motor_speed_actual", "value": 1247.5 } }
Sending Commands from the HMI
To write a variable value:
sendCommand('gm.write', { name: 'motor_speed_setpoint', value: 1500 });
To read a variable on demand (instead of subscribing):
const result = await sendCommand('gm.read', { name: 'motor_speed_actual' });
console.log(result.value);
To send a command to an external module:
sendCommand('modbus.status', {});
sendCommand('ethercat.get_state', { slave: 'ClearPath_0' });
Deploying the HMI
Build and deploy the web HMI:
cd www
npm install # First time only
npm run build # Creates www/dist/
cd ..
acctl push www # Uploads dist/ to the server
Then open your browser to http://<server_ip>:8080 to see the HMI.
During development, you can run the HMI in development mode with hot reloading:
cd www
npm run dev
This starts a local dev server (usually at http://localhost:5173). You will need to configure the WebSocket URL to point to your AutoCore server — check www/src/AutoCore.ts for the connection settings.