/* lp_BLE_Temp_uC (c)2022 Forward Computing and Control Pty. Ltd. This code is not warranted to be fit for any purpose. You may only use it at your own risk. This code may be freely used for both private and commercial use Provide this copyright is maintained. */ const char LOCAL_NAME[] = "T_1"; // say T_.. for Temp(C) sensors, H_.. for Temp(C),Humditiy(%) sensors, W_.. for Temp(C),Humdity(%),Barometer(hPa) sensors, WL_.. for Temp(C),Humdity(%),Barometer(hPa),Lux level(Lux) // keep this LOCAL_NAME short as it uses up available advertising data space (see below) // Format of advertized name // For T_.. devices LOCAL_NAME,degC // For H_.. devices LOCAL_NAME,degC,%RH // For W_.. devices LOCAL_NAME,degC,%RH,hPa // For WL_.. devices LOCAL_NAME,degC,%RH,hPa,Lux #include "SafeString.h" #include "BLEPeripheral.h" // Supply Capacitor Selection // ----------------------------- // For Advertising pulses (~12mA with no DC/DC converter fitted to the module) // No additional supply capacitors (just the 4.7uF on the module) => 0.785V peak with a 300 ohms source resistor and 0.665V with 150 ohms source resistor // The Nordic reference schematics for nRF52832 modules all include a 4.7uF supply capacitor which should already be included on the module // Other options with additioal supply capacitors added // 1 x 22uF 16V ceramic supply capacitor => 0.430V peak with 300 ohm source resistor and 0.400V with 150 ohm source resistor // 2 x 22uF 16V ceramic supply capacitor => 0.300V peak with 300 ohms sourc resistor and 0.285V with 150 ohm source resistor // Typical coin cell source resistance (internal resistance) is initally 10ohm rising to ~140ohms towards end life, for pulse loads, or higher for continual low currents (3uA) // see the charts in https://data.energizer.com/pdfs/lithiumcoin_appman.pdf and https://data.energizer.com/pdfs/cr2032_eu.pdf // so with no additional supply capacitors almost all the capacity of the CR2032 coil cell can be used down to 2.5V (2.5 - 0.75 = 1.75V > nRF52832 drop out voltage) // // Leakage current for 2 x 22uF 16V ceramic capacitors. Using 3M3 resistor measured at 3.423e6 ohms. // Then shunt the resistor with 2 x 22uF cap and wait minutes for the resistance to settle gave 3.38e6 ohms. // i.e. 269M // 3M423 = 3M38 so leakage resistance of 2x22uF caps is ~269M ohms => ~12nA or less leakage at 3.3 volts. i.e negligable // for comparison CR2032 coin cell losses ~1%/year of their capacity. 1% of 235mAH is 2.35mAH over 8760hrs/year => 269nA (0.27uA) battery internal leakage current. // Current consumption for this sketch see BLE_ADVERT_MS and BLE_NO_ADVERT_MS settings below // ----------------------------------- // Crystal LowFreq clock: no advertising but still running 6.64mV => ~2.66uA // RC LowFreq clock: no advertising but still running 11mV => ~4.4uA i.e. ~2uA more than crystal due to turning on HighFreq clock to recalibrate each 8secs // advertising ~70mV => ~28uA // Battery life for 10sec advert every 100sec // Crystal LowFreq clock: 10sec advert in 100sec => 28*10/100 + 2.66*(100-10)/100 = ~5.2uA for uC using Crystal // RC LowFreq clock: 10sec advert in 100sec => 28*10/100 + 4.4*(100-10)/100 = ~6.76uA for uC using RC // Using a CR2032 235mAh to 2V https://data.energizer.com/pdfs/cr2032_eu.pdf using no extra supply capacitors to handle the Tx current pulses // Crystal LowFreq clock: CR2032 gives 235e-3/5.2e-6 hrs = 45192hrs => 1883 days => ~5years 2months (e.g. GT832E_01 module) // RC LowFreq clock: CR2032 gives 235e-3/6.76e-6 hrs = 34763hrs => 1448 days => ~4years (eg KTBM522 module) // Battery life for 10sec advert every 30sec (i.e. 20sec between adverts blocks) // Crystal LowFreq clock: 10sec advert in 30sec => 28*10/30 + 2.66*(30-10)/30- = ~11.1uA for uC using Crystal // RC LowFreq clock: 10sec advert in 100sec => 28*10/30 + 4.4*(30-10)/30 = ~12.27uA for uC using RC // Using a CR2032 235mAh to 2V https://data.energizer.com/pdfs/cr2032_eu.pdf using no extra supply capacitors to handle the Tx current pulses // Crystal LowFreq clock: CR2032 gives 235e-3/11.1e-6 hrs = 21171hrs => 882 days => ~2years 5months (e.g. GT832E_01 module) // RC LowFreq clock: CR2032 gives 235e-3/12.27e-6 hrs = 19152hrs => 798 days => ~2years 2months (eg KTBM522 module) BLEPeripheral ble; // BLE_SCAN_DATA_MAX_VALUE_LENGTH == 29 in BLEDeviceLimits.h // to this is added length and type for total of 31 == max advertisize packet size // here we also set flags for not connectable which uses 3 bytes length(1), type(1), flags(1) // so MAX_SCAN_DATA_LEN reduced to 26 const size_t MAX_DATA_LEN = 26; // this can be split between say device NAME and Manufacturing Data // but that uses another two bytes for the length and type bytes for the Manufacturing Data // // For simplicity and readability here all the data is added to the NAME as ascii date comma separated // If using NAME and Manufacturing Data then sending data as binary in Manufacturing Data allows for more data. // // Note could also just have Manfacturing Data with out a device NAME but easier to read data in the name with scanning apps // uncomment this to enable Serial output uses a lot of supply current //#define DEBUG cSF(sfData, MAX_DATA_LEN); // Local name and formatted measurements SafeString will limit data to this length. Excess data is dropped NOT truncated see SafeString docs/tutorials unsigned short ADVERT_INTERVAL = 750; // default it 500, 750ms gives 13 advert packets in the 10 secs lp_timer BLE_Timer; // the advert timer // 10sec advert on 90sec advert off //const unsigned long BLE_ADVERT_MS = 10ul * 1000; // advertise for 10sec at 750ms intervals i.e. ~13 advert packets //const unsigned long BLE_NO_ADVERT_MS = 90ul * 1000; // go silent for 90sec // 10sec advert on 20sec advert off const unsigned long BLE_ADVERT_MS = 10ul * 1000; // advertise for 10sec at 750ms intervals i.e. ~13 advert packets const unsigned long BLE_NO_ADVERT_MS = 20ul * 1000; // go silent for 20sec float chipTemp = 0.0; float T_offset = 0; // to be set in calibration float tempCompensation(float reading) { return reading+T_offset; } // this method set the advertized NAME to include the data comma delimited void setAdvertData() { sfData = LOCAL_NAME; sfData += ','; chipTemp = getChipTemperature(); // -40C to 85C in 0.25degC steps chipTemp = tempCompensation(chipTemp); // add corrections sfData.print(chipTemp,1); // only one decimal place ble.setAdvertisedName(sfData.c_str()); // #ifdef DEBUG Serial.print("set data to "); Serial.println(sfData); #endif } void setup() { #ifdef DEBUG Serial.setPins(30, 29); // Rx 30 == D0, Tx 29 == D1 Serial.begin(115200); Serial.println(); for (int i = 10; i > 0; i--) { Serial.print(' '); Serial.print(i); delay(500); } Serial.println(); #endif // set advertised name ble.setConnectable(false); ble.setTxPower(+4); ble.setAdvertisingInterval(ADVERT_INTERVAL); setAdvertData(); // sets name and measurement data ble.begin(); #ifdef DEBUG Serial.println(" BLE started"); #endif BLE_Timer.startDelay(BLE_ADVERT_MS * 3, stopAdvert); // initially advertise for 30sec to make it easier to check the unit is running #ifdef DEBUG Serial.println("setup() finished"); #endif } void stopAdvert() { ble.end(); #ifdef DEBUG Serial.print("stop ble "); Serial.println(millis()); #endif BLE_Timer.startDelay(BLE_NO_ADVERT_MS, restartAdvert); //wait 90sec before restarting } void restartAdvert() { setAdvertData(); // pick up latest values ble.begin(); #ifdef DEBUG Serial.print("start ble ");; Serial.println(millis()); #endif BLE_Timer.startDelay(BLE_ADVERT_MS, stopAdvert); // stop in 10sec } void loop() { sleep(); // just sleep here waiting for the timer to trigger }