Jump to content

stargazine_ep39_banner.thumb.jpg.b87bddaa2aded94d2a3456c0589a82b9.jpg

Weather Station Ideas


Recommended Posts

6 minutes ago, Gina said:

Converting the ADC values to logic is easy


// Gray code logic levels
bool dirBit1 = false;
bool dirBit2 = false;
bool dirBit3 = false;
bool dirBit4 = false;

And in the loop;


    // Convert to logic levels
    dirBit1 = (dir1 > 2000);
    dirBit2 = (dir2 > 2000);
    dirBit3 = (dir3 > 2000);
    dirBit4 = (dir4 > 2000);

Next I need to convert the Gray code to binary.  I've found complicated looking code in a Google search but I think there should be something simpler.

A look up table perhaps? That seems easiest

  • Thanks 1
Link to post
Share on other sites
  • Replies 709
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

If I did that I'd still only have a few hundred posts James

Now two of us have said it, so it must be true James

Posted Images

Thinking...

Gray code to binary :-

  1. 0000  0    0
  2. 0001  1    1
  3. 0011  3    2
  4. 0010  2    3
  5. 0110  6    4
  6. 0111  7    5
  7. 0101  5    6
  8. 0100  4    7
  9. 1100 12   8
  10. 1101 13   9
  11. 1111 15  10
  12. 1110 14  11
  13. 1010 10  12
  14. 1011 11  13
  15. 1001   9  14
  16. 1000   8  15

int codeArray[16] = {0,1,3,2,7,6,4,5,15,14,12,13,8,9,11,10};

Edited by Gina
Link to post
Share on other sites

Found this code but I think I would prefer to use code I fully understand!  This still needs the bits converted to integer. 

1610256707_Screenshotfrom2020-08-2513-06-26.png.3cc16027ef55b64fe4ebc39b31bf922d.png

Edited by Gina
Link to post
Share on other sites
6 minutes ago, Gina said:

Found this code but I think I would prefer to use code I fully understand!  This still needs the bits converted to integer. 

I think it says "England expects that every man will do his duty" 

....or perhaps "Woman"

 

🙂

 

Link to post
Share on other sites
31 minutes ago, JeremyS said:

I think it says "England expects that every man will do his duty" 

....or perhaps "Woman"

 

🙂

 

Thanks for flagging that up Nelson.  Which eye do you use when observing. I see no clouds.

Regards Andrew 

  • Haha 1
Link to post
Share on other sites
1 minute ago, andrew s said:

Thanks for flagging that up Nelson.  Which eye do you use when observing. I see no clouds.

Regards Andrew 

I thought it was all pretty 'armless, Andrew

  • Haha 1
Link to post
Share on other sites

Now added Gray to binary conversion.

// ADC pins
const int An1 = 34;
const int An2 = 35;
const int An3 = 32;
const int An4 = 33;
// ADC readings
int dir1 = 0;
int dir2 = 0;
int dir3 = 0;
int dir4 = 0;
// Gray code logic levels
bool dirBit1 = false;
bool dirBit2 = false;
bool dirBit3 = false;
bool dirBit4 = false;
// Gray to binary table
int codeArray[16] = {0,1,3,2,7,6,4,5,15,14,12,13,8,9,11,10};
int dirn = 0;
    // Convert to logic levels
    dirBit1 = (dir1 > 2000);
    dirBit2 = (dir2 > 2000);
    dirBit3 = (dir3 > 2000);
    dirBit4 = (dir4 > 2000);

    // Convert bits to integer
    int Gray = 0;
    if (dir1 > 2000) {Gray = 8;};
    if (dir2 > 2000) {Gray = Gray + 4;};
    if (dir3 > 2000) {Gray = Gray + 2;};
    if (dir4 > 2000) {Gray = Gray + 1;};

    //  Convert Gray to binary
    dirn = codeArray[16];

The dirBitx set isn't needed with this shortcut.

Link to post
Share on other sites

Here is the full sketch for the wind sensors so far.  This will read the rotary encoder on the vane and count revolution of the anemometer and send the instantaneous wind direction and wind speed to the MQTT network.

// MQTT for wind sensors

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
********
Modified and added to by Gina 2020-08-21 onward
********
*/

const int Interval = 4500;  //  Set sampling interval in milliseconds
// ADC pins
const int An1 = 34;
const int An2 = 35;
const int An3 = 32;
const int An4 = 33;
// ADC readings
int dir1 = 0;
int dir2 = 0;
int dir3 = 0;
int dir4 = 0;

// Gray to binary table
int codeArray[16] = {0,1,3,2,7,6,4,5,15,14,12,13,8,9,11,10};
int dirn = 0;

// Set GPIO for Hall Sensor
const int HallSensorPin = 4;
int PulseCount = 0;

#include <WiFi.h>
#include <PubSubClient.h>

// Replace the next variables with your SSID/Password combination
const char* ssid = "Ubiquity";
const char* password = "********";

const char* mqtt_server = "192.168.1.140";

WiFiClient windClient;
PubSubClient client(windClient);
long lastMsg = 0;
char msg[50];
int value = 0;

// Checks if Hall sensor was triggered
void IRAM_ATTR HallTriggered() {
//  Serial.println("Hall Triggered");
  ++PulseCount; // Increment count
}

int Beaufort(int mph){
  if (mph < 1) return 0;
  else if (mph <= 3) return 1;
  else if (mph <= 7) return 2;
  else if (mph <= 12) return 3;
  else if (mph <= 18) return 4;
  else if (mph <= 24) return 5;
  else if (mph <= 31) return 6;
  else if (mph <= 38) return 7;
  else if (mph <= 46) return 8;
  else if (mph <= 54) return 9;
  else if (mph <= 63) return 10;
  else if (mph <= 72) return 11;
  else return 12;
}

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  
  // Hall Sensor mode INPUT_PULLUP
  pinMode(HallSensorPin, INPUT_PULLUP);
  // Set HallSensor pin as interrupt, assign interrupt function and set FALLING mode
  attachInterrupt(digitalPinToInterrupt(HallSensorPin), HallTriggered, FALLING);
}

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* message, unsigned int length) {
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
  String messageTemp;
  
  for (int i = 0; i < length; i++) {
    Serial.print((char)message[i]);
    messageTemp += (char)message[i];
  }
  Serial.println();

  // Feel free to add more if statements to control more GPIOs with MQTT

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("windClient")) {
      Serial.println("connected");
      // Subscribe
//      client.subscribe("esp32/output");
//      client.subscribe("esp32/roof");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  long now = millis();
  if(now - lastMsg > Interval) {
//    Serial.println("PulseCount :- ");
    lastMsg = now;
    
    // Convert the value to a char array
    char countString[8];
    dtostrf(PulseCount, 1, 0, countString);
    Serial.print("mph: ");
    Serial.println(countString);
    client.publish("wind/speed/mph", countString);

    // Get Beaufort value
    // Convert the value to a char array
    char BeaufortString[8];
    dtostrf(Beaufort(PulseCount), 1, 0, BeaufortString);
    Serial.print("Force: ");
    Serial.println(BeaufortString);
    client.publish("wind/speed/force", BeaufortString);
    PulseCount = 0;
    
    // Read wind vane optical sensor values
    dir1 = analogRead(An1);
    dir2 = analogRead(An2);
    dir3 = analogRead(An3);
    dir4 = analogRead(An4);
/*    Serial.print(dir1);
    Serial.print("  ");
    Serial.print(dir2);
    Serial.print("  ");
    Serial.print(dir3);
    Serial.print("  ");
    Serial.print(dir4);
    Serial.println("  ");*/

    // Convert Gray bits to integer
    int Gray = 0;
    if (dir1 > 2000) {Gray = 8;};
    if (dir2 > 2000) {Gray = Gray + 4;};
    if (dir3 > 2000) {Gray = Gray + 2;};
    if (dir4 > 2000) {Gray = Gray + 1;};

    //  Convert Gray to binary
    dirn = 15 - codeArray[Gray];
    // Convert the value to a char array
    char dirString[8];
    dtostrf(dirn, 1, 0, dirString);
    Serial.print("Direction: ");
    Serial.println(dirString);
    client.publish("wind/direction", dirString);
  
  }
}

 

Edited by Gina
Errors corrected
Link to post
Share on other sites

Sent the Gray code as well and that's working so it's in the Gray code to direction in binary that's wrong.

Edit - found my error!  Working now.  16 discrete directions in sequence.  Only thing is, it's going anti-clockwise instead of clockwise as seen from above.  I can fix that easily enough.  Now edited the sketch above.

Direction fixed and all working fine (as far as it goes).  This is just the instantaneous value and wants smoothing which I'll add next.

This screenshot of MQTT Explorer shows the vane direction as I turned it (turned it a bit too far in the middle).

434011851_Screenshotfrom2020-08-2516-17-23.png.808f1085a44d3fa61baed3507c233d72.png

 

Edited by Gina
Link to post
Share on other sites

The next stage in the wind sensors is mathematical.  Rather than just the instantaneous direction and the wind speed taken over a few seconds, I want Mean and Gust wind speed and an average direction rather the a direction that varies all over the place with turbulence.

The wind speed is straightforward.  The highest rev count in an extended time is taken as the gust speed and the average in that period is the Mean.  With the period being 10m and wanting readings more often than this I think I shall use a running average and maximum.

For the wind direction there is a procedure called Consensus Averaging that collects a number of values in "bins" and then an average of the bins with the highest number of counts is taken.  This uses an array of 20 integers where the direction counts are collected.

Link to post
Share on other sites

I think the easiest way of making a running average and maximum is to push them down a queue.

A10 = A9
A9 = A8
A8 = A7
etc.

This can be simplified using an array and decreasing index.  The average and maximum can also be derived from the array.

Link to post
Share on other sites

I'd probably use an array as a ring buffer and keep track of the next insertion point using an index pointer and modulo arithmetic.  If you keep track of the sum of all the values in the array you can avoid having to completely recalculate the average by subtracting the value at the position you're about to insert at from the existing sum, adding the new value and then dividing the sum by the number of values to get the average.

I think the consensus averaging can be done using an array as a ring buffer too, rather than duplicating values at positions 0 through 3 to 16 through 19, but I've not thought about that in any great detail.

James

  • Thanks 1
Link to post
Share on other sites

Yes, I thought of doing that myself but not sure how easy it would be.  I hadn't thought of subtracting the oldest value from the sum and adding the newest though.

A ring buffer for the consensus averaging was something I hadn't thought of but it makes a lot of sense as the direction is a ring.

Link to post
Share on other sites

I need to consider my various periods.

Quote

The gust speed and direction are defined by the maximum three second average wind speed occurring in any period…overall wind intensity is defined by the average speed and direction over the ten-minute period leading up to the reporting time. Mean wind over other averaging periods may also be calculated.” Met Office

ATM I'm using a 4.5s counting period for the anemometer speed count which would be good enough as the gust period since I'm not producing weather reports for publication.  I think a one minute reporting period would suffice for wind speed.  With a 10m period being standard for mean wind speed I could use a 10 integer ring buffer.

With an integral number of 4.5s periods not fitting into a minute I think the irregular sampling could be a problem plus I would like to abide by the standard for gusts so I'm having second thoughts about the 4.5s counting period.  I could use a 3s period and adjust the result by multiplying by 1.5.  Only the very low speeds would be affected and accurate low wind speeds are not relevant.  This would mean 20 counting periods to one reporting period and 10 reporting periods for the period over which the mean and gust wind speed would be calculated.

Link to post
Share on other sites

There are 3 periods or intervals.  A 3s period used to count anemometer revolutions and to read the instantaneous wind direction then a 60s period used as the reporting (message sending) period and finally a 10m period for the mean direction.

Link to post
Share on other sites

Example of modulus %

/* update one value in an array each time through a loop */

int values[10];
int i = 0;

void setup() {}

void loop()
{
  values[i] = analogRead(0);
  i = (i + 1) % 10;   // modulo operator rolls over variable  
}

 

Link to post
Share on other sites

I think I may use different periods for the wind speed and direction.  Although easier to have the same it isn't necessary and the ideal periods work out differently.

I reckon ring arrays will work for both speed and direction and seems to me a better approach to consensus averaging for the direction.

Link to post
Share on other sites

I was going to add the data from the rain gauge into the wind sensor unit with the gauge mounted on the same mast but now I'm having second thoughts and thinking it would be better fed to the ROR control unit as a second source for closing the roof, in addition to the rainfall information for the weather station - a "belt and braces" approach.

I'm also thinking of adding a sky temperature sensor into the weather data somewhere and guess the ROR control unit would make sense for that too.

Link to post
Share on other sites
3 hours ago, Gina said:

I was going to add the data from the rain gauge into the wind sensor unit with the gauge mounted on the same mast but now I'm having second thoughts and thinking it would be better fed to the ROR control unit as a second source for closing the roof, in addition to the rainfall information for the weather station - a "belt and braces" approach.

I'm also thinking of adding a sky temperature sensor into the weather data somewhere and guess the ROR control unit would make sense for that too.

How sensitive will be 1 tip bucket of water relative to how quick do you need to get the roof closed due to rain? Not sure I'd trust my rain gauge for that - I'd probably want a capacitance / resistance style rain detector for the RoR ?

Link to post
Share on other sites

I'd definitely rely on an electronic rain sensor.  Fine drizzle takes ages to tip a bucket on my rain gauge (which I think is 100 tips per inch of rainfall), but would get kit far wetter than I would like.

James

Link to post
Share on other sites

I certainly wouldn't rely on a rain gauge to close the ROR - it would only be a backup if everything else failed.  I'd rather have two different forms of rain detector though.  I've asked for suggestions in the past but got no replies.

Edited by Gina
Link to post
Share on other sites
2 hours ago, Gina said:

I certainly wouldn't rely on a rain gauge to close the ROR - it would only be a backup if everything else failed.  I'd rather have two different forms of rain detector though.  I've asked for suggestions in the past but got no replies.

https://www.weatherstations.co.uk/hydreon.htm

Perhaps? It certainly looks futuristic.

  • Thanks 1
Link to post
Share on other sites

Ah yes,  That's one I've read about before but couldn't remember what it was called.  I've posted in the DIY Observatories forum to see if others have used it and any experiences though I'm not sure this is the best place.

Edited by Gina
Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. By using this site, you agree to our Terms of Use.