본문 바로가기
Study/ESP8266(WIFI),ESP32(BLE,WIFI)

nodeMCU(ESP 8266) Arduino porting후 안드로이드 App 제어

by Answer Choi 2016. 1. 7.
반응형

이전 포스팅에 이어 nodeMCU에 Arduino를 포팅하는 걸로 해보겠습니다.


먼저 https://sandbox.sktiot.com/IoTPortal/sdk/sdkList# 로 접속해 Arduino용 sdk를 받아야합니다.


빨간 네모를 눌러 샘플코드를 하나 다운로드합니다.


그리고 녹색네모를 다운받아 확장자를 zip으로 바꿔주면 GMMP 라이브러리가 나타납니다.


GMMP라이브러리는 Arduino에서 zip으로 라이브러리추가를 해줍니다.


먼저 Arduino 소스코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <Time.h>
#include <ESP8266WiFi.h>
#include <GMMP.h>
#define USER_CONTROL_LED 0x80
#define LED_PIN 5
#define DEREGISTRATION_DEVICE_SWITCH_PIN 4
 
byte serverIp[] = {21111515213};
const int nServerPort = 31011;
const char* pszDomainCode = "<your domain code>";
const char* pszGWAuthID = "<your gateway auth ID>";
const char* pszGWMFID = "<your gateway manufacturer ID>";
const char* pszDeviceMFID = "<your device manufacturer ID>";
 
char* deviceId[LEN_DEVICE_ID];
byte mac[] = {0xAA0xBB0xCC0xDD0x110x22};  // Modify this with your ID address
 
int Recv(GMMPHeader* pstGMMPHeader, void* pBody)
{
  U8 cMessageType = pstGMMPHeader->ucMessageType; //메세지 타입 분석
 
  info(F("MsgType: "));
  infoln(cMessageType);
  if (cMessageType  == OPERATION_CONTROL_REQ) {                  //  GMMP_Control_Request
    stControlReqHdr* pstReqHdr = (stControlReqHdr*) pBody;
 
    infoln(F("ControlReq has been received."));
 
    char cResult = 0x00;
 
    int len = 0;
    if (pstReqHdr->usMessageBody) {
      len = strlen((char*) pstReqHdr->usMessageBody);
    }
    if (len > 0) {
      info(F("Control Msg Body: "));
      infoln((char*) pstReqHdr->usMessageBody);
    }
 
    long nTID = Char2int((char*) pstGMMPHeader->usTID, sizeof(pstGMMPHeader->usTID));
 
    debug(F("Received TID: "));
    debugln(nTID);
 
    int ret = GO_Control((char*) pstReqHdr->usGWID, (char*) pstReqHdr->usDeviceID, nTID, (char)pstReqHdr->ucControlType, cResult);
 
    if (ret != GMMP_SUCCESS) {
      errorln(F("ControRes Err!!"));
      free(pBody);
      return 1;
    }
 
    infoln(F("ControlRes has been sent."));
 
    infoln(pstReqHdr->ucControlType);
 
    if (pstReqHdr->ucControlType != USER_CONTROL_LED) {
      error(F("Unknown Control Msg: "));
      errorln(pstReqHdr->ucControlType);
      free(pBody);
      return 1;
    }
 
    if (pstReqHdr->usMessageBody[0== '1') {
      digitalWrite(LED_PIN, HIGH);
      infoln(F("LED ON"));
    } else if (pstReqHdr->usMessageBody[0== '0') {
      digitalWrite(LED_PIN, LOW);
      infoln(F("LED OFF"));
    } else {
      errorln(F("Unknown Control Msg Body; it must be '1' or '0'."));
      free(pBody);
      return 1;
    }
 
    delay(1000);
 
    ret = GO_Notifi((char*) pstReqHdr->usGWID, (char*) pstReqHdr->usDeviceID,
        (char)pstReqHdr->ucControlType, cResult, (char*) pstReqHdr->usMessageBody, 0);
 
    if (ret != GMMP_SUCCESS) {
      error(F("NotiReq Err: "));
      errorln(ret);
      free(pBody);
      return 1;
    }
 
    infoln(F("Control NotiReq has been sent."));
  } else if (cMessageType  == OPERATION_NOTIFICATION_RSP) {             //GMMP_Control_Notification_Response
    stNotificationRspHdr* pstRspHdr = (stNotificationRspHdr*) pBody;
 
    if (pstRspHdr->ucResultCode != 0x00) {
      error(F("NotiRes Err: "));
      errorln(pstRspHdr->ucResultCode);
      free(pBody);
      return 1;
    }
 
    infoln(F("NotiRes has been received."));
  } 
  free(pBody);
  return 0;
}
 
 
#define BUF_SIZE 10
GMMPHeader header;
void *pBody = NULL;
char sendBuf[BUF_SIZE];
 
void setup(void) {
  Serial.begin(115200);
  infoln(F("Start setup()"));
  info(F("Free memory size: "));
 
  pinMode(LED_PIN, OUTPUT);
  pinMode(DEREGISTRATION_DEVICE_SWITCH_PIN, INPUT);
  
  infoln(freeRam());  //ans
 
  Initialize(serverIp, nServerPort, pszDomainCode, pszGWAuthID, mac);
 
  SetCallFunction(Recv);
  
  int ret = GO_Reg(NULL, pszGWMFID);
 
  if (ret != GMMP_SUCCESS) {
    errorln(F("RegReq Error!!"));
    for(;;);
  }
 
  infoln(F("GW RegReq has been sent."));
 
}
 
void loop(void)
{
    
  info(hour());
  info(F(":"));
  info(minute());
  info(F(":"));
  infoln(second());
  delay(1000);
  
  int ret = GetReadData(&header, &pBody);
  if (ret != E_WOULDBLOCK) {
    infoln(F("******** NOT E_WOULDBLOCK *********"));
    info(F("Free memory size: "));
    infoln(freeRam());
  }
}
 
cs


LED 제어하는 부분만 빼고 다 제거하였습니다.


nodeMCU의 D1이 LED, D2가 button입니다.


아직 button의 기능은 없습니다.


기본적으로 Ethernet.h를 include하는데 ESP8266WiFi.h를 include했습니다.


아래는 GMMP.cpp의 include 부분입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
//#include <Ethernet.h>     //ans
#include <ESP8266WiFi.h>    //ans
#include <WiFiUdp.h>        //ans
#include <User_interface.h>    //ans
#include <Time.h>
#include "GMMP.h"
 
const char* ssid="your ap ssid";
const char* pwd="your ap password";
//EthernetUDP Udp;              //ans
WiFiUDP Udp;                    //ans
ESP8266WiFiClass Wifi;          //ans
#define TIMEZONE 9     // KST    //ans
//#define TIMEZONE 0     // GMT    //ans
cs


마찬가지로 Ethernet.h 대신 ESP8266WiFi.h를 include했고, 시간설정을 위해 WiFiUdp.h도 include했습니다.


TIMEZONE은 한국시간에 맞춰 KST 기준으로 바꿨습니다.


ssid와 pwd는 AP의 ssid와 pwd입니다. 아직은 수동으로^^;;


Initialize 부분입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
int Initialize(byte* serverIp,
        const int nPort,
        const char* pszDomainCode,
        const char* pszGWAuthID,
        byte* mac)
{
  infoln(F("Initialize()"));
 
    InitMemory();    
      infoln(F("Getting IP"));
    Wifi.begin(ssid,pwd);    //ans
    while(Wifi.status()!=WL_CONNECTED){    //waiting for conneting
        delay(1000);
        info(".");
    }
    info(F("Obtained IP: "));
    infoln(Wifi.localIP());     //ans
    delay(3000);            //ans
/*    ans
  if (Ethernet.begin(mac)) { 
    info(F("Obtained IP: "));
    infoln(Ethernet.localIP());     
    delay(3000);
  } else {
      
    fatalln(F("Failed to get IP."));
    for (;;);
  }
    */
    
  setTime();
 
    if(SetServerInfo(serverIp, nPort, pszGWAuthID, pszDomainCode) != 0)
    {
        return LIB_PARAM_ERROR;
    }
 
    SetTID(0);
 
    return GMMP_SUCCESS;
}
cs


Line 11 : ssid와 pwd로 AP에 접속시키는 부분입니다. 여기는 ESP8266WiFi.cpp에 있습니다.


특이한 점은 mac주소를 같이 넘겨주면 AP에 접속을 하지 못합니다.


1
int ESP8266WiFiClass::begin(char* ssid, char *passphrase, int32_t channel, const uint8_t* bssid)
cs


ESP8266WiFi.cpp에서 begin함수를 보면 ssid, password, channel, bssid를 받게되어 있습니다.


물론 헤더파일을 보면


1
int begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0const uint8_t* bssid = NULL);
cs


ssid를 제외한 나머지 파라메터는 초기화가 되어있어 파라메터를 쓰지않아도 됩니다.


일단 채널도 알 수는 없으니, ssid와 password만 넘기면 됩니다.


근데 왜 mac주소를 넘겼을때 AP에 접속을 못하느냐인데


begin함수를 살펴보면, mac주소를 세팅하는 부분이 나옵니다.


1
2
3
4
5
6
7
8
if (bssid) {
        
        conf.bssid_set = 1;
        memcpy((void *) &conf.bssid[0], (void *) bssid, 6);
    } else {
            
        conf.bssid_set = 0;
    }
cs


보시면 mac주소(bssid)가 넘어오면 bssid_set=1이 되고, 없으면 bssid_set=0이 됩니다.


station mode 설정 구조체인 station_config를 보면 아래와 같은 주석이 달려있습니다.


1
2
3
4
5
6
7
struct station_config {
    uint8 ssid[32];
    uint8 password[64];
    uint8 bssid_set;    // Note: If bssid_set is 1, station will just connect to the router
                        // with both ssid[] and bssid[] matched. Please check about this.
    uint8 bssid[6];
};
cs


bssid_set=1이면 router에 접속해야하고, ssid와 bssid를 match해야 된다고 합니다.


이 bssid는 device의 mac이 아닌 AP의 mac인듯 합니다.


BSSID(Basic Service Set)는 무선 LAN 표준인 802.11에서 48bit의 BSS(Basic Service Set)을 구분하기 위해 사용한다. 보통은 AP의 MAC주소를 사용하지만 IBSS(Independent basic Service Set)나 AD HOC을 사용할 경우 임의의 값으로 생성된다.    출처 위키


Line 12~15 : 위에서 접속은 시키지만 접속하는데 시간이 좀 걸립니다. 그래서 접속 될때까지


기다리도록 while문으로 처리했습니다.


Line 16~18 : 할당받은 IP를 가져와 뿌려줍니다.


Line 20~28 : 기존 코드인데 문제가 있어 위의 코드로 변경했습니다.


Line 31 : 시간정보를 가져옵니다.


1
2
3
4
5
void setTime()
{
  Udp.begin(NTP_PORT);
  setSyncProvider(getNtpTime);
}
cs


기존의 EthernetUDP 대신 include한 WiFiUDP로 바꿔주어서 따로 수정할 건 없습니다.


추가


Network.cpp 에서 아래부분 수정해 주세요.


1
2
3
4
5
6
7
8
//#include <Ethernet.h>     //ans#include <ESP8266WiFi.h>    //ans
#include "Network.h"
#include "GMMP_Operation.h"
 
int g_socket = -1;
 
//EthernetClient client;    //ans
WiFiClient client;          //ans
cs


1
2
3
4
5
6
7
8
9
10
11
12
int WriteTCP(char* pBuf, int nLen)
{
  debug(F("WriteTCP(): "));
  debugln(nLen);
 
    if (pBuf == NULL || nLen <= 0return LIB_PARAM_ERROR;
 
  //client.write(pBuf, nLen);   //ans
  client.write_P(pBuf, nLen);   //ans
 
    return GMMP_SUCCESS;
}
cs















 

반응형

인기글