개인적으로 IoT, Smart Factory 등 다양한 분야에서 활용할수 있을거라 생각됨.

 

1. 웹 어플리케이션을 통해 접근 가능.

2. 다양한 모듈을 지원하고 있기때문에 쉽게 개발 가능

3. OPC-UA등의 프로토콜을 지원해주기때문에 스마트 팩토리 등 다양한 분야에 접목 가능.

4. Rasberry Pi 등에서도 쉽게 구동 가능 

 

최근 정부에서 지원하는 스마트팩토리 사업으로 많은 곳에서 산업 현장에서는 생산 현장의 다양한 데이터를 요구로 하고 있는데, OPC 서버, 또는 데이터 수집용 PC를 구매하는 등의 비용을 라즈베리 파이 등으로 대체하여 비용절감도 가능할 것으로 보여짐.

 

기존에 설치되어 있는 설비들도 Modbus, BACNet, Serial, UDP등 통신을 지원한다면 이것도 쉽게 모니터링.

(또는 센서들의 값을 아두이노 등의 프로서세를 통해 받아오는것도 가능)

 

 

 

LS-PLC를 기준으로 데이터를 읽고, 데이터 저장(DB)등까지 포스팅 할 예정.

 

 

 

**NodeRed, NodeJS, Javascript에 대한 내용들은 아래 강의를 참조

  1. https://opentutorials.org/module/532 (생활코딩 JavaScript 강좌)
  2. https://opentutorials.org/course/2136 (생활코딩 NodeJS 강좌)
  3. https://goo.gl/3VvX2r (생활코딩 NodeJS 유튜브 재생목록)

 

생각보다 길지 않고 빨리 끝나네요. 

프론트엔드쪽도 크게 손대지 않고 간단히 처리하도록 하겠습니다. 

 

1. 

SignalR을 사용하기 위해 필요한 패키지를 npm으로 설치해줍니다. (ClientApp 폴더로 이동해서요)

npm install @microsoft/signalr

 

2. 

우선 Monitoring Component부터 우선 만들어줍니다. (./components/PlcMonitor.js)

기본적으로 클래스형으로 만들어져 있지만, 함수형이 쉽고 성능면에서 좋다고 합니다.

signalR의 hubConnectionBuilder를 사용할건데요, connection 객체를 만들어주고, 

속성을 지정해줍니다. 생각보다 어렵지 않습니다. 더군다나 데이터를 받기만 할거라서요.

 

**withUrl의 경우, 앱이 구동되는 url(localhost:****)을 적어주시면 되고, 마지막 /plc가 렌더링 될 페이지의 경로라고 생각하시면 됩니다. 이 부분은 앞서 서버쪽에서 마지막 startup.cs부분의 endpoints.MapHub<PlcHub>('/plc') 부분과 동일합니다.

 

** connection.on("ReceiveData", ~) 에서 데이터를 받는 부분입니다. 

 

import React, { useEffect, useState } from 'react';
import { HubConnectionBuilder } from '@microsoft/signalr';

const PlcMonitor = () => {
    const [data, setData] = useState([]);
    useEffect(() => {
        const connection = new HubConnectionBuilder()
            .withUrl('https://localhost:44327/plc')
            .withAutomaticReconnect()
            .build();

        connection.start()
            .then(result => {
                connection.on("ReceiveData", data => {
                    setData(data);
                });
            })
            .catch(e => console.log(e));
    }, [])

    return (
        <h1>{ data.value }</h1>
        )
}

export default PlcMonitor;

 

3. 이제 페이지 네이게이션 아이템에 추가해줍니다. 

 

1. 

가장 중요한 일은 프로젝트를 생성하는 일입니다. 최근엔 Visual Studio에서 ASP.NET CORE로 프로젝트를 생성할때 리액트를 프론트엔드로 선택할 수 있습니다.  ASP.NET Core 3.1 기준이라, ASP.NET으로 하는 경우 제대로 안될수도 있음을 미리 알아두시길 바랍니다 

 

 

2. 

프로젝트를 만든후 실행하면, 짜잔- 이렇게 기본 예제가 포함된 프로젝트가 실행됩니다. 프론트엔드 삼대장중 하나인 리액트로 만들어진 프로젝트가 완성되었습니다. 

 

3. 

우선 BackEnd쪽을 손대보도록 하겠습니다. Modbus.Net.Core, Modbus.Net.Modbus.Core 이 두가지를 Package Manager(Nuget Manager)로 설치해줍니다. 이 패키지는 모드버스 통신을 하기위함입니다. 그냥 온라인상에 돌아다니는 EasyModbus.Dll을 사용하면 더 편하겠지만, 이게 .net core 용이 아니라 동작이 안되요. 아니면 직접 프로토콜을 구현하셔도 됩니다. 

 

4. 

프로젝트 폴더에 Hubs 폴더를 추가하고, PlcHub.cs를 생성합니다. 

별다른 내용은 없어도 됩니다. 브라우저와 계속해서 데이터를 주고받는 경우엔 여기서 코드를 추가하시면 됩니다만,

이번의 경우 서버쪽에서 PLC쪽으로 계속해서 데이터를 전달해주기만 하는 예제라, 백그라운드에서 호스트를 돌릴거에요. 

 

나중에 시간이 되면 PLC로 데이터를 전달하는 것도 다루어 보겠습니다. 

(안전상의 이유로 웹페이지에서 PLC를 제어하는것은 추천드리지는 않습니다. 그러면서 글 제목이 PLC 제어라는게 아이러니네요. 그래도 모니터링이 된다면 제어도 간단하겠죠?)

 

 

5. 

프로젝트 하위 폴더에 Models폴더를 생성 후, PlcData.cs를 만들어줍니다. 

그리고 어떠한 내용을 전달할지 적어줍니다. 저는 Address와 해당 어드레스의 데이터를 프로퍼티로 잡아보겠습니다.

 

6. 

HostedService를 만들어줘야합니다. HostedService는 서버에서 호스팅 되는 서비스를 백그라운드로 돌려줍니다. 타이머로 주기적인 작업을 요하는 경우에 요긴하게 사용할수 있습니다. 

MSDN ) docs.microsoft.com/ko-kr/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio

기본 예제까지 충분히 나와있습니다. 

 

우선 Services 폴더를 프로젝트 하위 폴더에 생성 후 , PlcMonitorHostedService.cs를 만들어줍니다. 

코드는 다음과 같습니다.  모드버스는 EasyModbus.dll 이라는 라이브러리를 사용하면 편하지만 .net core 에선 안먹힙니다. 그냥 Nuget Manager에서 Modbus.Net.Modbus.Core를 추가해주세요. 

 

아래코드는 아이템 하나만 읽어 브라우저측으로 보내는 역할을 합니다. 

 

using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using TestApp.Hubs;
using Modbus.Net;
using Modbus.Net.Modbus;
using TestApp.Models;

namespace TestApp.Services
{
    //IHostedService를 상속받으면, 기본적으로 StartAsyc와 StopAsync로 타이머를 시작하고 멈출수 있습니다.
    //서버가 시작되면 자동으로 실행됩니다. 
    //IHubContext<PlcHub>는 SignalR로 통신하기 위한 컨텍스트입니다. 
    //machine 은 모드버스를 통신하기 위한 부분입니다. 
    
    public class PlcMonitorHostedService:IHostedService
    {
    	
        private Timer _timer;
        private readonly IHubContext<PlcHub> _hubContext;
        ModbusMachine machine;


		// 우선 생성자를 통해, HubContext를 만들어주고, 기본적인 모드버스 설정을 해줍니다. 
        // 모드버스 어드레스와 아이템 등을요.
        public PlcMonitorHostedService(IHubContext<PlcHub> hubContext)
        {

            _hubContext = hubContext;
            if (machine == null)
            {
                machine = new ModbusMachine(ModbusType.Tcp, "127.0.0.1:502", new List<AddressUnit>()
                {
                    new AddressUnit()
                    {
                        Id="1",
                        Area="4X",
                        Address=1,
                        CommunicationTag = "Add1",
                        DataType=typeof(ushort),
                        Zoom = 1,
                        DecimalPos = 0
                    }
                }, 2, 0);
            }

            machine.KeepConnect = true;
            machine.Connect();

        }


		//StartAsync는 서버가 실행되면 동작합니다.  TimeSpan에서 어느 주기로 프로그램을 실행할지 정해줍니다. 
        public Task StartAsync(CancellationToken cancellationToken)
        {

            _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
            return Task.CompletedTask;
        }
        
        
		// 실제 timer가 실행할 작업이죠. 어떤 모드버스가 연결되어 있는 경우, 
        // 해당 데이터를 읽어, SignalR을 통해 접속된 모든 브라우져로 데이터를 보냅니다. 
        // _hubContext.Clients.All.SendAsync에서 "ReceiveData"는 브라우져측, 즉 React에서 받을 함수의 이름입니다. 
        
        private void DoWork(object state)
        {

            try
            {
                if (machine.IsConnected)
                {
                    var result = machine.GetDatas(MachineGetDataType.CommunicationTag).MapGetValuesToSetValues();
                    var data = new PlcData
                    {
                        address = "40000",
                        value = result["Add1"].ToString()

                    };

                    _hubContext.Clients.All.SendAsync("ReceiveData", data);

                }
                else
                {
                    var failure = new PlcData
                    {
                        address = "null",
                        value = "Cannot Read Data"
                    };
                    _hubContext.Clients.All.SendAsync("ReceiveData", failure);
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.ToString());
            }
        }

        
	// IHostedService를 상속하면서 나온 StopAsync입니다. 서버가 멈추면 동작하죠.
        public Task StopAsync(CancellationToken cancellationToken)
        {
            _timer?.Change(Timeout.Infinite, 0);
            return Task.CompletedTask;
        }
    }
}

 

7.

이제 거의 다 끝났습니다. Startup.cs로 넘어가 컨피규레이션에 이렇게 추가해주시면 됩니다. 

public void ConfigureServices(IServiceCollection services)
{
    services.AddHostedService<PlcMonitorHostedService>();
    services.AddSignalR();
}
    
    
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
     app.UseEndpoints(endpoints =>
     {
          endpoints.MapControllerRoute(
              name: "default",
              pattern: "{controller}/{action=Index}/{id?}");
          endpoints.MapHub<PlcHub>("/plc");
      });
 }

 

 

 

+ Recent posts