Home | pfodApps/pfodDevices | WebStringTemplates | Java/J2EE | Unix | Torches | Superannuation | CRPS Treatment | | About Us

Forward Logo (image)      

BLE Low Power Indoor/Outdoor Weather Station
Sensors run for 4 1/2 Years on Coin cell

by Matthew Ford 13th Apr 2024 (originally posted 20th May 2022)
© Forward Computing and Control Pty. Ltd. NSW Australia
All rights reserved.

Indoor/Outdoor Weather Station – Rev 2a
using Simple, Very Low Power, BLE Sensors

Update 13th Apr 2024 – added code for VLEM7700 version of sensor
Update 23rd Sept 2023 – added note about cutting I2C pullups pad on VLEM7700
Update 16
th Jan 2023 – added high/low temperature comments
Update 14
th Jan 2023 – installing ESP32 V2.0.6 board support seems to fix the previous problems with Adafruit QT Py ESP32-C3)
Update 5
th November 2022 – Rev 2a added connection timeout
Update 6
th August 2022 – Rev 2 added hPa plot and charts and time/date
Update 1
st July 2022 – “Due to reports of Andy OS including an undisclosed cryptocurrency mining software we (CNET) have opted to remove the download link.” Try Bluestack instead.


This indoor/outdoor Weather Station is the third in a series of Very Low Power BLE - 2022 projects. The very low power BLE temperature, relative humidity and barometric pressure sensor is an extension of the Very Simple, Very Low Power BLE Temperature Sensor The BLE sensors operate between -40degC and 85degC, are simple to make and run for ~4 ½ years on a coin cell.

All the display code is in your Arduino sketch, so you can customize the display as you wish, such as changing temperature range to suit your locality (see the Sketch Configurations section below) and changing the colours to suit your taste. pfodApp has been under continual development for over 10 years and the current version runs on Android mobiles 8 years old, so you can use one of your discarded mobiles for this weather station display or you can buy an inexpensive second hand out of date tablet.

This revision 2 simplifies the BLE to WiFi bridge to just one less expensive board (ESP32-C3), no wiring needed. Revision 1 of the project is here. It also adds a hPa plot, time and date and a chart button to display the last 36 hrs of temperature, RH and hPa. (Code is also included to update the previous BLE-WiFi hardware) This project uses pfodApp to display the weather station on an Android mobile.

The project consists if 3 parts:-
1) the Weather Station display.
2) the BLE to WiFi bridge (ESP32-C3)
3) the Very Low Power BLE sensors


The Weather Station Display and BLE to WiFi Bridge
    The Display Gauges
The Very Low Power BLE Sensors
    Component Selection and Construction

Outline of the Project parts

The Weather Station Display

There are a number of options for the Weather Station Display :-

In this project, pfodApp will be used to display the Weather Station. pfodApp keeps all the display code in your Arduino sketch. No Android coding is required. Once you design the graphical gauges (see Custom Arduino Controls for Android), you can easily position and scale them on the screen. Since all the code is in your Arduino sketch you can modify the Weather Station display as you require. pfodApp also simplifies plotting. Revision 2 adds a chart button to open a chart page with the last 36hrs of measurements. You can zoom the plots using two finger pinch/spread.

You will know when you have the display/gauges setup correctly when other household members complain when the Weather Station is not running.

The BLE to WiFi bridge

To connect the BLE sensors to the Weather Station a BLE to WiFi bridge is used. Revision 1 use the simple hardware from Simple WiFi to Bluetooth Low Energy (BLE) Bridge and programs it to work as a BLE to WiFi bridge instead. This Revision 2 uses the cheaper ESP32-C3 single board to handle both the BLE and WiFi connections

The Very Low Power BLE Sensor

There are a number of options for the BLE sensors. This project covers a simple temperature sensor, a temperature + relative humidity + barometric pressure sensor and a a temperature + relative humidity + barometric pressure + light level sensor. Each of these sensors are simple to construct and will run for four (4) years on a CR2032 coin cell. You can read multiple sensors with the one BLE to WiFi bridge and you can read the same sensor with multiple BLE to WiFi bridges.

Failures at High and Low Temperatures

At temperatures below -5degC a user has reported run times of less than 2hrs for the temperature sensor running on a CR2032 coin cell. His solutions was to use 2xAA alkaline batteries instead.
At temperatures above 30degC with direct summer sun on the plastic box housing the ES32-C3 (BLE to WiFi bridge), the ESP32-C3 would reboot. The solution was to a) reposition the box out of the sun and b) add vent holes at each end of the box to allow circulation of air over the ESP32-C3 module.

Components Used

This project used the following parts :-

The Display
An old Nexus 7 tablet (2015) API V5.1.1 and USB supply and cable
pfodApp ~US$8.50

BLE to WiFi Bridge
ESP32-C3 Mini Development Board – ~US$9 https://www.sparkfun.com/products/18036
(Update 14
th Jan 2023 – installing ESP32 V2.0.6 board support seems to fix the previous problems with Adafruit QT Py ESP32-C3)
USB power supply (500mA or more)~US$6 https://www.sparkfun.com/products/12890 OR ~US$7 https://www.adafruit.com/product/1994 OR similar
USB A to Micro B cable~US$2 https://www.sparkfun.com/products/13244 (6 inches long) OR similar

The Very Low Power BLE Sensors
2 x GT832E_01 ~US$15.90 each, mounted on vero board
2 x Sparkfun BME280 board ~US$21.50 each
2 x Sparkfun coin cell holder PRT-00783 US$1.60 each and
2 x CR2032 coin cell PRT-00338 ~US$2.10 each
1 x programmer MuseLab, CMSIS-DAP (~US$9)
Optional -- 1 x Sparkfun VELM7700 (~US$6 and 10 x 22uF capacitors 445-173294-1-ND ~US$10 for 10 off

Arduino Librariesinstall the latest versions
ESPAutoWiFiConfig (prompts to install SafeString as well) – available from the Arduino Library manager or as zip files
pfodParser – available from the Arduino Library manager or as zip files
SparkFun_BME280_Arduino_Library-master.zip (local copy here) – install using Arduino Menu Sketch → Include Library → Add Zip file..
Very Low Power BLE board support as documented here.

Arduino Weather Station Sketch Rev 2
for ESP32-C3 ESP32C3_WeatherStation_Rev2a.zip
for ESP8266 (Rev 1 hardware) ESP8266_WeatherStation_Rev2a.zip

Hook up wire and vero board and plastic sheet/cases

The Weather Station Display and BLE to WiFi Bridge

Programming the ESP32-C3

To set up to program the ESP32-C3 see the instructions on Single Board BLE to WiFi Bridge ESP32 C3

The ESP32-C3 handles both the BLE scanning for the sensor broadcasts/advertising AND sets up a WiFi server to serve the Weather Station display and plot data. Unzip ESP32C3_WeatherStation_Rev2a.zip to your Arduino sketch directory (If you are updating Rev 1 ESP8266 hardware use ESP8266_WeatherStation_Rev2a.zip) and program the ESP32-C3.

Note: The program is large and you need to select the Partition Scheme for Huge APP (similarly for the ESP8266 if you are updated Rev 1 hardware)

Sketch Configurations

There are a number of setting to configure in the sketch. The WiFi connection is handled by the ESPAutoWiFiConfig library, so you don't need to specify your WiFi settings see ESP32 / ESP8266 Auto WiFi Config for the details.

The other configurations are:- BLE sensor names to scan for, Degrees C or Degrees F to display, Temperature Range to display, hPa correction to Mean Sea Level (MSL) and the Time Zone.

BLE Sensor Names

The BLE sensor names are set at the top of the display.cpp file. Here the outside sensor has a Lux sensor as well. For just Temp and RH and hPa, W_1, and W_2, would be appropriate.

// These are the names of the BLE devices to listen to
static const char OUTSIDE_DEVICE[] = "WL_1,"; // note the trailing , so T_1, does not match T_11,
static const char INSIDE_DEVICE[] = "W_1,";

These names must match the ones you coded into your BLE sensors. See the Very Low Power Sensors section below.

The ESP32-C3 sketch scans for all BLE devices nearby but filters for the advertised name of the devices it is interested in. The following code, in setup(), specifies which devices are of interest, using the names defined in display.cpp, accessed by the methods getOutsideDevice() and getInsideDevice()

  // add the names we are interested in NOTE the trailing , so that T_1, does not match T_11,
  LastSeen *devicePtr = new LastSeen(getOutsideDevice()); // note MUST use new since pfodLinkedPointerList uses delete when remove() called
  // add other devices here that you want to scan for
  devicePtr = new LastSeen(getInsideDevice());

A Weather sensor (W_1, ) Temperature + RH + hPa, and a Weather + Lux sensor (WL_1, ) are picked up. See Naming Sensors, below, for how the devices are named depending on their capabilities. If you use different sensors with other names you should change the OUTSIDE_DEVICE, INSIDE_DEVICE accordingly. The sketch simply continually scans for BLE devices and checks if their advertised name starts with one of those we are interested in. A linked list is used to hold the names we are interested in as well as when they were last scanned. Once a device of interest has been found further scans of it are ignored for the next 11secs since the sensors only advertise for 10secs every 100secs

Degrees C or Degrees F

Setting Degrees C or Degrees F is done via #define at the top of the display.cpp file. The default is degrees C, un-comment

#define DEGS_F

to get a degrees F display. The sensor measurements are always in degsC and stored in degsC and converted for degs F displays and charts

Temperature Ranges

The range of temperatures on the scales are set by the inside_temp, outside_temp constructors at the top of the display.cpp file. e.g

TempGauge_C inside_temp(&dwgs, false, 0, 35, false); // scale points on right, current temp on left 0 to 35degC range, no labels
TempGauge_C outside_temp(&dwgs, true, 0, 35, false); // scale points on left, current temp on right 0 to 35degC range, no labels

The inside and outside ranges must be set the same as only one scale is drawn for both.

If the temperature exceeds the scale range the correct reading will be displayed at the top or bottom of the scale.
The chart of the previous 36 hrs readings will automagically expand to accommodate higher or lower readings.

There is no configuration for the hPa plot on the main page. The correct current reading is always in red on the right but if the reading exceeds the scale those points are not plotted. Open the last 36hrs chart for all the entire plot.

Barometric Pressure Reading correction to Mean Sea Level

The barometric pressure falls with rising elevation so it is common to apply a correction for the sensor's elevation to reduce the reading to the Mean Sea Level reading. This correction is at the top of the display.cpp file.

float hPaOffset = +7.3; //hPa adjustment for altitude difference

It can be calculated by comparing your reading to that of a nearby meteorological station.

Time Zone

The time zone needs to be set to display the correct time and date taking into account the local timezone and daylight savings (if any). The timezone is set at the top of the ntpSupport.cpp file.

const char* get_ntpSupport_DefaultTZ() {
  return "AEST-10AEDT,M10.1.0,M4.1.0/3";

See see https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv for a list of time zones and their posix_tz strings and see Explanation of TZ strings (local copy here) for how this string is constructed.

Language for Labels

The code uses English language labels for the screen display, but you can edit the code to replace them with your own native language text. pfodApp accepts UTF-8 text. You may be able to just type your native text directly into the Arduino IDE. If not then you can use the UTF8converter1_0_1.jar program from Using Non-ASCII chars in Arduino to convert your text to Octal and then paste that into Arduino

The Display Gauges

The ESP32-C3 is programmed as a pfodDevice to serve up the Weather Station's graphical display to pfodApp on an Android mobile/tablet or PC or Mac running BlueStack. The Weather Station Display in this project is an old Android tablet. pfodApp will run on Android versions back to Lollipop (API 5), Nov 2014, so you probably have an old Android mobile lying around that you can use for the display.

There are lots of options for the layout and gauges used for the Weather Station. See Custom Arduino Controls for Android for a tutorial on creating pfodApp controls in your Arduino sketch. The display.cpp together with the various components in ESP32C3_WeatherStation_Rev2.zip creates the display above. The display refreshes every 20 seconds.

The sensors advertise the readings for 10sec every 100sec. If the ESP32-C3 BLE scanner misses a reading due to interference, out-of-range, low battery, etc then the display will update with the time since the last reading was received e.g. outside WL_1 will update to WL_1 4 mins ago.

The main screen display is a drawing menu item (A) that loads the dwg 'z' (see display.cpp) The dwg loaded consists of a number of sub-elements and an inserted dwg. The entire display is completely controlled by the Arduino's sketch code so you can change it as you wish to your own colours or language.

The Barometric Pressure Plot

The hPa plot on the main screen is coded in hPa_BarGraph.cpp. It differs from the other elements in that it is a separate dwg that is loaded separately from the main screen dwg and then scaled and inserted at the appropriate offset in the main screen dwg.

The sendMainMenu() code creates a dwg menu item (see the free pfodDesigner app for designing menu items) that fills the menu item with dwg 'z'


When pfodApp displays this menu item it automatically sends commands to load the dwg 'z'. Since messages sent to pfodApp are limited to 1024 bytes, the dwg is loaded in several parts. Once loaded the dwg is cached by pfodApp under the parser version number

pfodParser parser("V1");

so that subsequently only the changes need to be sent to update the existing dwg with the latest changes. These updates must be completely contained within a single 1024 byte message. 1024 bytes is not enough to send the various gauge updates AND the updates for the hPa plot. Making the hPa plot a separate dwg 'x' inserted in the main dwgs ('z') avoids this limitation.

In sendDrawing_z4(), the 5th part of dwg 'z', these statements insert the entire 'x' dwg at offset 59,127 with a scaling of times 0.07

  dwgs.pushZero(59, 127, 0.07); 
  dwgs.insertDwg().loadCmd('x').offset(0, 0).send();
  dwgs.popZero(); // undo the previous pushZero 

When pfodApp processes this part of the dwg message it queues commands to load the 'x' dwg and insert it. Again the initial load of 'x' is cached and subsequently only the updates are loaded to update dwg 'x' before inserting it.

Inserting dwgs can also be used to pan and zoom in on just part of a dwg. See Arduino UNO/Mega Starter for an example of zooming.

The Chart Button

The chart button is coded in ChartButton.cpp. The CharButton::draw() method draws the button background and adds a touchZone and a touchAction.

  dwgsPtr->touchZone().cmd(cmd).centered().size(8, 8).send(); 
    dwgsPtr->circle().idx(charCircle_idx).filled().color(dwgsPtr->BLUE).radius(11) // change colour and make larger

When pfodApp process a touchZone, it starts listening for user touches in that area. (The area is automatically enlarged to finger size if too small.) There are various types of touches the pfodApp touchZone can filter for:- TOUCH, finger DOWN, finger DRAG, finger UP, CLICK, PRESS, finger Enters zone, finger Exits zone, finger DOWN then UP and DISABLE. The default is just TOUCH.

See Custom Arduino Controls for Android for a tutorial on TouchZones.

When pfodApp detect the user's touch, it immediately updates the dwg with the update specified in the touchAction. In this case it makes the blue circle into a larger filled circle. At the same time, pfodApp sends the associated menuItem cmd and this touchZone cmd together with the touch co-ordinates and type of touch to the pfodDevice (the ESP32-C3). In the display.cpp, the code in the Arduino sketch, in handle_pfodParser(), processes this press and sends back a message to open the chart screen and start loading the last 36hrs of data.

    } else if ('A' == cmd) { // user pressed menu item that loaded drawing with load cmd 'z'
      byte dwgCmd = parser.parseDwgCmd();  // parse rest of dwgCmd, return first char of active cmd
      if ((dwgCmd == chart_cmd)) { // the click / touch filtering happens in the pfodApp to filter when to send these cmds
        // open plot window and send latest data
        parser.print(F("{=In/Out Temp/RH and Barometric Pressure`"));
        parser.print(ARRAY_SIZE); // plot all the data, default is to only plot last 500
        parser.print(F("~E HH:mm"));
        if (!sending_plotData) {
          parser.print(F("~C")); // clear last plot data
        parser.print(F("|date`0|hPa~1030~950~hPa`3|Temp In~100~30~\342\204\211`1|Temp Out~100~30~\342\204\211`1|RH In~100~0~RH%`2|RH Out~100~0~RH%`2}"));

The data is sent as simple csv (comma separated values) and can be logged to a file by pfodApp for later export and further processing.

Inside/Outside Temperatures

This display is a combination of two deg C gauges with labels suppressed on each gauge and the labels written separately in the middle.

TempGauge_C inside_temp(&dwgs, false, 0, 35, false); // scale points on right, current temp on left  0 to 35degC range, no labels
TempGauge_C outside_temp(&dwgs, true, 0, 35, false); // scale points on left, current temp on right  0 to 35degC range, no labels

The Inside / Outside labels are added separately (see the code in sendDrawing_z2() and sendDrawing_z3() in display.cpp). The temperature gauges include an indicator for the range of temperatures over the last 24hrs. Temp24hrMaxMin.cpp keeps track of the max/min over the last 24hrs.

The Relative Humidity Gauges

The Relative Humidity Gauge code is in rh_Gauge.cpp

The Lux Gauge

There is also a lux gauge, Lux_Gauge.cpp

The outside sensor includes a light sensor. This returns a lux reading. However the outside sensor is placed in the shade to prevent direct sun from effecting the temperature reading. This reduces the lux reading. To compensate for this the code in the display.cpp scales the reading by x 2 before storing it for display. This factor was estimated from another VEML7700 sensor in full sun. For the next project ,which intends to use the lux reading to turn the hall night lights on and off, the actual true lx value is not important as the switching set point can be set as necessary, however the x 2 factor gives a “Sunset” reading at sunset.

The Very Low Power BLE Sensors

Component Selection

The two basic components are a nRF52832 'bare' module and a coin cell (in a holder).

The following nRF52832 'bare' modules available from Aliexpress can be used. They include:-
GT832E_01 ~US$15.90 mounts on vero board
Jessinie XL52832-D01 nRF52832 module ~US4.90 and Jessinie Test Board Adapter Plate for NRF52832 ~US$1.70 – Total ~US$5.60
BLM-KTB522 ~US$6.30 (no crystal) pin for pin replacement for Skylab SKB369, needs to be mounted on a PCB

Those 'bare' nRF52832 do not have any extra components or power regulators that will used extra current.

Add to this a CR2032 coin cell and holder, e.g.
Sparkfun coin cell holder PRT-00783 US$1.60 and CR2032 coin cell PRT-00338 ~US$2.10 – Total US$3.70

So using the Jessinie module and adapter and a coin cell and holder the total cost (excluding shipping) is < US$10

A Simple BLE Temp Sensor for Beginners shows you how to use just these two components to get a usable BLE temperature sensor.
For the relative humidity and barometric pressure, you need to add a Sparkfun BME280 board (~US$21.50) Adding this very low power board gives about 4 and a half years of run time on a CR2032 coin cell. It also avoids the time consuming temperature calibration so you may choose to used it just for the temperature sensor also.
This project also includes a light sensor, Sparkfun VELM7700 (~US$6) . Sparkfun VELM6030 (~US$6) also looks suitable, but was not tested. Because the light sensor only works down to 2.5V, you do cannot access the full capacity of the coin cell (down to 2V). This reduces the run time to about 3 and a quarter years.

Note: the Adafruit versions of these boards Adafruit BME280 and Adafruit VEML7700 Lux Sensor are NOT suitable, because they include additional components that increase the supply current.


The WL_1 sensor, which includes a temperature, relative humidity, barometric pressure and light sensor, is placed outside and the W_1 sensor, without the light sensor, is used inside. If you don't want the light sensor, use the simpler W_.. sensor (see below) and modify the Weather Station Bridge code (below) to filter for W_.., instead of WL_1, e.g filter for W_2, for example if the sensor's name is W_2,

Naming Sensors

Since these sensors are so simple and inexpensive to make, you may well end up with a number of them advertising the temperature and/or other measurements, from various locations. To distinguish between them, the lp_BLE_Temp_uC.ino sketch uses the following convention. The temperature sensors advertised name starts with T_ followed by a number, e.g T_1, followed by a comma and the temperature value. This design will also be the basis for other sensors which add a very low power, temperature/humidity sensor or a temperature/humidity/barometric pressure sensor and/or a lux sensor.

This project used the following name format

Format of advertised name, e.g. T_5,25.5
LOCAL_NAME prefix T_.. devices LOCAL_NAME,degC
LOCAL_NAME prefix H_.. devices LOCAL_NAME,degC,%RH
LOCAL_NAME prefix W_.. devices LOCAL_NAME,degC,%RH,hPa
LOCAL_NAME prefix WL_.. devices LOCAL_NAME,degC,%RH,hPa,Lux

Set LOCAL_NAME, at the top of the sensor sketches and then use the prefix to parse the advertised data.

Sensor Construction

Follow the instructions in Easy Very Low Power BLE in Arduino -- Part 1 2022 to setup the Very Low Power BLE support for nRF52832 boards and programmers.

T_1 – Temperature Sensor

The construction and calibration of the T_1 sensor is described in Simple BLE Temp Sensor for Beginners. Because the nRF52832 on-board temperature measurement is not very accurate, the T_1 sensor requires calibration before use.
After determining the calibration correction the nRF52832 is programmed with the lp_BLE_Temp_uC.ino sketch. This sketch only has constant correction. You may need a formula as described Multi-point Calibration . The sketch is set to advertise for 10 secs every 100sec and T_1 should run for about 5 years on a CR2032 cell.

W_1 – Temperature, Humidity and Barometric Pressure Sensor

To avoid doing a multi-point calibration, you can instead fit a Sparkfun BME280 temperature, humidity and barometric pressure sensor. Again the circuit is trivial (pdf version)
If you don't need the sensor including the light sensor, WL_1, below, then this sensor can be used outside as well, but with a different LOCAL_NAME, say W_2

This sensor, named W_1, is programmed with the lp_BLE_GT832E_01_BME.ino sketch. Unzip lp_BLE_GT832E_01_BME.zip to your Arduino sketch directory.
This sensor will run for about 4 ½ years on a CR2032 coin cell.

WL_1 – Temperature, Humidity Sensor, Barometric Pressure and Lux level Sensor

In preparation for a future project that will turn the hall night lights on at sunset and off at sunrise, the outside sensor used here for the Weather Station includes a light sensor, SparkFun VEML7700. Note: Cut the I2C tracks on the back of VEML7700 to disconnect the two pullup resistors. The BMD280 provides the I2C pullups.

Unzip lp_BLE_GT832E_01_BME_Lux.zip to your Arduino sketch directory.

The VEML7700 light sensor has a minimum operating voltage of 2.5V. The 10 off, 22uF 16V ceramic capacitors supply the pulses of current the VEML7700 needs as the coin cell's voltage falls and its internal resistance increases. However even with these capacitors, the 2.5V cut off means a shorter effective operating life from a CR2032 coin cell, approximately 3 ¼ years. This sensor is named WL_1, following the naming convention established above. In the construction the backing plastic was folded over the top of the board to protect against dust etc settling on the circuit. The rest of the cover is open on the other 3 sides. In a more extreme climate, a more protective case would be needed.


This tutorial has presented an Indoor/Outdoor Weather Station using two very simple, very low power BLE temperature/RH/hPa sensors using only three components, a nRF52832 'bare' module a temperature/RH/hPa sensor and a coin cell. The sensors run for ~4 ½ years a CR2032 coin cell.

The display uses an old Android tablet and pfodApp. The gauges are fully customizable in the Arduino sketch. This Rev 2 add time and date and hPa plot and chart of the previous 36hrs values.

AndroidTM is a trademark of Google Inc. For use of the Arduino name see http://arduino.cc/en/Main/FAQ

The General Purpose Android/Arduino Control App.
pfodDevice™ and pfodApp™ are trade marks of Forward Computing and Control Pty. Ltd.

Forward home page link (image)

Contact Forward Computing and Control by
©Copyright 1996-2024 Forward Computing and Control Pty. Ltd. ACN 003 669 994