Close

Successfully Uploaded the Test Code to Transmitter Board

A project log for Solar Powered WiFi Weather Station V4.0

An affordable Open Source Weather Station for Everyone

open-green-energyOpen Green Energy 09/20/2022 at 06:460 Comments

After assembling the transmitter PCB board, I connected my USB to the TTL UART programmer to the programming port. The connections are as follows:

Programmer -----> PCB

3V3 ----> 3V3

Tx----> Rx

Rx----> Tx

GND---> GND

After connecting the programmer to the PCB board, I successfully uploaded the test code. The board is working as expected but I have to press the EN switch to start the execution. This is required only once after uploading the code.

I have tested the following:

1. All the I2C ports are working

2. Wind and Rain Sensors Ports working

3.  DS18B20 port is working

4. Battery charging through solar panel and USB port is working

5. LoRa module is working as expected but needs an external antenna

6. Battery and Solar Panel Voltage monitoring working

Test Code is attached below:

//======================================================================================//
// //
// Solar WiFi Weather Station V4.0 Firmware //
// //
// Developed by Debasish Dutta, Last Update: 14.09.2022 //
// //
//======================================================================================//
#include <SPI.h>
#include <LoRa.h>
#include <BME280I2C.h>
#include "Adafruit_SI1145.h"
#include <BH1750.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include "Wire.h"
//#include "esp_deep_sleep.h" //Library needed for ESP32 Sleep Functions
#include "time.h"
#include <sys/time.h>                   /* gettimeofday(), settimeofday() */
//=================== Pin assignment definitions ==========================================

//define the pins used by the LoRa transceiver module
#define SCK  18                 
#define MISO 19
#define MOSI 23
#define SS   15
#define RST  17
#define DIO0 13

// define sensors pin
#define WIND_SPD_PIN        26  //reed switch based anemometer count
#define RAIN_PIN            25  //reed switch based tick counter on tip bucket
#define WIND_DIR_PIN        35  //variable voltage divider output based on varying R network with reed switches
#define SOL_VOLT_PIN        36  //voltage divider for Solar panel monitor
#define BAT_VOLT_PIN        39  //voltage divider for battery monitor
#define TEMP_PIN            15  // DS18B20 hooked up to GPIO pin 15
//#define LED_PIN           14  //Diagnostics using built-in LED
#define LORA_PWR            16  // Power Switch to complete shutdown of LoRa module
#define SENSOR_PWR          26  // Power Switch to complete shutdown of all the sensors

#define batteryCalFactor 0.00263361
#define SolarCalFactor   0.00577798

//=======================================================================================

//433E6 for Asia
//866E6 for Europe
//915E6 for North America
#define BAND 433E6

//=======================================================================================

BME280I2C bme;
Adafruit_SI1145 uv = Adafruit_SI1145();
BH1750 lightMeter(0x23);
OneWire oneWire(TEMP_PIN);
DallasTemperature sensors(&oneWire);

//=========================Declaring Variables and Constants ==========================

// Variables used in reading temp,pressure and humidity (BME280)
float temperature, humidity, pressure;
// Variables used in reading UV Index (Si1145)
float UVindex;
// Variables used in reading Lux Level( BH1750 )
float lux;
// Variables used in reading battery and solar panel voltage
float batteryVolt;
float SolarVolt;
// Variables used in calculating the windspeed
volatile unsigned long timeSinceLastTick = 0;
volatile unsigned long lastTick = 0;
float windSpeed;
// Variables used in calculating the wind direction
int vin;
String windDir = "";
// Variables used for sending LoRa message
String LoRaMessage;

// Variables and constants used in tracking rainfall
#define S_IN_DAY 86400
#define S_IN_HR 3600
#define NO_RAIN_SAMPLES 500
RTC_DATA_ATTR volatile long rainTickList[NO_RAIN_SAMPLES];
RTC_DATA_ATTR volatile int rainTickIndex = 0;
RTC_DATA_ATTR volatile int rainTicks = 0;
RTC_DATA_ATTR int rainLastDay = 0;
RTC_DATA_ATTR int rainLastHour = 0;
RTC_DATA_ATTR int rainLastHourStart = 0;
RTC_DATA_ATTR int rainLastDayStart = 0;

long secsClock = 0;
//=========================Deep Sleep Time ================================================
//const int UpdateInterval = 1 * 60 * 1000000; // e.g. 0.33 * 60 * 1000000; // Sleep time
const int UpdateInterval = 0.2* 60 * 1000000; // e.g. 15 * 60 * 1000000; // // Example for a 15-Min update interval 15-mins x 60-secs * 10000

RTC_DATA_ATTR int bootCount = 0;
time_t now()
{
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };   /* btw settimeofday() is helpfull here too*/
// uint64_t sec, us;
uint32_t sec, us;
         gettimeofday(&tv, NULL); 
         (sec) = tv.tv_sec;  
         (us) = tv.tv_usec; 
return sec;
}

//========================= Setup Function ================================================
void setup()
{
pinMode( LORA_PWR, OUTPUT);
pinMode( SENSOR_PWR, OUTPUT);
digitalWrite( LORA_PWR, HIGH);
digitalWrite( SENSOR_PWR, HIGH);
Serial.begin(115200);
delay(25);
Serial.println("nWeather station powered on.n");

//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));

// Wind speed sensor setup. The windspeed is calculated according to the number
// of ticks per second. Timestamps are captured in the interrupt, and then converted into mph.
pinMode(WIND_SPD_PIN, INPUT); // Wind speed sensor
attachInterrupt(digitalPinToInterrupt(WIND_SPD_PIN), windTick, FALLING);
// Rain sesnor setup. Rainfall is tracked by ticks per second, and timestamps of
// ticks are tracked so rainfall can be "aged" (i.e., rain per hour, per day, etc)
pinMode(RAIN_PIN, INPUT); // Rain sensor
attachInterrupt(digitalPinToInterrupt(RAIN_PIN), rainTick, FALLING);
if (bootCount == 1) {
  Serial.println("First boot");
  // Zero out the timestamp array.
  for (int i = 0; i < NO_RAIN_SAMPLES; i++) rainTickList[i] = 0;
}
  Serial.print("Time: ");
  Serial.println(now());

 //Print the wakeup reason for ESP32 and touchpad too
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();
  
  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : 
      Serial.println("Wakeup caused by external signal using RTC_IO"); 
      rainTick();
      //Serial.println("Going to sleep now...");
      //delay(1000);
      //esp_deep_sleep_start();
      break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : 
      Serial.println("Wakeup caused by timer"); 
      break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }

esp_sleep_enable_ext0_wakeup(GPIO_NUM_25,0); //1 = High, 0 = Low

//==========================================
Wire.begin();
sensors.begin();
// Wire.begin(22, 21); // for BH1750
bme.begin(); // 0x76 is the address of the BME280 module
uv.begin(0x60); // 0x60 is the address of the GY1145 module
// Get 10 readings:
for (int i = 0; i < 10; i++) {
  Read_Sensors_Data(); // Read all the Sensors
  delay(500);
}
initLoRa(); // intialize LoRa 
send_LoRa_Data(); 
//printdata(); // Print all the sensors data on the serial monitor
// ESP32 Deep SLeep Mode
  esp_sleep_enable_timer_wakeup(UpdateInterval); 
  Serial.println("Going to sleep now...");
  Serial.flush(); 
  esp_deep_sleep_start(); 
}

//============== Code Block for LoRa Module ========================================================

void initLoRa() {
  SPI.begin(SCK, MISO, MOSI, SS);  //SPI LoRa pins
  LoRa.setPins(SS, RST, DIO0);     //setup LoRa transceiver module
  if (!LoRa.begin(BAND)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
  Serial.println("LoRa Initializing OK!");
}
//====================== Send LoRa Message to Receiver ===============================================
void send_LoRa_Data() {
  
  LoRaMessage = String(temperature) + "," + String(humidity) + "," + String(pressure / 100) + "," + String(UVindex) + ","+ String(lux) + "," ;
  LoRaMessage += String(windSpeed*2.4) + "," + String(windDir) + "," + String(float(rainTicks)*0.28) + "," + String(float(rainLastHour)*0.28) + "," + String(float(rainLastDay)*0.28)+ ","  ;
  LoRaMessage += String(sensors.getTempCByIndex(0))+ "," + String(batteryVolt)+ "," + String(SolarVolt) + "," ;
  
//String((sensors.getTempCByIndex(0) * 9.0) / 5.0 + 32.0) 
  
 //Send LoRa packet to receiver
  Serial.println("Sending packet");
  LoRa.beginPacket();
  LoRa.print(LoRaMessage);
  LoRa.endPacket();
}

//====================== Print Data on Serial Monitor ===============================================
void printdata(){
Serial.print("Air temperature [°C]: "); Serial.println(temperature);
Serial.print("Humidity [%]: "); Serial.println(int(humidity));
Serial.print("Barometric pressure [hPa]: "); Serial.println(pressure / 100);
Serial.print("UV: "); Serial.println(UVindex);
//Serial.print("Light: "); Serial.print(lux); Serial.println(" lx");
Serial.print("Windspeed: "); Serial.print(windSpeed*2.4); Serial.println(" mph");
Serial.print("Wind dir: "); Serial.print(" "); Serial.println(windDir);
Serial.print("Rainfall last hour: "); Serial.println(float(rainLastHour)*0.28, 3);
Serial.print("Rainfall last day: "); Serial.println(float(rainLastDay)*0.28, 3);
Serial.print("Rainfall to date: "); Serial.println(float(rainTicks)*0.28, 3);
Serial.print("Battery Level: "); Serial.println(batteryVolt);
Serial.print("Temperature in C: "); Serial.println(sensors.getTempCByIndex(0)); //print the temperature in Celsius
//Serial.print("Temperature in F: "); Serial.println((sensors.getTempCByIndex(0) * 9.0) / 5.0 + 32.0); //print the temperature in Fahrenheit
}
//================================ Loop Function ==============================================
void loop()
{
//Read_Sensors_Data(); // Read all the Sensors
//printdata(); // Print all the sensors data on the serial monitor
//Send_Data(); // Upload all the sensors data on the Internet ( Blynk App or Thingspeak )

//delay(5000);
// ESP32 Deep SLeep Mode
// esp_deep_sleep_enable_timer_wakeup(UpdateInterval);
// Serial.println("Going to sleep now...");
// esp_deep_sleep_start();
}


void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

//===================================================================================================
// Read Sensors Data ( BME280, Si1145,BH1750, Bat. Voltage, Wind Sensors, Rain Gauge )
//==================================================================================================
void Read_Sensors_Data()
{
    // Reading BME280 sensor
  bme.read(pressure, temperature, humidity, BME280::TempUnit_Celsius, BME280::PresUnit_Pa);
//***************************************************************************
// Reading DS18B20 sensor
sensors.requestTemperatures();
//***************************************************************************
// Reading GY1145 UV sensor
UVindex = uv.readUV();
// the index is multiplied by 100 so to get the
// integer index, divide by 100!
UVindex /= 100.0;
//**********************************************************************************
// Reading BH1750 sensor
lux = lightMeter.readLightLevel();

//**********************************************************************************
// Reading Battery and Solar Panel Voltage

int adc1 = analogRead(BAT_VOLT_PIN);
int adc2 = analogRead(SOL_VOLT_PIN);
Serial.print("ADC1 Value:");
Serial.println(adc1);
Serial.print("ADC2 Value:");
Serial.println(adc2);
batteryVolt = adc1 * batteryCalFactor; //  batteryCalFactor = Measured Battery Voltage / ADC Value or val
SolarVolt = adc2 * SolarCalFactor; 
  
//**********************************************************************************
// Read Weather Meters Datas ( Wind Speed, Rain Fall and Wind Direction )
static unsigned long outLoopTimer = 0;
static unsigned long wundergroundUpdateTimer = 0;
static unsigned long clockTimer = 0;
static unsigned long tempMSClock = 0;
// Create a seconds clock based on the millis() count. We use this
// to track rainfall by the second. We've done this because the millis()
// count overflows eventually, in a way that makes tracking time stamps
// very difficult.
//tempMSClock += millis() - clockTimer;
//clockTimer = millis();
//while (tempMSClock >= 1000)
//{
//secsClock++;
//tempMSClock -= 1000;
//}
// This is a once-per-second timer that calculates and prints off various
// values from the sensors attached to the system.
//if (millis() - outLoopTimer >= 2000)
//{
//outLoopTimer = millis();
// Windspeed calculation, in mph. timeSinceLastTick gets updated by an
// interrupt when ticks come in from the wind speed sensor.
if (timeSinceLastTick != 0) {
  windSpeed = 1000.0/timeSinceLastTick;
  Serial.print("wind: ");
  Serial.println(windSpeed);
}
// Calculate the wind direction and display it as a string.
windDirCalc();
rainLastHour = 0;
rainLastDay = 0;
secsClock = now();
// If there are any captured rain sensor ticks...
if (rainTicks > 0)
{
// Start at the end of the list. rainTickIndex will always be one greater
// than the number of captured samples.
int i = rainTickIndex-1;
// Iterate over the list and count up the number of samples that have been
// captured with time stamps in the last hour.
while ((rainTickList[i] >= secsClock - S_IN_HR) && rainTickList[i] != 0)
{
i--;
if (i < 0) i = NO_RAIN_SAMPLES-1;
rainLastHour++;
}
// Repeat the process, this time over days.
i = rainTickIndex-1;
while ((rainTickList[i] >= secsClock - S_IN_DAY) && rainTickList[i] != 0)
{
i--;
if (i < 0) i = NO_RAIN_SAMPLES-1;
rainLastDay++;
}
rainLastDayStart = i;
}
}

// Keep track of when the last tick came in on the wind sensor.
void windTick(void)
{
timeSinceLastTick = millis() - lastTick;
lastTick = millis();
}
// Capture timestamp of when the rain sensor got tripped.
void rainTick(void)
{
rainTickList[rainTickIndex++] = now();
if (rainTickIndex == NO_RAIN_SAMPLES) rainTickIndex = 0;
rainTicks++;
Serial.println("raintick");

}
// reading wind direction
void windDirCalc()
{
vin = analogRead(WIND_DIR_PIN);
if (vin < 150) windDir="202.5";
else if (vin < 300) windDir = "180";
else if (vin < 400) windDir = "247.5";
else if (vin < 600) windDir = "225";
else if (vin < 900) windDir = "292.5";
else if (vin < 1100) windDir = "270";
else if (vin < 1500) windDir = "112.5";
else if (vin < 1700) windDir = "135";
else if (vin < 2250) windDir = "337.5";
else if (vin < 2350) windDir = "315";
else if (vin < 2700) windDir = "67.5";
else if (vin < 3000) windDir = "90";
else if (vin < 3200) windDir = "22.5";
else if (vin < 3400) windDir = "45";
else if (vin < 4000) windDir = "0";
else windDir = "0";
}
//=============================End of the Program =================================

Discussions