Go Down

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

otronics

Here is a screenshot of my MySQL database.

I'm not sure the UV row is set-up correctly or even in the correct place:


PaulRB


You have added an extra column to the sensor_info table, so delete that. All you needed to do was add (insert) a row of data as I explained in an earlier post.

otronics


You have added an extra column to the sensor_info table, so delete that. All you needed to do was add (insert) a row of data as I explained in an earlier post.
Ah sorry I misunderstood.

All corrected and everything now talks to each other.

I need a bit more understanding on how often data uploads.

Are you saying your UV data uploads every x minutes but requires a resistor for it to work?

What I would like is for my data to (let's say) upload every 5 minutes.

If the current code does require a resistor to work, how would I code it to run without one?

PaulRB

To change the update period, you just need to change the time the esp spends in deep sleep. You found that line in the code before. There was a symbol used in that line which was multiplied by 1000, remember? You just need to change the symbol definition, which is at the top of the code. Its name tells you it's purpose:
Code: [Select]

#define SERVER_UPDATE_PERIOD 900000UL

900000 is 15 minutes in milliseconds.

With the esp chip, for some strange reason, you need to connect one of the digital pins to the reset pin to get the chip to wake from deep sleep. Its just the way they designed the chip. When the sleep timer circuit in the chip reaches zero, the digital pin briefly changes from high to low. If this is externaly connected to the reset pin, the chip gets reset and wakes up.

If you use a piece of wire between the digital pin and the reset pin, it will work and wake up at the end of the sleep time. But what you find is that there is an unwanted side effect to using a piece of wire. While in deep sleep, the chip will not respond when you hit "upload sketch" from the IDE. Normally, that also causes the chip to reset, but it can't because the reset-on-upload circuit on the Wemos can't overcome the digital pin that is pulling the reset line high. The digital pin is a stronger pull-up than the reset-on-upload circuit can pull it down. The way I fixed this was to connect the digital pin to the reset pin with a resistor, weakening it's ability to act as a pull-up somewhat and allowing the reset-on-upload circuit to work. 510R does the job well. I have seen others use a diode instead of the resistor.

I don't know why you don't want to use this resistor. The resistor would not be needed if you did not want to make use of the deep sleep feature. You could use delay() instead of deepSleep(). But the current drawn during the delay would be thousands of times higher than during deepSleep(), which is no good for battery operation.

otronics

To change the update period, you just need to change the time the esp spends in deep sleep. You found that line in the code before. There was a symbol used in that line which was multiplied by 1000, remember? You just need to change the symbol definition, which is at the top of the code. Its name tells you it's purpose:
Code: [Select]

#define SERVER_UPDATE_PERIOD 900000UL

900000 is 15 minutes in milliseconds.

With the esp chip, for some strange reason, you need to connect one of the digital pins to the reset pin to get the chip to wake from deep sleep. Its just the way they designed the chip. When the sleep timer circuit in the chip reaches zero, the digital pin briefly changes from high to low. If this is externaly connected to the reset pin, the chip gets reset and wakes up.

If you use a piece of wire between the digital pin and the reset pin, it will work and wake up at the end of the sleep time. But what you find is that there is an unwanted side effect to using a piece of wire. While in deep sleep, the chip will not respond when you hit "upload sketch" from the IDE. Normally, that also causes the chip to reset, but it can't because the reset-on-upload circuit on the Wemos can't overcome the digital pin that is pulling the reset line high. The digital pin is a stronger pull-up than the reset-on-upload circuit can pull it down. The way I fixed this was to connect the digital pin to the reset pin with a resistor, weakening it's ability to act as a pull-up somewhat and allowing the reset-on-upload circuit to work. 510R does the job well. I have seen others use a diode instead of the resistor.

I don't know why you don't want to use this resistor. The resistor would not be needed if you did not want to make use of the deep sleep feature. You could use delay() instead of deepSleep(). But the current drawn during the delay would be thousands of times higher than during deepSleep(), which is no good for battery operation.
Thanks for the explanation.

The board is powered by DC so no need to worry about battery life.

I will try the delay() feature soon as that is what I am after.

PaulRB

the delay() feature ... is what I am after.
Why?

P.S. please don't quote entire posts when you reply. It just makes the thread longer and doesn't add anything. If you want to question or comment on specific things, just quote those parts, like I just did. If you don't need to quote anything, you can hit Reply instead of Quote.

otronics


PaulRB

...problem of having to use a resistor
Sorry, I still don't get it. It sounds like you are saying that having to use a resistor is a problem. Resistors are tiny, cheap, the most basic component in electronics...

Anyway, it is all working now, graphs etc? Can you post pics? You are the first person I know to try to replicate my system, so it would be good to see it working.

otronics

Sorry, I still don't get it. It sounds like you are saying that having to use a resistor is a problem. Resistors are tiny, cheap, the most basic component in electronics...
Indeed, but one less thing to worry about when code can do the trick (which it now does).

Quote
Anyway, it is all working now, graphs etc? Can you post pics? You are the first person I know to try to replicate my system, so it would be good to see it working.
I want to test it for a couple of weeks first, then mount it outside.

Before I do, I have two last things that need attention:

* I don't think my UV sensor is coded correctly.

No matter how much light there is, the sensor_value reading is always 303 or 302.

Latest code is below.

Any ideas?

* What would be great is for the onboard LED to flash every time the code runs (in my case every 1 minute).

I see there is some LED code already in the script but I can't seem to get the LED to flash on each loop.

How would I do this?

Once these are sorted, I am pretty much done aside from testing.

Code: [Select]
extern "C" {
#include "user_interface.h"
}

#include <ESP8266WiFi.h>
#include <Wire.h>
#include <SoftwareSerial.h>

#define SLAVE_RX D3
#define SLAVE_TX D4

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

// Use WiFiClient class to create TCP connections
WiFiClient wsClient;

// Serial connection with slave MCU
SoftwareSerial slaveMCU(SLAVE_RX, SLAVE_TX, false, 64);

const char ssid[]     = "";
const char password[] = "";
const char host[]     =  "217.199.187.197";

IPAddress ip(192,168,0,44);
IPAddress gateway(192,168,0,1);
IPAddress subnet(255,255,255,0);

const double e = 2.71828;

int readSerialWord() {
 
  byte h = slaveMCU.read();
  byte l = slaveMCU.read();
  return word(h, l);
 
}

void setup() {

  Serial.begin(115200);

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

  Serial.println("MP8511 example");
 
}

void loop() {

  Serial.println();
  Serial.println("Calculating Sensor Values");

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

  Serial.println();
  Serial.print("Connecting to WiFi");

  unsigned long startTime = millis();
  WiFi.begin(ssid, password);
  WiFi.config(ip, gateway, subnet);
  WiFi.mode(WIFI_STA); // Station Mode
  WiFi.hostname("Weather Station");

  while (WiFi.status() != WL_CONNECTED && millis() - startTime < 30000UL) {
    delay(100);
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    Serial.print(".");
  }

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println();
    Serial.println("WiFi connection failed");
    digitalWrite(LED_BUILTIN, LOW);
  }
  else {
    digitalWrite(LED_BUILTIN, HIGH);

    Serial.println();
    Serial.print("WiFi connected, SSID: ");
    Serial.print(WiFi.SSID());
    Serial.print(" signal: ");
    Serial.print(WiFi.RSSI());
    Serial.print(" IP address: ");
    Serial.println(WiFi.localIP());

    Serial.println();
    Serial.print("connecting to ");
    Serial.println(host);

    const int httpPort = 80;
    if (!wsClient.connect(host, httpPort)) {
      Serial.println("Host connection failed");
    }
    else {

      String sensors, values;

        if (uvLevel >= 0 && uvLevel <= 65000) {
        sensors += "UV";
        values += uvLevel;
      }

      // We now create a URL for the request
      String url = "/otronics.co.uk/Weather/UV/script.php";
      url += "?sensor=";
      url += sensors;
      url += "&value=";
      url += values;

      Serial.print("Requesting URL: ");
      Serial.println(url);

      // This will send the request to the server
      wsClient.print(String("GET ") + url + " HTTP/1.1\r\n" +
                     "Host: " + host + "\r\n" +
                     "Connection: close\r\n\r\n");

      while (!wsClient.available()) {
        if (millis() - startTime > 30000UL) {
          Serial.println("request failed");
          break;
        }
        delay(1000);
      }

      Serial.println("Response from server:");
      Serial.println("----------------------------------------");
      // Read all the lines of the reply from server and print them to Serial
      while (wsClient.available()) {
        String line = wsClient.readStringUntil('\r');
        Serial.print(line);
      }

      Serial.println();
      Serial.println("----------------------------------------");
      Serial.print("Time taken: ");
      Serial.println( millis() - startTime);

    }
    Serial.println("Disconnecting Wifi");
    WiFi.disconnect();
  }

  Serial.println("Sleeping...!");
  delay(60000);

}

//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;
}

PaulRB

Connect your multimeter to the output signal of the sensor. Do you see the reading change with light levels? Don't forget there is not much UV light from domestic lighting, you need sunlight.

If you see differences, what range of values?

Put some extra Serial.println() statements to print out the values calculated for uvLevel, outputVoltage and uvIntensity.

I also notice that you calculate outputVoltage from uvLevel, then you calculate uvIntensity from outputVoltage, but then nothing is done with uvIntensity. What gets sent to the server is uvLevel.

otronics

I will give the multimeter a go soon.

What I did try last night is the other UV project code that simply displays the UV level on my laptop.

I shone a torch on the UV sensor (not ideal I know but it works) and the values changed from 0 to 0.50 so the UV sensor does indeed work.

So yes, there is a code problem somewhere in this project.

otronics

Re/ * What would be great is for the onboard LED to flash every time the code runs (in my case every 1 minute).

I have now coded the LED to flash when I desire it.

So, the very last thing code-wise is the UV sensor - I've not had any more of a look at that yet.

I have purchased a project box - Paul, do you have any problem with condensation with your sensor in the project box?

PaulRB

Can't say I've noticed any condensation. The box is almost sealed. There's a tight gap around the cable going in (I didn't use any kind of gromit).

What box have you chosen? I need a replacement, ideally something with a domed glass cover.

This is the current box. As I said way back at the start of this thread, the screws have corroded and the clear cover has gone milky.

otronics

That is pretty much the same box as mine.

After a quick search, I can't find any project boxes with a glass case. Not to say there isn't one.

Could always do the old trick of getting an outside light, strip it out, and install it at an angle facing the sun (although it could be a slight eyesore).

Something like this:


otronics

#104
Jun 26, 2018, 02:27 am Last Edit: Jun 26, 2018, 11:12 pm by otronics
OK, back to coding.

So, I guess I need uvIntensity to be sent to the server rather than uvLevel?

If so, how would I do this?

I have done more tweaking of the code and added those Serial.println() statements (they work fine).

Latest code:

Code: [Select]
extern "C" {
#include "user_interface.h"
}

#include <ESP8266WiFi.h>
#include <Wire.h>
#include <SoftwareSerial.h>

#define SLAVE_RX D3
#define SLAVE_TX D4

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

// Use WiFiClient class to create TCP connections
WiFiClient wsClient;

// Serial connection with slave MCU
SoftwareSerial slaveMCU(SLAVE_RX, SLAVE_TX, false, 64);

const char ssid[]     = "";
const char password[] = "";
const char host[]     =  "217.199.187.197";

IPAddress ip(192,168,0,45);
IPAddress gateway(192,168,0,1);
IPAddress subnet(255,255,255,0);

const double e = 2.71828;

int readSerialWord() {
 
  byte h = slaveMCU.read();
  byte l = slaveMCU.read();
  return word(h, l);
 
}

void setup() {

  Serial.begin(115200);

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

  pinMode(2, OUTPUT);
 
}

void loop() {

    digitalWrite(2, LOW);
    delay(500);
    digitalWrite(2, HIGH);
    delay(500);

  Serial.println();
  Serial.println("Calculating sensor values...");
  Serial.println();

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

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

  Serial.print(" | ML8511 voltage: ");
  Serial.print(outputVoltage);

  Serial.print(" | UV Intensity (mW/cm^2): ");
  Serial.print(uvIntensity);

  Serial.println();

  Serial.println();
  Serial.print("Connecting to WiFi");

  unsigned long startTime = millis();
  WiFi.begin(ssid, password);
  WiFi.config(ip, gateway, subnet);

  while (WiFi.status() != WL_CONNECTED && millis() - startTime < 30000UL) {
    delay(100);
    Serial.print(".");
  }

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println();
    Serial.println("WiFi connection failed");
  }
  else {
    digitalWrite(2, LOW);
    delay(100);
    digitalWrite(2, HIGH);
    delay(100);
    digitalWrite(2, LOW);
    delay(100);
    digitalWrite(2, HIGH);
    delay(100);

    Serial.println();
   
    Serial.println();
    Serial.print("WiFi connected. SSID: ");
    Serial.print(WiFi.SSID());
    Serial.print(" | Signal: ");
    Serial.print(WiFi.RSSI());
    Serial.print(" | IP address: ");
    Serial.println(WiFi.localIP());

    Serial.println();
    Serial.print("connecting to ");
    Serial.println(host);

    const int httpPort = 80;
    if (!wsClient.connect(host, httpPort)) {
      Serial.println("Host connection failed");
    }
    else {

      String sensors, values;

        if (uvLevel >= 0 && uvLevel <= 65000) {
        sensors += "UV";
        values += uvLevel;
      }

      // We now create a URL for the request
      String url = "/otronics.co.uk/Weather/UV/script.php";
      url += "?sensor=";
      url += sensors;
      url += "&value=";
      url += values;

      Serial.print("Requesting URL: ");
      Serial.println(url);

      // This will send the request to the server
      wsClient.print(String("GET ") + url + " HTTP/1.1\r\n" +
                     "Host: " + host + "\r\n" +
                     "Connection: close\r\n\r\n");

      while (!wsClient.available()) {
        if (millis() - startTime > 30000UL) {
          Serial.println("request failed");
          break;
        }
        delay(1000);
      }
      Serial.println();
      Serial.println("Response from server:");
      Serial.println("-----------------------------------------------------------------------");
      // Read all the lines of the reply from server and print them to Serial
      while (wsClient.available()) {
        String line = wsClient.readStringUntil('\r');
        Serial.print(line);
      }
     
      Serial.println("-----------------------------------------------------------------------");
      Serial.print("Time taken: ");
      Serial.println( millis() - startTime);

    }
    Serial.println("Disconnecting Wifi");
    WiFi.disconnect();
  }

  Serial.println("Sleeping...");
  delay(60000);

}

//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;
}

Go Up