Getting Started
Prerequisites
- .NET 10 SDK
- Network access to a Beckhoff TwinCAT PLC — not required for the simulated quick start below
- (Optional) An OIDC identity provider (Keycloak, Entra ID, etc.)
Try It Without a PLC
Adsify’s ADS access is provided by the Dahlke.TwinCAT.Ads
library, which supports simulated, in-memory PLC targets alongside real ones. The
appsettings.Simulation.json profile configures a demo target with Mode: "Simulated"
and seeded values, so you can run most of the API — no TwinCAT installation, no
hardware, no ADS router:
git clone https://github.com/patdhlk/adsify.git
cd adsify
dotnet build Adsify.sln
ASPNETCORE_ENVIRONMENT=Simulation dotnet run --project src/Adsify.Api --urls "http://localhost:5000"curl http://localhost:5000/api/plcs
curl http://localhost:5000/api/plcs/demo/variables/MAIN.Speed
curl http://localhost:5000/api/plcs/demo/symbols403, which looks like an authentication failure rather than a port collision. Pick
another port (--urls "http://localhost:5080") or disable AirPlay Receiver under
System Settings → General → AirDrop & Handoff.Simulation is unauthenticated — it bypasses authentication the same way
Development does, so every request gets full admin access with no token required.
This profile is for local development only; never expose it on a shared network.Simulation is per-target configuration, not a separate connection type: set
"Mode": "Simulated" on any target in PlcTargets and seed it with InitialValues.
Real and simulated targets can coexist in one configuration — see
Configuration for the full PlcTargets reference.
InitialValues seeded
from a JSON file binds through IConfiguration, which stores every value as a string
with no memory of its original JSON type. Every seeded value — numbers, booleans,
strings alike — reads back as a JSON string with typeName: "STRING": a seeded
1500 returns "1500", not 1500; a seeded true returns "True", not true. A
real PLC (or a target seeded programmatically in code) returns properly typed values
with a real PLC type name. Don’t expect simulated and real responses to be
byte-for-byte identical for the same nominal value.Quick Start
1. Clone and build
git clone https://github.com/patdhlk/adsify.git
cd adsify
dotnet build Adsify.sln2. Configure your PLC connection
Edit src/Adsify.Api/appsettings.Development.json:
{
"AmsRouter": {
"Name": "Adsify",
"NetId": "192.168.1.78.1.1",
"TcpPort": 48898,
"LoopbackIP": "127.0.0.1",
"LoopbackPort": 48898,
"ChannelPortType": "Loopback",
"Routes": [
{
"Name": "MyPLC",
"Address": "192.168.1.136",
"NetId": "192.168.1.136.1.1"
}
]
},
"PlcTargets": {
"MyPLC": {
"AmsNetId": "192.168.1.136.1.1",
"Port": 851,
"DisplayName": "My TwinCAT PLC"
}
}
}Replace the IP addresses and AMS Net IDs with your actual PLC values.
3. Run
ASPNETCORE_ENVIRONMENT=Development dotnet run --project src/Adsify.Api --urls "http://localhost:5000"4. Test
# List connected PLCs
curl http://localhost:5000/api/plcs
# Read a variable
curl http://localhost:5000/api/plcs/MyPLC/variables/MAIN.nCounter
# Browse symbols
curl http://localhost:5000/api/plcs/MyPLC/symbols
# Device info
curl http://localhost:5000/api/plcs/MyPLC/device/info5. Explore the API
Open the Swagger UI at http://localhost:5000/swagger to see all available endpoints with AI-optimized descriptions.
MCP for AI Assistants
Adsify includes a built-in Model Context Protocol (MCP) server that lets AI assistants interact with PLCs through natural language.
Enable the MCP server in your configuration:
{
"Features": {
"Mcp": { "Enabled": true }
}
}Then configure your AI assistant to connect to the /mcp endpoint. See the MCP Server documentation for client setup instructions and the full list of available tools and resources.
Try asking your AI assistant: “List all PLCs and show their status.”