본문 바로가기
대한상공회의소 스마트팩토리 교육/데이터베이스

[데이터베이스 운영] DBMS 기초 «수업-10» : [미니프로젝트 Ver 3.0] 스마트 팩토리 설비관리 S/W Using C# & MySQL & Arduino

by 나는영하 2022. 5. 19.

※ 주의사항 

본 블로그는 수업 내용을 바탕으로 제가 이해한 부분을 정리한 블로그입니다.
본 내용을 참고로만 보시고, 틀린 부분이 있다면 지적 부탁드립니다!

감사합니다😁

 


미니프로젝트 Ver 3.0

스마트 팩토리 설비관리 S/W


대망의 [미니프로젝트 Ver 3.0]을 소개드릴 차례입니다. 

지난 미니프로젝트 Ver1과 Ver2는 이미지 영상처리를 주제로 프로젝트를 진행하였다면 이번 Ver3은 데이터베이스 연동을 메인으로 하여 진행하였습니다. 

 

간단히 설명을 드리자면 Arduino에 온습도 모듈 센서와 RFID 센서를 연결합니다. 

온습도 모듈 센서(DHT-11)를 통해 들어오는 센서 데이터 값은 C#과 Serial 및 DB 연동을 통해 바로 MySQL의 테이블에 저장을 하고, RFID 센서에 사용자가 카드를 태깅할때마다 카드 ID 값을 전달받고 이를 통해 사용자(관리자) 관리 기능을 제공하였습니다. 그리고 DB에 저장된 온습도 센서의 데이터 값은 C#의 윈폼을 통해 사용자에게 직관적으로 모니터링 기능을 구현하였습니다. 

 

 

1. 프로젝트 시연 동영상 및 코딩 소스

1-1. 시연 동영상

https://tv.kakao.com/channel/3941697/cliplink/428680847

 

1-2. 코딩 소스(C#)

[미니프로젝트Ver3.0]C#_Code.zip
0.01MB

 

 

1-3. 코딩 소스(Arduino & MySQL)

220508_arduino.txt
0.00MB
220508_MySQL.txt
0.00MB

 

 


2. 스마트 팩토리 설비관리 S/W 개요

2-1. 프로젝트 작업 환경

프로젝트 계통도

✔ 프로젝트 이름 : [미니프로젝트 Version 3.0] 스마트 팩토리 설비관리 S/W

✔ 사용 OS : Windows 10 (Pro 64Bit)

✔ 사용 언어 : C#, C(Arduino), Quarry(MySQL)

✔ 사용 Tool : VisualStudio2022, Arduino IDE, MySQL Workbench

✔ 프로젝트 기간 : 2022. 05. 04 ~ 2022. 05. 10(7일)


2-2. 데이터베이스(MySQL) 구축 : 테이블 설계

1) smartUser 테이블 & workerTime 테이블

(좌)smartUser 테이블 / (우) workerTime 테이블

✔ 관리자의 계정 생성 및 관리, 출퇴근 기록부 확인용

✔ 각 테이블의 RFID 열은 각각 PRIMARY KEY와 FOREIGN KEY

순서(Num)는 데이터 생성시 자동으로 증가하도록 AUTO_INCREMENT 사용

✔ 생성일 및 퇴근시간 열은 DEFAULT 값으로 현재 시간 입력(CURRENT_TIMESTAMP)

 

2) dht11 테이블

dht11 테이블

✔ 온습도 센서값 저장용 테이블(5초에 한번씩) --> C# 타이머 이벤트

 순서(Num)는 데이터 생성시 자동으로 증가하도록 AUTO_INCREMENT 사용

✔ 측정 시간은 DEFAULT 값으로 현재 시간 입력(CURRENT_TIMESTAMP)

 

※ 쿼리문은 본문 상단에 위치한 소스 코드 파일 참고

 


2-3. 하드웨어 구축(Arduino)

프로젝트 작업 사진(Arduino)

1) 헤더문 및 전처리문

#include <SPI.h>
#include <MFRC522.h>
#include "DHT.h"

#define SS_PIN 53
#define RST_PIN 5
#define DHTPIN 2     // Digital pin connected to the DHT sensor
#define DHTTYPE DHT11   // DHT 11

MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class
MFRC522::MIFARE_Key key;
DHT dht(DHTPIN, DHTTYPE);
String smartStatus;

RFID와 온습도센서(DHT11)과 관련된 코드 및 헤더파일들은 기존의 라이브러리를 참고해서 사용하였습니다.

 

2) Setup 함수부

void setup() {
  Serial.begin(9600);
  SPI.begin(); // Init SPI bus
  rfid.PCD_Init(); // Init MFRC522
  dht.begin();
  smartStatus = "rfid";
}

3) RFID 인식

 if (smartStatus == "rfid") {

    if (Serial.available() > 0) {
      char data = (char)Serial.read();
      if (data == 'a')smartStatus = "dht11";
      else smartStatus = "rfid";
    }

    if ( ! rfid.PICC_IsNewCardPresent()) return;
    if ( ! rfid.PICC_ReadCardSerial()) return;

    String output;
    for (int i = 0; i < 4; i++) {
      output += String(rfid.uid.uidByte[i], HEX);
    }
    Serial.println(output);

    // Halt PICC
    rfid.PICC_HaltA();
    // Stop encryption on PCD
    rfid.PCD_StopCrypto1();
  }

✔ smartStatus 변수값에 따른 센서 동작 수행

 - <rfid>일 경우 RFID 카드 데이터 인식

 - <dht11>일 경우 온습도 센서 데이터 인식

✔ RFID에서 아두이노로 오는 데이터는 16진수 데이터이기 때문에 이를 문자열 형태로 변형해서 전송

 

4) 온습도 센서(DHT11) 인식

else if (smartStatus == "dht11") {
    if (Serial.available() > 0) {
      char data = (char)Serial.read();
      if (data == 'a')smartStatus = "dht11";
      else smartStatus = "rfid";
    }
    delay(5000);
    float h = dht.readHumidity(); // 습도
    float t = dht.readTemperature(); // 온도
    float hic = dht.computeHeatIndex(t, h, false); // 체감온도
    Serial.println(String(h) + "," + String(t) + "," + String(hic));
  }

2-4. 소프트웨어 구축(C#)

C# Form 계통도

C# Windows Forms 앱(.NET Framework)을 통해 GUI환경으로 소프트웨어를 구축하였습니다. 

총 7개의 폼과 2개의 사용자 정의 컨트롤이 유기적으로 동작하는 소프트웨어를 구성하였습니다.

SerialPort를 통해 데이터를 받는 이벤트부는 ConnectForm에 위치해있으며, DB를 사용하는 Form에서는 ConnectForm의 DB연결 String을 클래스의 전달인자로 받아서 DB연결 및 쿼리문 처리를 수행하게 됩니다. 

 

※ 두개의 센서를 동시에 사용할 경우 RFID의 데이터와 온습도 센서의 데이터를 구분해서 받도록 하는 부분을 구성하지 못해서 메인 폼에서 버튼을 통해 한개의 센서 데이터만 받도록 수정하였습니다. 추후 최종 프로젝트에서 다중센서의 데이터를 수집할때는 개선해보도록 하겠습니다.😥 (아두이노에서 DB로 바로 데이터를 저장하면 어떨까요..?)


3. 스마트 팩토리 설비관리 S/W 기능 설명

※ Form 이미지를 보면서 간략한 코드 및 동작 설명만 진행합니다.

전체적인 코드는 첨부한 코드 파일을 참고해주세요 😁

3-1. 메인화면

메인화면에서는 3곳의 Form으로 이동을 할 수 있습니다. 

1) DB와 아두이노를 연결하는 ConnectForm

2) 온습도 센서(DHT11)의 데이터값을 실시간으로 모니터링하는 SensorForm,

3) RFID 센서를 통해 관리자(사용자)의 데이터를 관리하는 userForm

이중에서 2번과 3번은 SerialPort를 연결하기 전에는 비활성화 상태로 놓여지게 됩니다.

(RFID 카드와 온습도 센서가 정상적으로 동작해야 해당폼을 사용할 수 있기 때문에 초기는 비활성화 상태로 설정해두었습니다. 😀)

 

✔ 우측 하단 CheckBox의 상태에 따른 이벤트 발생 함수부

private void checkbox_CheckedChanged(object sender, EventArgs e)
        {
            if (cfm.serialPort1.IsOpen)
            {
                if (checkbox.Checked == true)
                {
                    cfm.serialPort1.Write("a");
                    checkbox.Text = "온습도 센서 인식";
                    cfm.status = "dht11";
                }
                else
                {
                    cfm.serialPort1.Write("b");
                    checkbox.Text = "RFID 카드 인식";
                    cfm.status = "rfid";
                }
            }
            else
            {
                MessageBox.Show("시리얼 포트가 닫혀있습니다.");
            }
        }

 connectForm을 생성자로 호출하여서 SerialPort가 연결되어있고, 메인화면의 CheckBox의 상태에 따라 센서를 다르게 인식하도록 구성하였습니다. 

connectForm 생성자

CheckBox의 상태에 따라 connectForm에서 연결한 SerialPort를 통해 아두이노로 'a' 또는 'b'의 문자열을 보내게 됩니다. 그러면 아두이노에서 'a'를 받는지 'b'를 받는지 구분하여서 'a'를 받을때는 온습도 센서가 동작하도록 하고, 'b'를 받을때는 RFID 카드를 인식할 수 있도록 구성하였습니다.

 

또한 status의 변수 값에 따라 아두이노에서 보내오는 데이터를 바로 DB에 저장하거나(온습도 센서일 경우) 아니면 또 다른 변수에 저장(RFID 센서일 경우)해서 추후 다른 폼에서 가공하여 사용하게 됩니다.


3-2. 연결화면

1) SerialPort 연결 코드부

 if (!serialPort1.IsOpen)
            {
                serialPort1.PortName = comboBox1.Text;
                // "COM" + nud_port.Value.ToString();
                serialPort1.BaudRate = int.Parse(tb_speed.Text);
                serialPort1.Open();
                pb_serial.BackColor = Color.Green;
                listBox1.Items.Add(comboBox1.Text + "과 연결되었습니다.");
                btn_ok.Enabled = false;
                this.DialogResult = DialogResult.OK;
            }

2) DataBase 연결 코드부

 try{
        connStr = "Server = 192.168.56.101; Uid = " + tb_id.Text + "; Pwd = " + tb_pwd.Text + "; Database = smartfactory; Charset = UTF8";
        conn = new MySqlConnection(connStr);
        conn.Open();                
        if (conn.Ping() == true)
        {
            MySqlCommand cmd = new MySqlCommand("", conn);
            listBox1.Items.Add(tb_id.Text + "님 안녕하세요. DB와 연결되었습니다.");                    
            tb_id.Text = "";
            tb_pwd.Text = "";
            pb_db.BackColor = Color.Green;
            btn_db_ok.Enabled = false;
            this.DialogResult = DialogResult.Yes;
        }

3) Serial Port Data Received 이벤트 함수부

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {

            if (serialPort1.IsOpen)
            {
                if (status == "dht11")
                {
                    string rawdata = serialPort1.ReadLine();
                    rawdata = rawdata.Replace("\n", "").Replace("\r", "");
                    string[] data = rawdata.Split(',');
                    dht11_Humidity = data[0]; //습도
                    dht11_Temperature = data[1]; //온도
                    dht11_computeHeatIndex = data[2]; // 체감온도 
                    
                    listBox1.Items.Add(dht11_Humidity + " %% " + dht11_Temperature + " %% " + dht11_computeHeatIndex); // 5초마다 한번씩 습도,온도,체감온도 값 받음 
                                      
                    cmd = new MySqlCommand("", conn);
                    sql = "INSERT INTO dht11(humi, temp, hic) VALUES(" + dht11_Humidity + "," + dht11_Temperature + ","+ dht11_computeHeatIndex +")";
                    cmd.CommandText = sql;
                    cmd.ExecuteNonQuery();                 
                }
                else if (status == "rfid")
                {
                    tag_id = serialPort1.ReadLine();
                    listBox1.Items.Add(tag_id);
                }
            }
        }

 ✔ Serial Port를 통해 데이터가 수신되었을 경우 이벤트 발생

(UART를 통해 RFID값과 온습도 값을 보내오는 경우)


3-3. 센서 모니터링 화면

 

1) Timer_Tick 이벤트 함수부(일부)

 private void timer1_Tick(object sender, EventArgs e)
        {
            // 5초마다 타이머 리셋 --> 실시간 타이머 표시
            // 온습도센서가 데이터를 보내는 시간이 5초 단위이기 때문에
            using (MySqlConnection conn = new MySqlConnection(connStr))
            {
                DataSet ds = new DataSet();
                String sql = "SELECT * FROM dht11 ORDER BY dht11_date DESC limit 1";
                MySqlDataAdapter adpt = new MySqlDataAdapter(sql, conn);
                adpt.Fill(ds, "dht11");

                float chart_temp = float.Parse(ds.Tables[0].Rows[0]["temp"].ToString());
                float chart_humi = float.Parse(ds.Tables[0].Rows[0]["humi"].ToString());
                float chart_hic = float.Parse(ds.Tables[0].Rows[0]["hic"].ToString());

                for (int i = 0; i < tempAry.Length - 1; i++)
                {
                    tempAry[i] = tempAry[i + 1];
                    humiAry[i] = humiAry[i + 1];
                    hicAry[i] = hicAry[i + 1];
                }
 // ----------------------------이하 차트 드로잉 코드부 생략 -------------------------------- //

✔ C#에서 5초마다 dht_11 테이블의 최상단 데이터를 가지고와서(SELECT) 차트에 드로잉 해준다(Timer 사용)


3-4. 로그인 및 관리자 추가 화면

1) 신규 관리자 로그인 화면

Arduino에서 보내온 RFID 번호를 기준으로 DB 조회

✔ 해당 RFID와 일치하는 데이터가 있을 경우 :

 - 사용자가 이름과 비밀번호 입력 → 해당 이름과 비밀번호가 DB와 일치할 경우 workerForm 으로 이동

✔ 해당 RFID와 일치하는 데이터가 없을 경우 :

 - 관리자 추가 Button 활성화(DEFAULT 비활성화) → 클릭 시 newUserForm 으로 이동 

 

2) 신규 관리자 등록 화면

✔ 해당 RFID를 고유 번호로 사용할 관리자의 인적사항 입력

✔ 신규관리자 생성시 DB상에는 자동으로 생성 일자 입력

 - DB상 DEFAULT일 경우 CURRENT_TIMESTAMP 함수 수행


3-5. 출퇴근 기록 화면 

1) 퇴근처리 버튼 클릭 함수부

private void btn_out_Click(object sender, EventArgs e)
        {           
            sql = "SELECT * FROM workerTime ORDER BY num DESC LIMIT 1";
            cmd.CommandText = sql;
            MySqlDataReader reader = cmd.ExecuteReader();
            
            while (reader.Read())
            {
                num = int.Parse(reader["num"].ToString());
            }
            reader.Close();

            String leaveTime;
            leaveTime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
            sql = "UPDATE workerTime SET leaveTime = '" + leaveTime + "' WHERE num = "+ num;
            cmd.CommandText = sql;
            int count = cmd.ExecuteNonQuery();
            if (count > 0)
            {
                MessageBox.Show("퇴근처리되었습니다.");
                panel_main.Controls.Clear();
                workersc1 = new workerScreen.workerScreen1(rfid_id, connStr);
                panel_main.Controls.Add(workersc1);
            }
        }

✔ "퇴근처리" 버튼 클릭 시 해당 RFID 카드 기준 가장 최근 DB의 데이터 조회

✔ 퇴근시간 열(leaveTime)에 현재 시간(DateTime.Now) 입력

 


3-6. 관리자 데이터 관리 및 수정 화면

1) 관리자 데이터 관리 화면

✔ 수정 및 삭제하고자 할 관리자 계정을 Check Box 선택 후 [삭제] 또는 [수정] 클릭

✔ "삭제" 클릭 시 Yes Or No 메시지 박스 출력 후 DB 삭제

✔ "수정" 클릭 시 관리자 수정 창(userUpdateForm)으로 이동

 

2) 관리자 데이터 수정 화면

✔ 관리자가 비밀번호 입력 후 편집 버튼 클릭

→ DB상 비밀번호와 비교 대조

✔ 일치할 경우 이름, 비밀번호, 부서명, 직책, 생년월일 수정 가능 (해당 TextBox 활성화)

댓글