@joyautomation/tentacle@0.0.33Built and signed on GitHub ActionsBuilt and signed on GitHub Actions
A modern soft PLC with native Pub/Sub and a GraphQL API. It's designed to be containerized (running docker or kubernetes).
Tentacle
A modern PLC (Programmable Logic Controller) implementation in TypeScript/Deno with support for Modbus, OPC UA, and Sparkplug MQTT protocols.
Features
- 🔌 Multi-protocol support:
- Modbus TCP/IP
- OPC UA
- Sparkplug MQTT
- 🚀 Built with TypeScript and Deno for type safety and modern development
- 📊 GraphQL API for easy integration
- ⚡ High-performance asynchronous I/O
- 🔄 Automatic reconnection handling
- 📝 Comprehensive logging and error handling
Installation
# Add to your deps.ts or import_map.json import * as tentacle from "joyautomation/tentacle@$VERSION";
Quick Start
Here's a simple example that creates a PLC with Modbus and MQTT:
import { createPlc } from "joyautomation/tentacle"; // Define your PLC configuration const config = { tasks: { readModbus: { interval: 1000, // Run every second variables: ["temperature", "pressure"], }, }, variables: { temperature: { source: { type: "modbus", register: 40001, registerType: "HOLDING_REGISTER", format: "FLOAT32", }, }, pressure: { source: { type: "modbus", register: 40003, registerType: "HOLDING_REGISTER", format: "FLOAT32", }, }, }, mqtt: { main: { serverUrl: "mqtt://localhost:1883", groupId: "Sparkplug B/Group", edgeNode: "Node1", clientId: "tentacle-plc1", }, }, sources: { modbus1: { type: "modbus", host: "192.168.1.100", port: 502, unitId: 1, }, }, }; // Create and start the PLC const plc = await createPlc(config); // Access the GraphQL API const server = await createGraphQLServer(plc); server.listen(4000);
GraphQL API
The PLC exposes a GraphQL API for monitoring and control. Here are some example queries:
# Get PLC status query { plc { runtime { tasks { name lastRun nextRun error } variables { name value quality timestamp } mqtt { connected lastMessageSent } sources { name connected error } } } }
Configuration
Tasks
Tasks are periodic operations that read or write variables:
tasks: { name: string; interval: number; variables: string[]; enabled?: boolean; }
Variables
Variables represent data points that can be read from or written to sources:
variables: { name: string; source: { type: "modbus" | "opcua"; // Modbus-specific config register?: number; registerType?: ModbusRegisterType; format?: ModbusFormat; // OPC UA-specific config nodeId?: string; }; }
Sources
Sources define the connections to external systems:
sources: { name: string; type: "modbus" | "opcua"; // Modbus-specific config host?: string; port?: number; unitId?: number; // OPC UA-specific config endpointUrl?: string; }
Error Handling
Tentacle uses the Result type from @joyautomation/dark-matter for consistent error handling:
import { type Result } from "@joyautomation/dark-matter"; const result = await plc.writeVariable("temperature", 23.5); if (!result.success) { console.error(`Failed to write: ${result.error}`); }
Contributing
Contributions are welcome! Please read our Contributing Guidelines for details.
License
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
Add Package
deno add jsr:@joyautomation/tentacle
Import symbol
import * as tentacle from "@joyautomation/tentacle";
Import directly with a jsr specifier
import * as tentacle from "jsr:@joyautomation/tentacle";
Add Package
pnpm i jsr:@joyautomation/tentacle
pnpm dlx jsr add @joyautomation/tentacle
Import symbol
import * as tentacle from "@joyautomation/tentacle";
Add Package
yarn add jsr:@joyautomation/tentacle
yarn dlx jsr add @joyautomation/tentacle
Import symbol
import * as tentacle from "@joyautomation/tentacle";
Add Package
npx jsr add @joyautomation/tentacle
Import symbol
import * as tentacle from "@joyautomation/tentacle";
Add Package
bunx jsr add @joyautomation/tentacle
Import symbol
import * as tentacle from "@joyautomation/tentacle";