Thursday, April 13, 2017

Temperature and hygrometer with FlashAir + Arduino + Raspberry Pi (3) : Send measured data from Arduino to Raspberry Pi

Table of contents.
  1. Read values from sensor
  2. Read from SD card with iSDIO
  3. Send values from arduino to Raspbery Pi
  4. Visualize on Raspberry Pi

It's readied to use FlashAir from Arduino.
Let's send data via Flash Air to Raspberry Pi.
The all of following source code is put in Github.

Connect arduino and Flash Air



The each function of SD card pins is as follows.
I use 4th pin as the chip select pin.
SilkFunction
CDDo not use
CSChip select
CLKClock
SDOOutput
SDIInput
GNDGround
3.3V3.3V power
5V5V power


Read a parameter file from FlashAir storage

Read a parameter from a file on SD card volume.

The parameter is ID number of a target location.
Its file name is "id.txt".
A single number (Location ID) is written in the file.

Temperature and humidity values are stored with Location ID in Raspberry Pi.
When an arduino measures at another place, you can modify the location ID in Flash Air.
So then, several places can be measured by a single arduino.

To be honest, I wanted to store all WiFi parameters in SD card, but the memory of arduino became depleted and arduino became unstable...

// Include SD card library
#include 
#include 

// Chip select
#define CHIP_SELECT_PIN 4

// File path
#define ID_FILE "/id.txt"

int ID = 0;

// Read file from SD
char* SD_read( char* path, char* buf, size_t s ) {

  delay(1000);

  File file = SD.open(path,FILE_READ);
  if ( !file ) { return ""; }

  String str = "";
  while (file.available()) { str += char(file.read()); }
  file.close();

  str.toCharArray(buf, s);

  return buf;
}

// Setup SD card
void setup_SD() {
  // Initialize SD card.
  Serial.println(F("Initializing SD card..."));  

  // SS ピンを出力にしておかないと SD カードライブラリが動作しないらしい
  // SS pin must be output to activate SD card library.
  pinMode(SS, OUTPUT);
  if (!SD.begin(CHIP_SELECT_PIN)) {
    Serial.println(F("Card failed, or not present"));
    abort();
  }

    : 

  // Convert text to integer.
  char buf[32];
  ID = atoi(SD_read(ID_FILE,buf,32));
  Serial.print(F("ID="));
  Serial.println(ID);

}

void setup() {
  // Initialize UART for message print.
  Serial.begin(9600);
  while (!Serial) {
    ;
  }

  setup_SD();
}


Wake up WiFI only at sending data

Since power consumption is intense if WiFi keeps running, leave it off when not in use.

#include 
#include 

// Interval of measurement
#define LOG_INTERVAL 600000

char SSID[] = "{WiFi SSID}";
char NETWORKKEY[] = "{WiFi password}";
char API_HOST[] = "{IP address of Raspberry Pi}";
char API_PATH[] = "/api.php";

uint8_t buffer[512];
uint32_t nextSequenceId = 0;

// Use iSDIO_waitResponse of Flash Air tutorial
boolean iSDIO_waitResponse(uint32_t sequenceId) {
  :
}

// Use iSDIO_disconnect of Flash Air tutorial
boolean iSDIO_disconnect(uint32_t sequenceId) {
  :
}

// Use iSDIO_connect of Flash Air tutorial
boolean iSDIO_connect(uint32_t sequenceId, const char* ssid, const char* networkKey) {
  :
}

// Modify iSDIO_http of tutorial.
// Target address and parameters are acceptable as arguments.
boolean iSDIO_http(uint32_t sequenceId, char* host, char* path, char* param) {
  Serial.println(F("http command: "));
  memset(buffer, 0, 512);
  uint8_t* p = buffer;
  p = put_command_header(p, 1, 0);

  // 0x21 means "Without SSL"
  p = put_command_info_header(p, 0x21, sequenceId, 2);

  // Target host is the IP address of Raspberry Pi
  p = put_str_arg(p, host);  // Argument #1.

  // HTTP header
  char getParam[128];
  sprintf(getParam,
    "GET %s?%s HTTP/1.1\r\n"
    "Host: %s\r\n"
    "User-Agent: FlashAir\r\n"
    "\r\n", path, param, host);
  Serial.println(getParam);
  p = put_str_arg(p, getParam);
  put_command_header(buffer, 1, (p - buffer));
  return SD.card.writeExtDataPort(1, 1, 0x000, buffer) ? true : false;
}

// Setup SD
void setup_SD() {
  // Initialize SD card.
  Serial.println(F("Initializing SD card..."));  

  pinMode(SS, OUTPUT);
  if (!SD.begin(CHIP_SELECT_PIN)) {
    Serial.println(F("Card failed, or not present"));
    abort();
  }
 
  // Read the previous sequence ID.
  if (SD.card.readExtMemory(1, 1, 0x420, 0x34, buffer)) {
    if (buffer[0x20] == 0x01) {
      nextSequenceId = get_u32(buffer + 0x24);
      iSDIO_waitResponse(nextSequenceId);
      nextSequenceId++;
    } else {
      nextSequenceId = 0; 
    }
  } else {
    Serial.println(F("Failed to read status."));
    nextSequenceId = 0; 
  }

  char buf[32];
  ID = atoi(SD_read(ID_FILE,buf,32));
  Serial.print(F("ID="));
  Serial.println(ID);
  }
}

void setup() {
  // Initialize UART for message print.
  Serial.begin(9600);
  while (!Serial) {
    ;
  }

  setup_SD();
}

void loop() {

  // Measure time
  unsigned long start = millis();
  digitalWrite(13,HIGH);

  //  Measure temperature and humidity
 int chk = DHT.read22(DHT_PIN);
  if ( chk != 0 ){
    Serial.println(F("Fail to read humidity."));
    delay(1000);
    return;
  }

  // Make HTTP parameters
  char humid[8];
  char temp[8];
  char param[32];
  sprintf(param,"ID=%d&H=%s&T=%s",
    ID,dtostrf(DHT.humidity,5,2,humid),dtostrf(DHT.temperature,5,2,temp));
  Serial.print(F("PARAM:"));
  Serial.println(param);

  // Wake up WiFi
  // If it fails, retry it three times.
  for ( int retry = 3; retry > 0; retry -- ) {
    delay(1000);
    if( iSDIO_connect(nextSequenceId, SSID, NETWORKKEY) &&
      iSDIO_waitResponse(nextSequenceId) ) {
      Serial.println(F("Connected"));
      retry = 0;
    } else {
      Serial.print(F("Failed or waiting. errorCode="));
      Serial.println(SD.card.errorCode(), HEX);
    }
    nextSequenceId++;
  }

  // HTTP GET
  for ( int retry = 3; retry > 0; retry -- ) {
    delay(1000);
    if ( iSDIO_http(nextSequenceId,API_HOST,API_PATH,param) &&
      iSDIO_waitResponse(nextSequenceId)) {
        Serial.println(F("OK"));
        retry = 0;
    } else {
      Serial.print(F("Failed or waiting. errorCode="));
      Serial.println(SD.card.errorCode(), HEX);
    }
    nextSequenceId++;
  }

  //Stop WiFi
  if (iSDIO_disconnect(nextSequenceId) &&
      iSDIO_waitResponse(nextSequenceId)) {
    Serial.println(F("Success."));
  } else {
    Serial.print(F("Failed or waiting. errorCode="));
    Serial.println(SD.card.errorCode(), HEX);
  }
  nextSequenceId++;

  digitalWrite(13,LOW);

  // Sleep until the next time
  unsigned long span = millis() - start;
  if ( span > LOG_INTERVAL ) { return; }
  unsigned long sleep_time = LOG_INTERVAL - span;
  Serial.print(F("SLEEP => "));
  Serial.println(sleep_time,DEC);

  // Power save
  delaySleep(sleep_time);
}


Power saving wait

Since measuring and sending ends in a few seconds, most of the time is waiting time.

In order to appropriately save power, it is necessary to isolate the power supply with relays and to stop FlashAir and DHT22 while Arduino is stopped.
Then stop Arduino using WDT (Watch Dog).

However, that is troublesome...
So, I reduced just a little power only for delay .

void delaySleep(unsigned long t) {
  unsigned long t0;
  if( t <= 16 ) {
    delay(t);
  }
  else{
    t0 = millis();
    set_sleep_mode (SLEEP_MODE_IDLE);
    while( millis() - t0 < t ) {
      sleep_mode();
    }
  }
}


The Arduino side is now complete!
However, it fails to connect...of course.
There are no target host.

Next time, we will set Raspberry Pi up as host.

No comments:

Post a Comment