jpenner64
Published © GPL3+

Sony Spresense Weather Tracking

Arduino weather stations are pretty common these days. This project applies this function to the new Sony's Spresense, with an added bonus.

IntermediateFull instructions provided4 hours2,874
Sony Spresense Weather Tracking

Things used in this project

Hardware components

Spresense boards (main & extension)
Sony Spresense boards (main & extension)
Spresense is a newer version of the Sony's Spritzer
×1
ESP8266-01
×1
BMP180
×1
Photo resistor
Photo resistor
Photo Resistor is more commonly known as an LDR
×1
Resistor 10k ohm
×1
M/F DuPont style jumpers
×1
LDR - Light Detecting Resistor (Photocell)
Ambient light results may vary based on the type of LDR and resistor used. Sourcing parts from the same vendor offered only this model which should work fairly well as light values are relative.
×1

Software apps and online services

Arduino IDE
Arduino IDE
ThingSpeak API
ThingSpeak API
ThingSpeak is an online iot data hosting provider and is free for small projects. See https://thingspeak.com for creating your own channel

Story

Read more

Schematics

Light Sensor

Code

WeatherPost for Sony SPRESENSE

Arduino
Example code of a Weather Station and provided for porting to and using capabilities of the Sony SPRESENSE
//-----------------------------------------------------------------------------------------
// WeatherPost
// - An Enhancement to ESP8266-01 and ThingSpeak integration with Sony's Arduino Spritzer
// James Penner
// March 11, 2018    Created
// March 25, 2018    Updated  Satellite, Temperature, Preasure, and Light data post to ThinkSpeak
// March 30, 2018    Switch from Adafruit to SparkFun BMP180 library
// May 20, 2018      Ported from Spritzer to SPRESENSE; Corrections and comments added
//                   Corrected reference to analog port from 0 to A0 (SPRESENSE issue #80)
//-----------------------------------------------------------------------------------------
// Wiring Sony's Arduino Spritzer/SPRESENSE
// Spritzer  Color    ESP8266     LDR/Cell  BMP180  Arduino
// --------  -------  ----------  --------  ------  -------
// 3.3vdc    Red      VCC 3.3vdc  3.3vdc    3.3vdc  3.3vdc
// 3.3vdc    Red      CH_CD       -         -       3.3vdc
// GND       Black    GND         GND       GND     GND
// D0(RX)    Green    TX          -         -       D10(RX) Using SoftwareSerial for Arduino
// D1(TX)    Yellow   RX          -         -       D11(TX) Using SoftwareSerial for Arduino
// A0        White    -           Signal    -       A0
// D14/SDA   White    -           -         SDA     A4
// D15/SCL   Blue     -           -         SCL     A5
//-----------------------------------------------------------------------------------------
// The following is a base code used to support a multi sensor read and post to a data store;
// In this case, the data store selected is ThingSpeak. This code is stripped from my
// WeatherStationTS.ino application and its intent is to transpose to standard code to the
// SPRESENSE.
//-----------------------------------------------------------------------------------------
// Changes:
// - Serial connection: Since the SPRESENSE has a seperate UART, the softwareSerial was removed
//   and Serial2 used in its place.
//   The RX/TX connections (D0/D1) are used.
// - Analog Reference: SPRESENSE Analog port 0, must be referenced a A0, and cannot be referenced
//   as 0 in Spritzer and UNO
// General features:
// - SPRESENSE is connected to an ESP2866-01
// - Programming connects to wireless AP (local network), then subsequently connects and
//   posts simulated data to ThingSpeak
// - GNSS satalite locating and posting of geo coordinates to ThingSpeak channel
// - BMP180 added for Temperature and Barometric presure readings; posted to ThingSpeak channel
// - Photocell added for Ambient light readings; posted to ThingSpeak channel
// Enhancement next steps
// - Wire a sensor to take readings and substitute in posting for your own use!
//-----------------------------------------------------------------------------------------
// See WeatherPost document for revisions to the ESP8266-01 sketch to understand changes
//-----------------------------------------------------------------------------------------
//Basic Requirements:
// - Sony Arduino SPRESENSE
// - Preflashed ESP8266-01 module
// - An account set up on ThingSpeak
// - DuPont style, M-F Jumper wires; Red(2), Black(1), Yellow(1), Green(1) 
//-----------------------------------------------------------------------------------------
// ESP8266 Commands:
// AT                                                       OK
// AT+RST                                                   OK
// AT+CIPMUX=0                                              OK
// AT+CWMODE=1                                              OK
// AT+CWJAP="NetID","Password"                              OK
// AT+CIPSTART="TCP","144.212.80.11",80                     CONNECT, OK
// AT+CIPSEND=45                                            OK, >
// GET /update?key=********549JQXB1&field1=50f              OK, +IPD,3:508CLOSED or busy s...
// AT+CWQAP                                                 OK, WIFI DISCONNECT
// Other comands
//  AT+CWLAP                                                C+CWLAP: (...
//  AT+CIPSTA="192.168.0.47"                                OK
//  AT+CIPCLOSE                                             OK
//-----------------------------------------------------------------------------------------
// Key GNSS data elements:
//   pNavData->latitude                                      // Latitude
//   pNavData->longitude                                     // Longitude
//   pNavData->time.year                                     // Year
//   pNavData->time.month                                    // Month
//   pNavData->time.day                                      // Day
//   pNavData->time.hour                                     // Hour
//   pNavData->time.minute                                   // Minutes
//   fsec                                                    // Seconds in floating point notation
//   float fsec = (float)pNavData->time.sec + ((float)pNavData->time.usec / 1000000);
//   pNavData->getSatelliteElevation(1)                      // Elevation of Satellite 1
// ------------------------------------------------------------------------------
#include <SFE_BMP180.h>                    // Include SparkFun library to support BMP180
#include <Wire.h>                          // Include the synchronous Wire library
SFE_BMP180 bmp180;                         // Instantiate the BMP library functions
#define ALTITUDE 213.36                    // Altitude of your location in meters (Default for BMP180)
#include <GNSS.h>                          // Include the Sony Spritzer GPS library
SpGnss gnss;                               // Instanciate the GNSS library functions
#define SSID        "Net_ID"               // Must be changed - WiFi SSID/Hostname
#define PASS        "drowssap"             // Must be changed - Encrypted password
#define APIKEY      "********549JQXB1"     // Must be changed - API Key Sandbox on ThingSpeak Channel
#define IP          "184.106.153.149"      // IP address of thingspeak.com from my location
#define MONITOR     true                   // Debuging messages over the monitor
#define BROADCAST   true                   // Broadcast readings to ThingSpeak
#define POST_PERIOD 120000                 // 2 minutes = 120,000ms = 120sec
#define CELPIN      A0                     // Analog pin for the PhotoCell (Ambient Light)
//---------------------------------------------------------------------
String cmd;                                // Output string to the ESP8266
String passcode;                           // Decrypted Network password
float xTemp = 76.9;                        // Dummy Temerature          76.9  F
float xTempC = 8.3;                        // Dummy Temerature          8.3   C
float xHumi = 23.3;                        // Dummy Humidity            23.3  %
float xPres = 873.6;                       // Dummy Barometric preasure 873.6 mb
float xInHg = 29.3;                        // Dummy Barometric preasure 29.3  inHg
int xLite = 738;                           // Dummy Ambient light       738   ambient
float xWspd = 12.8;                        // Dummy Wind speed          12.8  mph
int xWdir = 270;                           // Dummy Wind Direction      270   compass
float xLong = 0.0;                         // Default Longitude         0.0
float xLati = 0.0;                         // Default Latitude          0.0
unsigned long markTime;                    // Time mark for the delay timer
int cri = 0;                               // Index for connection
SpNavData *pNavData;                       // Pointer for NavData
char caString[36];                         // Character Array for formating String
char buff[12];                             // Character Array buffer to support sprintf conversion
bool BMPfailure = false;                   // Set flag for BMPfailure
char bmpStatus;                            // Used for bmp180 function call status (single byte 0-255)

// === Set up ================================================================================
void setup(){
  if (MONITOR) Serial.begin(9600);
  if (MONITOR){
    Serial.println("Sony Spritzer ESP8266-01 posting to ThingSpeak");
    Serial.println("James Penner / March 20, 2018");
    Serial.println();
  }
  Serial2.begin(115200);
  while(!Serial2){
    ; // wait for ESP8266 port to open/connect; vehicle Monitoring
  }

  Serial.println("ESP8266: Serial connection made");
  if (bmp180.begin()){
    Serial.println("BMP180: Sensor is OK");
    BMPfailure = false;
  }else{
    BMPfailure = true;
  }

  gnss.setDebugMode(PrintInfo);                              // Put GPS readings into a debug mode
  int r;
  r = gnss.begin();                                          // Initialize GNSS handling
  if (r != 0){                                               // Error encountered
    Serial.print("GNSS: Unable to initialize! (");Serial.print(r);Serial.println(")");
  }else{
    r = gnss.start(COLD_START);                              // Start GNSS listening
    if (r != 0){                                             // Error encountered
      Serial.print("GNSS: Unable to start! (");Serial.print(r);Serial.println(")");
    }else{
      Serial.println("GNSS: Is online/listening");           // GSNN is online 
    }
  }  

  passcode = decryptPass(PASS);
}

// --- Satellite check -----------------------------------------------------------------------
boolean getNavData(SpNavData *pNavData){
  boolean ret;
  if (pNavData->posDataExist == 0)  {
    Serial.println("GNSS: Position is not yet fixed");
    ret = false;
  }else{
    ret = true;
  }
  return ret;
}

// === Main loop =============================================================================
void loop(){
  randomSeed(analogRead(0));                                    // Standard Arduino technique using unused Analog pin noise to seed
  double tempT, tempP;                                          // Used for bmp180 function calls
  if (MONITOR){Serial.println("Start reporting cycle....");Serial.println();}
  Led_On(LED0);

  bmpStatus = bmp180.startTemperature();
  if (bmpStatus != 0){
    delay(bmpStatus);                                           // Wait for measurement to complete (bus time)
    bmpStatus = bmp180.getTemperature(tempT);
    if (bmpStatus != 0){
      xTemp = ((tempT*9.0)/5.0)+32.0;                           // Read Celsius convert to Fahrenheit
      bmpStatus = bmp180.startPressure(3);                      // Set oversampling 0-... (10)
      if (bmpStatus != 0){
        delay(bmpStatus);                                       // Wait for measurement to complete (bus time)
        bmpStatus = bmp180.getPressure(tempP,tempT);
//        if (isnan(tempP)){
//          Serial.print("a-NAN p("); Serial.print(tempP); Serial.println(")");
//          Serial.print("a-NAN t("); Serial.print(tempT); Serial.println(")");
//        }
        if (bmpStatus != 0){
          xPres = tempP;                                        // Read mb
          xPres = bmp180.sealevel(tempP,ALTITUDE);              // Compensate for Altitude
        }else{
          xPres = 0.0;
          Serial.println("BMP180: Error retrieving Pressure; 0mb used!");
        }
      }else{
        xPres = 0.0;
        Serial.println("BMP180: Error Starting Pressure readings; 0mb used!");
      }
    }else{
      xTemp = 0.0;
      Serial.println("BMP180: Error retrieving Temperature; 0.0F used!");
    }
  }else{
    xTemp = 0.0;
    Serial.println("BMP180: Error Starting Temperature readings; 0.0F used!");
  }
  
  xLite = analogRead(CELPIN);                                  // Read Ambient Light from Analog pin
  
  xHumi = 23.3+random(15.0);                                   // Simulate Humidity +variation
  xInHg = 29.3+random(1.0);                                    // Simulate variation
  xWspd = 12.8+random(20.0);                                   // Simulate variation
  xWdir = 270+random(45);                                      // Simulate variation
  // --- Get location --------------------------------------------------------------------------
  if (gnss.waitUpdate(-1)){                                    // Have an update?
    SpNavData NavData;
    gnss.getNavData(&NavData);                                 // Receive in Nav data if available
    if (getNavData(&NavData)){                                 // There is data!
      pNavData = &NavData;
      xLong = (float) (pNavData->longitude);                   // recaset to float
      xLati = (float) (pNavData->latitude);                    // recaset to float
      Serial.print("GNSS: Found Satellite! Position is ");
      sprintf(caString, "%3.6f, %3.6f\0", pNavData->longitude, pNavData->latitude);
      Serial.println(caString);
    }else{
      Serial.println("GNSS: No satellite discovered");         // No satellite yet
      xLong = 0.0;                                             // Default if not read longitude
      xLati = 0.0;                                             // Default if not read latitude
    }
  }else{
    Serial.println("GNSS: Data not updated");                  // Catch if data not updated
  }
  // --- Post Readings -----------------------------------------------------------------------
  waitTime(4000);
  connectWifi();
  waitTime(1000);
  if (BROADCAST) postReadings();
  waitTime(4000);
  Led_Off(LED0);
  Led_Off(LED1);
  Led_Off(LED2);
  Led_Off(LED3);
  
  delay(POST_PERIOD);
}

boolean connectWifi(){
  Led_On(LED1); 
  if (MONITOR) Serial.println("\nAT> AT ------------------------------------------------------------");
  Serial2.println("AT");                        // Check:                     OK is returned
  waitTime(500);
  if (MONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
  waitTime(100);

  if (MONITOR) Serial.println("\nAT> AT+RST --------------------------------------------------------");
  Serial2.println("AT+RST");                        // Check:                     OK is returned
  waitTime(5500);
  if (MONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
  waitTime(1000);

  if (MONITOR) Serial.println("\nAT> AT+CIPMUX=0 -------------------------------------------------");
  Serial2.println("AT+CIPMUX=0");                   // Single connection mode:    OK is returned
  waitTime(500);
  if (MONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
  waitTime(100);
  
  if (MONITOR) Serial.println("\nAT> AT+CWMODE=1 ---------------------------------------------------");
  Serial2.println("AT+CWMODE=1");                   // Access Point=0, Station=1: OK is returned
  waitTime(500);
  if (MONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
  waitTime(100);
  
  if (MONITOR) Serial.println("\nAT> AT+CWLAP ------------------------------------------------------");
  Serial2.println("AT+CWLAP");                   // List Access Points
  waitTime(7000);
  if (MONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
  waitTime(2000);
  
  Led_On(LED2); 
  cmd="AT+CWJAP=\"";cmd+=SSID;cmd+="\",\"";cmd+=passcode;cmd+="\"";
  if (MONITOR){ Serial.print("\nAT> ");Serial.print(cmd); Serial.println(" ---------------------------------------");}
  for (int cri=0; cri <= 3; cri++){
    Serial2.println(cmd);                   // Join Access Point:  OK is returned after about 3-4 seconds
    Serial2.flush();
    waitTime(6000);
    if (Serial2.find((char *)"OK")){
      if (MONITOR){
        Serial.println(cmd);
        Serial.print("Network Connected! ("); Serial.print(cri); Serial.println(")");
      }
      cri=5;
      break;
    }
  } 
  if (cri==3){
    if (MONITOR){
      while (Serial2.available() > 0) Serial.write(Serial2.read());
      Serial.println("AT+CWJAP failed...");
    }
  }
  if (MONITOR){
    while (Serial2.available() > 0) Serial.write(Serial2.read());
    Serial.write("AT+CWJAP=SSID and Passcode");     // Do not expose decypted password
  }
  waitTime(100);

  if (MONITOR) Serial.println("\nAT> AT+CIFSR ------------------------------------------------------");
  Serial2.println("AT+CIFSR");                     // Check Connection status
  Serial2.flush();
  waitTime(2000);
  if (MONITOR){
    while (Serial2.available() > 0) Serial.write(Serial2.read());
    Serial.println();
  }
}

//--- V2.0 ------------------------------------------------------------
void postReadings(){
  cmd = "AT+CIPSTART=\"TCP\",\"";
  cmd += IP;
  cmd += "\",80";
  Led_On(LED3); 
  if (MONITOR) Serial.println("\nAT> AT+CISTART ----------------------------------------------------");
  for (int cri=0; cri <= 3; cri++){
    Serial2.println(cmd);                   // Conenct to ThingSpeak: CONNECT is returned after about 1-2 seconds
    Serial2.flush();
    waitTime(4000);
    if (Serial2.find((char *)"CONNECT")){
      if (MONITOR){
        Serial.println(cmd);
        Serial.print("Thingspeak Connected! ("); Serial.print(cri); Serial.println(")");
      }
      cri=5;
      break;
    }
  } 
  if (cri==3){
    if (MONITOR){
      while (Serial2.available() > 0) Serial.write(Serial2.read());
      Serial.println("Thingspeak Connection failed...");
    }
  }

  cmd = "GET /update?api_key="; cmd += APIKEY;
  cmd += "&field1=";   sprintf(buff,"%.2f",xTemp);     cmd += buff;
  cmd += "&field2=";   sprintf(buff,"%.2f",xHumi);     cmd += buff;
  cmd += "&field3=";   sprintf(buff,"%.2f",xPres);     cmd += buff;
  cmd += "&field4=";                                   cmd += xLite;
  cmd += "&field5=";   sprintf(buff,"%.2f",xWspd);     cmd += buff;
  cmd += "&field6=";                                   cmd += xWdir;
  cmd += "&field7=";   sprintf(buff,"%.6f",xLong);     cmd += buff;
  cmd += "&field8=";   sprintf(buff,"%.6f",xLati);     cmd += buff;
  cmd += "\r\n";

  if (MONITOR){ Serial.print("\nAT> AT+CIPSEND=");Serial.print(cmd.length()); Serial.println(" ------------------------------------------------");}
  Serial2.print("AT+CIPSEND=");
  Serial2.println(cmd.length());                // Send length of IP string:  OK is returned  
  Serial2.flush();
  waitTime(2000);
  if (MONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());

  if (MONITOR) Serial.println("\n> GET -------------------------------------------------------------");
  Serial.print("> "); Serial.println(cmd);
  Serial2.println(cmd);                         // Send Get/Post command:     SEND OK and +IPD,1:5CLOSED are returned
  Serial2.flush();
  waitTime(3000);
  if (MONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());

  if (MONITOR) Serial.println("\nAT> AT+CWQAP ------------------------------------------------------");
  Serial2.println("AT+CWQAP");
  Serial2.flush();
  waitTime(3000);
  if (MONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
}
//------------------------------------------------------------------------
// Custom routine to decrypt password; somewhat obfuscates it from code
//------------------------------------------------------------------------
String decryptPass(String inStr){
  String outStr = "";
  char x;
  for (int i = 0; i < inStr.length(); i++){
    x = (byte(inStr[i]) + 8 - i);
    outStr = outStr + x;
  }
  return outStr;
}
//------------------------------------------------------------------------
// Suplement to delay() fucntion as delay() does not pause all actions and is asynchronous. 
//------------------------------------------------------------------------
void waitTime(int milsec){
  markTime = millis();
  while (millis()-markTime < milsec){
  }
}

Credits

jpenner64
3 projects • 6 followers
Contact

Comments

Please log in or sign up to comment.