Commit 36bfc116 authored by Spark's avatar Spark
Browse files

Merge remote-tracking branch 'origin/premaster' into who

parents ea90c8ea e11c97e9
/*
# 실내 데이터 수집기 코드
## 사용자 변수
1. String SSID
2. String SSPW
3. String EUEIP
4. int EUEPORT
5. String ID
6. String locCode
## PC에 연결하여 동작 (시리얼 모니터 사용 O)
시리얼 모니터를 통해 상태를 확인하는 경우, 사용자 변수들의 값만 변경하여 사용합니다.
## 아두이노 단독 실행 (시리얼 모니터 사용 X)
시리얼 모니터를 사용하지 않는 경우, 사용자 변수 값 변경 이외에 아래 "Serial.~~" 꼴로 된 라인은 모두 주석처리 해줍니다.
*/
#include <SoftwareSerial.h> #include <SoftwareSerial.h>
#include <DHT.h> #include <DHT.h>
#include <DHT_U.h> #include <DHT_U.h>
#include <TimeLib.h>
#include <DS1302RTC.h>
#define ESP_TX 2 // ESP8266 모듈의 TX 핀
#define ESP_RX 3 // ESP8266 모듈의 RX 핀
#define ESPPIN_TX 2 // ESP 8266 모듈의 TX 핀 #define RTC_CLK 4 // DS1302RTC 모듈의 CLK 핀
#define ESPPIN_RX 3 // ESP 8266 모듈의 RX 핀 #define RTC_DAT 5 // DS1302RTC 모듈의 DAT 핀
#define RTC_RST 6 // DS1302RTC 모듈의 CLK 핀
#define DHTPIN 7 // DHT11 핀 #define DHT_DAT 10 // DHT11 핀
#define DHTTYPE DHT11 // DHT 모듈 종류 #define DHTTYPE DHT11 // DHT 모듈 종류
#define CDS_D 4 // CDS 모듈 디지털 핀 #define CDS_D 8 // CDS 모듈 디지털 핀
#define CDS_A A0 // CDS 모듈 아날로그 핀 #define CDS_A A0 // CDS 모듈 아날로그 핀
uint32_t delayMS; // 센서를 읽는 지연시간 uint32_t delayMS; // 센서를 읽는 지연시간
SoftwareSerial esp(ESPPIN_TX,ESPPIN_RX); SoftwareSerial esp(ESP_TX,ESP_RX); // ESP 모듈 객체 생성
DHT_Unified dht(DHTPIN, DHTTYPE); DHT_Unified dht(DHT_DAT, DHTTYPE); // DHT 모듈 객체 생성
DS1302RTC rtc(RTC_RST, RTC_DAT, RTC_CLK); // RTC 모듈 객체 생성
String SSID = "Wifi_SSID"; // Wifi - SSID String SSID = "Wifi_SSID"; // Wifi - SSID
...@@ -26,9 +55,11 @@ String SSPW = "Wifi_SSPW"; // Wifi - SSPW ...@@ -26,9 +55,11 @@ String SSPW = "Wifi_SSPW"; // Wifi - SSPW
String EUEIP = "EUE_IP"; // Web Server - IP String EUEIP = "EUE_IP"; // Web Server - IP
int EUEPORT = 8081; // Web Server - Port int EUEPORT = 8081; // Web Server - Port
// 함수 선언부
void connectESP(); void connectESP();
void connectWifi(); void connectWifi();
void sendData(String vars); void sendData(String vars);
void printTime(tmElements_t tm);
void setup() { void setup() {
...@@ -41,8 +72,30 @@ void setup() { ...@@ -41,8 +72,30 @@ void setup() {
connectESP(); // ESP 모듈 탐색 connectESP(); // ESP 모듈 탐색
connectWifi(); // ESP 모듈 wifi 연결 connectWifi(); // ESP 모듈 wifi 연결
// DS1302 RTC 모듈이 작동 중인지 확인
if(rtc.haltRTC()){
Serial.println("The DS1302 is stopped.");
rtc.haltRTC(0);
Serial.println("The DS1302 starts.");
delay(100);
} else{
Serial.println("The DS1302 is working");
}
Serial.println();
// DS1302 RTC 모듈이 쓰기 금지 모드 상태인지 확인
if(rtc.writeEN() == 0){
Serial.println("The DS1302 is write protected.");
} else{
Serial.println("The DS1302 can write.");
rtc.writeEN(false);
Serial.println("Write protected is started.");
}
Serial.println();
dht.begin(); // DHT11 센서 작동 시작 dht.begin(); // DHT11 센서 작동 시작
Serial.println("DHT11 Unified Sensor Start."); Serial.println("DHT11 Unified Sensor Start.");
Serial.println();
sensor_t sensor; // dht11 구조체 생성 sensor_t sensor; // dht11 구조체 생성
...@@ -57,6 +110,7 @@ void setup() { ...@@ -57,6 +110,7 @@ void setup() {
Serial.print ("Min Value : "); Serial.print(sensor.min_value); Serial.println(" *C"); Serial.print ("Min Value : "); Serial.print(sensor.min_value); Serial.println(" *C");
Serial.print ("Resolution : "); Serial.print(sensor.resolution); Serial.println(" *C"); Serial.print ("Resolution : "); Serial.print(sensor.resolution); Serial.println(" *C");
Serial.println("------------------------------------"); Serial.println("------------------------------------");
Serial.println();
// 습도센서 정보 프린트 // 습도센서 정보 프린트
dht.humidity().getSensor(&sensor); dht.humidity().getSensor(&sensor);
...@@ -69,55 +123,75 @@ void setup() { ...@@ -69,55 +123,75 @@ void setup() {
Serial.print ("Min Value : "); Serial.print(sensor.min_value); Serial.println("%"); Serial.print ("Min Value : "); Serial.print(sensor.min_value); Serial.println("%");
Serial.print ("Resolution : "); Serial.print(sensor.resolution); Serial.println("%"); Serial.print ("Resolution : "); Serial.print(sensor.resolution); Serial.println("%");
Serial.println("------------------------------------"); Serial.println("------------------------------------");
Serial.println();
delayMS =sensor.min_delay /1000; // 센서를 읽는 시간을 최소로 설정 delayMS =sensor.min_delay /1000; // 센서를 읽는 시간을 최소로 설정
} }
void loop() { void loop() {
String input = "";
// 측정기 분류(IN / OUT)
String type_ = "In";
// 사용자 ID
String ID = "Admin";
// 지역 코드 tmElements_t tm; // 시간 데이터를 저장하는 변수
String locCode = "3743011"; if(rtc.read(tm) == 0){
// DHT11 모듈의 측정 event printTime(tm);
sensors_event_t event;
if(tm.Minute % 10 == 0 && tm.Second == 0){
// 온도 // Wifi 연결 확인
dht.temperature().getEvent(&event); String cmd = "AT+CWJAP?";
float temp = event.temperature; esp.println(cmd);
String str_Temp = String(temp); if(esp.find("No AP")){
Serial.println("Wifi disconnected, try to connect...");
// 습도 connectESP(); // ESP 모듈 탐색
dht.humidity().getEvent(&event); connectWifi(); // ESP 모듈 wifi 연결
float humi = event.relative_humidity; }
String str_Humi = String(humi);
String input = ""; // 전송할 데이터
// 광도
int lights = analogRead(CDS_A); String date = ""; // 전송 시점 데이터
String str_Lights = String(lights); date += String(tmYearToCalendar(tm.Year));
date += tm.Month < 10 ? '0' + String(tm.Month) : String(tm.Month);
input += "type=" + type_; date += tm.Day < 10 ? '0' + String(tm.Day) : String(tm.Day);
input += "&id=" + ID; date += tm.Hour < 10 ? '0' + String(tm.Hour): String(tm.Hour);
input += "&locCode" + locCode; date += tm.Minute < 10 ? '0' + String(tm.Minute) : String(tm.Minute);
input += "&temp=" + str_Temp;
input += "&humi=" + str_Humi; sensors_event_t event; // dht 모듈의 데이터 수집
input += "&lights=" + str_Lights;
Serial.println(input); // 온도 데이터
dht.temperature().getEvent(&event);
// 데이터 전송 float temp = event.temperature;
sendData(input); String str_Temp = isnan(temp) != 0 ? "none" : String(temp);
// 습도 데이터
dht.humidity().getEvent(&event);
float humi = event.relative_humidity;
String str_Humi = isnan(humi) != 0 ? "none" : String(humi);
// 조도 데이터
int lights = analogRead(CDS_A);
String str_Lights = isnan(lights) != 0 ? "none" : String(lights);
String type_ = "In";
String ID = "eue_tester1";
String locCode = "3124053";
input += "type=" + type_;
input += "&id=" + ID;
input += "&locCode=" + locCode;
input += "&date=" + date;
input += "&temp=" + str_Temp;
input += "&humi=" + str_Humi;
input += "&lights=" + str_Lights;
sendData(input);
}
}
// 10분마다 전송 진행 delay(1000); // 1초 단위로 확인하기 위한 지연
delay(600000);
} }
// ESP모듈 연결 // 함수 정의부
// ESP 모듈 연결 함수
void connectESP(){ void connectESP(){
esp.println("AT"); esp.println("AT");
Serial.println("AT Sent"); Serial.println("AT Sent");
...@@ -126,55 +200,71 @@ void connectESP(){ ...@@ -126,55 +200,71 @@ void connectESP(){
Serial.println("ESP8266 Not Found."); Serial.println("ESP8266 Not Found.");
} }
Serial.println("OK Command Received."); Serial.println("OK Command Received.");
Serial.println();
} }
// 공유기와 연결 // Wifi 연결 함수
void connectWifi(){ void connectWifi(){
// ESP8266 모듈 Client로 설정 String cmd = "AT+CWMODE=1"; // Client로 설정
String cmd = "AT+CWMODE=1";
esp.println(cmd); esp.println(cmd);
Serial.println("Set ESP8266 to client."); Serial.println("Set ESP8266 to client.");
// 공유기와 연결
Serial.println("Connecting to Wifi..."); Serial.println("Connecting to Wifi...");
cmd = "AT+CWJAP=\"" + SSID + "\"," + SSPW + "\""; cmd = "AT+CWJAP=\"" + SSID + "\"," + SSPW + "\""; // Wifi 연결
esp.println(cmd); esp.println(cmd);
// 연결 확인
while(!esp.find("OK")); while(!esp.find("OK"));
Serial.println("Wifi Connected"); Serial.println("Wifi Connected");
// 연결된 공유기 확인 cmd = "AT+CWJAP?"; // 현재 연결된 AP 정보 확인, 연결 안되어있을 시 "No AP" 출력
cmd = "AT+CWJAP?";
esp.println(cmd); esp.println(cmd);
Serial.write(esp.read()); Serial.write(esp.read());
Serial.println();
} }
// 서버에 데이터 전송 함수
void sendData(String input){ void sendData(String input){
// ESP 모듈을 통해 Server와 연결
// ESP 모듈을 통해 Server로 데이터 전송
esp.println("AT+CIPSTART=\"TCP\",\"" + EUEIP + "\"," + EUEPORT); esp.println("AT+CIPSTART=\"TCP\",\"" + EUEIP + "\"," + EUEPORT);
if(esp.find("Error")){ if(esp.find("Error")){
Serial.println("AT+CIPSTART Error..."); Serial.println("AT+CIPSTART Error...");
} }
// 서버로 전송할 데이터 작성 // Get 방식을 이용한 전송
String vars = input;
String msg = "GET /data/input?"; String msg = "GET /data/input?";
msg += vars; msg += input;
msg += " HTTP/1.0\r\n\r\n"; msg += " HTTP/1.0\r\n\r\n";
esp.print("AT+CIPSEND="); esp.print("AT+CIPSEND=");
esp.println(msg.length()); esp.println(msg.length());
delay(2000); delay(2000);
// 데이터 전송
if(esp.find(">")){ if(esp.find(">")){
esp.print(msg); esp.print(msg);
Serial.println(msg);
Serial.println("Data sent."); Serial.println("Data sent.");
delay(1000); delay(1000);
} }
// 서버와 연결 종료
Serial.println("Connection Closed."); Serial.println("Connection Closed.");
esp.println("AT+CIPCLOSE"); esp.println("AT+CIPCLOSE");
Serial.println();
} }
// 시간 출력 함수
void printTime(tmElements_t tm){
Serial.print(tmYearToCalendar(tm.Year));
Serial.print(" / ");
Serial.print(tm.Month < 10 ? '0' + String(tm.Month) : tm.Month);
Serial.print(" / ");
Serial.print(tm.Day < 10 ? '0' + String(tm.Day) : tm.Day);
Serial.print(" - ");
Serial.print(tm.Hour < 10 ? '0' + String(tm.Hour) : tm.Hour);
Serial.print(" : ");
Serial.print(tm.Minute < 10 ? '0' + String(tm.Minute) : tm.Minute);
Serial.print(" : ");
Serial.println(tm.Second < 10 ? '0' + String(tm.Second) : tm.Second);
Serial.println();
}
\ No newline at end of file
/*
# 실외 데이터 수집기 코드
## 사용자 변수
1. String SSID
2. String SSPW
3. String EUEIP
4. int EUEPORT
5. String locCode
6. float lati
7. float lng
## PC에 연결하여 동작 (시리얼 모니터 사용 O)
시리얼 모니터를 통해 상태를 확인하는 경우, 사용자 변수들의 값만 변경하여 사용합니다.
## 아두이노 단독 실행 (시리얼 모니터 사용 X)
시리얼 모니터를 사용하지 않는 경우, 사용자 변수 값 변경 이외에 아래 "Serial.~~" 꼴로 된 라인은 모두 주석처리 해줍니다.
*/
#include <SoftwareSerial.h> #include <SoftwareSerial.h>
#include <TimeLib.h>
#include <DS1302RTC.h>
#define ESPPIN_TX 2 // ESP 8266 모듈의 TX 핀 #define ESP_TX 2 // ESP8266 모듈의 TX 핀
#define ESPPIN_RX 3 // ESP 8266 모듈의 RX 핀 #define ESP_RX 3 // ESP8266 모듈의 RX 핀
#define RTC_CLK 4 // DS1302RTC 모듈의 CLK 핀
#define RTC_DAT 5 // DS1302RTC 모듈의 DAT 핀
#define RTC_RST 6 // DS1302RTC 모듈의 CLK 핀
SoftwareSerial esp(ESPPIN_TX,ESPPIN_RX); SoftwareSerial esp(ESP_TX,ESP_RX); // ESP 모듈 객체 생성
DS1302RTC rtc(RTC_RST, RTC_DAT, RTC_CLK); // RTC 모듈 객체 생성
String SSID = "Wifi_SSID"; // Wifi - SSID String SSID = "Wifi_SSID"; // Wifi - SSID
...@@ -14,48 +44,92 @@ String SSPW = "Wifi_SSPW"; // Wifi - SSPW ...@@ -14,48 +44,92 @@ String SSPW = "Wifi_SSPW"; // Wifi - SSPW
String EUEIP = "EUE_IP"; // Web Server - IP String EUEIP = "EUE_IP"; // Web Server - IP
int EUEPORT = 8081; // Web Server - Port int EUEPORT = 8081; // Web Server - Port
// 함수 선언부
void connectESP(); void connectESP();
void connectWifi(); void connectWifi();
void sendData(String vars); void sendData(String vars);
void printTime(tmElements_t tm);
void setup() { void setup() {
Serial.begin(9600); // Serial monitor의 통신 속도 9600으로 설정 Serial.begin(9600); // Serial monitor의 통신 속도 9600으로 설정
esp.begin(9600); // esp모듈의 통신 속도 9600으로 설정 esp.begin(9600); // esp모듈의 통신 속도 9600으로 설정
}
void loop() {
connectESP(); // ESP 모듈 탐색 connectESP(); // ESP 모듈 탐색
connectWifi(); // ESP 모듈 wifi 연결 connectWifi(); // ESP 모듈 wifi 연결
String input = ""; // DS1302 RTC 모듈이 작동 중인지 확인
if(rtc.haltRTC()){
// 측정기 분류(IN / OUT) Serial.println("The DS1302 is stopped.");
String type_ = "Out"; rtc.haltRTC(0);
Serial.println("The DS1302 starts.");
// 지역 코드 delay(100);
String locCode = "3743011"; } else{
Serial.println("The DS1302 is working");
// 지역의 위도(Latitude), 경도(Longitude) }
float lati = 37.241706; Serial.println();
String str_lati = String(lati,6);
float lng = 131.864889; // DS1302 RTC 모듈이 쓰기 금지 모드 상태인지 확인
String str_lng = String(lng,6); if(rtc.writeEN() == 0){
Serial.println("The DS1302 is write protected.");
input += "type=" + type_; } else{
input += "&locCode=" + locCode; Serial.println("The DS1302 can write.");
input += "&lat=" + str_lati; rtc.writeEN(false);
input += "&lng=" + str_lng; Serial.println("Write protected is started.");
Serial.println(input); }
Serial.println();
// 데이터 전송 }
sendData(input);
void loop() {
tmElements_t tm; // 시간 데이터를 저장하는 변수
if(rtc.read(tm) == 0){
printTime(tm);
if(tm.Minute % 10 == 0 && tm.Second == 0){
// Wifi 연결 확인
String cmd = "AT+CWJAP?";
esp.println(cmd);
if(esp.find("No AP")){
Serial.println("Wifi disconnected, try to connect...");
connectESP(); // ESP 모듈 탐색
connectWifi(); // ESP 모듈 wifi 연결
}
String input = ""; // 전송할 데이터
String date = ""; // 전송 시점 데이터
date += String(tmYearToCalendar(tm.Year));
date += tm.Month < 10 ? '0' + String(tm.Month) : String(tm.Month);
date += tm.Day < 10 ? '0' + String(tm.Day) : String(tm.Day);
date += tm.Hour < 10 ? '0' + String(tm.Hour): String(tm.Hour);
date += tm.Minute < 10 ? '0' + String(tm.Minute) : String(tm.Minute);
String type_ = "Out";
String locCode = "3743011";
float lati = 37.241706;
String str_lati = String(lati,6);
float lng = 131.864889;
String str_lng = String(lng,6);
input += "type=" + type_;
input += "&locCode=" + locCode;
input += "&date=" + date;
input += "&lat=" + str_lati;
input += "&lng=" + str_lng;
sendData(input);
}
}
// 30분마다 전송 진행 delay(1000); // 1초 단위로 확인하기 위한 지연
delay(1800000);
} }
// ESP모듈 연결 // 함수 정의부
// ESP 모듈 연결 함수
void connectESP(){ void connectESP(){
esp.println("AT"); esp.println("AT");
Serial.println("AT Sent"); Serial.println("AT Sent");
...@@ -64,55 +138,71 @@ void connectESP(){ ...@@ -64,55 +138,71 @@ void connectESP(){
Serial.println("ESP8266 Not Found."); Serial.println("ESP8266 Not Found.");
} }
Serial.println("OK Command Received."); Serial.println("OK Command Received.");
Serial.println();
} }
// 공유기와 연결 // Wifi 연결 함수
void connectWifi(){ void connectWifi(){
// ESP8266 모듈 Client로 설정 String cmd = "AT+CWMODE=1"; // Client로 설정
String cmd = "AT+CWMODE=1";
esp.println(cmd); esp.println(cmd);
Serial.println("Set ESP8266 to client."); Serial.println("Set ESP8266 to client.");
// 공유기와 연결
Serial.println("Connecting to Wifi..."); Serial.println("Connecting to Wifi...");
cmd = "AT+CWJAP=\"" + SSID + "\"," + SSPW + "\""; cmd = "AT+CWJAP=\"" + SSID + "\"," + SSPW + "\""; // Wifi 연결
esp.println(cmd); esp.println(cmd);
// 연결 확인
while(!esp.find("OK")); while(!esp.find("OK"));
Serial.println("Wifi Connected"); Serial.println("Wifi Connected");
// 연결된 공유기 확인 cmd = "AT+CWJAP?"; // 현재 연결된 AP 정보 확인, 연결 안되어있을 시 "No AP" 출력
cmd = "AT+CWJAP?";
esp.println(cmd); esp.println(cmd);
Serial.write(esp.read()); Serial.write(esp.read());
Serial.println();
} }
// 서버에 데이터 전송 함수
void sendData(String input){ void sendData(String input){
// ESP 모듈을 통해 Server로 데이터 전송 // ESP 모듈을 통해 Server로 데이터 전송
esp.println("AT+CIPSTART=\"TCP\",\"" + EUEIP + "\"," + EUEPORT); esp.println("AT+CIPSTART=\"TCP\",\"" + EUEIP + "\"," + EUEPORT);
if(esp.find("Error")){ if(esp.find("Error")){
Serial.println("AT+CIPSTART Error..."); Serial.println("AT+CIPSTART Error...");
} }
// 서버로 전송할 데이터 작성 // Get 방식을 이용한 전송
String vars = input;
String msg = "GET /data/input?"; String msg = "GET /data/input?";
msg += vars; msg += input;
msg += " HTTP/1.0\r\n\r\n"; msg += " HTTP/1.0\r\n\r\n";
esp.print("AT+CIPSEND="); esp.print("AT+CIPSEND=");
esp.println(msg.length()); esp.println(msg.length());
delay(2000); delay(2000);
// 데이터 전송
if(esp.find(">")){ if(esp.find(">")){
esp.print(msg); esp.print(msg);
Serial.println(msg);
Serial.println("Data sent."); Serial.println("Data sent.");
delay(1000); delay(1000);
} }
// 서버와 연결 종료
Serial.println("Connection Closed."); Serial.println("Connection Closed.");
esp.println("AT+CIPCLOSE"); esp.println("AT+CIPCLOSE");
Serial.println();
} }
// 시간 출력 함수
void printTime(tmElements_t tm){
Serial.print(tmYearToCalendar(tm.Year));
Serial.print(" / ");
Serial.print(tm.Month < 10 ? '0' + String(tm.Month) : tm.Month);
Serial.print(" / ");
Serial.print(tm.Day < 10 ? '0' + String(tm.Day) : tm.Day);
Serial.print(" - ");
Serial.print(tm.Hour < 10 ? '0' + String(tm.Hour) : tm.Hour);
Serial.print(" : ");
Serial.print(tm.Minute < 10 ? '0' + String(tm.Minute) : tm.Minute);
Serial.print(" : ");
Serial.println(tm.Second < 10 ? '0' + String(tm.Second) : tm.Second);
Serial.println();
}
\ No newline at end of file
...@@ -20,12 +20,31 @@ ...@@ -20,12 +20,31 @@
- [ESP8266 와이파이 모듈 전용 어댑터](https://smartstore.naver.com/mechasolution_com/products/3448897447?NaPm=ct%3Dkh5sj8sw%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D967033f4922b6288b4279fe63965a7511c1ecf4b) : ESP8266 wifi 모듈을 쉽게 사용하기 위한 어댑터 - [ESP8266 와이파이 모듈 전용 어댑터](https://smartstore.naver.com/mechasolution_com/products/3448897447?NaPm=ct%3Dkh5sj8sw%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D967033f4922b6288b4279fe63965a7511c1ecf4b) : ESP8266 wifi 모듈을 쉽게 사용하기 위한 어댑터
- [DS1302 RTC 모듈](https://smartstore.naver.com/domekit/products/599920174?NaPm=ct%3Dkqm1qi9x%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3De00f325f99c7d23306f06a0380ccc65a28ff29a6) : 시간 정보를 저장할 수 있는 모듈
## 사용 라이브러리 ## 사용 라이브러리
- Adafruit Sensor Library : [https://github.com/adafruit/Adafruit_Sensor](https://github.com/adafruit/Adafruit_Sensor) - Adafruit Sensor Library : [https://github.com/adafruit/Adafruit_Sensor](https://github.com/adafruit/Adafruit_Sensor)
- DHT Sensor Library : [https://github.com/adafruit/DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library) - DHT Sensor Library : [https://github.com/adafruit/DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library)
- DS1302 RTC Library : [https://playground.arduino.cc/Main/DS1302RTC/](https://playground.arduino.cc/Main/DS1302RTC/)
- Time Library : 아두이노 라이브러리 관리 -> "Time by Michael Margolis" 검색 및 설치
## Arduino 참고 자료 ## Arduino 참고 자료
- [https://it-g-house.tistory.com/entry/%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8Arduino-%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%95%98%EA%B8%B0-Wifi-ESP-01%EC%97%B0%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95](https://it-g-house.tistory.com/entry/%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8Arduino-%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%95%98%EA%B8%B0-Wifi-ESP-01%EC%97%B0%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95) - [https://it-g-house.tistory.com/entry/%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8Arduino-%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%95%98%EA%B8%B0-Wifi-ESP-01%EC%97%B0%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95](https://it-g-house.tistory.com/entry/%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8Arduino-%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%95%98%EA%B8%B0-Wifi-ESP-01%EC%97%B0%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95)
- [https://cafe.naver.com/mechawiki/122](https://cafe.naver.com/mechawiki/122) - [https://cafe.naver.com/mechawiki/122](https://cafe.naver.com/mechawiki/122)
## Arduino 주의 사항 (외부 전원을 통한 독립적 실행)
### 외부 전원 공급 (UNO R3 보드 기준 작성)
- 전원 공급 방식 참고 : https://chipwired.com/can-arduino-run-without-computer/
- UNO 보드의 DC 배럴 잭으로 전원을 공급 받는 경우 : 7V ~ 12V 사이의 전원을 공급
### 외부 실행시 Serial 관련 함수 생략
아두이노 학습 진행시 시리얼 모니터를 활용하기에, 코드에 Serial 함수를 필수적으로 생각할 수 있습니다. 하지만, 시리얼 모니터를 쓰지 않을 경우에는 Serial관련 함수를 적지 않습니다. Serial 관련 함수를 이용시, 시리얼 모니터를 켜야 코드가 동작될 뿐아니라 외부 전원을 공급하여 실행하고자 할 때 전혀 동작하지 않습니다.
- 시리얼 모니터 사용 O : Serial 관련 함수 사용 할 것.
- 시리얼 모니터 사용 X : Serial 관련 함수 사용 하지 않을 것.
...@@ -4,10 +4,11 @@ ...@@ -4,10 +4,11 @@
| Category | HTTP Method | URI | Description | | Category | HTTP Method | URI | Description |
| -------------- | ----------- | -------------------------- | ----------------------------------------------------------- | | -------------- | ----------- | -------------------------- | ----------------------------------------------------------- |
| Root Directory | ﹒ | /api | api 서버를 통해 들어오는 기본 경로 |
| Data Collector | GET | /data/input?... | 아두이노를 통해 수집한 자료 등록 (내부, 외부는 쿼리로 구분) | | Data Collector | GET | /data/input?... | 아두이노를 통해 수집한 자료 등록 (내부, 외부는 쿼리로 구분) |
| Data - User | GET | /data/user/:id | 사용자 지정 장소의 데이터 요청 | | Data - User | GET | /data/user/:id | 사용자 지정 장소의 데이터 요청 |
| Data - Outside | GET | /data/outside/:id | 해당 지역구의 데이터 요청 | | Data - Outside | GET | /data/outside/:id | 해당 지역구의 데이터 요청 |
| Local Code | GET | /loccode/do | 행정 구역 코드 '도' 요청 | | Local Code | GET | /loccode/doe | 행정 구역 코드 '도' 요청 |
| Local Code | GET | /loccode/si-gun-gu/:id | 사용자 입력 '도'에 따른 행정 구역 코드 '시군구' 요청 | | Local Code | GET | /loccode/si-gun-gu/:id | 사용자 입력 '도'에 따른 행정 구역 코드 '시군구' 요청 |
| Local Code | GET | /loccod/eup-myeon-dong/:id | 사용자 입력 '시군구'에 따른 행정 구역 코드 '읍면동' 요청 | | Local Code | GET | /loccod/eup-myeon-dong/:id | 사용자 입력 '시군구'에 따른 행정 구역 코드 '읍면동' 요청 |
| Auth | POST | /signup | 회원가입 요청 | | Auth | POST | /signup | 회원가입 요청 |
...@@ -41,3 +42,8 @@ ...@@ -41,3 +42,8 @@
- [x] 사용자 등록 ( Register ) - [x] 사용자 등록 ( Register )
2021.05.07 +) Data Collector의 경우 Post 방식으로 보내주는 것이 맞으나, 현재 Get방식을 이용하고 있습니다. 올해 초 부터 아두이노에서 POST로 전송을 하고자 여러 자료를 찾아 봤지만, 방법을 찾지 못해 일단 진행 하였습니다. 방법을 발견하면 수정을 진행하겠습니다. 2021.05.07 +) Data Collector의 경우 Post 방식으로 보내주는 것이 맞으나, 현재 Get방식을 이용하고 있습니다. 올해 초 부터 아두이노에서 POST로 전송을 하고자 여러 자료를 찾아 봤지만, 방법을 찾지 못해 일단 진행 하였습니다. 방법을 발견하면 수정을 진행하겠습니다.
### 2021.07.12 \_ 경로 수정
1. 도 정보를 가져오는 경로 수정
: loccode/do -> loccode/doe
...@@ -9,12 +9,14 @@ ...@@ -9,12 +9,14 @@
∟ Local Code (SGG/시군구) ∟ Local Code (SGG/시군구)
∟ Local Code (EMD/읍면동) ∟ Local Code (EMD/읍면동)
∟ Outside ∟ Outside
∟ weather.csv
∟ YYYY (연) ∟ YYYY (연)
∟ YYYYMM (연/월) ∟ YYYYMM (연/월)
∟ YYYYMMDD (연/월/일) ∟ YYYYMMDD (연/월/일)
∟ weather.csv ∟ weather.csv
∟ Users ∟ Users
∟ ID (사용자 개인 ID) ∟ ID (사용자 개인 ID)
∟ weather.csv
∟ YYYY (연) ∟ YYYY (연)
∟ YYYYMM (연/월) ∟ YYYYMM (연/월)
∟ YYYYMMDD (연/월/일) ∟ YYYYMMDD (연/월/일)
...@@ -24,9 +26,17 @@ ...@@ -24,9 +26,17 @@
데이터가 저장되는 경로의 구조입니다. 데이터가 저장되는 경로의 구조입니다.
- 1차 : 지역별 대분류 - 통합 데이터
- 2차 : 사용자와 외부 정보 분류
- 3차 : 연 / 월 / 일 분류 1. 지역별 분류
2. 외부 / 내부 구분
3. 내부의 경우 사용자 아이디별 구분
- 날짜별 분류 데이터
1. 지역별 대분류
2. 사용자와 외부 정보 분류
3. 연 / 월 / 일 분류
<br><br> <br><br>
...@@ -38,9 +48,9 @@ ...@@ -38,9 +48,9 @@
외부 데이터는 다음과 같은 형식으로 저장됩니다. 외부 데이터는 다음과 같은 형식으로 저장됩니다.
| Month | Date | Hour | Minute | Temperature | Humidity | Press | Wind Speed | | Date | Temperature | Humidity | Press | Wind Speed |
| :---: | :--: | :--: | :----: | :---------: | :------: | :-------: | :--------: | | :-------------------------: | :---------: | :------: | :-------: | ---------- |
| 월 | 일 | 시 | | 온도(℃) | 습도(%) | 기압(hPa) | 풍속(m/s) | | YYYYMMDDHHmm ( 연월일시) | 온도(℃) | 습도(%) | 기압(hPa) | 풍속(m/s) |
<br><br> <br><br>
...@@ -48,9 +58,9 @@ ...@@ -48,9 +58,9 @@
사용자가 설정한 장소의 데이터는 다음과 같은 형식으로 저장됩니다. 사용자가 설정한 장소의 데이터는 다음과 같은 형식으로 저장됩니다.
| Month | Date | Hour | Minute | Temperature | Humidity | Lights | | Date | Temperature | Humidity | Lights |
| :---: | :--: | :--: | :----: | :---------: | :------: | :----: | | :-------------------------: | :---------: | :------: | :----: |
| 월 | 일 | 시 | | 온도(℃) | 습도(%) | 광도 | | YYYYMMDDHHmm ( 연월일시) | 온도(℃) | 습도(%) | 광도 |
<br><br> <br><br>
......
...@@ -30,7 +30,11 @@ ...@@ -30,7 +30,11 @@
"mysql2": "^2.2.5", "mysql2": "^2.2.5",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
"node-schedule": "^2.0.0", "node-schedule": "^2.0.0",
"pug": "^3.0.0" "nodemailer": "^6.6.2",
"pg": "^8.6.0",
"pg-hstore": "^2.3.4",
"pug": "^3.0.0",
"sequelize": "^6.6.5"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^2.0.4" "nodemon": "^2.0.4"
......
...@@ -14,6 +14,7 @@ import locCodeRouter from "./routers/locCodeRouter"; ...@@ -14,6 +14,7 @@ import locCodeRouter from "./routers/locCodeRouter";
const app = express(); const app = express();
// Page Views for Development test.
app.set("view engine", "pug"); app.set("view engine", "pug");
app.set("views", path.join(__dirname, "views")); app.set("views", path.join(__dirname, "views"));
......
import fs from "fs"; import fs from "fs";
import fetch from "node-fetch"; import fetch from "node-fetch";
import { serverMSG, statusCode } from "../serverinfo"; import { serverMSG, statusCode } from "../serverinfo";
import { pool as db, dbMSG, pool } from "../db"; import db from "../db/index";
import dotenv from "dotenv"; import dotenv from "dotenv";
dotenv.config(); dotenv.config();
const OUT = "Out";
const IN = "In";
const OUTSIDE = "Outside";
const USERS = "Users";
// 데이터 수집 기로 부터 받아온 지역 코드 세분화
const locCodeSep = (code = "") => {
const DO = code.slice(0, 2);
const SGG = code.slice(0, 5);
const EMD = code;
const loc = {
DO: DO,
SGG: SGG,
EMD: EMD,
};
return loc;
};
// 데이터가 들어온 시간 데이터 생성
const getTimeInfo = () => {
const cur = new Date();
const year = cur.getFullYear();
const month = cur.getMonth() + 1;
const date = cur.getDate();
const hour = cur.getHours();
const minute = cur.getMinutes();
const time = {
year: year,
month: month,
date: date,
hour: hour,
minute: minute,
};
return time;
};
// Data 접근 경로 반환, DB에 존재 하지 않을 시 Update 동작
const getDataDIR = async (loc, time, type, id) => {
const year = time.year;
const month = time.month < 10 ? `0${time.month}` : time.month;
const date = time.date < 10 ? `0${time.date}` : time.date;
const select_query =
"SELECT DATALINK" +
" " +
`FROM ${type === OUT ? "LOCINFO" : "USER"}` +
" " +
`WHERE ${type === OUT ? `CODE=${loc.EMD}` : `ID='${id}'`}`;
const [row, fields] = await db.execute(select_query);
let baseDIR;
if (row.length != 0) baseDIR = row[0]["DATALINK"];
else baseDIR = null;
// DB에 Data 저장 경로가 존재하지 않을 시 UPDATE
if (baseDIR === null) {
baseDIR =
"/data" +
`/${loc.DO}` +
`/${loc.SGG}` +
`/${loc.EMD}` +
`/${type === OUT ? OUTSIDE : USERS + "/" + id}`;
const update_query =
`UPDATE ${type === OUT ? "LOCINFO" : "USER"}` +
" " +
`SET DATALINK='${baseDIR}'` +
" " +
`WHERE ${type === OUT ? `CODE=${loc.EMD}` : `ID='${id}'`}`;
db.execute(update_query);
}
const timeDIR = `/${year}` + `/${year}${month}` + `/${year}${month}${date}`;
// 최종 Data 저장소 경로
const repoDIR = process.env.LOCAL_SERVER_DIR + baseDIR + timeDIR;
return repoDIR;
};
// 데이터를 파일 형식으로 저장
const storeData = (type, time, loc, fdir, data) => {
const fileName = "weather.csv";
fs.open(fdir + `/${fileName}`, "a", (err, fd) => {
if (err) {
// Directory가 존재하지 않는 경우, 생성
if (err.code === "ENOENT") {
console.log("There is no directory.");
fs.mkdirSync(fdir, { recursive: true }, (err) => {
if (err) console.log(err);
});
console.log("Create directory.");
}
// 그 외의 에러는 출력
else console.log(err);
}
fs.appendFile(fdir + `/${fileName}`, data, (err) => {
if (err) console.log(err);
else
console.log(
`${time.year}/${time.month}/${time.date} ${time.hour}:${
time.minute
} - ${loc.EMD} ${type === OUT ? OUTSIDE : USERS} data append.`
);
});
});
};
// 외부 수집기로 부터 들어온 정보 처리 // 외부 수집기로 부터 들어온 정보 처리
const handleOutData = async (locCode, lat, lng) => { const handleOutData = async (locCode, date, lat, lng) => {
// OpenWeatherAPI로 부터 지역의 날씨 정보획득을 위해 지역의 경도와 위도, API Key, 단위 기준 metric 전달 // OpenWeatherAPI로 부터 지역의 날씨 정보획득을 위해 지역의 경도와 위도, API Key, 단위 기준 metric 전달
const response = await fetch( const response = await fetch(
`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lng}&appid=${process.env.OPENWEATHERMAP_API_KEY}&units=metric` `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lng}&appid=${process.env.OPENWEATHERMAP_API_KEY}&units=metric`
...@@ -139,45 +19,56 @@ const handleOutData = async (locCode, lat, lng) => { ...@@ -139,45 +19,56 @@ const handleOutData = async (locCode, lat, lng) => {
const press = json["main"]["pressure"]; const press = json["main"]["pressure"];
const wind_speed = json["wind"]["speed"]; const wind_speed = json["wind"]["speed"];
const loc = locCodeSep(locCode); await db.Weather_out.create(
const time = getTimeInfo(); {
loc_code: Number(locCode),
const fdir = await getDataDIR(loc, time, OUT, OUTSIDE); collected_at: date,
temp: temp,
const data = `${time.month},${time.date},${time.hour},${time.minute},${temp},${humi},${press},${wind_speed}\n`; humi: humi,
press: press,
storeData(OUT, time, loc, fdir, data); wind_speed: wind_speed,
},
{
logging: false,
}
);
}; };
// 내부 수집기로 부터 들어온 정보 처리 // 내부 수집기로 부터 들어온 정보 처리
const handleInData = async (id, locCode, temp, humi, lights) => { const handleInData = async (id, date, temp, humi, lights) => {
const loc = locCodeSep(locCode); db.Weather_in.create(
const time = getTimeInfo(); {
host: id,
const fdir = await getDataDIR(loc, time, IN, id); collected_at: date,
// 데이터 형식 - [ 월 | 일 | 시 | 분 | 온도 | 습도 | 광도 ] temp: temp,
const data = `${time.month},${time.date},${time.hour},${time.minute},${temp},${humi},${lights}\n`; humi: humi,
lights: lights,
storeData(IN, time, loc, fdir, data); },
{
logging: false,
}
);
}; };
// 데이터 수신 처리 // 데이터 수신 처리
export const getDataInput = (req, res) => { export const getDataInput = (req, res) => {
try { try {
if (req.query.type === OUT) { if (req.query.type === "OUT") {
// 외부 데이터 수집기 // 외부 데이터 수집기
const { const {
query: { locCode, lat, lng }, query: { locCode, date, lat, lng },
} = req; } = req;
handleOutData(locCode, lat, lng); console.log(locCode, date, lat, lng);
// handleOutData(locCode, date, lat, lng);
} else { } else {
// 내부 데이터 수집기 동작 // 내부 데이터 수집기 동작
const { const {
query: { id, locCode, temp, humi, lights }, query: { id, locCode, date, temp, humi, lights },
} = req; } = req;
handleInData(id, locCode, temp, humi, lights); console.log(id, locCode, date, temp, humi, lights);
// handleInData(id, date, temp, humi, lights);
} }
res.status(statusCode.ok).send(serverMSG.server_ok); res.status(statusCode.ok).send(serverMSG.server_ok);
...@@ -188,7 +79,7 @@ export const getDataInput = (req, res) => { ...@@ -188,7 +79,7 @@ export const getDataInput = (req, res) => {
}; };
// 사용자의 데이터 가져오기 및 예측 값 전송 // 사용자의 데이터 가져오기 및 예측 값 전송
export const getUserData = (req, res) => { export const getUserWeatherData = (req, res) => {
const { const {
params: { id }, params: { id },
} = req; } = req;
......
import { pool as db, dbMSG } from "../db"; import db from "../db/index";
import { serverMSG, statusCode } from "../serverinfo"; import { serverMSG, statusCode } from "../serverinfo";
// 각각의 지역 코드 정보를 가져오는
const getQueryResult = async (query) => {
let isError = false;
let result;
try {
const [row, fields] = await db.execute(query);
result = row;
console.log(dbMSG.query_success);
} catch (error) {
//Error Log
console.log("", error);
isError = true;
// 발생한 오류가 DB와 연결 오류인지 확인 후 Error Message 지정 및 전달
if (error.code === "ECONNREFUSED") result = dbMSG.connection_err;
else result = dbMSG.query_err;
}
return [isError, result];
};
// Do Code에 대한 GET 요청 처리 // Do Code에 대한 GET 요청 처리
export const getDo = async (req, res) => { export const getDoe = async (req, res) => {
const query = "SELECT CODE, DONAME FROM LOCDO"; const result = await db.Doe.findAll({ logging: false });
const [isError, result] = await getQueryResult(query);
if (!isError) { if (result) {
res.status(statusCode.ok).json({ DO: result }); res.status(statusCode.ok).json({ DO: result });
} else { } else {
console.log(result);
res.status(statusCode.err).send(serverMSG.server_err); res.status(statusCode.err).send(serverMSG.server_err);
} }
}; };
...@@ -45,12 +18,13 @@ export const getSGG = async (req, res) => { ...@@ -45,12 +18,13 @@ export const getSGG = async (req, res) => {
params: { id }, params: { id },
} = req; } = req;
const query = `SELECT CODE, SGGNAME FROM LOCSIGUNGU WHERE DOCODE = ${id}`; const result = await db.Sgg.findAll({
where: { code_doe: Number(id) },
const [isError, result] = await getQueryResult(query); logging: false,
});
if (!isError) { if (result) {
res.status(statusCode.ok).json({ DO: id, SGG: result }); res.status(statusCode.ok).json({ DO: Number(id), SGG: result });
} else { } else {
console.log(result); console.log(result);
res.status(statusCode.err).send(serverMSG.server_err); res.status(statusCode.err).send(serverMSG.server_err);
...@@ -63,12 +37,13 @@ export const getEMD = async (req, res) => { ...@@ -63,12 +37,13 @@ export const getEMD = async (req, res) => {
params: { id }, params: { id },
} = req; } = req;
const query = `SELECT CODE, EMDNAME FROM LOCINFO WHERE SGGCODE = ${id}`; const result = await db.Emd.findAll({
where: { code_sgg: Number(id) },
const [isError, result] = await getQueryResult(query); logging: false,
});
if (!isError) { if (result) {
res.status(statusCode.ok).json({ SGG: id, EMD: result }); res.status(statusCode.ok).json({ SGG: Number(id), EMD: result });
} else { } else {
console.log(result); console.log(result);
res.status(statusCode.err).send(serverMSG.server_err); res.status(statusCode.err).send(serverMSG.server_err);
......
import db from "../db/index";
import dotenv from "dotenv";
import nodemailer from "nodemailer";
import { serverMSG, statusCode } from "../serverinfo";
dotenv.config();
const postMail = async (email, token) => {
const transporter = nodemailer.createTransport({
service: process.env.NODEMAILER_SERVICE,
auth: {
type: "OAuth2",
user: process.env.NODEMAILER_USER,
clientId: process.env.NODEMAILER_GAMIL_CLIENT_ID,
clientSecret: process.env.NODEMAILER_GMAIL_CLIENT_PASSWORD,
refreshToken: process.env.NODEMAILER_GMAIL_REFRESH_TOKEN,
},
tls: {
rejectUnauthorized: false,
},
});
const mailOptions = {
from: `EUE Auth Supply <${process.env.NODEMAILER_USER}>`,
to: email,
subject: "EUE 사용자 계정 확인용 메일.",
text: `You enter locCode : ${locCode}.`,
};
try {
const mailResult = await transporter.sendMail(mailOptions);
console.log(`Mail sent - ID : ${mailResult.messageId}`);
res
.status(statusCode.ok)
.json({ msg: serverMSG.server_ok, content: mailResult.response });
} catch (err) {
console.log("Mail Sending Failuer.");
console.log(err);
res
.status(statusCode.err)
.json({ msg: serverMSG.server_err, content: err });
}
};
// Page for Development Test.
export const getSignup = (req, res) => {
res.render("signup", { pagename: "Sign Up" });
};
// Page for Development Test.
export const getLogin = (req, res) => {
res.render("login", { pagename: "Log In" });
};
// Function for Signup Proccess.
export const postSignup = async (req, res) => {
const {
body: { email, locCode },
} = req;
const result = db.User.findOne({
where: { email: email },
logging: false,
});
if (result) {
res.status(statusCode.err).json({
msg: serverMSG.server_err,
content: "You are aleady registered",
});
} else {
db.User.create({ email: email, locCode: locCode }, { logging: false });
// 로그인 페이지로 넘겨주기.
}
};
export const postLogin = (req, res) => {
const {
body: { email },
} = req;
const result = db.User.findOne({
where: { email: email },
logging: false,
});
if (result) {
// token 발행
const token = "ex Token";
// 토큰이 포함된 로그인 링크 전송
postLogin(email, token);
res
.status(statusCode.ok)
.json({ msg: serverMSG.server_ok, content: "Send Mail Successfully." });
} else {
res
.status(statusCode.err)
.json({
msg: serverMSG.server_err,
content: "You are still not our user.",
});
}
};
import mysql from "mysql2/promise";
import dotenv from "dotenv";
dotenv.config();
// MySQL Config
const db_config = {
host: process.env.MYSQL_HOST || "localhost",
user: process.env.MYSQL_USER || "root",
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE || "EUE",
connectionLimit: 5,
};
// Creation of MySQL Pool, and Export
export const pool = mysql.createPool(db_config);
// Messages for Data Base.
export const dbMSG = {
connection_err: "DB Connection Error.",
query_success: "DB Query Success.",
query_err: "DB Querry Error.",
};
/*
# EUE Server Database Schema
- DataBase : PostgreSQL
- 실제 서버 동작시 Sequelize가 models 디렉토리의 모델들에 따라 테이블을 생성합니다. 따라서 해당 SQL파일은 참고용으로 사용합니다.
1. LOC_DO
- 행정구역 도/특별시/특별자치시 이름과 코드 저장
- LOCSIGUNGU와 LOC_EMD에 참조됨
2. LOC_SGG
- 행정구역 시/군/구 이름과 코드 저장
- LOC_DO를 참조
- LOC_EMD에 참조됨
3. LOC_EMD
- 행정구역 읍/면/동 이름과 코드
- LOC_DO와 LOC_SGG를 참조
- USERS와 WEATHER_OUT에 참조됨
4. USERS
- 사용자 ID, PassWord, 거주지역코드
- LOC_EMD를 참조
5. WEATHER_IN
- 사용자 ID, 수집 날짜 및 시간, 온도, 습도, 광도
- USERS와 LOC_EMD 참조
6. WEATHER_OUT
- 지역 코드, 수집 날짜 및 시간, 온도, 습도, 기압, 풍속
- LOC_EMD 참조
*/
CREATE TABLE DOE
(
CODE INT NOT NULL,
NAME_DO VARCHAR(20) NOT NULL,
PRIMARY KEY(CODE_DO)
);
CREATE TABLE SGG
(
CODE INT NOT NULL,
CODE_DO INT NOT NULL,
NAME_SGG VARCHAR(20) NOT NULL,
PRIMARY KEY(CODE),
FOREIGN KEY(CODE_DO) REFERENCES DO(CODE) ON UPDATE CASCADE ON DELETE RESTRICT
);
CREATE TABLE EMD
(
CODE INT NOT NULL,
CODE_DO INT NOT NULL,
CODE_SGG INT NOT NULL,
NAME_EMD VARCHAR(20) NOT NULL,
PRIMARY KEY(CODE),
FOREIGN KEY(CODE_DO) REFERENCES DO(CODE) ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY(CODE_SGG) REFERENCES SGG(CODE) ON UPDATE CASCADE ON DELETE RESTRICT
);
CREATE TABLE USERS
(
EMAIL VARCHAR(320) UNIQUE NOT NULL,
PW VARCHAR(20) NOT NULL,
LOC_CODE INT NOT NULL,
PRIMARY KEY(EMAIL),
FOREIGN KEY(LOC_CODE) REFERENCES EMD(CODE) ON UPDATE CASCADE ON DELETE RESTRICT
);
CREATE TABLE WEATHER_IN
(
HOST VARCHAR(320) NOT NULL,
COLLECTED_AT TIMESTAMP NOT NULL,
TEMP FLOAT DEFAULT 0,
HUMI FLOAT DEFAULT 0,
LIGHTS FLOAT DEFAULT 0,
PRIMARY KEY(EMAIL,COLLECTED_AT),
FOREIGN KEY(EMAIL) REFERENCES USERS(EMAIL) ON UPDATE CASCADE ON DELETE RESTRICT
);
CREATE TABLE WEATHER_OUT
(
LOC_CODE INT NOT NULL,
COLLECTED_AT TIMESTAMP NOT NULL,
TEMP FLOAT DEFAULT 0,
HUMI FLOAT DEFAULT 0,
PRESS FLOAT DEFAULT 0,
WIND_SPEED FLOAT DEFAULT 0,
PRIMARY KEY(LOC_CODE, COLLECTED_AT),
FOREIGN KEY(LOC_CODE) REFERENCES EMD(CODE) ON UPDATE CASCADE ON DELETE RESTRICT
);
\ No newline at end of file
import Sequelize from "sequelize";
import dotenv from "dotenv";
import Doe from "../models/doe";
import Sgg from "../models/sgg";
import Emd from "../models/emd";
import User from "../models/user";
import Weather_in from "../models/weather_in";
import Weather_out from "../models/weather_out";
dotenv.config();
const envs = process.env;
// DB의 정보를 모두 담고 있는 객체 생성
const db = {};
// PostgreSQL과 연결된 Sequelize 객체 생성
const sequelize = new Sequelize(
envs.DB_DATABASE,
envs.DB_USER,
envs.DB_PASSWORD,
{
host: envs.DB_HOST,
dialect: "postgres",
}
);
// db 객체에 값 입력
db.sequelize = sequelize;
// model들 생성
db.Doe = Doe;
Doe.init(sequelize);
db.Sgg = Sgg;
Sgg.init(sequelize);
db.Emd = Emd;
Emd.init(sequelize);
db.User = User;
User.init(sequelize);
db.Weather_in = Weather_in;
Weather_in.init(sequelize);
db.Weather_out = Weather_out;
Weather_out.init(sequelize);
// model들 간에 Association 생성
Doe.associate(db);
Sgg.associate(db);
Emd.associate(db);
User.associate(db);
Weather_in.associate(db);
Weather_out.associate(db);
// Messages for Data Base.
const msg = {
connection_success: "DB Connection Success.",
connection_err: "DB Connection Error.",
query_success: "DB Query Success.",
query_err: "DB Querry Error.",
};
db.msg = msg;
export default db;
import fs from "fs";
import db from "./index";
export const setLocTables = () => {
// File Read
let originData = fs.readFileSync("data/admAddressCode.csv", "utf8");
// Separate Data & Input Data
let sepData = originData.split("\r\n");
let doeCodeSet = new Set();
let sggCodeSet = new Set();
let doeList = [];
let sggList = [];
let emdList = [];
console.log("Start Location data insertion...");
sepData.forEach(async (line) => {
line = line.replace(/\s/g, "");
let addr = line.split(",");
// Get Local Codes and Names
const doeCode = Number(addr[0]);
let doeName = addr[1];
doeName = doeName.replace(/\s/g, "");
const sggCode = Number(addr[2]);
let sggName = addr[3];
sggName = sggName.replace(/\s/g, "");
const emdCode = Number(addr[4]);
let emdName = addr[5];
emdName = emdName.replace(/\s/g, "");
// Save Loc Info to array.
if (!doeCodeSet.has(doeCode)) {
doeCodeSet.add(doeCode);
doeList.push({ code_doe: doeCode, name_doe: doeName });
}
if (!sggCodeSet.has(sggCode)) {
sggCodeSet.add(sggCode);
sggList.push({
code_sgg: sggCode,
name_sgg: sggName,
code_doe: doeCode,
});
}
emdList.push({
code_emd: emdCode,
name_emd: emdName,
code_doe: doeCode,
code_sgg: sggCode,
});
});
console.log("Inserting Location Data...");
// Insert to DB.
doeList.map(async (node) => {
await db.Doe.create(node, { logging: false });
});
sggList.map(async (node) => {
await db.Sgg.create(node, { logging: false });
});
emdList.map(async (node) => {
await db.Emd.create(node, { logging: false });
});
console.log("Finish the insertion!");
};
export default setLocTables;
import app from "./app"; import app from "./app";
import dotenv from "dotenv"; import dotenv from "dotenv";
import "./schedules"; // 매일 자정 데이터 처리 import "./schedules"; // 매일 자정 데이터 처리
import db from "./db/index";
import setLocTables from "./db/locationSetting";
dotenv.config(); dotenv.config();
...@@ -10,4 +12,16 @@ const handleListening = () => { ...@@ -10,4 +12,16 @@ const handleListening = () => {
console.log(`✅ Listening on : http://localhost:${PORT}`); console.log(`✅ Listening on : http://localhost:${PORT}`);
}; };
// DB 연결
db.sequelize
.sync({ force: true })
.then(() => {
console.log(db.msg.connection_success);
})
.then(() => setLocTables())
.catch((err) => {
console.log(db.msg.connection_err);
console.log(err);
});
app.listen(PORT, handleListening); app.listen(PORT, handleListening);
/*
# DB의 Do(도) 테이블의 모델입니다.
- 도 코드와 이름 정보를 저장합니다.
*/
import { DataTypes, Model } from "sequelize";
export class Doe extends Model {
static init(sequelize) {
return super.init(
{
code_doe: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
},
name_doe: {
type: DataTypes.STRING(20),
allowNull: false,
},
},
{
sequelize,
timestamps: false,
paranoid: false,
}
);
}
static associate(db) {
// Doe모델을 참조하는 테이블들에 대한 외래키 설정
db.Doe.hasMany(db.Sgg, {
foreignKey: "code_doe",
sourceKey: "code_doe",
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
db.Doe.hasMany(db.Emd, {
foreignKey: "code_doe",
sourceKey: "code_doe",
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
}
}
export default Doe;
/*
# DB의 EMD(읍면동) 테이블의 모델입니다.
- 읍/면/동의 코드와 이름을 저장합니다.
- 외래키로 Do 코드와 SGG 코드를 사용합니다.
*/
import { DataTypes, Model } from "sequelize";
export class Emd extends Model {
static init(sequelize) {
return super.init(
{
code_emd: {
type: DataTypes.INTEGER,
allowNull: true,
primaryKey: true,
},
name_emd: {
type: DataTypes.STRING(20),
allowNull: false,
},
},
{
sequelize,
timestamps: false,
paranoid: false,
}
);
}
static associate(db) {
// emd 모델이 참조하는 테이블에 대한 외래키 설정
db.Emd.belongsTo(db.Doe, {
foreignKey: "code_doe",
targetKey: "code_doe",
});
db.Emd.belongsTo(db.Sgg, {
foreignKey: "code_sgg",
targetKey: "code_sgg",
});
// emd 모델을 참조하는 테이블에 대한 외래키 설정
db.Emd.hasMany(db.User, {
foreignKey: "loc_code",
sourceKey: "code_emd",
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
db.Emd.hasMany(db.Weather_out, {
foreignKey: "loc_code",
sourceKey: "code_emd",
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
}
}
export default Emd;
/*
# DB의 SGG(시군구) 테이블의 모델입니다.
- 시/군/구의 코드와 이름을 저장합니다.
- 외래키로 Do 코드를 사용합니다.
*/
import { DataTypes, Model } from "sequelize";
export class Sgg extends Model {
static init(sequelize) {
return super.init(
{
code_sgg: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
},
name_sgg: {
type: DataTypes.STRING(20),
allowNull: false,
},
},
{
sequelize,
timestamps: false,
paranoid: false,
}
);
}
static associate(db) {
// Sgg 모델이 참조하는 테이블에 대한 외래키 설정
db.Sgg.belongsTo(db.Doe, {
foreignKey: "code_doe",
targetKey: "code_doe",
});
// Sgg 모델을 참조하는 테이블에 대한 외래키 설정
db.Sgg.hasMany(db.Emd, {
foreignKey: "code_sgg",
sourceKey: "code_sgg",
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
}
}
export default Sgg;
/*
# DB의 Users 테이블의 모델입니다.
- email과 비밀번호를 저장합니다.
- 외래키로 EMD 코드를 사용합니다.
*/
import { DataTypes, Model } from "sequelize";
export class User extends Model {
static init(sequelize) {
return super.init(
{
email: {
type: DataTypes.STRING(320),
allowNull: false,
primaryKey: true,
},
password: {
type: DataTypes.STRING(20),
allowNull: false,
},
},
{
sequelize,
timestamps: false,
paranoid: false,
}
);
}
static associate(db) {
// User 모델이 참조하는 테이블에 대한 외래키 설정.
db.User.belongsTo(db.Emd, {
foreignKey: "loc_code",
targetKey: "code_emd",
});
// User 모델을 참조하는 테이블에 대한 외래키 설정.
db.User.hasMany(db.Weather_in, {
foreignKey: "host",
sourveKey: "email",
onDelete: "CASCADE",
onUpdate: "CASCADE",
});
}
}
export default User;
import { DataTypes, Model } from "sequelize";
import User from "./user";
export class Weather_In extends Model {
static init(sequelize) {
return super.init(
{
host: {
type: DataTypes.STRING(320),
primaryKey: true,
references: {
model: User,
key: "email",
},
},
collected_at: {
type: DataTypes.DATE,
primaryKey: true,
},
temp: {
type: DataTypes.FLOAT,
defaultValue: 0,
},
humi: {
type: DataTypes.FLOAT,
defaultValue: 0,
},
lights: {
type: DataTypes.FLOAT,
defaultValue: 0,
},
},
{
sequelize,
timestamps: false,
paranoid: false,
}
);
}
static associate(db) {
// weather_in 모델이 참조하는 테이블에 대한 외래키 설정.
db.Weather_in.belongsTo(db.User, {
foreignKey: "host",
targetKey: "email",
});
}
}
export default Weather_In;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment