WinCC Unified Open Pipe es una interfaz que permite conectar aplicaciones personalizadas al Runtime de WinCC Unified. Open Pipe proporciona un conjunto limitado de funcionalidades. Sin embargo, su principal ventaja radica en la flexibilidad, ya que el código de conexión puede escribirse en cualquier lenguaje de programación que soporte la tecnología “pipes”, como Python, Node.js o PowerShell.

Después de la descripción, no te puede faltar la documentación necesaria 🙂

Potenciando tu SCADA WinCC Unified Runtime

El objetivo del proyecto es que nuestro proyecto en Node.js se encargá de suscribirse a las alarmas del Runtime de WinCC Unified y, cuando detecte una alarma de máxima prioridad, reproducira el texto de la alarma en los altavoces del Servidor SCADA de la sala de control.

Flujo general del proyecto:

  • Crear un proyecto en Node.js que se comunique con el WinCC Unified Runtime y nos permita suscribirnos a las alarmas para recibir notificaciones.
  • Los pasos para crear el proyecto una vez instalado Node.js

  • El código app.js que puedes copiar directamente
const net = require('net');
const express = require('express');
const say = require('say');

const app = express();
const PORT = 3000;
const pipePath = '\\\\.\\pipe\\HmiRuntime';

let lastAlarmValue = "FALSE"; // Estado previo de la alarma
let clients = []; // Lista de clientes conectados

// Conexión con Open Pipe
const client = new net.Socket();

client.connect(pipePath, () => {
  console.log('Conectado a Open Pipe');

  // Comando para suscribirse a las alarmas
  const subscribeCommand = JSON.stringify({
    Message: "SubscribeAlarm",
    Params: {
      SystemNames: [],
      Filter: "Name = 'AlarmOpenPipe'",
      LanguageId: 1033
    },
    ClientCookie: "myAlarmSubscription"
  }) + '\n';

  client.write(subscribeCommand);
  console.log('Suscripcion enviada al servidor.');
});

// Escuchar datos de Open Pipe
client.on('data', (data) => {
  const response = data.toString();

  try {
    const jsonResponse = JSON.parse(response);

    if (jsonResponse.Message === "NotifySubscribeAlarm") {
      const alarms = jsonResponse.Params?.Alarms;

      if (!alarms || alarms.length === 0) return;

      alarms.forEach(alarm => {
        const mensaje = alarm.EventText?.trim();
        const alarmValue = alarm.Value;

        if (!mensaje) return;

        // Detectar solo el cambio de 0 a 1 (alarma activada)
        if (lastAlarmValue === "FALSE" && alarmValue === "TRUE") {
          console.log(`ALARMA ACTIVADA: ${mensaje}`);

          // Enviar a los clientes suscritos y limpiar la lista
          clients.forEach(res => res.json({ alarm: alarm.Name, text: mensaje }));
          clients = [];

          // Usar voz para reproducir el mensaje
          say.getInstalledVoices((voiceErr, voices) => {
            if (!voiceErr) {
              const chosenVoice = voices.find(v => v.toLowerCase().includes('helena'))
                || voices.find(v => v.toLowerCase().includes('sabina'))
                || 'Microsoft Helena Desktop';
              say.speak(mensaje, chosenVoice);
            } else {
              console.error('Error al obtener voces:', voiceErr);
            }
          });
        }

        lastAlarmValue = alarmValue; // Actualizar estado de la alarma
      });
    }
  } catch (error) {
    console.error('Error procesando la respuesta:', error);
  }
});

// Manejo de errores de conexión
client.on('error', (error) => {
  console.error('Error en la conexion:', error);
});

// API para suscripciones
app.get('/subscribe', (req, res) => {
  clients.push(res);
});

// Iniciar servidor
app.listen(PORT, () => {
  console.log(`Servidor API corriendo en http://localhost:${PORT}`);
});


Y ya tenemos montado todo lo necesario…


Y una imagen vale más que mil palabras… ¡unos segundos de video!
Activa el sonido 😉