Go Down

Topic: UV sensor via wireless and data upload to the Internet (Read 4215 times) previous topic - next topic

PaulRB

So... What versions were you using before? To be a "good Arduino Citizen", what you should do now is upgrade the versions one step at a time and test compiling the sketch at each stage. When you figure out which version of which package breaks, raise a issue on GitHub or something.

otronics

So, the code has uploaded.

Looking at the Serial Monitor, something isn't quite right.

I have an error followed by gibberish as it tries to connect:

... Attempting to connect to WPA network...
H!ˆˆÑ()ôD‚ ?
... Attempting to connect to WPA network...
?)�þ1§Œ
ÿ
... Attempting to connect to WPA network...
?)�þ1§Œ
ÿ
... Attempting to connect to WPA network...


This is the board I have purchased: https://www.ebay.co.uk/itm/NodeMcu-Development-Board-ESP8266-12E-WIFI-CH340-v3-USB-ESP12-ESP-12-UK-SELLER/152711990999?ssPageName=STRK%3AMEBIDX%3AIT&_trksid=p2060353.m2749.l2649

NodeMCU 0.9 (ESP-12 Module) is the board I have selected in the Arduino IDE. The 12-E board option yields the same result.

Any ideas?

I have even tried connecting it to a wifi network without a password and it still doesn't connect.

otronics

I have done some tests:

* I have uploaded a script that scans and prints available wi-fi networks. This works.

* I have uploaded a script that tests a given wifi network. I have connected to my wifi no problem so the board is OK.

There must be a problem with the UV code.

I have though managed to get the UV code uploading with the latest IDE (1.8.5).

Aside from that, the problem remains: the script still won't connect to wifi.

otronics

Is someone with a genuine Arduino (and wi-fi shield) willing to upload the code, test it and see if they can get their wireless to connect?

Thank you.

PaulRB

I thought you said it must be the UV code that was the problem?

It's been a while since you posted your latest full code, so on the interests of avoiding any wasted effort, I think you should post it again. I remember it's quite large, so just attach it rather than using code tags in multiple sections.

otronics

It may well be the code but I need to rule out hardware as well.

UV code:

Code: [Select]
#include <WiFi.h>
#include "plotly_streaming_wifi.h"

// Sign up to plotly here: https://plot.ly
// View your API key and streamtokens here: https://plot.ly/settings
#define nTraces 3
// View your tokens here: https://plot.ly/settings
// Supply as many tokens as data traces
// e.g. if you want to ploty A0 and A1 vs time, supply two tokens
char *tokens[nTraces] = {"lbula7u8rd", "86m41ss1sa"};
// arguments: username, api key, streaming token, filename
plotly graph = plotly("otronics", "ZRzvr46eGrhf6UN0VG9r", tokens, "test", nTraces);

// Setup UV Sensor (ML8511) Pins
int UVOUT = A0;
const byte REF_3V3 = A0;

int status = WL_IDLE_STATUS;     // the Wifi radio's status
char ssid[] = ""; //  your network SSID (name)
char pass[] = ""; // // your network password

void wifi_connect(){
    // attempt to connect using WPA2 encryption:
    Serial.println("... Attempting to connect to WPA network...");
    status = WiFi.begin(ssid, pass);
    // if you're not connected, stop here:
    if ( status != WL_CONNECTED) {
      Serial.println("... Couldn't get a WiFi connection, trying again");
      wifi_connect();
    }
    // if you are connected, print out info about the connection:
    else {
      Serial.println("... Connected to network");
    }
}

void setup() {

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // Initialize pinMode for UV Sensor
  pinMode(UVOUT, INPUT);
  pinMode(REF_3V3, INPUT);

  wifi_connect();

  graph.fileopt="overwrite"; // See the "Usage" section in https://github.com/plotly/arduino-api for details
  bool success;
  success = graph.init();
  if(!success){while(true){}}
  graph.openStream();
}

void loop() {

  int uvLevel = averageAnalogRead(UVOUT);
  int refLevel = averageAnalogRead(REF_3V3);
  float outputVoltage = 3.3 / refLevel * uvLevel;
  float uvIntensity = mapfloat(outputVoltage, 0.99, 2.9, 0.0, 15.0);

  Serial.print("MP8511 output: ");
  Serial.print(uvLevel);
  graph.plot(millis(), uvLevel, tokens[0]);

  Serial.print("MP8511 voltage: ");
  Serial.print(outputVoltage);
  graph.plot(millis(), outputVoltage, tokens[1]);

  Serial.print("UV Intensity (mW/cm^2): ");
  Serial.print(uvIntensity);
  graph.plot(millis(), uvIntensity, tokens[2]);

  delay(200);

}

//Takes an average of readings on a given pin
//Returns the average
int averageAnalogRead(int pinToRead)
{
  byte numberOfReadings = 8;
  unsigned int runningValue = 0;

  for(int x = 0 ; x < numberOfReadings ; x++)
    runningValue += analogRead(pinToRead);
  runningValue /= numberOfReadings;

  return(runningValue);
}

//The Arduino Map function but for floats
//From: http://forum.arduino.cc/index.php?topic=3922.0
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

otronics

cpp file:

Code: [Select]
#include "Arduino.h"
#include <WiFi.h>
#include "plotly_streaming_wifi.h"

plotly::plotly(char *username, char *api_key, char* stream_tokens[], char *filename, int nTraces)
  {
    log_level = 2;  // 0 = Debugging, 1 = Informational, 2 = Status, 3 = Errors, 4 = Quiet (// Serial Off)
    dry_run = false;
    username_ = username;
    api_key_ = api_key;
    stream_tokens_ = stream_tokens;
    filename_ = filename;
    nTraces_ = nTraces;
    maxpoints = 30;
    fibonacci_ = 1;
    world_readable = true;
    convertTimestamp = true;
    timezone = "America/Montreal";
    fileopt = "overwrite";
}

bool plotly::init(){
    //
    //  Validate a stream with a REST post to plotly
    //
    if(dry_run && log_level < 3){
        Serial.println(F("... This is a dry run, we are not connecting to plotly's servers..."));
    }
    else if(log_level < 3) {
        Serial.println(F("... Attempting to connect to plotly's REST servers"));
    }
    while ( !client.connect("plot.ly", 80) ) {
        if(log_level < 4){
            Serial.println(F("... Couldn\'t connect to plotly's REST servers... trying again!"));
        }
        fibonacci_ += fibonacci_;
        delay(min(fibonacci_, 60000));
    }
    fibonacci_ = 1;
    if(log_level < 3){} Serial.println(F("... Connected to plotly's REST servers"));
    if(log_level < 3){} Serial.println(F("... Sending HTTP Post to plotly"));
    print_(F("POST /clientresp HTTP/1.1\r\n"));
    print_(F("Host: plot.ly:80\r\n"));
    print_(F("User-Agent: Arduino/0.6.0\r\n"));

    print_(F("Content-Length: "));
    int contentLength = 126 + len_(username_) + len_(fileopt) + nTraces_*(87+len_(maxpoints)) + (nTraces_-1)*2 + len_(filename_);
    if(world_readable){
        contentLength += 4;
    } else{
        contentLength += 5;
    }
    print_(contentLength);
    // contentLength =
    //   44  // first part of querystring below
    // + len_(username)  // upper bound on username length
    // + 5   // &key=
    // + 10  // api_key length
    // + 7  // &args=[...
    // + nTraces*(87+len(maxpoints)) // len({\"y\": [], \"x\": [], \"type\": \"scatter\", \"stream\": {\"token\": \") + 10 + len(\", "maxpoints": )+len(maxpoints)+len(}})
    // + (nTraces-1)*2 // ", " in between trace objects
    // + 22  // ]&kwargs={\"fileopt\": \"
    // + len_(fileopt)
    // + 16  // \", \"filename\": \"
    // + len_(filename)
    // + 21 // ", "world_readable":
    // + 4 if world_readable, 5 otherwise
    // + 1   // closing }
    //------
    // 126 + len_(username) + len_(fileopt) + nTraces*(86+len(maxpoints)) + (nTraces-1)*2 + len_(filename)
    //
    // Terminate headers with new lines
    print_(F("\r\n\r\n"));

    // Start printing querystring body
    print_(F("version=2.3&origin=plot&platform=arduino&un="));
    print_(username_);
    print_(F("&key="));
    print_(api_key_);
    print_(F("&args=["));
    // print a trace for each token supplied
    for(int i=0; i<nTraces_; i++){
        print_(F("{\"y\": [], \"x\": [], \"type\": \"scatter\", \"stream\": {\"token\": \""));
        print_(stream_tokens_[i]);
        print_(F("\", \"maxpoints\": "));
        print_(maxpoints);
        print_(F("}}"));
        if(nTraces_ > 1 && i != nTraces_-1){
            print_(F(", "));
        }
    }
    print_(F("]&kwargs={\"fileopt\": \""));
    print_(fileopt);
    print_(F("\", \"filename\": \""));
    print_(filename_);
    print_(F("\", \"world_readable\": "));
    if(world_readable){
        print_("true");
    } else{
        print_("false");
    }
    print_(F("}"));
    // final newline to terminate the POST
    print_(F("\r\n"));

    //
    // Wait for a response
    // Parse the response for the "All Streams Go!" and proceed to streaming
    // if we find it
    //
    char allStreamsGo[] = "All Streams Go!";
    int asgCnt = 0; // asg stands for All Streams Go
    char url[] = "\"url\": \"http://plot.ly/~";
    char fid[4];
    int fidCnt = 0;
    int urlCnt = 0;
    int usernameCnt = 0;
    int urlLower = 0;
    int urlUpper = 0;
    bool proceed = false;
    bool fidMatched = false;

    if(log_level < 2){
        Serial.println(F("... Sent message, waiting for plotly's response..."));
    }
    if(!dry_run){
        char c;
        while(client.connected()){
            if(client.available()){
                c = client.read();

                if(log_level < 2) Serial.print(c);
                //
                // Attempt to read the "All streams go" msg if it exists
                // by comparing characters as they roll in
                //

                if(asgCnt == len_(allStreamsGo) && !proceed){
                    proceed = true;
                }
                else if(allStreamsGo[asgCnt]==c){
                    asgCnt += 1;
                } else if(asgCnt > 0){
                    // reset counter
                    asgCnt = 0;
                }

                //
                // Extract the last bit of the URL from the response
                // The url is in the form http://plot.ly/~USERNAME/FID
                // We'll character-count up through char url[] and through username_, then start
                // filling in characters into fid
                //

                if(log_level < 3){
                    if(url[urlCnt]==c && urlCnt < len_(url)){
                        urlCnt += 1;
                    } else if(urlCnt > 0 && urlCnt < len_(url)){
                        // Reset counter
                        urlCnt = 0;
                    }
                    if(urlCnt == len_(url) && fidCnt < 4 && !fidMatched){
                        // We've counted through the url, start counting through the username
                        if(usernameCnt < len_(username_)+2){
                            usernameCnt += 1;
                        } else {
                            // the url ends with "
                            if(c != '"'){
                                fid[fidCnt] = c;
                                fidCnt += 1;
                            } else if(fidCnt>0){
                                fidMatched = true;
                            }
                        }
                    }
                }
            }
        }
        client.stop();
    }
    if(!dry_run && !proceed && log_level < 4){
        Serial.println(F("... Error initializing stream, aborting. Try again or get in touch with Chris at chris@plot.ly"));
    }

    if(!dry_run && proceed && log_level < 3){
        Serial.println(F("... A-ok from plotly, All Streams Go!"));
        if(fidMatched){
            Serial.print(F("... View your streaming plot here: https://plot.ly/~"));
            Serial.print(username_);
            Serial.print(F("/"));
            for(int i=0; i<fidCnt; i++){
                Serial.print(fid[i]);
            }
            Serial.println(F(""));
        }
    }
    return proceed;

}
void plotly::openStream() {
    //
    // Start request to stream servers
    //
    if(log_level < 3){} Serial.println(F("... Connecting to plotly's streaming servers..."));
    char server[] = "arduino.plot.ly";
    int port = 80;
    while ( !client.connect(server, port) ) {
        if(log_level < 4) Serial.println(F("... Couldn\'t connect to servers... trying again!"));
        fibonacci_ += fibonacci_;
        delay(min(fibonacci_, 60000));
    }
    fibonacci_ = 1;
    if(log_level < 3){} Serial.println(F("... Connected to plotly's streaming servers\n... Initializing stream"));

    print_(F("POST / HTTP/1.1\r\n"));
    print_(F("Host: arduino.plot.ly\r\n"));
    print_(F("User-Agent: Arduino\r\n"));
    print_(F("Transfer-Encoding: chunked\r\n"));
    print_(F("Connection: close\r\n"));
    if(convertTimestamp){
        print_(F("plotly-convertTimestamp: \""));
        print_(timezone);
        print_(F("\"\r\n"));
    }
    print_(F("\r\n"));

    if(log_level < 3){} Serial.println(F("... Done initializing, ready to stream!"));
}

void plotly::closeStream(){
    print_(F("0\r\n\r\n"));
    client.stop();
}
void plotly::reconnectStream(){
    while(!client.connected()){
        if(log_level<4) Serial.println(F("... Disconnected from streaming servers"));

otronics

cpp continued:

Code: [Select]
closeStream();
        openStream();
    }
}
void plotly::jsonStart(int i){
    // Print the length of the message in hex:
    // 15 char for the json that wraps the data: {"x": , "y": }\n
    // + 23 char for the token: , "token": "abcdefghij"
    // = 38
    if(log_level<2) Serial.print(i+44, HEX);
    if(!dry_run) client.print(i+44, HEX);
    print_("\r\n{\"x\": ");
}
void plotly::jsonMiddle(){
    print_(", \"y\": ");
}
void plotly::jsonEnd(char *token){
    print_(", \"streamtoken\": \"");
    print_(token);
    print_("\"}\n\r\n");
}

int plotly::len_(int i){
    // int range: -32,768 to 32,767
    if(i > 9999) return 5;
    else if(i > 999) return 4;
    else if(i > 99) return 3;
    else if(i > 9) return 2;
    else if(i > -1) return 1;
    else if(i > -10) return 2;
    else if(i > -100) return 3;
    else if(i > -1000) return 4;
    else if(i > -10000) return 5;
    else return 6;
}
int plotly::len_(unsigned long i){
    // max length of unsigned long: 4294967295
    if(i > 999999999) return 10;
    else if(i > 99999999) return 9;
    else if(i > 9999999) return 8;
    else if(i > 999999) return 7;
    else if(i > 99999) return 6;
    else if(i > 9999) return 5;
    else if(i > 999) return 4;
    else if(i > 99) return 3;
    else if(i > 9) return 2;
    else return 1;
}
int plotly::len_(char *i){
    return strlen(i);
}
void plotly::plot(unsigned long x, int y, char *token){
    reconnectStream();
    jsonStart(len_(x)+len_(y));
    print_(x);
    jsonMiddle();
    print_(y);
    jsonEnd(token);
}
void plotly::plot(unsigned long x, float y, char *token){
    reconnectStream();

    char s_[15];
    dtostrf(y,2,3,s_);

    jsonStart(len_(x)+len_(s_)-1);
    print_(x);
    jsonMiddle();
    print_(y);
    jsonEnd(token);
}
void plotly::print_(int d){
    if(log_level < 2) Serial.print(d);
    if(!dry_run) client.print(d);
}
void plotly::print_(unsigned long d){
    if(log_level < 2) Serial.print(d);
    if(!dry_run) client.print(d);
}
void plotly::print_(float d){
    if(log_level < 2) Serial.print(d);
    if(!dry_run) client.print(d);
}
void plotly::print_(char *d){
    if(log_level < 2) Serial.print(d);
    if(!dry_run) client.print(d);
}
void plotly::print_(const __FlashStringHelper* d){
    if(log_level < 2) Serial.print(d);
    if(!dry_run) client.print(d);
}

PaulRB

I don't have one of your UV sensors available (the only one is installed in my outdoor weather station. I have a few other i2c sensors I can use to test, but then the code will not be 100% the same. Will try to see if it works for me this evening or weekend, on a Wemos Mini

otronics

PS/ .h file:

Code: [Select]
#ifndef plotly_streaming_wifi_h
#define plotly_streaming_wifi_h

#include "Arduino.h"

#include <WiFi.h>

class plotly
{
    public:
        plotly(char *username, char *api_key, char* stream_tokens[], char *filename, int nTraces);
        WiFiClient client;
        bool init();
        void openStream();
        void closeStream();
        void reconnectStream();
        void jsonStart(int i);
        void jsonMiddle();
        void jsonEnd(char *token);

        void plot(unsigned long x, int y, char *token);
        void plot(unsigned long x, float y, char *token);

        int log_level;
        bool dry_run;
        int maxpoints;
        bool world_readable;
        bool convertTimestamp;
        char *timezone;
        char *fileopt;

    private:
        void print_(int d);
        void print_(unsigned long d);
        void print_(float d);
        void print_(char *d);
        void print_(const __FlashStringHelper* d);

        int len_(int i);
        int len_(unsigned long i);
        int len_(char *i);

        unsigned long fibonacci_;
        char *username_;
        char *api_key_;
        char** stream_tokens_;
        char *filename_;
        int nTraces_;

};
#endif

otronics

I don't have one of your UV sensors available (the only one is installed in my outdoor weather station. I have a few other i2c sensors I can use to test, but then the code will not be 100% the same. Will try to see if it works for me this evening or weekend, on a Wemos Mini
Thank you.

Yes - I've not got to the testing of the UV sensor yet.

I'll worry about that when I've got that far!

PaulRB

I may have got you a bit further:
Code: [Select]
�... Attempting to connect to WPA network...
..... Connected to network
... Attempting to connect to plotly's REST servers
... Connected to plotly's REST servers
... Sending HTTP Post to plotly
... Error initializing stream, aborting. Try again or get in touch with Chris at chris@plot.ly

Soft WDT reset

ctx: cont
sp: 3ffef430 end: 3ffef610 offset: 01b0

>>>stack>>>
3ffef5e0:  3fffdad0 00000000 3ffee484 40201f96  
3ffef5f0:  feefeffe feefeffe 3ffee5e0 40203cb8  
3ffef600:  feefeffe feefeffe 3ffee5f0 40100718  
<<<stack<<<

 ets Jan  8 2013,rst cause:2, boot mode:(1,6)


 ets Jan  8 2013,rst cause:4, boot mode:(1,6)

wdt reset



I don't have a plotly account, so not surprising that this was as far as I got.

Updated files attached. You were #include-ing the wrong libraries for ESP8266. Also there was a missing macro for min(x,y) which I added by guessing the correct definition (I hope).

otronics

After some tweaking by putting the logging into debug mode, it connects.

It sends some 'data' (not actually working) but outputs this error:

"warning": "token not in streamObj or len(token) != 10"

You can see where the data is supposed to be here:

https://plot.ly/~otronics/1/#/plot

It connects once, and then outputs a constant 'Cannot connect to Plotly's servers thereafter'

Re/ the lack of data - I think we need to go back to basics.

To this end, I have now uploaded this code to my board to test the UV sensor.

Code: [Select]
int UVOUT = A0; //Output from the sensor
const byte REF_3V3 = A0; //3.3V power on the Arduino board

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

  pinMode(UVOUT, INPUT);
  pinMode(REF_3V3, INPUT);

  Serial.println("MP8511 example");
}

void loop()
{
  int uvLevel = averageAnalogRead(UVOUT);
  int refLevel = averageAnalogRead(REF_3V3);
 
  //Use the 3.3V power pin as a reference to get a very accurate output value from sensor
  float outputVoltage = 3.3 / refLevel * uvLevel;
 
  float uvIntensity = mapfloat(outputVoltage, 0.99, 2.9, 0.0, 15.0);

  Serial.print("MP8511 output: ");
  Serial.print(uvLevel);

  Serial.print(" MP8511 voltage: ");
  Serial.print(outputVoltage);

  Serial.print(" UV Intensity (mW/cm^2): ");
  Serial.print(uvIntensity);
 
  Serial.println();
 
  delay(100);
}

//Takes an average of readings on a given pin
//Returns the average
int averageAnalogRead(int pinToRead)
{
  byte numberOfReadings = 8;
  unsigned int runningValue = 0;

  for(int x = 0 ; x < numberOfReadings ; x++)
    runningValue += analogRead(pinToRead);
  runningValue /= numberOfReadings;

  return(runningValue); 
}

//The Arduino Map function but for floats
//From: http://forum.arduino.cc/index.php?topic=3922.0
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}


It partially works.

Using the Serial Monitor it outputs this data:

Code: [Select]
MP8511 output: 310 MP8511 voltage: 3.30 UV Intensity (mW/cm^2): 18.14
MP8511 output: 310 MP8511 voltage: 3.30 UV Intensity (mW/cm^2): 18.14
MP8511 output: 310 MP8511 voltage: 3.30 UV Intensity (mW/cm^2): 18.14
MP8511 output: 310 MP8511 voltage: 3.30 UV Intensity (mW/cm^2): 18.14
MP8511 output: 310 MP8511 voltage: 3.30 UV Intensity (mW/cm^2): 18.14
MP8511 output: 310 MP8511 voltage: 3.30 UV Intensity (mW/cm^2): 18.14


No matter where I move the sensor (dark or sun), the readings are the same.

I have it connected as follows (although it's not an Arduino of course but an ESP8266).



Any ideas why I am getting the same readings?

PaulRB

Because of this:
Code: [Select]

int UVOUT = A0; //Output from the sensor
const byte REF_3V3 = A0; //3.3V power on the Arduino board

then later
Code: [Select]

int uvLevel = averageAnalogRead(UVOUT);
int refLevel = averageAnalogRead(REF_3V3);

float outputVoltage = 3.3 / refLevel * uvLevel;

As both refLevel and uvLevel are the same value (with maybe a little analog noise, most of which is smoothed out by averaging) outputVoltage is always 3.3. Basic maths.

I think you need to go back to the example circuits & code for the sensor. You have gone off in a strange direction.

otronics

Because of this:
Code: [Select]

int UVOUT = A0; //Output from the sensor
const byte REF_3V3 = A0; //3.3V power on the Arduino board

then later
Code: [Select]

int uvLevel = averageAnalogRead(UVOUT);
int refLevel = averageAnalogRead(REF_3V3);

float outputVoltage = 3.3 / refLevel * uvLevel;

As both refLevel and uvLevel are the same value (with maybe a little analog noise, most of which is smoothed out by averaging) outputVoltage is always 3.3. Basic maths.

I think you need to go back to the example circuits & code for the sensor. You have gone off in a strange direction.
This:

Code: [Select]

int UVOUT = A0; //Output from the sensor
const byte REF_3V3 = A0; //3.3V power on the Arduino board


Is the same code copied from the Plotly code.

As this wasn't giving me any readings, I thought it was best to go back to basics to test the UV sensor actually works.

How would I connect it up/code it using the basic script above? I don't suppose I am far off what I have done already...

Once I am satisfied the UV sensor works, I can go back to fixing the Plotly code.

Go Up