Help Noob w/Mega->ESP8266->Tentacle->Thingspeak

I’m working on a swimming pool water monitoring system (ok, I’m really working on learning this stuff), and I’ve been up for the past 36 hours trying to get this to work.

I’ve got a Mega, a cheapo ESP8266 wifi sheild and a Tentacle sensor shield and I’d like to post/stream the data online, perhaps to Thingspeak.

The first hurdle was getting the 8266 working. I discovered (after only 6 hours of frustration) that if I wire it up instead of piggybacking it on to the Mega, it will work.

But, I only got it to work with SoftwareSerial.h (hence the communication on pins 10 and 11).

So, I was hoping those who know more than I do (which is 100% of you), would take a look at this code and see what could be done better/smarter/more-robust/etc.?

Also, it’s 5:50am and I just don’t have it in me to figure out how to convert the char variable SensorData from Celsius to Fahrenheit (it’s a type thing).

If there’s a better way, even if that means starting from scratch, I’d appreciate hearing that also.

Thank you!

#include <SoftwareSerial.h>
#include <Wire.h>                     // enable I2C.

char sensordata[30];                  
byte sensor_bytes_received = 0;       
byte code = 0;                        
byte in_char = 0;                     

int channel_ids[] = {111};
char *channel_names[] = {"DO", "ORP", "PH", "EC"}; 

#define TOTAL_CIRCUITS 1              
#define SSID "upstairs"
#define PASS "yyyyy"
#define EMONCMS_IP "80.243.190.58"         // emoncms.org
#define THINGSPEAK_IP "184.106.153.149"    // thingspeak.com
#define MAX_FAILS 3

SoftwareSerial espSerial(10, 11);          // RX, TX

//#include <DHT.h>
//DHT dht(3, DHT11);

unsigned long sample_interval = 20000;
unsigned long last_time;
int fails = 0;

void setup() {
  pinMode(10, INPUT);    // softserial RX - yellow
  pinMode(11, OUTPUT);   // softserial TX - blue
  pinMode(9, OUTPUT);    // esp reset - white
  pinMode(3, INPUT);     // DHT - ...
 
  delay(3000);           // to enable uploading??
 
  // Same speed, ESP softserial cannot be faster than 19200
  Serial.begin(9600);    
  espSerial.begin(9600);
  espSerial.setTimeout(2000);
  Wire.begin();         // enable I2C port.
 
//  dht.begin();

  last_time = millis();  // get the current time;
 
  Serial.print(F("send Tentable shield sensor data to ThingSpeak.com using ESP8266 "));
  Serial.print(F("every "));
  Serial.print(sample_interval/1000);
  Serial.println(F("s."));
  
  if (!resetESP()) return;
  if (!connectWiFi()) return;
}

void echoAll() {
  while (espSerial.available()) {
    char c = espSerial.read();
    Serial.write(c);
    if(c=='\r') Serial.print('\n');
  }
}

boolean resetESP() {
   // - test if module ready
   Serial.print(F("reset ESP8266..."));
 
   // physically reset EPS module
   digitalWrite(9, LOW);          
   delay(100);
   digitalWrite(9, HIGH);  
   delay(500);
   
   if (!send("AT+RST", "ready", F("%% module no response"))) return false;
   
   Serial.print(F("module ready..."));
   return true;
}

boolean connectWiFi() {
  int tries = 5;
  
  while(tries-- > 0 && !tryConnectWiFi());
  
  if (tries <= 0) {
    Serial.println(F("%% tried X times to connect, please reset"));
    return false;
  }
  
  delay(500); // TOOD: send and wait for correct response?
  
  // set the single connection mode
  espSerial.println("AT+CIPMUX=0");
  
  delay(500); // TOOD: send and wait for correct response?
  // TODO: listen?
  
  return true;
}

boolean tryConnectWiFi() {
   espSerial.println("AT+CWMODE=1");
   delay(2000); // TOOD: send and wait for correct response?
   
   String cmd="AT+CWJAP=\"";
   cmd+=SSID;
   cmd+="\",\"";
   cmd+=PASS;
   cmd+="\"";
   
   if (!send(cmd, "OK", F("%% cannot connect to wifi..."))) return false;
   
   Serial.println(F("WiFi OK..."));
   return true;
}

boolean send(String cmd, char* waitFor, String errMsg) {
    espSerial.println(cmd);
    if (!espSerial.find(waitFor)) {
      Serial.print(errMsg);
      return false;
    }
    return true;
}

boolean connect(char* ip) {
   String cmd; 
   cmd = "AT+CIPSTART=\"TCP\",\"";
   cmd += ip;
   cmd += "\",80";
   espSerial.println(cmd);
   // TODO: this is strange, we wait for ERROR
   // so normal is to timeout (2s) then continue
   if(espSerial.find("Error")) return false;
   return true;
}

boolean sendGET(String path) {
   String cmd = "GET ";
   cmd += path;
   
   // Part 1: send info about data to send
   String xx = "AT+CIPSEND=";
   xx += cmd.length();
   if (!send(xx, ">", F("%% connect timeout"))) return false;
   Serial.print(">");
   
   // Part 2: send actual data
   if (!send(cmd, "SEND OK", F("%% no response"))) return false;
   
   return true;
}

void loop() {

for (int channel = 0; channel < TOTAL_CIRCUITS; channel++) {       // loop through all the sensors
  
    Wire.beginTransmission(channel_ids[channel]);     // call the circuit by its ID number.
    Wire.write('r');                          // request a reading by sending 'r'
    Wire.endTransmission();                         // end the I2C data transmission.
    
    delay(1000);  // AS circuits need a 1 second before the reading is ready

    sensor_bytes_received = 0;                        // reset data counter
    memset(sensordata, 0, sizeof(sensordata));        // clear sensordata array;

    Wire.requestFrom(channel_ids[channel], 48, 1);    // call the circuit and request 48 bytes (this is more then we need).
    code = Wire.read();

    while (Wire.available()) {          // are there bytes to receive?
      in_char = Wire.read();            // receive a byte.

      if (in_char == 0) {               // null character indicates end of command
        Wire.endTransmission();         // end the I2C data transmission.
        break;                          // exit the while loop, we're done here
      }
      else {
        sensordata[sensor_bytes_received] = in_char;      // append this byte to the sensor data array.
        sensor_bytes_received++;
      }
    }
    
    Serial.print(channel_names[channel]);   // print channel name
    Serial.print(':');

    switch (code) {                       // switch case based on what the response code is.
      case 1:                             // decimal 1  means the command was successful.
        Serial.println(sensordata);       // print the actual reading
        break;                              // exits the switch case.

      case 2:                             // decimal 2 means the command has failed.
        Serial.println("command failed");   // print the error
        break;                              // exits the switch case.

      case 254:                           // decimal 254  means the command has not yet been finished calculating.
        Serial.println("circuit not ready"); // print the error
        break;                              // exits the switch case.

      case 255:                           // decimal 255 means there is no further data to send.
        Serial.println("no data");          // print the error
        break;                              // exits the switch case.
    }

 

  } // for loop 


// boolean sendDataThingSpeak(float temp, float hum)
{
   if (!connect(THINGSPEAK_IP)) return false;

   String path = "/update?key=xxxxxxxx&field1=";
   path += sensordata;
   path += "&field2=";
   path += ".TEST";
   path += "\r\n";
   if (!sendGET(path)) return false;
   
   Serial.print(F(" thingspeak.com OK"));
   return true;
}
}

I think I figure out the C to F conversion (rather, how to apply arithmetic functions to char type variables).

(strtoul(sensordata,NULL,10)*1.8+32)

int channel_ids[] = {111};
char *channel_names[] = {"DO", "ORP", "PH", "EC"};

4 names and 1 ID?

PaulS: int channel_ids[] = {111}; char *channel_names[] = {"DO", "ORP", "PH", "EC"};

4 names and 1 ID?

Thanks for looking!

The final implementation will have 4 sensors (4 channels):

Water temp before heater (typical pool water temp) Water temp after heater (to indicate that the heater is working) Ph ORP (sanitation level)

Second phase will be controlling an acid delivery system (Ph), the salt water generator (ORP), and the heater remotely.

And I'd love to have regular emails automatically sent with these readings.

I'm just starting to put it together (it's all still on my bench), so just 1 sensor for now.

This is super cool fun stuff (even with the learning curve)!