Yet another Millis question - apologies in advance!

Hi all

Hopefully a basic one here. I have a project that does 3 things:
1.) fades an LED up and down (will be a status LED eventually) - fade up and down with a 30 millis delay
2.) reads a bunch of sensors and sends them over a 433 LoRa radio to a Raspi - every 10 minutes
3.) If the soil moisture sensor is below 20% moisture, turn on a pump - with a 1 second delay on this loop.

Easy enough and currently 100% functional.

Here’s the code:

//Arduino Raspberry Pi wireless Comunnication through LoRa - SX1278
//Sending Soil Moisture values from Arduino through Radio head LoRa without ACK

#include <Wire.h>
#include <SPI.h> //Import SPI library 
#include <RH_RF95.h> // RF95 from RadioHead Library 
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

//#include <avr/wdt.h> // WDT library (added Jan 30)

#define RFM95_CS 10 //CS if Lora connected to pin 10
#define RFM95_RST 9 //RST of Lora connected to pin 9
#define RFM95_INT 2 //INT of Lora connected to pin 2

// Change to 434.0 or other frequency, must match RX's freq!
#define RF95_FREQ 434.0

//set the sea level pressure?
#define SEALEVELPRESSURE_HPA (airPressure + 1)

#define UP 0
#define DOWN 1

Adafruit_BME280 bme;

// Singleton instance of the radio driver
RH_RF95 rf95(RFM95_CS, RFM95_INT);

const byte pwmLED = 3;
// constants for min and max PWM
const int minPWM = 0;
const int maxPWM = 255;
// State Variable for Fade Direction
byte fadeDirection = UP;
// Global Fade Value
// but be bigger than byte and signed, for rollover
int fadeValue = 0;
// How smooth to fade?
byte fadeIncrement = 5;

int counter;
int ledPin = 3;  //LED thats blinking
int soilMoistureValue = 0; //realtime value from sensor (analog)
int soilMoisturePercent= 0; //digital mapped percent of moisture
int airTemperature = 0; // air temp
int airPressure = 0; // air pressure
int altitude = 0; //altitude
int airHumidity = 0; //air humidity
int lightVal;
int lightPercent;
int waterPump = 0;//put water pump pin number here!! idiot.

const int AirValue = 600;   //resistance value of the air
const int WaterValue = 300;  //resistance value of water
const int BrightSun = 1100;   //value of LightVal in a bright day
const int DarkNight = 25;  //value of LightVal in a dark room

unsigned long time_now = 0;
int fadeInterval = 50; //LED Fade Interval
int sensorInterval = 600000; //Interval for sending data to Raspi over Lora
int pumpInterval = 1000; //Interval between checking soil moisture and turning pump on and off

unsigned long previousFadeMillis;
unsigned long previousSensorMillis;
unsigned long previousPumpMillis;

void setup() 
//Initialize Serial Monitor

//wdt reset initialize
//  wdt_enable(WDTO_1S); //added Jan 30
// Reset LoRa Module 
  pinMode(RFM95_RST, OUTPUT); 
  digitalWrite(RFM95_RST, LOW);
  digitalWrite(RFM95_RST, HIGH);

  analogWrite(pwmLED, fadeValue); 
  pinMode(waterPump, OUTPUT);

//Initialize LoRa Module
  while (!rf95.init()) {
    Serial.println("LoRa radio init failed");
    while (1);

 //Set the default frequency 434.0MHz
  if (!rf95.setFrequency(RF95_FREQ)) {
    Serial.println("setFrequency failed");
    while (1);

  //Initialize the BME280 temp/pressure/humidity sensor
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);

   rf95.setTxPower(22, false); //Transmission power of the Lora Module

void Fade(unsigned long thisMillis) {

  if (thisMillis - previousFadeMillis >= fadeInterval) {
    // yup, it's time!
    if (fadeDirection == UP) {
      fadeValue = fadeValue + fadeIncrement;  
      if (fadeValue >= maxPWM) {
        // At max, limit and change direction
        fadeValue = maxPWM;
        fadeDirection = DOWN;
    } else {
      //if we aren't going up, we're going down
      fadeValue = fadeValue - fadeIncrement;
      if (fadeValue <= minPWM) {
        // At min, limit and change direction
        fadeValue = minPWM;
        fadeDirection = UP;
    // Only need to update when it changes
    analogWrite(pwmLED, fadeValue);  
    // reset millis for the next iteration (fade timer only)
    previousFadeMillis = thisMillis;

void Sensor(unsigned long thisMillis) {
//  if(thisMillis -previousSensorMillis >= time_now){
//        Serial.println("sensor loop initialized");
//  }
  if (thisMillis - previousSensorMillis >= sensorInterval) {
    Serial.print("Soil Moisture Value: "); 
    if(soilMoisturePercent > 100)
      Serial.print("Soil Moisture Percentage: ");
      Serial.println("100 %");
    else if(soilMoisturePercent <0)
      Serial.print("Soil Moisture Percentage: ");
      Serial.println("0 %");
    else if(soilMoisturePercent >0 && soilMoisturePercent < 100)
      Serial.print("Soil Moisture Percentage: ");
    Serial.print("Temperature: ");
    Serial.print("Pressure: ");
    Serial.print("Approx. Altitude: ");
    Serial.print("Humidity: ");
    Serial.print("Light Percent: ");

    //end debugging
    char buf[80]={0}; //80 byte message
    sprintf(buf, "%d|%d|%d|%d|%d|%d",soilMoisturePercent,airTemperature, airPressure,altitude,airHumidity,lightPercent); //can add in new variables here, but don't forget to add another|%d 
    rf95.send((uint8_t *)buf,80); // send integer measured value as C-string, six byte packet
    // reset millis for the next iteration (sensor timer only)
    previousSensorMillis = thisMillis;

void Pump(unsigned long thisMillis) {
  if (thisMillis - previousPumpMillis >= pumpInterval) {
    Serial.print("Soil Moisture Percentage: ");
    if (soilMoisturePercent <= 20) {
//      digitalWrite(waterPump, HIGH);
        Serial.println("pumping water now");
//      digitalWrite(waterPump, LOW);
        Serial.println("not pumping water");  
    // reset millis for the next iteration (pump timer only)
    previousPumpMillis = thisMillis;

void loop()
  unsigned long currentMillis = millis();
  soilMoistureValue = analogRead(A0);  // Soil Moisture Value
  soilMoisturePercent = map(soilMoistureValue, AirValue, WaterValue, 0, 100); // Soil Moisture Percent
  airTemperature = bme.readTemperature(); // Air Temperature Value
  airPressure = bme.readPressure() / 100.0F; // Air Pressure Value
  altitude = bme.readAltitude(SEALEVELPRESSURE_HPA); // Approximate Altitude
  airHumidity = bme.readHumidity(); // Air Humidity Value
  lightVal = analogRead(A1); // Raw Light Sensor
  lightPercent = map(lightVal, DarkNight, BrightSun, 0, 100); // Soil Moisture Percent
//  wdt_reset(); //wdt reset - added Jan 30


The part where I’m failing is due to the long delay on step 2 above - the 10 minute delay on sending data.

Right now the code waits 10 minutes to send the initial packet of data to the Raspi. I am hoping to modify this code to send the code once on initialisation, and then WAIT 10 minutes to send the next one, rather than turn on, wait 10 minutes, and then send the first packet of data.

Any ideas on how to modify this?


Put all the code from your sensor function except the millis stuff into a new function. Call it from sensor when millis tells you to. Also call it from setup.

Or you could use a flag which is initially set to a value that causes you to do the send immediately i.e if (miilis is right OR flag is set). As soon as you've done the first send reset it.


unsigned long time_now = 0;
unsigned long fadeInterval = 50; //LED Fade Interval
unsigned long sensorInterval = 600000; //Interval for sending data to Raspi over Lora
unsigned long pumpInterval = 1000; //Interval between checking soil moisture and turning pump on and off

unsigned long previousFadeMillis;
unsigned long previousSensorMillis = sensorInterval; // set the start time at the end of the interval
unsigned long previousPumpMillis;

You should not mix variable types in the math. You could store ints to work with unsigned longs but you should cast them as unsigned long even if the compiler will just to make your intentions clear when reading the code.

It's easier to declare the variables used in the math all the same unless you need to be really tight with RAM. In that case start the tightening with making pin numbers and other small values as bytes, not ints. Then use the F() macro to print constants (puts the text in flash and keeps it there) and PROGMEM numerical constants before mixed-type math.

Note that type int can hold -32768 to 32767. 600000 won't fit an int, what you get are the low 16 bits of the 32 bit long that 600000 will fit.

Also --- time variables should be unsigned, now - start doesn't work with signed values after a while. How long depends on the variable type, unsigned int can time intervals as long as 65.535 minutes and unsigned long intervals can be up to 49.7-some days.