Resource Conflicts,.. and app corruptions

I think,... but have no evidence, other than my App almost fails,.. but no quite.

To explain,.. I am using a nano as a thermostatically PWM (4wire) controlled fan,.. to keep my router (Pfsense Box) cooled, albeit it with some BlueTooth coms to monitor activity and status.
In 'main loop' I create a 10 second loop doing different things at each second, so as not to overload things. Reading each sensor once per 10sec loop.
But reading, If bluetooth active connection the serial port to see if there is any data available,.. and likewise to update the Android App with current status, as well as return new Fan duty cycle to turn fan override on for 1hr if required.
I also try to measure fan RPM,.. if fast speed,.. using a MicroSecond timer,.. and if slow, ( less than 100rpm ) via a period counter...
Now the system can run for many hours if not days without issue,.. but will ultimately start getting corrupt Amb air temperature.
I have approx. 1050 bytes of free memory when compiled, and keep serial print to a minimum,.. but no matter what I try 'Amb air' sensor fails to read,...
'I assume',.. this is probably due to the array of sensor ID addresses being written over,... but I do not know by what?,.. or what mechanism is causing this,.. I have thought about using fixed addresses for the sensors,.. rather than using a 'search',.. and although this might fix / fudge the issue it is not addressing the route cause,.. IMHO.
Is anyone else able to shed any light on what I might need to address to resolve my memory corruptions.
I did wonder if the strings used during BlueTooth were messing things up until I removed the bluetooth not active flag was implemented to prevent unnecessary processing during normal running.
One thing I also wondered is do I need to establish the interrupt variables with more compiler directives,.. eg 'const',.. I just don't know.
I have included my source files ( all concatenated into a single text file ) for review.
Many tx for any feedback, corrections or criticisms...

// Init_Defines.hold
// -------------------------------------

#include <LiquidCrystal_I2C.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <SoftwareSerial.h>

SoftwareSerial MyBlue(12, 11); // RX to Ard | TX  from Ard

LiquidCrystal_I2C lcd(0x27, 20, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display

/* we always wait a bit between updates of the display */
unsigned long delaytime = 50;
byte Patt_Time[1];
byte HexByteSplit[4];
byte Time[1];
byte Patt[1];
byte FanTime, ticktime, Segmenttime, tenthsec = 0;

#define MaxTemp 60
#define MinTemp 30
#define dutydiv 10
// ----------------------------------
unsigned long currentMillis, PreviousMillis = millis();

// -----------------------------------

// Temperature stuff, connected to Digital PIN 3
#define ds18b20      3
OneWire oneWire(ds18b20);
DallasTemperature sensors(&oneWire);

// arrays to hold device addresses
DeviceAddress Ambient, Heatsink;

uint8_t index2arry;
// Assign address manually. The addresses below will need to be changed
// to valid device addresses on your bus. Device address can be retrieved
// by using either oneWire.search(deviceAddress) or individually via
// sensors.getAddress(deviceAddress, index)
// DeviceAddress Ambient =
// DeviceAddress Heatsink   =
//#define LongPrint
#define NumberSensors 2
#define SensorArrySize 5
float temperatureArray[NumberSensors][SensorArrySize + 1] {
  {21, 21, 21, 21, 21, 21 },
  {31, 31, 31, 31, 31, 31 }
};   // 5 entries, with Postion [6] used as avaerage

byte  temperatureIndex = -1;      // Intialise Index to array next average to -1 as will be incremented on 1st use
byte  id = 0;
char Display[10];        // 8 digit display
char fltbuff[10];        // buffer for float conversion

float AmbTemp, HeatSinkTemp, TempInc;
float minAmb = 25, maxAmb = 25, minhtsk = 25, maxhtsk = 25;
//int  maxrpm = 0, Dcycle;
int LCDLEDTimer = 0;
int  Dcycle = 0;
#define minmaxtimeout 120000
#define TimerLoadValue 3600   // default time-out 1hr
#define maxindatalen 20


//char inData[maxindatalen]; // Allocate some space for the string
char inChar = -1; // Where to store the character read
byte index = 0;   // Index into array; where to store the character
//char outstring[50];
char  preData[8];
char  actData[5];
char  postData[8];
int BTdutyCycle = 0;
int BTdutyTimer = 0;

unsigned long lastcount = 0;
unsigned long timediff = 0;

#define SWstate A6
int StatePin = A1;
int SwitchState = SWstate;
int StateBT = 0;
//int counter;

// -------------------------------------------------------------------
const byte interruptPin = 2;     // Pin used to read fan rotational speed

// Fan Interupt Stuff
volatile unsigned long RotorPulseCount = 0;
//unsigned int FanSpeed = 0;
const unsigned int pulsesPerRev = 2;
//const unsigned long now;
//const unsigned long interval;
unsigned long lastPulseTime = 0;
unsigned long rpm = 0;
unsigned long RPMslowfinalcount, slowCountDiff = 0;
unsigned long slowRPMcountSTART = 0;
byte TimeoutRPMcount = 0;  // used to check if rotor is actually rotating

//int fanVal;
byte DutyCycle = 1;
unsigned long FANlastmillis = 0;

//float FanCountPeriod, RAWFanRPM, FanCalcRPM, FanCalcTest; ;

const byte OC1A_PIN = 9;
const byte OC1B_PIN = 10;

const word PWM_FREQ_HZ = 25000; //Adjust this value to adjust the frequency
const word TCNT1_TOP = 16000000 / (2 * PWM_FREQ_HZ);

// --------------------------------------------------------------------

//#define Chk_Bit(var,pos) ((var) & (1<<(pos)))
//#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)
//https://stackoverflow.com/questions/523724/c-c-check-if-one-bit-is-set-in-i-e-int-variable
//#define bit_set(val, bit_no) (((val) >> (bit_no)) & 1)
#define Chk_Bit(val, bit_no) (((val) >> (bit_no)) & 1)

#define Set_Bit(var,pos) ((var) |= (1<<(pos)))

#define Clr_Bit(var,pos) ((var) &=  ~(1<<(pos)))

#define Tog_Bit(var,pos) ((var) ^= (1<<(pos)))

#define DefaultFlags 0b00000000

// ----------------------------
byte Status_Flags = 0;           // 8 Bit Register
#define ENfastRPM      0       // 1
#define ENslowRPM      1       // 2
#define BackLightStatus   2      // 4  1 if on, 0 if off
#define SensorError     3        // 8   1 if error 0 No-error
#define WriteTemp       4        // 16  1 ignore checks to start and write all values, 0 check for valid temperatures
#
#define CriticalBattVolt  5     // 32
#define Supp65volt      6       // 64
#define sample          7       // 128

// -----------------------------

#define LedFlash 6
byte activity = 0;
byte ErrorCount = 0;  // count will roll round after 256

// ---------------------------------------
// Setup.ino
// *******************************************************************
void setup() {
  Serial.begin(57600);
  MyBlue.begin(9600);
  Wire.begin();
  lcd.init();                      // initialize the lcd
  lcd.backlight();
  Set_Bit(Status_Flags, BackLightStatus);

  lcd.home();
  lcd.print("Fan Control");
  lcd.setCursor(0, 1);
  lcd.print("Start...");

  Serial.println(F("display setup"));
  FanCalcs();
  delay(1000);

  // Setup pin to flash LED in Switch
  pinMode(LedFlash, OUTPUT);

  Set_Bit(Status_Flags, WriteTemp);       // Set Flag so all temperature data get written to array

  // ------------------------------------
  // Check if sensors present
  if (!sensors.getAddress(Ambient, 0)) Serial.println(F("Unable to find address for Device 0"));
  if (!sensors.getAddress(Heatsink, 1)) Serial.println(F("Unable to find address for Device 1"));

  // --------------------------------------------------------

  // fan setup

  pinMode(interruptPin, INPUT);       // Pin 2 is tacho input to which a fan is connected
  EnableFastRPM();
  //  attachInterrupt(digitalPinToInterrupt(interruptPin), FANrpmISR, RISING);        // attach and enable FastRPM interrupt 2
  //  attachInterrupt(digitalPinToInterrupt(interruptPin), SlowRPMCount, RISING);        // attach and enable slowRPM interrupt 2

  pinMode(OC1A_PIN, OUTPUT);        // This sets the PWM pin output...

  // Clear Timer1 control and count registers
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;

  TCCR1A |= (1 << COM1A1) | (1 << WGM11);
  TCCR1B |= (1 << WGM13) | (1 << CS10);
  ICR1 = TCNT1_TOP;

  //  fanVal = 25;

  LCDLEDTimer = 300; // give an initial timeout value of 300 seconds
  lcd.clear();

}
// ------------------------------------------------------------
void EnableFastRPM() {
  detachInterrupt(digitalPinToInterrupt(interruptPin));
  Clr_Bit(Status_Flags, ENslowRPM); // clear both flags just to be safe
  Clr_Bit(Status_Flags, ENfastRPM); //
  //
  // timers and vraiables for fast checking using micro seconds are all set and sorted with ISR
  attachInterrupt(digitalPinToInterrupt(interruptPin), FANrpmISR, RISING);        // attach and enable FastRPM interrupt 2
  //  attachInterrupt(digitalPinToInterrupt(interruptPin), SlowRPMCount, RISING);        // attach and enable slowRPM interrupt 2
  Set_Bit(Status_Flags, ENfastRPM);   // Set Bit zero to a 1 to show fast RPM enabled
  Serial.println(F("Fast RPM Enabled"));
}

void EnableSlowRPM() {
  detachInterrupt(digitalPinToInterrupt(interruptPin));
  Clr_Bit(Status_Flags, ENslowRPM); //
  Clr_Bit(Status_Flags, ENfastRPM); //

  slowRPMcountSTART = micros();
  TimeoutRPMcount = 0;
  RotorPulseCount = 0;
  // now we see how long to get 20 interupts whilst in slow mode count
  //  attachInterrupt(digitalPinToInterrupt(interruptPin), FANrpmISR, RISING);        // attach and enable FastRPM interrupt 2
  attachInterrupt(digitalPinToInterrupt(interruptPin), SlowRPMCount, RISING);        // attach and enable slowRPM interrupt 2
  Set_Bit(Status_Flags, ENslowRPM);   // Set Bit zero to a 1 to show fast RPM enabled
  Serial.println(F("Slow RPM Enabled"));
}
// FanCtrl7-8.ino
// **********************************************************************************************
#include "Init_Defines.h"
// Sketch uses 16156 bytes (52%) of program storage space. Maximum is 30720 bytes.
// Global variables use 873 bytes (42%) of dynamic memory, leaving 1175 bytes for local variables. Maximum is 2048 bytes.


void loop() {
  do {
    delay(10);
    // Do Nothing
  } while ( ( millis() - PreviousMillis ) < 100 );
  // we land here every 0.1 of a second

  // Read Blue Tooth every 1/10 second
  readSerialBlu();
  //  Now see what we have to do
  //  processBlueRead();

  tenthsec++;
  if ( tenthsec > 9 ) {  // count is zero to 9, so 10 increments
    tenthsec = 0;
  }

  // We go past here every 1/10 of a second
  // Turn fan off
  if ( millis() > 2000  && millis() < 2200 ) { // after switch on between 2 and 2.2 second set duty cycle to zero
    Dcycle = 0;
    setPwmDuty((100 - Dcycle));     // This inverts the value sent to the PWM,.. as output transistor inverts output
  }
  // ----------------------
  // Clear the Write data flag so data will now be checked before commiting to array
  // One off timer that counts from reset time zero
  if ( millis() > 180000  && millis() < 180200 ) { // after switch on between 3 and 3 minutes+1sec reset max rpm to zero
    // this gives enough time to write to flag twice
    Clr_Bit(Status_Flags, WriteTemp);
    Serial.println(F("Temperatre write bad data flag cleared"));
  }

  // -----------------------------------

  //  So now we read BlueTooth connection status once every second
  StateBT = analogRead(StatePin);  // read the input pin to determine the BlueTooth connection status
  //  Serial.print("State Pin ->");
  //  Serial.println(StateBT);          // debug value
  SwitchState = analogRead(SWstate); // 138 closed or 73 open  <> 100 can be the threshold
  //  Serial.print("Switch State Pin ->");
  //  Serial.println(SwitchState);          // debug value

  // Now check if we need to turn backlight on without doing it multiple times
  if ( SwitchState > 100 ) {
    SetBacklightON();
    //
    //    //    Serial.print("backlight status>");
    //    //    Serial.println(Chk_Bit(Status_Flags, BackLightStatus));
    //
    //    if ( Chk_Bit(Status_Flags, BackLightStatus) == 0 ) {
    //      lcd.backlight();  // Turn Backlight ON
    //      Set_Bit(Status_Flags, BackLightStatus);
    //      //      Serial.println("Backlight ON");
    //    }
    //    LCDLEDTimer = 1800;      // 1800;  // 1/2 hr timer
  }

  //    Serial.print("Switch state >");
  //    Serial.println(SwitchState);

  // Toggle LED Light in switch
  // digitalWrite(LedFlash, !digitalRead(LedFlash));  // toggle state

  // **********************************************************************

  /*
     This creates a 1 second timer,...
     so 1 miniute will have a total count of 60
  */
  if ( tenthsec == 0 ) {
    ticktime++;
    if ( ticktime > 10) {
      ticktime = 0;

      //      Serial.println("");
    }
    //    Serial.print(ticktime);
    //    Serial.print(" ");

    //    timediff =  millis() - lastcount;
    //    Serial.println(timediff);
    //    lastcount = millis();


    EvalLCDLight();

    if ( BTdutyTimer > 0 ) {
      // this will allow timer to count down to Zero
      BTdutyTimer--;
    }

    TimeoutRPMcount++; // this just increments a local counter to timeout if no rotor pulses

    EvaluateSlowRPM();

    ActivityIcons();

    switch  (ticktime)
    {
      case 0:
        FanTime++;
        if ( FanTime > 6 ) {
          FanTime = 0;
          SetFanCntl();
        }
        break;

      case 1:

        Inc_Temp_Store_indx();      // This increments the storage pointer for the next store
        // of temperature value into array
        SerialwriteBlu();

        break;

      case 2:
        // Sensor reads take approx 750mS,.. and lock system, so stagger
        // reads at 2 a 7 seconds of the 10second cycle
        GetTemp(0, Ambient);
        break;

      case 3:
        DisplayDutyCycleRPM(Dcycle);       // Pass Float number for conversion and display
        break;

      case 4:
        DisplayTempUpdate();       // Pass Float number for conversion and display
        //        DisplayTempUpdate(HeatSinkTemp);   // Pass Float number for conversion and display
        break;

      case 5:
        // determine which mode is running
        if ( (Chk_Bit(Status_Flags, ENfastRPM)  == 1 )  && ( rpm < 100 )) {
          //          Serial.println("Fastrpm is checked as enabled, and rpm less than 100");
          EnableSlowRPM();
          Serial.println(F("SLOWrpm is now enabled "));
        } else if  ( (Chk_Bit(Status_Flags, ENslowRPM)  == 1 )  && ( rpm > 100 )) {
          //          Serial.println("Slowrpm is enabled but rpm is greater than 100");
          EnableFastRPM();
          Serial.println(F("FASTrpm is now enabled "));
        }
        break;

      case 7:
        DisplayDutyCycleRPM(Dcycle);       // Pass Float number for conversion and display
        break;

      case 8:
        GetTemp(1, Heatsink);
        break;

      case 9:
        DisplayTempUpdate();       // Pass Float number for conversion and display
        //        DisplayTempUpdate(HeatSinkTemp);   // Pass Float number for conversion and display
        //        Serial.println(ErrorCount);
        break;
    }
  }
  PreviousMillis = millis();
}
// Bluetooth.ino
// **************************************************************************************
/*
   Send string formatted as follows
   Data to send to Android App
   p1=1230p2=2200p3=-06p4=24  25 chars
   ss;1230;36;25;-06;24;34;24;34;32;150;ee;-  41 Char
   p5=34p6=24p7=34p8=32    45 chars or one line

  Updated 30 April2021 include set  cycle
   p1 > ss
   p2 > current  measured rpm
   p3 > current set Duty Cycle
   p4 > set RPM time-out
   p5 > Current Amb temperature measured
   p6 min Amb temperature measured
   p7> max Amb temperature measured
   p8> Current Heat sink temperature measured
   p9> min Heat Sink temperature measured
   p10 max Heat Sink temperature measured
   p11 ErrorCount
   p12> ee;-

*******************************************
   Data to recieve
   Dcycle;12;DCend
*/

void readSerialBlu() {
  if ( StateBT > 500 ) {
    char inData[maxindatalen];
    index = 0;
    inData[index] = '\0'; // Null terminate the string on zero length string

    while (MyBlue.available() > 0) {    // Don't read unless
      // you know there is data
      //    Always read the data... so as to not block buffer
      //    but dont save as will get buffer overflow
      inChar = MyBlue.read(); // Read a character
      if (index < ( maxindatalen - 1) ) // One less than the size of the array
      {
        //      inChar = MyBlue.read(); // Read a character
        inData[index] = inChar; // Store it
        index++; // Increment where to write next
        inData[index] = '\0'; // Null terminate the string
      }
    }

    // Serial data now has been read,.. now we must process it
    //void processBlueRead() { no nonlger a subroutine
    //  char inData[maxindatalen];
    if ( index > 0 ) {    // variable 'index' indexes input string as it is read in from bluetooth device
      //    Serial.print("Data to process >");
      //    Serial.println(inData);
      // -------------------------
      char *pntr;
      byte i = 0;
      pntr = strtok(inData, ";");  // set pointer to 1st byte of the string.

      while (pntr && i < 3)
      {
        //    BTReadField[i] = pntr;
        if ( i == 0 ) {
          if ( strlen(pntr) < 7 ) {
            strcpy(preData, pntr);
          } else {
            Serial.println(F("stringpre too long"));
          }
        } else if ( i == 1 ) {
          if ( strlen(pntr) < 4 ) {
            strcpy(actData, pntr);
          } else {
            Serial.println(F("stringdata too long"));
          }
        } else if ( i == 2 ) {
          if ( strlen(pntr) < 6 ) {
            strcpy(postData, pntr);
          } else {
            Serial.println(F("stringpost too long"));
          }
        }
        pntr = strtok(NULL, ";");
        ++i;
      }

      //    Serial.print("the Numeric data >");
      BTdutyCycle = atoi(actData);
      //    Serial.println(BTdutyCycle);

      // ----
      Dcycle = BTdutyCycle;
      //    fanVal = Dcycle;
      setPwmDuty((100 - Dcycle));     // This inverts the value sent to the PWM,.. as output transistor inverts output
      //    Serial.print("Fan Duty Cycle >");
      //    Serial.println(fanVal);

      if ( Dcycle == 19 ) {
        // ----
        // Start Timer
        BTdutyTimer = 65;   // this just loads a short value that will timeout quickly
        SetBacklightON();
        Serial.println(F("Setting duty cycle timer to short timer"));
      } else {
        BTdutyTimer = TimerLoadValue;    // Load default timeout nominally 1hr
        // Now check if we need to turn backlight on without doing it multiple times
        if ( Chk_Bit(Status_Flags, BackLightStatus) == 0 ) {
          SetBacklightON();
        }
        Serial.println(F("Backlight on due to Btooth"));
        Serial.print(F("Setting duty cycle to >"));
        Serial.print(Dcycle);
        Serial.println(F(", and timer to 60"));
      }
      // ----------------------------

      //    // clear index and buffer
      //    index = 0;
      //    inData[index] = '\0'; // Null terminate the string on zero length string
    }
  }
}


// ------------------------------------------------
void SerialwriteBlu() {
  char outstring[20];
  // eg
  //  ss;1230;100;60;24.0;25.0;25.0;24.3;24.3;25.0;200;ee;-      54 chars  max length
  //  ss;1230;100;60;    -- send up to timer 15 chars with each send
  //  24.0;25.0;25.0;    --
  //  24.3;24.3;25.0;
  //  200;ee;-      54 chars  max length


  //  ss;0;0;0;24.1;24.1;25.0;24.5;24.5;25.0;0;ee;-              46 chars  min number
  //
  char convertString[10];

  //  StateBT = analogRead(StatePin);  // read the input pin to determine the BlueTooth connection status
  //  Serial.print("State Pin ->");
  //  Serial.println(StateBT);          // debug value

  if ( StateBT > 500 ) {
    //  Serial.println("\nData to write back");
    //   p2 > current rpm measured
    //    char asciCurrRPM[6];
    itoa(rpm,  convertString, 10);    // 10 is the base
    strcpy(outstring, "ss;");
    strcat(outstring, convertString);
    strcat(outstring, ";");

    //  Serial.print("ASC rpm ->");
    //  Serial.println(convertString);
    //  Serial.print("RAW rpm ->");
    //  Serial.println(rpm);

    //  ascDutyCylce added 30Apr2021
    //     p3 > Current Duty Cycle
    char ascDutyCylce[4];
    itoa(Dcycle, convertString, 10);
    strcat(outstring, convertString);
    strcat(outstring, ";");

    //  Serial.print("Duty cycle value to transmit>");
    //  Serial.println(convertString);

    //   p4 > Current Time-out counter value in minutes
    //    char ascTimer[6];
    if ( BTdutyTimer != 0 ) {         // Check first to see if timer is actually running
      // / 60 to get from minutes timer,,, and +60 so display show less minutes correctly
      // and times out when less than 1 minute as sums are not float numbers
      itoa(((BTdutyTimer + 60) / 60), convertString, 10 ); // 10 is the base
    } else {
      itoa((BTdutyTimer / 60), convertString, 10 );        // no offsetting required
    }
    strcat(outstring, convertString);
    strcat(outstring, ";");

    // **************
    MyBlue.print(outstring);               // Write the character to Bluetooth
    Serial.print(outstring);
    // **************


    //  Serial.print("RAW BTdutyTimer ->");
    //  Serial.println(convertString);
    //  Serial.print("ASC Timer ->");
    //  Serial.println(convertString);
    // -------------------------
    //     p5 > Current Amb temperature measured
    //    char asciiAmbTemp[6];
    dtostrf(AmbTemp, 4, 1, convertString);
    strcpy(outstring, convertString);
    strcat(outstring, ";");
    //  Serial.println(convertString);

    // p6
    //    char asciiAmbMinTemp[6];
    dtostrf(minAmb, 4, 1, convertString);
    strcat(outstring, convertString);
    strcat(outstring, ";");
    //  Serial.println(convertString);

    // p7
    //    char asciiAmbMaxTemp[6];
    dtostrf(maxAmb, 4, 1, convertString);
    strcat(outstring, convertString);
    strcat(outstring, ";");
    //  Serial.println(convertString);

    // **************
    MyBlue.print(outstring);               // Write the character to Bluetooth
    Serial.print(outstring);
    // **************

    // -------------------------
    //     p8 > Current Heat sink temperature measured
    //    char asciiHeatSinkTemp[6];
    dtostrf(HeatSinkTemp, 4, 1, convertString);
    strcpy(outstring, convertString);
    strcat(outstring, ";");
    //  Serial.println(convertString);

    // p9
    //    char asciiHeatSinkMinTemp[6];
    dtostrf(minhtsk, 4, 1, convertString);
    strcat(outstring, convertString);
    strcat(outstring, ";");
    //  Serial.println(convertString);

    // p10
    //    char asciiHeatSinkMaxTemp[6];
    dtostrf(maxhtsk, 4, 1, convertString);
    strcat(outstring, convertString);
    strcat(outstring, ";");
    //  Serial.println(convertString);

    // **************
    MyBlue.print(outstring);               // Write the character to Bluetooth
    Serial.print(outstring);
    // **************

    // p11
    //    char asciiErrorCount[4];
    itoa(ErrorCount, convertString, 10);
    strcpy(outstring, convertString);
    strcat(outstring, ";ee;-");
    //  Serial.println(convertString);

    // ******************
    MyBlue.println(outstring);               // Write the final character string to Bluetooth
    Serial.println(outstring);                // NOTE!! this has terminating <CR> LF at end if print
    // ************************
    //    Serial.println("ss;870;3500;22;14;28;44;34;52;150;ee;-"); // 38 chars
  }



}
// ------------------------------------------------
// Display.ino
// *************************************************************************
void ActivityIcons() {
  activity++;
  if ( activity > 7 ) {
    activity = 0;
  }

  if ( activity == 0 ) {
    lcd.setCursor(7, 0);
    lcd.print(" ");
    lcd.setCursor(7, 1);
    lcd.print(" ");
  } else if ( activity == 1 ) {
    lcd.setCursor(7, 0);
    lcd.print(".");
    lcd.setCursor(7, 1);
    lcd.print(" ");
  } else if ( activity == 2 ) {
    lcd.setCursor(7, 0);
    lcd.print(":");
    lcd.setCursor(7, 1);
    lcd.print(" ");
  } else if ( activity == 3 ) {
    lcd.setCursor(7, 0);
    lcd.print(":");
    lcd.setCursor(7, 1);
    lcd.print(".");
  }  else if ( activity == 4 ) {
    lcd.setCursor(7, 0);
    lcd.print(":");
    lcd.setCursor(7, 1);
    lcd.print(":");
  } else if ( activity == 5 ) {
    lcd.setCursor(7, 0);
    lcd.print(".");
    lcd.setCursor(7, 1);
    lcd.print(":");
  }  else if ( activity == 6 ) {
    lcd.setCursor(7, 0);
    lcd.print(" ");
    lcd.setCursor(7, 1);
    lcd.print(":");
  } else if ( activity == 7 ) {
    lcd.setCursor(7, 0);
    lcd.print(" ");
    lcd.setCursor(7, 1);
    lcd.print(".");
  }
}
// ----------------------------------------
void EvalLCDLight() {

  if (LCDLEDTimer != 0  ) {
    LCDLEDTimer--;
  } else if ( LCDLEDTimer == 0 && BTdutyTimer < 2000 ) {
    if ( Chk_Bit(Status_Flags, BackLightStatus) == 1 ) {
      Clr_Bit(Status_Flags, BackLightStatus);
      lcd.noBacklight();    // this will turn the backlight off for both conditions being TRUE
      Serial.println(F("Backlight Off"));
      //      Serial.print("backlight status>");
      //      Serial.println(Chk_Bit(Status_Flags, BackLightStatus));
    }
  }

}

// ----------------------------------------
void DisplayTempUpdate() {
  char outstring[5];
  if ( Chk_Bit(Status_Flags, SensorError) == 0 ) {  // if sensor error do not update temperature

    lcd.setCursor(8, 1);
    strcpy(outstring, "Air");               // Start string for Ambient Air
    lcd.print(outstring);
    lcd.print(AmbTemp, 1); // Set output to 1 dp
    lcd.print("C");

    lcd.setCursor(8, 0);
    strcpy(outstring, "Hsk");               // Start string for Heat Sink
    lcd.print(outstring);
    lcd.print(HeatSinkTemp, 1); // Set output to 1 dp
    lcd.print("C");

    // We will now display how much of the manual timer remains

    // if less than minute left
    if ( BTdutyTimer < 10 ) {
      dtostrf((BTdutyTimer + 60 ) / 60, 2, 0, outstring);
      strcpy(outstring, "<1");
    } else {
      dtostrf((BTdutyTimer + 60 ) / 60 , 2, 0, outstring);
    }
    strcat(outstring, "m");
    // And if timer is at zero
    if ( BTdutyTimer == 0 ) {
      strcpy(outstring, "-- ");
    }
    // And finally just print it
    lcd.setCursor(4, 0);
    lcd.print(outstring);
  }
}

// ---------------------------------------
void  DisplayDutyCycleRPM(int duty) {
  if ( Chk_Bit(Status_Flags, SensorError) == 0 ) {   // if sensor error do not update temperature
    itoa(duty, fltbuff, 10);  // duty = value 0 -> 100
    strcat(fltbuff, "%");

    byte stringLen = strlen(fltbuff);

    if ( stringLen == 2 ) {
      strcat(fltbuff, "  ");
    } else if ( stringLen == 3 ) {
      strcat(fltbuff, " ");
    }

    // Print duty cycle to Display
    lcd.setCursor(0, 0);
    lcd.print(fltbuff);

    // ------------------------------------------------
    //  validateRPM();
    // Print RPM to 2nd line of display
    lcd.setCursor(0, 1);
    itoa(rpm, fltbuff, 10);
    strcat( fltbuff , "rpm" );

    stringLen = strlen(fltbuff);

    if ( strlen(fltbuff) == 4 ) {
      strcat(fltbuff, "   " );                 // add 4 spaces
    } else if  ( strlen(fltbuff) == 5 ) {
      strcat(fltbuff, "  " );                  // add 3 spaces
    } else if  ( strlen(fltbuff) == 6 ) {
      strcat(fltbuff, " " );                   // add 2 spaces
    }

    lcd.print(fltbuff);
    //  lcd.print("XXX");
  }
}

// --------------------------------
void SetBacklightON() {
  if ( Chk_Bit(Status_Flags, BackLightStatus) == 0 ) {
    lcd.backlight();  // Turn Backlight ON  as well
    LCDLEDTimer = 1800;      // 1800;  // 1/2 hr timer
    Set_Bit(Status_Flags, BackLightStatus);
    Serial.println(F("Backlight ON"));
  }
}
// FanCtrl.ino
// *************************************************************************************


void SetFanCntl() {
  // if timer is running no need to process this automatic loop
  if ( BTdutyTimer == 0 ) {
    //    Serial.println("\n-----------------In fan control");
    // HeatSinkTemp
    if (HeatSinkTemp > MinTemp) {

      Dcycle = 10;
      float TrackTemp = MinTemp;

      while ( TrackTemp < HeatSinkTemp ) {

        //        Serial.print("Dcycle ->");
        //        Serial.println(Dcycle);
        //        Serial.print("TrackTemp ->");
        //        Serial.println(TrackTemp);

        TrackTemp += TempInc;
        Dcycle += 10;
      }
    } else {
      Dcycle = 0;
    }

    //    fanVal = Dcycle;
    //  fanVal = 15;  // used to force a duty cycle and turn fan on or off
    //  fanVal = 1;
    setPwmDuty((100 - Dcycle));     // This inverts the value sent to the PWM,.. as output transistor inverts output
    //    Serial.print("Fan Duty Cycle >");
    //    Serial.println(fanVal);
  }


  // Emergency error Check-----------------------
  // This caters for situation where sensor is disconnected
  if ( HeatSinkTemp < -100  || ErrorCount > 200 ) {
    Dcycle = 60;
    setPwmDuty((100 - Dcycle));     // This inverts the value sent to the PWM,.. as output transistor inverts output

    if ( HeatSinkTemp < -100 ) {
      lcd.setCursor(2, 0);
      lcd.print("Sensor Error");
      lcd.setCursor(2, 1);
      lcd.print("Sensor Error");
      Serial.println(F("Sensor Error"));
      Set_Bit(Status_Flags, SensorError);   // Set Sensor Error Flag
      lcd.backlight();  // Turn Backlight ON
      Set_Bit(Status_Flags, BackLightStatus);
      LCDLEDTimer = 1800;      // 1800;  // 1/2 hr timer

    } else if ( ErrorCount > 200 ) {
      lcd.setCursor(3, 0);
      lcd.print("Error Count");
      lcd.setCursor(3, 1);
      lcd.print("Error Count");
      Serial.println(F("Error Count"));
      Set_Bit(Status_Flags, SensorError);   // Set Sensor Error Flag
      lcd.backlight();  // Turn Backlight ON
      Set_Bit(Status_Flags, BackLightStatus);
      LCDLEDTimer = 1800;      // 1800;  // 1/2 hr timer
    } else if ( HeatSinkTemp > -100 &&  Chk_Bit(Status_Flags, SensorError) == 1 ) {
      Clr_Bit(Status_Flags, SensorError);   // Clear Sensor Error Flag
      lcd.clear();      // Clear LCD display
    }
  }
}

// ------------------------------------------------------------
//void validateRPM() {
//  // Check that RPM values are sensible
//
//  if ( rpm > 4000 ) {
//    rpm = 2800;
////    Serial.println("RPM reset to 99rpm as rpm > 4000rpm");
//  } else if ( rpm < 75 ) {
//    rpm = 0;
////    Serial.println("RPM reset to 0rpm as rpm > 50rpm");
//  }
//
//  if ( rpm > maxrpm ) {
//    maxrpm = rpm;
//  }
//}
// ----------------------------------------------------------
void FanCalcs() {
  // This calculates the Temp Increment eg. (60 - 30 ) / 10 = 3
  TempInc = ( MaxTemp - MinTemp ) / dutydiv;

  // And then prints it to the LCD
  lcd.setCursor(0, 0);
  lcd.print("Temp Inc. ->");
  lcd.print(TempInc);
}
// ----------------------
void EvaluateSlowRPM() {

  //    ( TimeoutRPMcount > 20 && Chk_Bit(Status_Flags, ENslowRPM) == 1)
  //    ( RotorPulseCount > 20 && Chk_Bit(Status_Flags, ENslowRPM) == 1 )

  // NB if rotor is slow/sationary count will never pass 20.. need to check for this
  // so we have run for 10 seconds with someclocks from fan,.

  //  Serial.print("\nChk_Bit(Status_Flags, ENslowRPM) ");
  //  Serial.println(Chk_Bit(Status_Flags, ENslowRPM) );
  //
  //  Serial.print("RotorPulseCount");
  //  Serial.println(RotorPulseCount);
  //
  //  Serial.print("status flags >");
  //  Serial.println(Status_Flags, BIN);
  //
  //  Serial.print("TimeoutRPMcount >");
  //  Serial.println(TimeoutRPMcount);

  if ( RotorPulseCount > 0 && Chk_Bit(Status_Flags, ENslowRPM) == 1  ) { // check bit position value
    // ie it has stopped
    RPMslowfinalcount = micros();   // we now set and end point for the timer
    slowCountDiff = RPMslowfinalcount - slowRPMcountSTART;

    //    Serial.print("Timerdiff =");
    //    Serial.println(slowCountDiff);
    //    Serial.print("RotorPulseCount =");
    //    Serial.println(RotorPulseCount);

    //    rpm = 60000000UL / (slowCountDiff * pulsesPerRev);
    // timediff / 1000000 to get to seconds
    // divide into number of pulses to get number of pulses per second ( /2 for no. pulses per rev) x60 to get to minutes
    rpm = ( RotorPulseCount / pulsesPerRev / (slowCountDiff / 1000000)) * 60;

    //    Serial.print("Slow rpm Value");
    //    Serial.println(rpm);

    TimeoutRPMcount = 0;
    slowRPMcountSTART = micros();
    RotorPulseCount = 0;
    // -----------------------------
    // --------elseif---------------  8 second timeout
  } else if  ( TimeoutRPMcount > 8 && Chk_Bit(Status_Flags, ENslowRPM) == 1 ) {   // ==2 BIN 10
    //      time caculations irrelavent as time-out has occured
    //      RPMslowfinalcount = micros();   // we now set and end point for the timer
    //      slowCountDiff = RPMslowfinalcount - slowRPMcountSTART;

    // just check see that rotor count is zero
    //        Serial.print("RotorPulseCount =");
    //        Serial.println(RotorPulseCount);

    // count timeout exceeded so rotor in NOT rotating,
    // and we need to reset counters and rpm speed to zero
    TimeoutRPMcount = 0;
    slowRPMcountSTART = micros();
    RotorPulseCount = 0;
    rpm = 0;     // still!!

  }

  //  // this just prints the variables for test purposes
  //  TimeoutRPMcount++; // this just increments a local counter to timeout if no rotor pulses
  //  Serial.print("Print the state of the ENslowRPM flag>B");
  //  Serial.println(Chk_Bit(Status_Flags, ENslowRPM));
  //
  //  if ( Chk_Bit(Status_Flags, ENslowRPM) == 1 ) { // is this 1 or 10 Binary ie 2
  //    Serial.print("\n---------------- runningRotorPulseCount =");
  //    Serial.println(TimeoutRPMcount);
  //  }

}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
void setPwmDuty(byte duty) {
  OCR1A = (word)(duty * TCNT1_TOP) / 100;
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
void FANrpmISR() {
  /*
      do not add additional stuff to this function as it is executed with the ISR
      so additional serial.prints etc screws timing up else where
      just keep it simple!!!!!!
  */
  rpm = 0;
  unsigned long now = micros();
  unsigned long interval = now - lastPulseTime;
  if ( interval > 2000 ) {
    rpm = 60000000UL / (interval * pulsesPerRev); // 60seconds (unassigned Long,.. so no sign bit)
    lastPulseTime = now;
  }
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
void SlowRPMCount() { /* this code will be executed every time the interrupt 0 (pin2 Goes High.*/
  //       just keep it simple!!!!!!
  RotorPulseCount++;    // we want to count say 20 pulses and see how long it takes...
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ReadTemps.ino
// *************************************************

void Inc_Temp_Store_indx() {

  // Setup temperatureIndex for next save within array
  // This sets the next store location within the 2 x 5 array for ech temperature sensor.
  // it starts at -1,.. so the first increment takes it to zero,..
  // and then cycles around on a count of 5
  // The last location of the array is used to store the average of the previous 5 reads

  temperatureIndex++;
  // Now check if out of array range
  if ( temperatureIndex > SensorArrySize - 1 ) {
    temperatureIndex = 0;          // increment Storage location within Array
  }
}
/*
  GetTemp(0, Ambient);
  GetTemp(1, Heatsink);

  }
*/
// ----------------------------------------------------------------

void GetTemp(byte id, DeviceAddress addr) {
  // First we turn the LED switch light on to show activity
  digitalWrite(LedFlash, HIGH );

  // Enable this section to print the sensor Ids..address
  //  Serial.println();
  //  printAddress(addr);
  //  Serial.print("ReadTemp ID ->");
  //  Serial.println(id);

  sensors.requestTemperatures();
  float TempValue = sensors.getTempC(addr);   // Get Temperature Reading from Sensor
  // Current Sensor value now read,..
  //  Serial.println(TempValue);

  //------------------------------------------------------
  if  ( Chk_Bit(Status_Flags, WriteTemp) == 0 ) {
    // so is it a good value
    // Now we try some error checking to ensure no silly values get stored into array
    if ( (TempValue < temperatureArray[id][SensorArrySize] + 10 ) && (TempValue > temperatureArray[id][SensorArrySize] - 10  ) ) {
      // As long as new temperature is within a +- 10degree window it will get saved into array
      // This assumes temperature is a slow changing paramater
      temperatureArray[id][temperatureIndex] = TempValue; // Store New temperature reading in Array
      //      Serial.println("Good sensor value");
    } else if  ( TempValue < -100 ) {
      temperatureArray[id][temperatureIndex] = TempValue; // this saves the value (-127C) for a disconnected Sensor
      ErrorCount++;
      lcd.setCursor(7, 0);
      lcd.print("E");
      // So that the disconnected error checking will trigger and turn the fan on
      //      Serial.println("Really bad sensor value, ie disconnected");
    } else {
      // and this just saves the average back in to the array, so as to not skew the average
      temperatureArray[id][temperatureIndex] = temperatureArray[id][SensorArrySize];
      ErrorCount++;
      lcd.setCursor(7, 0);
      lcd.print("e");
      //      Serial.println("Bad sensor value, saved average back into array");
    }
  } else {
    temperatureArray[id][temperatureIndex] = TempValue; // Store New temperature reading in Array
    //    Serial.println("Good 1st sensor value");
  }
  // ------------------------------------------------------


  // now Reset average number out counter location
  for (byte idx = 0; idx < NumberSensors; ++idx) {
    // Sum all values to last index
    // But 1st reset value to zero
    temperatureArray[id][SensorArrySize] = 0;
  }

  for (byte idx = 0; idx < SensorArrySize; ++idx)  { // Note Less than SensorArrySize
    // Now we Sum all the values into the last index
    temperatureArray[id][SensorArrySize] += temperatureArray[id][idx];
  }

  // Create Average by simply dividing by 5
  temperatureArray[id][SensorArrySize] = (temperatureArray[id][SensorArrySize]) / 5;
  //
  //      Serial.print("Temp ID =>0x");
  //      Serial.println((addr[1]), HEX);

  switch  (addr[1]) {
    // Sensor Ids
    // Ambient   = 10-5A-56-C6-00-08-00-55
    // Heat Sink = 10-59-47-C6-00-08-00-BD

    // New Test Sensors
    // 28-73-81-D0-05-00-00-ED
    // 28-7A-DB-45-92-08-02-AB


    case 0x7A:    // Ambient


      AmbTemp = temperatureArray[id][SensorArrySize];
      if ( millis() > minmaxtimeout ) {  // Dont write initial temperatures into min/max value,.. allow timeout bafore saving
        if ( AmbTemp < minAmb ) {
          minAmb = AmbTemp;
        }
        if ( AmbTemp > maxAmb ) {
          maxAmb = AmbTemp;
        }
      }

      //      Serial.print("Ambient Temp =>");
      //      Serial.println(AmbTemp);
      break;


    case 0x73:    // Heat Sink
      HeatSinkTemp = temperatureArray[id][SensorArrySize];  // SensorArrySize =5
      if ( millis() > minmaxtimeout ) { // Dont write initial temperatures into min/max value,.. allow timeout bafore saving
        if ( HeatSinkTemp < minhtsk ) {
          minhtsk = HeatSinkTemp;
        }
        if ( HeatSinkTemp > maxhtsk ) {
          maxhtsk = HeatSinkTemp;
        }
      }
      //      Serial.print("HeatSinkTemp Temp =>");
      //      Serial.println(HeatSinkTemp);
      break;
  }


  //  Serial.print("Average =>");
  //  Serial.println(temperatureArray[id][SensorArrySize]);


#ifdef LongPrint
  // ----------------------------------
  // Long printout
  Serial.print("temperature Array ");

  for (byte idx = 0; idx < SensorArrySize + 1; ++idx)   {
    if ( idx == 0 && id == 0 ) {
      Serial.print("Ambient  -0->");
    } else if ( idx == 0 && id == 1 ) {
      Serial.print("Heatsink -1->");
    }

    Serial.print(idx);
    if ( idx == temperatureIndex ) {
      Serial.print("-> Indx Pnt->");
    } else {
      Serial.print("-> ");
    }
    Serial.print(temperatureArray[id][idx]);
    if ( idx < SensorArrySize ) {
      Serial.print("<,  ");
    } else {
      Serial.print("<  ");
    }
  }
  Serial.println(F("last Num is Average"));
  // -----------------------------------

#endif
  digitalWrite(LedFlash, LOW );
}

// ----------------------------------------------------------------
// function to print a device address
void printAddress(DeviceAddress deviceAddress) {
  for (uint8_t i = 0; i < 8; i++) {
    // zero pad the address if necessary
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
    if ( i < 7 ) {
      Serial.print("-");
    }
  }
  Serial.println("");
}
// **********************************************************************

complete.ino (39.7 KB)

Welcome back.
Moved you to project guidance and posted your code for you as it may get you some better results.

As separate files might have been a bit easier.
Also the excessive amount of comments make it a little harder.

If a variable is modified inside an ISR and read outside of it or vice versa, it needs to be declared 'volatile'

Didn't find the reading procedure for it.
The combination of swSerial and the external and an extra timer interrupt are probably going to influence each other, but i doubt this is the issue you experience.

Which variables are you taking about here ?
No offence, but how about sorting your (global) variables a bit more by type, and putting all your defines in one place and have definitions in 'ALL_CAPITALS' So it becomes a bit easier to find which constants are used.
If you think the addresses may get written over, then you declare them as 'const' But if that is because you are writing beyond the size of a different 'global' array, that will just result something else being written over.
If you can clean up your code and point to where you think the issue is then maybe there is something to be found.
So Remove excess comments, and preferably comment on the same line to the code.
Remove excess empty lines. remove any code that is commented out. If it is not being executed, it is not part of the issue, but it is causing a lack of overview.
Split the code up again and put it separately in </> code-tags
Your loop() function is way to big ! a significant part should be moved into a function.

Sounds like a memory issue, but where to even look.

...and if it cannot be accessed atomically, ie if it is a multibyte variable, like an "int", it must be copied with interrupts disabled in non-interrupt context

OK Guys,... tx for the input,.. ( i can take it :grinning:),, some useful stuff that I will need to get my head around,.. tidying up my code,.. and accessing variables updated within ISR,...
As you say there is a lot of unnecessary commented code,.. not needed for sure as there were used as the project developed over time,.. so this code can go..
One final thought,.. is 1k of free memory, ( when compiled ) a reasonable amount of free memory to run with....
rgds

Should be easily enough, if it is half of what you start out with, that can hardly be the issue. Of course local variables do take some space, but it should be enough.

Is this a wild guess, or do you have specific indications that this might be the problem? If not, it could be just about anything directly related to the sensors or not even that.

In general with DS18B20 sensors I'd suggest not querying their addresses at all, but simply hardcoding them or storing them in a configuration file/EEPROM if you desire. After all, the sensor addresses aren't going to change unless you swap out a sensor. The temperature readout works MUCH faster if you supply a specific address instead of reading by index.

Moreover, the OneWire interface is kind of iffy on an Arduino without hardware support for it. Its timings are pretty critical and it all has to be fashioned in software. Interrupts occurring during OneWire transactions can easily spoil the broth, and it looks like you've got a whole slew of them active at all times. When doing OneWire transactions, I'd suggest to stop all other communications to the outside world first, perform a Serial.flush() to prevent hardware Serial to interrupt your process and essentially ensure that the Nano is dedicated to the single task of doing the OneWire thing.

Of course, all this only helps if the problem is indeed directly related to the sensor readout. If it's caused by, as you suggest, an array going out of bounds or something like that, all bets are off again.

tx for comments feedback guys,.... its good to have you thoughts etc,...
I am now heading a direction to hard code the Sensor addresses, rather than a search,... also to drop the resolution,.. as this will make transmission quicker, as at 12 bit res,.. data takes just under a second to receive... so plenty of time to mess any serial comms up and vise-versa.
Also looked at my serial Bluetooth input,.. and tidied up the receive routine, with some overflow checks, as well as checking and extending some other strings with checks,.. which may be overflowing.
If I use Serial.flush(),.. how does this help,.. and if I turn of Interrupts does this kill the DS18B20 temperature reads,.. How does the nano derive its timings for temperature reads,..
As I know there are many house keeping activities going on in the background that are,.. sort of out of normal scope.
Now Just waiting for the weather to cool down,.. as system is still cooling,.. albeit in a limped mode,.. ( knocks 15C or so of the running temp of router heatsink during this period of UK heatwave ).. So not worth messing with ATM.

It should be far shorter with direct addressing. I can do a full bus search with 5 devices on the bus and a readout in less than 1000ms IIRC.

It prevents serial transfers to mess up timings during OneWire transactions. It's usually not necessary with DS18B20s but I ran into trouble with this with home-made OneWire devices.

No, the library you use for the sensors is not interrupt driven.

OK,.. The story so far,... Since my last post,. I have implemented many of the suggestions in this thread,.. To this end I have included my source files,.. Should anyone wish to review/copy.

However, having implemented the s/w changes,.. improved the code in places, etc,.. I reached a point where the nano would just no update,.. having tried all avenues,.. I conceded I would have to change the nano,.. as it has probably lost its boot loader,.. although the last version of program still continued to execute.
So reluctantly I set about replacing the nano,... and rather than go for a resource stretched nano board I decided to fit/install a small footprint mega... and fix two birds with one stone,.. new board and new processing/resource power.

With new board installed,.. reassigned pins as pin don't necessarily translate directly,.. (note software serial and available/usable pins ). The project is now up and running, and keeping my pfsense box nice and cool.

The DS18B20 failed reads no longer happen, Zero fails in 48hrs. BTooth comms is much better so win win.

It would seem that one 1k of free memory was not enough here,.. I guess I was using too many subroutines etc,.. for the available memory, and I was probably stretching the power/resources of a nano.
As for the old nano,.. with no wires attached, and connected via single USB cable,.. it still cannot be programmed.

Tx to folks for their input,.. and suggestions

ReadAnaloguePins.ino (702 Bytes)
FanCtrlV10-3.ino (2.4 KB)
Init_Defines.h (4.5 KB)
DisplayUp.ino (5.0 KB)
FanCntrl.ino (5.4 KB)
OneSecondCHK.ino (1.9 KB)
Read_Temps.ino (5.7 KB)
Setup.ino (3.3 KB)
BlutoothComs.ino (9.0 KB)

It would seem my new found confidence with the updated code and better h/w was a little premature,...
Although the system runs more reliably,.. temperature measurements eventually seem to get corrupted,.. and throw things into disarray.
Maybe 1k of memory is enough,... I suspect,.. I am overwriting the length of a defined char array someone where,.. its just a case of finding out where, and why.

Question re Library behaviour,.. when the int array for a probe address is defined at start,... does the program system ever refresh this array,... or is it as I assume, 'set once, read many'.
are there any thing I can do to improve temperature acquisition,.. and prevent false reads.

I have stopped serial reads from Blu-tooth when nothing attached/paired,.. as i assume the HC06 handles the blutooth pairing,.. and once a device is connected,.. that is when the state pin changes state/polarity.

Rgds

The story continues,... having purchased a USB extender over CAT5,.. I was/am able to debug and upload whilst unit is installed and running.
So,.. I discovered my 'rpm sums' were not working,.. and after some investigation I found this is a compiler 'gotcha',.. for the unwary, like myself, I am now wiser....
For anyone wondering what I am referring to pls see this resource that I found that 'spread enlightenment'.

https://www.baldengineer.com/arduino-math-fixes.html

The upshot of these 'sums' failing was that silly over flow results would mess-up string conversions, and I believe would trash data for reading the sensors... leading to read errors.

I am still doing some more code refining,... tidying things up etc,... but so far code is much more reliable.

Without digging through your code, could you share the equations that are problematic ?
Casting can be so important, even (and maybe more so) when multiplying constants.
The link you shared, makes clear that on an 8-bit AVR the 'default' type in which the calculation is performed is a 'signed 16-bit' integer (on an ESP this is signed 32-bit) unless the variable is of a different type.

This is the code I currently use to evaluate rpm fan speed....

void EvaluateFanSpeed() {

  if ( Dcycle > 14 ) {
    // --------Start Interupt Count----------------
    Rpm_Count = 0;
    time_millis_now = millis(); // Start milliSecond timer for fan interupts
    attachInterrupt(digitalPinToInterrupt(interruptPin), FANrpmISR, RISING);
    //    time_micros_1st = micros();
    while (millis() < time_millis_now + 800) {
      //wait approx. [800] ms
    }
    detachInterrupt(digitalPinToInterrupt(interruptPin));
    // --------end Interupt Count----------------

    if ( Rpm_Count > 1 ) {
      unsigned long Z1 = ( Rpm_Count - 1 ) / 2;
      float Z3 = (float)Z1;
      float Z4 = ( Z3 / 0.80 ) * 60.00 ;  // 800mS, Seconds to Minutes

      // https://www.baldengineer.com/arduino-math-fixes.html
      rpm = (int)Z4 ;
      Serial.print("After Sums>");
      Serial.println(rpm);
    }
  } else {
    rpm = 0;
    Serial.print("After No-Duty >");
  }
  Serial.print("%");
  Serial.println(rpm);
}
FANrpmISR() { Rpm_Count++ }

At low rpm,.. around 1200rpm driven by a duty cycle of 20%,.. calculations are fine,.. and I can actually measure the rpm,.. to get a similar result,.. so good!!.
However at high rpm,... where the fan is generating lots of interrupts,.. well more than it should,... things understandably got to pot.
with a 90% duty cycle,.. fan speed can be measured at slightly less than 3000rpm,.. however my system read more than 4400 interrupts equating to approx,. 2200 revs/sec.. and 132Krpm,.. which is just rubbish.
I have included a small amount of decoupling on the tacho input,... but this does not seem to filter out some erroneous interrupt count, which in turn creates a string conversion error.
Anyone have any thoughts as to why I get so many interrupts?
Am I missing some other little 'gotcha'...

Many tx

Well the variable declarations are missing (and relevant)
please include declarations for Rpm_Count.
There doesn't seem to be anything wrong with your calculation, though i think i would do the whole thing in integer.

rpm = (uint32_t) (Rpm-Count - 1)  * 30 ; 

and simply increase the measuring time to 1000ms

On first glance this :

while (millis() < time_millis_now + 800) 

Is going to cause an issue after 50 days (it should be millis() - time_millis_now < 800 )
Not the issue at hand of course.

For that we need to see the hardware setup. Please provide a schematic (not Fritzing)

Many tx for the feedback,.. Ah sorry for not sharing declarations,..

unsigned int rpm;

I see what your saying about increasing the time,.. and I can see that will save code wrt float and int,... I think I may increase the step time as such to 1.5second increment.... So time enough to perform fan timings as well as read temperatures,.. ( which can take up to a second).
Have implemented the millis() change,.. I assume that works as the bits roll-round when the subtraction is effected,.. as the millis() counter 'counts over to zero'.
As for interrupts I can only think there is 'noise',.. on the input causing the silly numbers... What is the schematic tool of choice,.. as I to find fritz'ing a bit of a pain... as i to like to see a good ol' schematic to read.
Rgds

My thought exactly, hence the request. What is the mode of interruptPin

Pen and paper are an option, personally i use WindowsXP paint, icm with a bunch of bitmaps.

It is Rpm-Count that i need to see.

There is also the issue of you turning the interrupt on & off like that, which may not always quite work the way one expects . It should work the way you do it, but there are some details. you should not be attaching and detaching, but leaving it attached, but just disable and re-enable it.
this thread deals with that, but if processing time is not much of an issue, a simpler solution would be to

FANrpmISR() { 
if (isrEN) Rpm_Count++;  // what happened to the semicolon here in your code ?
 }

which has the ISR running all the time, but just disables the count. That does slow your processor down a bit of course, when the fan is running.

Ah tx for the feedback,.. Let me read and digest the ISR stuff,..

int Rpm_Count = 0;

I figured an 'int' type count would be sufficient for my rpm calculations...
rgds

But it should be declared 'volatile'

volatile int Rpm_Count = 0;

for a variable that is modified and or read, both in and out of the ISR.
The other issue is that int is a 2 byte variable, which theoretically could be modified while it is being used outside of the interrupt, but in your case that is not really possible.

Ok,.. So the story so far,... back to the hardware design to review the tacho signal,... I am lucky in that I own a scope so am able to look a what is going on. In my initial design I had designed the input signal to the Arduino port to max out at 3.3v.... When I looked at the signal on the scope


I realised the was a lot of noise, on the top part of the square wave and further analysis of this noise ( which had a rep. rate around 100Khz ), which I assumed to be the switching frequency of my power supply. So all I had to do was reduce this noise spike,... this I did with a 100pf ceramic capacitor. I also reviewed the spec for the arduino input,.. to see where the threshold/transistions occurred, and then realised the error of my assumptions etc etc... arduino input are designed for 5volts,.. although the HC-06 bluetooth device is 3.3volts on its inputs.
So a redesign of the divider network from the (open-Collector) Fan_tacho output, lead me to the following circuit design.
Tacho input
For reference, the interrupt input is the same as the tacho signal,.. ( i just cannot give the same net two names (obviously).
Ironiclly I found this simple circuit with just 2 resistors gave the desired result, When the Tacho out from fan was open circuit,.. I got very close to 5volts, and been an open collector output,.. went to near ground when active, I may add a 4.7volt zener across the capacitors to ensure no over voltage reaches the arduino input, but so far ( after one week ), the system has been run continuously with no bad temperatures returned. even with the occasional bluetooth connection to see all is well.
So in summary:
My Fundamental problem was a low threshold setting for the tach/ rpm count signal,.. which meant the arduino was sometimes counting the SMPS switching frequency,.. which when multiplied up etc,.. overflowed data typed allocated,.. and totally blew their conversion to string.... which is what I believe was corrupting my temperature readings.
I have yet to implement the 'if (isrEN) rpm_count++' within my ISR,.. so may come back an checkin before I let the thread be archived.
Thanks for the help pointers.
Rgds