WeMosを使ってみる

RaspberryとのSocket通信(Raspberry→WeMos)


前回、Raspberry側がサーバー、WeMos側がクライアントのSocket通信 を紹介しました。
そこで、今回はRaspberry側がクライアント、WeMos側がサーバーのSocket通信を紹介します。

【WeMos側】

WeMos側のスケッチは以下の通りです。
クライアントから受信した大文字を小文字に変換して送り返す単純なものです。
サーバー側なのでIPアドレスを固定にしています。
相手側(今回はRaspberry)とポート番号(今回は9876番を使用)を合わせて下さい。
ここが合っていないと正しく通信できません。
赤字の部分は自分の環境に合わせて変更してください。
/*
 *  Simple TCP Server
 */

#include <ESP8266WiFi.h>

const char* ssid = "**********";
const char* password = "**********";

#define SERVER_PORT 9876

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(SERVER_PORT);

void setup() {
  Serial.begin(115200);

// config static IP
  Serial.println();
  Serial.println();
  IPAddress ip(192, 168, 10, 90);
  IPAddress gateway(192, 168, 10, 1);
  IPAddress subnet(255, 255, 255, 0);
  Serial.print(F("Setting static ip to : "));
  Serial.println(ip);
  WiFi.config(ip, gateway, subnet);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  // Print the IP address
  Serial.println(WiFi.localIP());
 
  // Start the server
  server.begin();
  Serial.println("Server started");
}

void loop() {
  char smsg[30];
  char rmsg[30];

  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }

  int size;
  while((size = client.available()) > 0) {
    Serial.print("TCP Server Receive Size=");
    Serial.println(size);
    size = client.read((uint8_t *)rmsg,size);
    for(uint32_t i = 0; i < size; i++) {
      if(isalpha(rmsg[i])) {
        smsg[i] = toupper(rmsg[i]);
      } else {
        smsg[i] = rmsg[i];
      } // end if
    } // end for

    client.write(smsg, size);
   
    Serial.write((uint8_t *)smsg,size);
    Serial.write("->");
    Serial.write((uint8_t *)rmsg,size);
    Serial.println("");
  } // end while

  Serial.println("Client disonnected");
  // The client will actually be disconnected
  // when the function returns and 'client' object is detroyed
}

このスケッチを実行するとArduino-IDEのシリアルモニターはこのように表示されます。
固定のIPアドレスがアサインされています。


【Raspberry側】

以下のコード(client.c)をコンパイルして実行します。
コンパイルは単純に「cc -o client client.c」で、実行は「sudo ./client」です。
なお、以下のコードはパケット分割に対応していません。
パケット分割に対応したコードはこちらで公開しています。
/*
 Simple Socket Client
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <limits.h>
#include <ctype.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int retryTotal=0;

#define PORT 9876 //サーバープログラムとポート番号を合わせてください

int connect2(struct sockaddr_in * dstAddr, int dstAddrLen) {
  int dstSocket;
  int retry = 0;
  int retryMax = 10;
  time_t start_time, end_time;
  double dtime;

  while (1) {
    //ソケットの生成
    dstSocket = socket(AF_INET, SOCK_STREAM, 0);

    //接続
    write(1,"Connecting...",13);
    time( &start_time );
    if (connect(dstSocket, (struct sockaddr *)dstAddr, dstAddrLen) == 0) return(dstSocket);
    time( &end_time );
    dtime=difftime( end_time, start_time );
    retry++;
    printf("接続できませんでした retry=%d difftime=%f\n",retry,dtime);
    retryTotal++;
    close(dstSocket);
    if (retry > retryMax) return(-1);
    sleep(10);
  }
}

int main(int argc, char **argv){
  // IP アドレス,ソケット,sockaddr_in 構造体
  char destination[32];
  int dstSocket;
  struct sockaddr_in dstAddr;

  //struct sockaddr_in addr;
  struct hostent *hp;
  char  buf[1024];
  int number = 0;
  int numrcv;
  int loopMax;
  int loopCnt;

  time_t start_time=0, end_time;
  double dtime;

  loopMax=INT_MAX;
  if (argc == 2) {
    loopMax=atoi(argv[1]);
  }
  // 相手先アドレスの入力と送る文字の入力
  printf("サーバーマシンのIPは?:");
  scanf("%s", destination);

  //sockaddr_in 構造体のセット
  //bzero((char *)&dstAddr, sizeof(dstAddr));
  memset((char *)&dstAddr, 0, sizeof(dstAddr));
  dstAddr.sin_family = AF_INET;
  dstAddr.sin_port = htons(PORT);

  hp = gethostbyname(destination);
  if (hp == NULL) {
    printf("不正な名前です\n");
    return(-1);
  }
  //bcopy(hp->h_addr, &dstAddr.sin_addr, hp->h_length);
  memcpy(&dstAddr.sin_addr, hp->h_addr, hp->h_length);

  for(loopCnt=0;loopCnt<loopMax;loopCnt++) {
    dstSocket = connect2(&dstAddr, sizeof(dstAddr));
    printf("dstSocket=%d\n",dstSocket);
    if (dstSocket < 0) {
      printf("%s に接続できませんでした\n",destination);
      return(-1);
    }
    printf("%s に接続しました\n",destination);
    if (start_time == 0) time( &start_time );

    memset(buf,0,sizeof(buf));
    sprintf(buf,"data from raspberry %05d",number);
    number++;
    printf("Send=[%s]",buf);
    //パケットの送信
    write(dstSocket, buf, strlen(buf));
    //パケットの受信
    memset(buf,0,sizeof(buf));
    numrcv = read(dstSocket, buf, 1024);
    printf("→Recv=[%s]\n",buf);
    close(dstSocket);
    sleep(5);
  } // end for
  time( &end_time );
  dtime=difftime( end_time, start_time );
  printf("loop=%d difftime=%f[sec] %f[min] retry=%d\n",loopMax,dtime,dtime/60,retryTotal);
  return(0);
}

プログラムを起動すると以下の表示となりますので、サーバ側(WeMos)のIPアドレスを指定します。


Arduino-IDEのシリアルモニターはこのように表示されます。


しばらく放置しましたが、順調に動いています。


次は、MQTTを使った通信を紹介します。

続く....