npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@egjr/mc3e

v1.1.0

Published

Cliente MC Protocol 3E nativo para PLCs Mitsubishi Serie Q/L. Leitura e escrita de dispositivos (D, M, X, Y, W, R, etc.) com suporte a Word, Double Word e Float.

Readme

@egjr/mc3e

npm version license node

Biblioteca MC Protocol 3E (binário) nativa para comunicação com PLCs Mitsubishi Série Q/L em Node.js.

  • Zero dependências — usa apenas TCP sockets nativos (net).
  • Suporta todos os dispositivos: D, M, X, Y, W, R, Z, Timers, Counters e mais.
  • Tipos de dados: Word (16 bits), Double Word (32 bits), Float IEEE 754 (32 bits).
  • Pronta para uso como dependência em qualquer aplicação Node.js.

Índice


Instalação

npm install @egjr/mc3e

Quick Start

const { Mc3eClient } = require("@egjr/mc3e");

async function main() {
  const client = new Mc3eClient({
    host: "192.168.68.40",
    port: 2001,
  });

  // Ler registrador D0 (Word 16 bits)
  const d0 = await client.readDevice("D", 0);
  console.log("D0 =", d0); // ex: 1234

  // Escrever valor no registrador D0
  await client.writeDevice("D", 0, 5678);

  // Ler entrada digital X0
  const x0 = await client.readDevice("X", 0);
  console.log("X0 =", x0); // true ou false

  // Ler temperatura como Float (D10 + D11)
  const temp = await client.readFloat("D", 10);
  console.log("Temperatura =", temp);
}

main().catch(console.error);

API da Biblioteca

Construtor

const { Mc3eClient } = require("@egjr/mc3e");

const client = new Mc3eClient(options);

Parâmetros de options

| Parâmetro | Tipo | Padrão | Descrição | |-----------|------|--------|-----------| | host | string | — | (obrigatório) Endereço IP do PLC | | port | number | — | (obrigatório) Porta TCP do módulo Ethernet | | timeoutMs | number | 3000 | Timeout de comunicação em milissegundos | | networkNo | number | 0x00 | Número da rede (Network No.) | | pcNo | number | 0xFF | Número do PC (PC No.) | | ioNo | number | 0x03FF | Número do módulo I/O (Request destination module I/O No.) | | stationNo | number | 0x00 | Número da estação (Request destination station No.) | | monitoringTimer | number | 0x0010 | Timer de monitoramento do PLC (em unidades de 250ms) |

Exemplo com todas as opções

const client = new Mc3eClient({
  host: "192.168.68.40",
  port: 2001,
  timeoutMs: 5000,
  networkNo: 0x00,
  pcNo: 0xFF,
  ioNo: 0x03FF,
  stationNo: 0x00,
  monitoringTimer: 0x0010,
});

readDevice(deviceName, deviceNo, count)

Lê um ou mais pontos de um dispositivo do PLC.

Parâmetros

| Parâmetro | Tipo | Padrão | Descrição | |-----------|------|--------|-----------| | deviceName | string | — | Nome do dispositivo ("D", "M", "X", "Y", etc.) | | deviceNo | number | — | Número do ponto (ex: 0, 100, 500) | | count | number | 1 | Quantidade de pontos a ler |

Retorno

| Tipo de dispositivo | count = 1 | count > 1 | |---------------------|-------------|-------------| | bit (M, X, Y...) | boolean | boolean[] | | word (D, W, R...) | number (0–65535) | number[] |

Exemplos

// Leitura única — Word
const d100 = await client.readDevice("D", 100);
// => 4567

// Leitura múltipla — 10 registradores consecutivos
const d0_d9 = await client.readDevice("D", 0, 10);
// => [100, 200, 300, 0, 0, 0, 0, 0, 0, 0]

// Leitura de bit
const m0 = await client.readDevice("M", 0);
// => true

// Leitura múltipla de bits
const m0_m7 = await client.readDevice("M", 0, 8);
// => [true, false, true, false, false, false, false, false]

// Leitura de entrada digital (Input)
const x0 = await client.readDevice("X", 0);
// => true

// Leitura de saída digital (Output)
const y10 = await client.readDevice("Y", 10);
// => false

writeDevice(deviceName, deviceNo, value)

Escreve um ou mais pontos em um dispositivo do PLC.

Parâmetros

| Parâmetro | Tipo | Descrição | |-----------|------|-----------| | deviceName | string | Nome do dispositivo | | deviceNo | number | Número do ponto inicial | | value | number \| boolean \| Array | Valor a escrever. Para word: inteiro (-32768 a 65535). Para bit: true/false. Aceita array para escrita múltipla. |

Exemplos

// Escrever Word
await client.writeDevice("D", 0, 1234);

// Escrever múltiplos registradores (D0=100, D1=200, D2=300)
await client.writeDevice("D", 0, [100, 200, 300]);

// Escrever bit — ligar M0
await client.writeDevice("M", 0, true);

// Escrever bit — desligar Y10
await client.writeDevice("Y", 10, false);

// Escrever múltiplos bits (M0=ON, M1=OFF, M2=ON)
await client.writeDevice("M", 0, [true, false, true]);

readDWord(deviceName, deviceNo)

Lê um valor Double Word (32 bits inteiro) ocupando 2 registradores consecutivos.

Parâmetros

| Parâmetro | Tipo | Descrição | |-----------|------|-----------| | deviceName | string | Nome do dispositivo word ("D", "W", "R", etc.) | | deviceNo | number | Número do primeiro registrador |

Retorno

number — Valor inteiro de 32 bits (0 a 4294967295 unsigned, ou -2147483648 a 2147483647 signed).

Exemplo

// Lê D0 (low) + D1 (high) como inteiro 32 bits
const value = await client.readDWord("D", 0);
// => 70000

Nota: O valor é montado como (D[n+1] << 16) | D[n] (little-endian, padrão Mitsubishi).


writeDWord(deviceName, deviceNo, value)

Escreve um valor Double Word (32 bits inteiro) em 2 registradores consecutivos.

Parâmetros

| Parâmetro | Tipo | Descrição | |-----------|------|-----------| | deviceName | string | Nome do dispositivo word | | deviceNo | number | Número do primeiro registrador | | value | number | Valor inteiro (-2147483648 a 4294967295) |

Exemplo

await client.writeDWord("D", 0, 70000);
// D0 = 4464 (0x1170), D1 = 1 (0x0001)
// Resultado: (1 << 16) | 4464 = 70000

readFloat(deviceName, deviceNo)

Lê um valor Float IEEE 754 (32 bits) ocupando 2 registradores consecutivos.

Parâmetros

| Parâmetro | Tipo | Descrição | |-----------|------|-----------| | deviceName | string | Nome do dispositivo word | | deviceNo | number | Número do primeiro registrador |

Retorno

number — Valor de ponto flutuante IEEE 754.

Exemplo

// Lê D10 + D11 como float
const temperatura = await client.readFloat("D", 10);
// => 3.140000104904175

writeFloat(deviceName, deviceNo, value)

Escreve um valor Float IEEE 754 (32 bits) em 2 registradores consecutivos.

Parâmetros

| Parâmetro | Tipo | Descrição | |-----------|------|-----------| | deviceName | string | Nome do dispositivo word | | deviceNo | number | Número do primeiro registrador | | value | number | Valor numérico finito |

Exemplo

await client.writeFloat("D", 10, 3.14);

Atalhos retrocompatíveis

Métodos de conveniência para o registrador D:

// Equivale a readDevice("D", deviceNo)
const value = await client.readD(0);

// Equivale a writeDevice("D", deviceNo, value)
await client.writeD(0, 1234);

Utilitários

DEVICES

Constante exportada com todos os dispositivos suportados e seus códigos binários MC:

const { DEVICES } = require("@egjr/mc3e");

console.log(DEVICES.D);
// => { code: 0xa8, type: "word", label: "Data Register" }

console.log(Object.keys(DEVICES));
// => ["X", "Y", "M", "L", "F", "V", "B", "S", "SS", "SC", "TS", "TC", "CS", "CC", "SB", "SM", "D", "W", "R", "ZR", "TN", "SN", "CN", "SW", "SD", "Z"]

getDevice(name)

Busca um dispositivo pelo nome (case-insensitive). Lança erro com a lista de dispositivos válidos se não encontrado.

const { getDevice } = require("@egjr/mc3e");

const dev = getDevice("D");
// => { code: 0xa8, type: "word", label: "Data Register", name: "D" }

getDevice("INVALIDO");
// => Error: Dispositivo 'INVALIDO' nao reconhecido. Validos: X, Y, M, L, ...

Dispositivos Suportados

Dispositivos de Bit

| Dispositivo | Código MC | Descrição | |-------------|-----------|-----------| | X | 0x9C | Input (Entrada digital) | | Y | 0x9D | Output (Saída digital) | | M | 0x90 | Internal Relay (Relé interno) | | L | 0x92 | Latch Relay (Relé com retenção) | | F | 0x93 | Annunciator (Anunciador) | | V | 0x94 | Edge Relay (Relé de borda) | | B | 0xA0 | Link Relay (Relé de link) | | S | 0x98 | Step Relay (Relé de passo) | | SM | 0x91 | Special Relay (Relé especial) | | SB | 0xA1 | Link Special Relay | | TS | 0xC1 | Timer Contact (Contato de timer) | | TC | 0xC0 | Timer Coil (Bobina de timer) | | SS | 0xC7 | Timer Contact — Retentive (Com retenção) | | SC | 0xC6 | Timer Coil — Retentive (Com retenção) | | CS | 0xC4 | Counter Contact (Contato de contador) | | CC | 0xC3 | Counter Coil (Bobina de contador) |

Dispositivos de Word

| Dispositivo | Código MC | Descrição | |-------------|-----------|-----------| | D | 0xA8 | Data Register (Registrador de dados) | | W | 0xB4 | Link Register (Registrador de link) | | R | 0xAF | File Register (Registrador de arquivo) | | ZR | 0xB0 | File Register — Block (Bloco) | | TN | 0xC2 | Timer Current Value (Valor atual do timer) | | SN | 0xC8 | Timer Current Value — Retentive | | CN | 0xC5 | Counter Current Value (Valor atual do contador) | | SW | 0xB5 | Link Special Register | | SD | 0xA9 | Special Register (Registrador especial) | | Z | 0xCC | Index Register (Registrador de índice) |


Tipos de Dados

| Tipo | Bits | Registradores | Método de Leitura | Método de Escrita | Faixa | |------|------|---------------|-------------------|-------------------|-------| | Word | 16 | 1 | readDevice() | writeDevice() | 0–65535 (unsigned) | | Double Word | 32 | 2 | readDWord() | writeDWord() | 0–4294967295 (unsigned) | | Float | 32 | 2 | readFloat() | writeFloat() | IEEE 754 single precision | | Bit | 1 | — | readDevice() | writeDevice() | true / false |

Para Double Word e Float, os dados ocupam 2 registradores consecutivos no formato little-endian: registrador N = word baixa, registrador N+1 = word alta.


Exemplos de Integração

Monitoramento contínuo de variáveis

const { Mc3eClient } = require("@egjr/mc3e");

const client = new Mc3eClient({ host: "192.168.68.40", port: 2001 });

async function monitorar(deviceName, deviceNo, intervalMs = 1000) {
  console.log(`Monitorando ${deviceName}${deviceNo} a cada ${intervalMs}ms...`);

  setInterval(async () => {
    try {
      const value = await client.readDevice(deviceName, deviceNo);
      console.log(`[${new Date().toISOString()}] ${deviceName}${deviceNo} = ${value}`);
    } catch (err) {
      console.error(`Erro: ${err.message}`);
    }
  }, intervalMs);
}

monitorar("D", 0, 500);

Leitura de múltiplos registradores em lote

const { Mc3eClient } = require("@egjr/mc3e");

const client = new Mc3eClient({ host: "192.168.68.40", port: 2001 });

async function lerProcesso() {
  // Ler 10 registradores D consecutivos (D100..D109)
  const dados = await client.readDevice("D", 100, 10);

  // Ler temperatura como Float (D200 + D201)
  const temperatura = await client.readFloat("D", 200);

  // Ler contador como Double Word (D300 + D301)
  const contador = await client.readDWord("D", 300);

  // Ler status das entradas
  const sensor1 = await client.readDevice("X", 0);
  const sensor2 = await client.readDevice("X", 1);

  return {
    registradores: dados,
    temperatura,
    contador,
    sensores: { sensor1, sensor2 },
  };
}

lerProcesso().then(console.log).catch(console.error);

Uso com Express (API própria)

const express = require("express");
const { Mc3eClient } = require("@egjr/mc3e");

const app = express();
const client = new Mc3eClient({ host: "192.168.68.40", port: 2001 });

app.get("/temperatura", async (req, res) => {
  try {
    const temp = await client.readFloat("D", 10);
    res.json({ temperatura: temp });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.listen(3000, () => console.log("API rodando na porta 3000"));

Uso com TypeScript

import { Mc3eClient, DEVICES, getDevice } from "@egjr/mc3e";

const client = new Mc3eClient({
  host: "192.168.68.40",
  port: 2001,
  timeoutMs: 5000,
});

async function main(): Promise<void> {
  const valor: number = await client.readDevice("D", 0);
  const bits: boolean = await client.readDevice("M", 0);
  const temp: number = await client.readFloat("D", 10);

  console.log({ valor, bits, temp });
}

main();

Múltiplos PLCs

const { Mc3eClient } = require("@egjr/mc3e");

const plc1 = new Mc3eClient({ host: "192.168.68.40", port: 2001 });
const plc2 = new Mc3eClient({ host: "192.168.68.41", port: 2001 });

async function sincronizar() {
  // Ler valor do PLC1 e escrever no PLC2
  const valor = await plc1.readDevice("D", 0);
  await plc2.writeDevice("D", 100, valor);
  console.log(`Sincronizado: D0=${valor}`);
}

sincronizar().catch(console.error);

Códigos de Erro MC

Quando o PLC retorna um erro, a biblioteca lança um Error com propriedades adicionais:

| Código | Mensagem | Descrição | |--------|----------|-----------| | 0x0050 | Erro de conversão ASCII/Binário | Communication Data Code da CPU não corresponde ao modo do cliente | | 0x0051 | Quantidade de dados não corresponde | Número de palavras enviadas diverge do campo Number of device points | | 0x0055 | Escrita recusada pelo PLC | Proteção de escrita remota, CPU em STOP, ou restrição no módulo Ethernet | | 0xC050 | Erro no número de série da CPU | Número de série ASCII inválido na requisição | | 0xC051 | Dados de escrita incompatíveis | Tipo de dispositivo incompatível com a operação | | 0xC056 | Número de pontos excede o limite | Device points solicitados excedem o limite da CPU | | 0xC058 | Comando não suportado pela CPU | Comando não suportado — verificar modelo e firmware | | 0xC059 | Erro de tipo comando/subcomando | Par comando/subcomando não reconhecido | | 0xC05B | CPU em modo incompatível | CPU em STOP/PAUSE — colocar em RUN | | 0xC05C | Dispositivo inexistente | Dispositivo não existe nesta CPU | | 0xC05D | Erro de senha remota | Senha remota necessária ou incorreta | | 0xC05F | Requisição não pode ser executada | Módulo Ethernet não pode encaminhar a requisição | | 0xC060 | Erro de número de dispositivo | Número do dispositivo fora da faixa | | 0xC061 | Comprimento de dados inválido | Comprimento dos dados da requisição inválido |


Tratamento de Erros

const { Mc3eClient } = require("@egjr/mc3e");

const client = new Mc3eClient({ host: "192.168.68.40", port: 2001 });

try {
  await client.writeDevice("D", 0, 1234);
} catch (error) {
  console.error("Mensagem:", error.message);
  // => "[0x0055] Escrita recusada pelo PLC"

  if (error.endCode) {
    console.error("Código:", `0x${error.endCode.toString(16).padStart(4, "0")}`);
    // => "0x0055"
  }

  if (error.detail) {
    console.error("Detalhe:", error.detail);
    // => "O PLC recusou a operacao de escrita. Causas provaveis: ..."
  }
}

Erros comuns

| Erro | Causa | Solução | |------|-------|---------| | Timeout de comunicação com PLC | PLC inacessível ou IP/porta incorretos | Verificar rede, IP, porta e firewall | | Erro de socket: ECONNREFUSED | Porta TCP não aberta no PLC | Verificar configuração do módulo Ethernet no GX Works2 | | [0x0055] Escrita recusada | Proteção de escrita ativa | Desabilitar Remote Password ou liberar escrita no módulo Ethernet | | [0xC05B] CPU em modo incompatível | CPU em STOP | Colocar CPU em modo RUN | | [0xC05C] Dispositivo inexistente | Dispositivo não existe no modelo | Verificar manual da CPU |


Arquitetura do Protocolo

┌──────────────────────────────────────────────────────────┐
│                     Aplicação Node.js                     │
│                                                          │
│  const client = new Mc3eClient({ host, port })           │
│  await client.readDevice("D", 0)                         │
└──────────────┬───────────────────────────────────────────┘
               │
               │  TCP Socket (net.Socket)
               │
┌──────────────▼───────────────────────────────────────────┐
│                 MC Protocol 3E (Binary)                   │
│                                                          │
│  Request Frame:                                          │
│  ┌─────────┬────────┬───────┬─────────┬─────────┐       │
│  │Subheader│Access  │Req.   │Command  │ Device  │       │
│  │ 0x5000  │Route   │Data   │+ Sub.   │ Data    │       │
│  │ (2 B)   │(5 B)   │Len(2B)│ (4 B)   │ (N B)  │       │
│  └─────────┴────────┴───────┴─────────┴─────────┘       │
│                                                          │
│  Response Frame:                                         │
│  ┌─────────┬────────┬───────┬─────────┬─────────┐       │
│  │Subheader│Access  │Resp.  │End Code │Response │       │
│  │ 0xD000  │Route   │Len(2B)│ (2 B)   │ Data    │       │
│  │ (2 B)   │(5 B)   │       │0=OK     │ (N B)  │       │
│  └─────────┴────────┴───────┴─────────┴─────────┘       │
└──────────────┬───────────────────────────────────────────┘
               │
               │  Ethernet / TCP
               │
┌──────────────▼───────────────────────────────────────────┐
│        PLC Mitsubishi Série Q/L                          │
│        Módulo Ethernet (porta 2001)                      │
└──────────────────────────────────────────────────────────┘

Comandos MC utilizados

| Comando | Código | Subcomando | Descrição | |---------|--------|------------|-----------| | Batch Read | 0x0401 | 0x0000 (word) | Leitura de dispositivos word | | Batch Read | 0x0401 | 0x0001 (bit) | Leitura de dispositivos bit | | Batch Write | 0x1401 | 0x0000 (word) | Escrita em dispositivos word | | Batch Write | 0x1401 | 0x0001 (bit) | Escrita em dispositivos bit |


Observações de Segurança

⚠️ ATENÇÃO: Esta biblioteca comunica diretamente com equipamentos industriais. Escritas incorretas podem causar falhas de processo, danos a equipamentos ou riscos à segurança.

  • Teste sempre em ambiente controlado antes de usar em produção.
  • Valide os valores antes de escrever no PLC.
  • Configure proteções no PLC (Remote Password, restrições no módulo Ethernet) conforme necessário.
  • A biblioteca usa apenas net (nativo do Node) — zero dependências externas.

Licença

MIT