Skip to main content
Home
This release is 3 versions behind 0.0.37 — the latest version of @joyautomation/tentacle. Jump to latest

Built 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).

This package works with DenoIt is unknown whether this package works with Cloudflare Workers, Node.js, Bun, Browsers
It is unknown whether this package works with Cloudflare Workers
It is unknown whether this package works with Node.js
This package works with Deno
It is unknown whether this package works with Bun
It is unknown whether this package works with Browsers
JSR Score
100%
Published
2 weeks ago (0.0.33)

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.

Built and signed on
GitHub Actions

New Ticket: Report package

Please provide a reason for reporting this package. We will review your report and take appropriate action.

Please review the JSR usage policy before submitting a report.

Add Package

deno add jsr:@joyautomation/tentacle

Import symbol

import * as tentacle from "@joyautomation/tentacle";
or

Import directly with a jsr specifier

import * as tentacle from "jsr:@joyautomation/tentacle";

Add Package

pnpm i jsr:@joyautomation/tentacle
or (using pnpm 10.8 or older)
pnpm dlx jsr add @joyautomation/tentacle

Import symbol

import * as tentacle from "@joyautomation/tentacle";

Add Package

yarn add jsr:@joyautomation/tentacle
or (using Yarn 4.8 or older)
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";