Skip to content

Este software realiza una comunicación serial RS232 entre dos balanzas OHAUS . Trabajo realizado por la pasante Melani en la Planta de Newsan TDF

Notifications You must be signed in to change notification settings

AngieSiles/BalanzaOHAUS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Balanza Ohaus

JavaScript HTML5 CSS3 Electron Nodejs JSON Git

Pantalla Inicial Este proyecto tiene como finalidad reconocer si un peso se encuentra dentro o fuera de un rango, ingresando valores de un peso predeterminado y una tolerancia mínima y máxima. El sistema toma información en tiempo real desde un puerto serial (COM), que envía datos de peso y unidad de medida, los procesa y muestra su estado visualmente en la interfaz.

Características principales

  • Visualización de puestos de balanzas.
  • Detección de peso dentro o fuera del rango permitido.
  • Apertura y cierre de puertos COM desde la interfaz.
  • Detección automática de puertos disponibles.
  • Comunicación en tiempo real mediante Socket.IO.

Funcionamiento general

  • El trabajo se divide en dos partes principales:
  1. Servidor – serverv2.js Es el backend del sistema, encargado de manejar la comunicación con la balanza real a través del puerto COM. Desde aquí se detectan los puertos disponibles, se abren o cierran conexiones y se procesan los datos que llegan en tiempo real desde la balanza (peso y unidad de medida).
  2. Cliente – index.html y script.js El archivo index.html muestra la interfaz visual con los puestos de balanza y sus valores en tiempo real. Por otro lado, script.js se encarga de la comunicación entre el cliente y el servidor, utilizando Socket.IO. En este archivo están las funcionalidades específicas para verificar si el peso está dentro del rango permitido, manejar los eventos de los sockets, actualizar el color de los puestos y controlar la apertura o cierre de puertos desde la interfaz.
El sistema se comunica en tiempo real utilizando Socket.IO, lo que permite que cada lectura de peso enviada desde el servidor se refleje de inmediato en la pantalla del usuario, sin necesidad de recargar la página.

¿Cómo funciona?

  • El servidor detecta los puertos COM disponibles usando la librería serialport.
  • Cuando el usuario selecciona un puerto y abre la conexión al enviar con esto los datos de peso determinado y la tolerancia, el servidor empieza a leer los datos enviados por la balanza.
  • Esos datos (peso y unidad) se envían al cliente mediante un socket.
  • En el frontend, se procesa el peso recibido y se compara con el peso objetivo y la tolerancia ingresados.
  • Si el valor está dentro del rango permitido → la pantalla se vuelve verde. Vista de interfaz
  • Si está fuera → se vuelve roja. Vista de interfaz

Peso dentro del rango elegido

Pantalla balanza dentro del rango En esta pantalla podemos visualizar que se pone verde cuando el peso está dentro del rango de diferencia o suma de la tolerancia permitida

Peso fuera del rango elegido

Pantalla balanza fuera del rango En esta pantalla podemos visualizar que se pone roja cuando el peso está fuera del rango de diferencia o suma de la tolerancia permitida

Funciones/Partes importantes de codigo

1. Recibimiento y procesamiento de los datos en el cliente

En script.js, el cliente recibe los valores emitidos por el servidor y cambia el color de fondo según si el peso está dentro o fuera del rango:

    socket.emit("abrirPuerto", puertoSeleccionado);
    socket.on("peso", (data) => {
        console.log("Abierto");
        console.log("puestos", puestos);

        if (puestos[puestoId.id] && puestos[puestoId.id].puerto === data.puerto) {
            const pesoElement = document.getElementById(`peso${puestoId.id}`);
            const valor = data.valor;
            const unidad = data.unidad;
            pesoElement.innerText = valor.toFixed(1) + unidad;
            const { defecto, diferencia } = puestos[puestoId.id];
            if (valor > defecto - diferencia && valor < defecto + diferencia) {
                pesoElement.style.backgroundColor = "#61D864";
                pesoElement.style.color = "#449646";
            } else {
                pesoElement.style.backgroundColor = "#FF625B";
                pesoElement.style.color = "#BE4843";
            }

        }
    });

Qué hace:

  • Llama al evento de abrir el puerto
  • Escucha los datos del servidor.
  • Muestra el peso actual.
  • Cambia el color dependiendo del resultado.

2. Apertura del puerto y Lectura de datos desde el puerto COM

Este fragmento del servidor (serverv2.js) muestra cómo se abre un puerto COM y se procesan los datos recibidos desde la balanza:

function abrirPuerto(puertoCOM) {
    const puerto = new SerialPort({ path: puertoCOM, baudRate: 9600 }, (err) => {
        if (err) {
            console.log(`Error al abrir puerto ${puertoCOM}: ${err.message}`);
            io.emit('statusCOM', { puerto: puertoCOM, estado: false });
            return;
        }
    });
    const parser = puerto.pipe(new ReadlineParser({ delimiter: '\n' }));
    conexiones[puertoCOM] = {
        puerto,
        parser,
        estado: false
    };
    puerto.on('open', () => {
        console.log(`Puerto ${puertoCOM} abierto`);
        conexiones[puertoCOM].estado = true;
        io.emit('statusCOM', { puerto: puertoCOM, estado: true });

        puerto.write("Z\r\n");
        puerto.write("CP\r\n");
    });
    parser.on('data', (data) => {
        const receivedData = data.trim();
        const match = receivedData.match(/(-?\d+(\.\d+)?)/);
        if (match) {
            const peso = parseFloat(match[0]);
            // Emitimos indicando de qué puerto viene
            io.emit('peso', { puerto: puertoCOM, valor: peso, unidad: 'g' });
        }
    });
}

Qué hace:

  • Abre el puerto seleccionado.
  • Lee los datos enviados por la balanza.
  • Los convierte a número y los envía al cliente por Socket.IO.

3. Listado en tiempo real de los puertos disponibles

El sistema detecta automáticamente los puertos disponibles y los actualiza cada segundo:

setInterval(async () => {
    const listaPuertos = await listarPuertosCOM();
    if (JSON.stringify(listaPuertos) !== JSON.stringify(puertosPrevios)) {
        puertosPrevios = listaPuertos;
        io.emit('puertosCOM', listaPuertos);
        console.log("puertos actualizada:", listaPuertos);
    }
}, 1000);

Qué hace:

  • Verifica constantemente si hay cambios en los puertos conectados por alguna conexión o desconexión en tiempo real.
  • Actualiza la lista en el frontend sin necesidad de recargar la página.

4. Lista de puertos en la interfaz

Recibe del servidor la lista de puertos COM disponibles y los muestra en el menú desplegable para que el usuario pueda seleccionarlos:

function obtenerPuertos() {
    socket.on("puertosCOM", (listaPuertos) => {
        const select = document.getElementById("puertoCOMSelect");
        select.innerHTML = "";
        if (listaPuertos.length === 0) {
            select.innerHTML = '<option value="">no hay puertos</option>';
        } else {
            listaPuertos.forEach(puerto => {
                select.innerHTML += `<option value="${puerto}">${puerto}</option>`;
            });
        }
    });
}
obtenerPuertos()

Qué hace:

  • Muestra los puertos COM disponibles en la interfaz para que el usuario pueda elegir uno.
    • Si no hay puertos disponibles, muestra un mensaje indicando “no hay puertos”.
    • Si hay puertos disponibles, los agrega como opciones seleccionables en la interfaz.
  • Actualiza la lista automáticamente cuando el servidor envía cambios.

5. Interfaz visual

El HTML muestra cada “puesto” de balanza, con el valor del peso y el botón de configuración:

<div class="puesto" id="P#">
  <div class="titulo">
    <button class="btn" onclick="abrir(P#)">
      <img src="Assest/Group 4013.png" class="ajustes">
    </button>
    <span>PUESTO #</span>
  </div>
  <div class="cuerpo" id="pesoP1">0.0</div>
</div>

Qué hace:

  • Cada “puesto” representa una balanza conectada.
  • Cuando el usuario la configura, se abre una ventana para elegir el puerto, peso predeterminado y tolerancia.

6. Cierre de puerto

Esta parte del servidor se encarga de manejar el cierre de la conexión con el puerto COM. Hay dos formas en que puede ocurrir el cierre:

  • Cierre automático: Se ejecuta cuando el puerto se cierra por causas externas (por ejemplo, si se desconecta la balanza). Actualiza el estado del puerto, avisa al cliente y elimina la conexión.
puerto.on('close', () => {
    console.log(`Puerto ${puertoCOM} cerrado`);
    conexiones[puertoCOM].estado = false;
    io.emit('statusCOM', { puerto: puertoCOM, estado: false });
    delete conexiones[puertoCOM];
});
  • Cierre manual: Permite cerrar el puerto manualmente desde el servidor (por ejemplo, si el usuario lo solicita desde la interfaz).
function cerrarPuerto(puertoCOM) {
    if (conexiones[puertoCOM] && conexiones[puertoCOM].puerto.isOpen) {
        conexiones[puertoCOM].puerto.close();
        console.log(`Puerto ${puertoCOM} cerrado manualmente`);
    }
}

Qué hace:

  • Cierra la conexión entre el servidor y el puerto COM.
  • Detiene el envío de datos hacia el cliente.
  • Actualiza el estado del puerto para que el sistema sepa que ya no está activo.
  • Evita que se sigan recibiendo lecturas de peso de la balanza.

7. Cierre de puerto en el cliente

En el frontend, se realiza un cierre manual del puerto COM cuando el usuario decide finalizar la conexión con un puesto (desde el lugar de configuración). Esto detiene la recepción de datos y limpia la interfaz visual correspondiente.

buttoncerrar.addEventListener('click', function() {
    if (puestoActivo !== null) {
        finalizar(puestoActivo);
        puestoActivo = null;
    } else {
        const error = document.getElementById("error");
        error.innerText = `No hay puerto abierto`;
        console.log("no hay puesto");
    }
});

function finalizar(puestoId) {
    if (!puestos[puestoId]) return;

    const puerto = puestos[puestoId].puerto;
    socket.emit("cerrarPuerto", puerto);
    console.log("Puerto cerrado:", puerto);

    const pesoElement = document.getElementById(`peso${puestoId}`);
    pesoElement.innerText = "0.0";
    pesoElement.style.backgroundColor = "#02194A";
    pesoElement.style.color = "white";

    delete puestos[puestoId];

    document.getElementById("caja").style.display = "none";
    document.getElementById("opacidad").style.opacity = "1";
}

Qué hace:

  • Comprueba si hay un puerto abierto
  • Llama a la funcion finalizar() en caso que si
  • Llama al servidor para cerrar el puerto COM manualmente.
  • Detiene la recepción de datos de ese puesto.
  • Limpia la interfaz visual del puesto, dejando el valor en 0 y restaurando los colores por defecto.
  • Elimina la referencia al puesto del registro interno del cliente (puestos).

Manejo de servidor al cliente

En esta parte se manejan las conexiones con el cliente y se envían los datos necesarios para que el frontend pueda interactuar con los puertos COM.

io.on('connection', async (socket) => {
    console.log('Cliente conectado:', socket.id);

    // Enviar la lista de puertos disponibles
    const listaPuertos = await listarPuertosCOM();
    socket.emit('puertosCOM', listaPuertos);

    // Abrir puerto
    socket.on('abrirPuerto', (puertoSeleccionado) => {
        abrirPuerto(puertoSeleccionado);
    });

    // Cerrar puerto
    socket.on('cerrarPuerto', (puertoSeleccionado) => {
        cerrarPuerto(puertoSeleccionado);
    });

    // Detectar desconexión del cliente
    socket.on('disconnect', () => {
        console.log('Cliente desconectado:', socket.id);
    });
});

¿Qué hace?

  • Envía al cliente la lista de puertos COM disponibles.
  • Permite al cliente abrir y cerrar puertos desde la interfaz.
  • Mantiene actualizada la conexión con cada cliente y detecta cuando se desconecta.

Electron

Para convertir el proyecto en una aplicación de escritorio utilizamos Electron. Electron permite empaquetar una aplicación web (HTML, CSS y JavaScript) junto con un servidor Node.js, de forma que el sistema pueda ejecutarse directamente desde una computadora sin necesidad de usar el navegador o instalar dependencias adicionales.

De esta manera, la aplicación puede funcionar como un programa independiente, que se abre con doble clic, manteniendo la comunicación en tiempo real con las balanzas y ofreciendo una interfaz moderna y accesible.

¿Dónde manejamos esto? Main.js

Qué hace:

  • Crea una ventana de la aplicación.
  • Carga la interfaz web (index.html) dentro de esa ventana.
  • Mantiene el servidor corriendo en segundo plano, comunicándose con los puertos y el cliente por Socket.IO.

About

Este software realiza una comunicación serial RS232 entre dos balanzas OHAUS . Trabajo realizado por la pasante Melani en la Planta de Newsan TDF

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors