카테고리 없음

리필스테이션 동작 코드 설명과 문제점

지구빵집 2021. 5. 18. 15:07
반응형

 

 

대부분 문제는 간단하다. 복잡한 사람만이 있다. 아니면 계속 복잡도를 증가시키는 시스템은 항상 존재한다. 단순한 방법으로 문제를 이해하면 단순하게 풀지만 복잡하게 받아들이면 복잡한 해결책이 나온다. 단순하게 풀었다고 해결책이 맞는 것은 아니지만 정답일 확률은 높다. 다른 사람이 받아들이기도 쉽다. 

 

반복하며 진화해 온 인간에게 단계마다 필요한 것은 사건 Event 이었다. 아주 완벽한 진화를 점점 반복하도록 도와주는 사건이다. 반복하고 사건을 만나 다시 진화하는 일은 지금의 인간에게서도 마찬가지로 적용된다. 아주 똑같다. 멈추지 않고 계속되는 일이다.

 

 

일단 코드는 첨부한다.

 

#include <SPI.h>
#include <WiFiNINA.h> // NANO 33 IoT에서 Wi-Fi 기능을 사용하기 위한 라이브러리 입니다.
#include <PubSubClient.h>
#include <SimpleDHT.h>
#include "arduino_secrets.h"

//please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)

//24V on off Relay
int relay_control = 2; //Relay LOW Enable

//define DHT11 pin connection
int pinDHT11 = 9;
SimpleDHT11 dht11(pinDHT11);

//define timer sampling rate 1000=1sec
uint32_t sampleRate = 1000; //sample rate in milliseconds, determines how often TC5_Handler is called

//time variable

uint32_t time_tick_onesecond=0;
uint32_t flag_300seconds = 0;

const char* mqtt_server = "192.168.168.107"; // MQTT 서버를 입력합니다.
const char* mqtt_username = "wapple";
const char* mqtt_password = "refill2021!";
const char* machine_code = "ne0005";

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

unsigned char pumpout_flag = 1;

void setup_wifi() {
    delay(10);
    WiFi.begin(ssid, pass); // 앞서 설정한 ssid와 페스워드로 Wi-Fi에 연결합니다.
    while (WiFi.status() != WL_CONNECTED) 
    { //처음 연결될 때 까지 0.5초 마다 Wi-Fi 연결상태를 확인합니다.
        Serial.println("Connecting WiFi...");
        delay(500);
    }
    //randomSeed(micros()); // 렌덤 문자를 위한 렌덤 시드를 설정합니다.
    Serial.println("Connected to WiFi. print Wifi Status");
    printWifiStatus();
}

int Loop = 0; // LED의 토글을 위해 사용되는 변수입니다.
String ordercode;
String pubstring;
int pumpout_time;

void callback(char* topic, byte* payload, unsigned int length) {
    // Topic에 메시지가 도착하면 실행되는 콜백입니다.
    //Serial.println(length);

    String myString = String((char *)payload);
    String realString = myString.substring(0, length);
    Serial.println(myString.length());
    Serial.println(realString);

    //parsing: 기계코드와 용량 분리
    /// 서버에서 용량을 보낸다. 기계코드, 추출량 ml, 주문번호(추출 완료 후 다시 보낸다)
    int first = realString.indexOf(","); // 첫번째 콤마위치
    int second = realString.indexOf(",",first+1); // 두번째 콤마 위치
    int third = realString.indexOf(",",second+1); // 세번째 콤마 위치
    int strlength = realString.length(); // 문자열 길이
    String str1 = realString.substring(0, first); // 첫번째 토큰
    String str2 = realString.substring(first+1, second); // 두번째 토큰*/
    ordercode = realString.substring(second+1, strlength); // 세번째 토큰*/
    Serial.println(str1);
    Serial.println(str2);
    Serial.println(ordercode);

    pumpout_time = str2.toInt();
    if(str1 == machine_code) //머신코드가 자기라면
    {
        Serial.print("pump operate time");
        Serial.println(str1);
        pumpout_flag = 1;
    }    
}

void pump_operate(int pump_out_time)
{
    //pump_out_time = 57;
    Serial.print(pump_out_time);
    Serial.println(" * 100msecond pump on");
    
    digitalWrite(relay_control, LOW);
    delay(pump_out_time * 100);
    digitalWrite(relay_control, HIGH);    
    
    pubstring="";
    pubstring = machine_code;
    pubstring += ",";
    pubstring += ordercode;
    pubstring += ",";
    pubstring += "T";
    Serial.print(pubstring);
    //client.publish("complete", toCharArray(pubstring));
    if(!client.connected()) 
    {
        client.connect(""); // 앞서 설정한 클라이언트 ID로 연결합니다.
        client.subscribe("operate"); // inTopic 토픽을 듣습니다. topic 츨 구독
    }
    if (client.connected()) 
    {
        client.publish("complete", toCharArray(pubstring));
        Serial.print("complete");
    }  
}

void reconnect() {
    while (!client.connected()) {
//       String clientId = "ArduinoNANO33IoTClinet-"; // 클라이언트 ID를 설정합니다.
//        clientId += String(random(0xffff), HEX); // 같은 이름을 가진 클라이언트가 발생하는것을 방지하기 위해, 렌덤 문자를 클라이언트 ID에 붙입니다.
//        if (client.connect(clientId.c_str())) 
        { // 앞서 설정한 클라이언트 ID로 연결합니다.
            if (client.connect("")) 
            { // 앞서 설정한 클라이언트 ID로 연결합니다.
                client.subscribe("operate"); // inTopic 토픽을 듣습니다. topic 츨 구독
            } 
            else 
            {
                delay(1000); //5000
            }
        }
    }
}

void setup() {
    pinMode(relay_control, OUTPUT);     // 2번 relay control - low enable
    digitalWrite(relay_control, HIGH);
    Serial.begin(9600);
    setup_wifi();

    //setup Timer
    tcConfigure(sampleRate); //configure the timer to run at <sampleRate>Hertz
    tcStartCounter(); //starts the timer

    //setup MQTT server
    client.setServer(mqtt_server, 1883); // Wait----MQTT 서버에 연결합니다. + 159+ 2 line
    if(client.connect(machine_code, mqtt_username, mqtt_password)) //27second
    {
        Serial.println("\tMQTT Connected");
    }
    client.setCallback(callback);
    Serial.println("\tSetup End...");
}

void loop() {       
    //여기 MQT 서버 연결 확인
   if (!client.connected()) {
        reconnect();
        Serial.println("\tReconnecting...");
    }
    client.loop();

    // 5분에 한 번씩 보낸다. test는 10초 만들어 
    //client.publish("log", "kawng, re12345, 25.6, 67.4"); //기계코드(string), 온도(float), 습도(float), 정상유무(bool) ->> kawng, re12345, 25.6, 67.4" - 5분 
    //client.publish("complete", "기계코드, T/F");
    // 두번째는 용량 보내면 동작 후 보낸다. 기계코드, T/F

    //flag를 두어야지   
    if(flag_300seconds > 300) //every 5minute send
    {
        send_temphumi();
        flag_300seconds = 0;     
    }

    if(pumpout_flag == 1)
    {    
        // 시간만큼 동작한다.
        pump_operate(pumpout_time);
        pumpout_flag = 0;        
    }
}

void send_temphumi()
{
    //Serial.println("=================================");
    //Serial.println("Sample DHT11...");
  
    // read without samples.
    byte temperature = 0;
    byte humidity = 0;
    int err = SimpleDHTErrSuccess;
    if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
        Serial.print("Read DHT11 failed, err="); Serial.print(SimpleDHTErrCode(err));
        Serial.print(","); Serial.println(SimpleDHTErrDuration(err)); delay(1000);
        return;
    }
  
    //Serial.print("Sample OK: ");
    //Serial.print((int)temperature); Serial.print(" *C, "); 
    //Serial.print((int)humidity); Serial.println(" H");
    
    pubstring="";
    pubstring = machine_code;
    pubstring += ",";
    pubstring += String((int)temperature);
    pubstring += ",";
    delay(500);  
    pubstring += String((int)humidity);
    pubstring += ",";
    pubstring += "T";

    client.publish("log", toCharArray(pubstring));
    Serial.print(pubstring);
}

char* toCharArray(String str) {
  return &str[0];
}

//void publish(string doc, string topic) {
//  client.publish(toCharArray(topic), toCharArray(buffer));
//}


void printWifiStatus() 
{
    // print the SSID of the network you're attached to:
    Serial.print("SSID: ");
    Serial.println(WiFi.SSID());

    // print your board's IP address:
    IPAddress ip = WiFi.localIP();
    Serial.print("IP Address: ");
    Serial.println(ip);

    // print the received signal strength:
    long rssi = WiFi.RSSI();
    Serial.print("signal strength (RSSI):");
    Serial.print(rssi);
    Serial.println(" dBm");
}

//온도 습도 데이터를 수집하여 5분에 한번 보낸다. 데이터는 int
int get_temp()
{
  //delay(2000);
  byte temperature = 0;
  byte humidity = 0;
  
  if (dht11.read(pinDHT11, &temperature, &humidity, NULL)) {
    Serial.print("Read DHT11 temp failed.");
    return 0;
  }
  else{
    return (int)temperature;  
  }
}

int get_humi()
{
  //delay(2000);
  byte temperature = 0;
  byte humidity = 0;
  
  if (dht11.read(pinDHT11, &temperature, &humidity, NULL)) {
    Serial.print("Read DHT11 humi failed.");
    return 0;
  }else{
    return (int)humidity;
  }
}




void test_topic_split()
{
  String readTopic="abcdefghijklmn,300";
  int length = readTopic.length();
  Serial.println(length);
  String readTopicLength = readTopic.substring(0, length);
 
  //parsing: 기계코드와 용량 분리
  /// 서버에서 용량을 보낸다. 기계코드, 추출량 단위는 ml
  int first = readTopicLength.indexOf(","); // 첫번째 콤마위치
  int second = readTopicLength.indexOf(",",first+1); // 두번째 콤마 위치
  int strlength = readTopicLength.length(); // 문자열 길이
  String str1 = readTopicLength.substring(0, first); // 첫번째 토큰
  String str2 = readTopicLength.substring(first+1, second); // 두번째 토큰
  Serial.println(str1);
  Serial.println(str2);

  int operationTime = str2.toInt();
  
}


//Here Start Timer function
//this function gets called by the interrupt at <sampleRate>Hertz

void TC5_Handler (void) {
  //YOUR CODE HERE  
  time_tick_onesecond++;
  flag_300seconds++;

  Serial.println(time_tick_onesecond);
  
  // END OF YOUR CODE
  TC5->COUNT16.INTFLAG.bit.MC0 = 1; //Writing a 1 to INTFLAG.bit.MC0 clears the interrupt so that it will run again
}


/* 
 *  TIMER SPECIFIC FUNCTIONS FOLLOW
 *  you shouldn't change these unless you know what you're doing
 */

//Configures the TC to generate output events at the sample frequency.
//Configures the TC in Frequency Generation mode, with an event output once
//each time the audio sample frequency period expires.
 void tcConfigure(int sampleRate)
{
 // select the generic clock generator used as source to the generic clock multiplexer
 GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)) ;
 while (GCLK->STATUS.bit.SYNCBUSY);

 tcReset(); //reset TC5

 // Set Timer counter 5 Mode to 16 bits, it will become a 16bit counter ('mode1' in the datasheet)
 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
 // Set TC5 waveform generation mode to 'match frequency'
 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
 //set prescaler
 //the clock normally counts at the GCLK_TC frequency, but we can set it to divide that frequency to slow it down
 //you can use different prescaler divisons here like TC_CTRLA_PRESCALER_DIV1 to get a different range
 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1024 | TC_CTRLA_ENABLE; //it will divide GCLK_TC frequency by 1024
 //set the compare-capture register. 
 //The counter will count up to this value (it's a 16bit counter so we use uint16_t)
 //this is how we fine-tune the frequency, make it count to a lower or higher value
 //system clock should be 1MHz (8MHz/8) at Reset by default
 TC5->COUNT16.CC[0].reg = (uint16_t) (SystemCoreClock / sampleRate);
 while (tcIsSyncing());
 
 // Configure interrupt request
 NVIC_DisableIRQ(TC5_IRQn);
 NVIC_ClearPendingIRQ(TC5_IRQn);
 NVIC_SetPriority(TC5_IRQn, 0);
 NVIC_EnableIRQ(TC5_IRQn);

 // Enable the TC5 interrupt request
 TC5->COUNT16.INTENSET.bit.MC0 = 1;
 while (tcIsSyncing()); //wait until TC5 is done syncing 
} 

//Function that is used to check if TC5 is done syncing
//returns true when it is done syncing
bool tcIsSyncing()
{
  return TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY;
}

//This function enables TC5 and waits for it to be ready
void tcStartCounter()
{
  TC5->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; //set the CTRLA register
  while (tcIsSyncing()); //wait until snyc'd
}

//Reset TC5 
void tcReset()
{
  TC5->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
  while (tcIsSyncing());
  while (TC5->COUNT16.CTRLA.bit.SWRST);
}

//disable TC5
void tcDisable()
{
  TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
  while (tcIsSyncing());
}
// end of code.

 

 

 

 

반응형