WiFi Bamboo Bathroom Scale

Records weight online via MQTT. Displays time, date, inside temp, outside temp data received from a second existing controller.

Similar projects worth following
Repeatability and accuracy of the old scale is very poor. Around 1 or 2 lbs. Resolution is also only 0.5 lbs so I decided to make a better one that includes automatic recording to a graph in the cloud. It's repeatable to within 0.1 lb. Returning to exactly zero is not a problem at all either. Impressive. It's calibrated with my weight using the doctor's scale.
It's made from a $4, nice looking, warm on the feet, dollar store bamboo cutting board. The slot for the display already existed.
I used a bright, hi-res OLED display instead of a low-res LCD. The onboard NodeMCU blue LED is used as a night light under the scale. A photoresistor in a voltage divider circuit connected to analog input AO is used to turn on or off the night light and also initiates the OLED display routine when the bathroom light is turned on in the morning. OLED display turns off when it times out or bathroom light turned off. A USB charger is used instead of batteries to power it.

Records weight in the morning with MQTT if weight measurement  above a threshold and exactly the same for 2.0 secs after adding 0.05 and then truncating digits to the right of 0.1 lb. Displays recorded weight then "Sent" when conditions met. 

I highly recommend Adafruit MQTT for an HMI including remote recording. I use the free version. Once you get the hang of it it's very quick and easy compared to creating a local only web  page hosted on the device. I often do both.

I also record temp and humidity outside, upstairs and in the basement every minute. This is useful when we are away so I can check the furnace is operating OK.

Remember to check your weight under exactly the same conditions. Just the liquid in a cup of coffee is 0.6 lbs.

Total cost of components  is around $20.

I followed this website and video for the wiring.

For NodeMCU I used D6 and D7.

For programming I just added the HX711_basic_example applicable code to my typical NodeMCU program.

I created an equation to correct for the zero offset and scale to read in pounds. It reads -548448 unloaded. Varies a bit during the year.  NodeMCU is 32 bit so big  numbers are no problem.

    weightlbsraw = scale.read_average(20); // average 20 readings
    weightlbs = (548358 + weightlbsraw)/9431.7; // equation in my case - unloaded zero offset is first raw number 

It updates the unloaded zero offset (tare function) at 4 a.m. every day to counter any drift. That doesn't seem to be necessary so far but humidity changes over the year may affect the weight of the wood a bit.

 I mounted the load cells on rings of 0.2" plywood to allow the center to flex. 2.25" OD 1" ID. Cut with hole saws. Assembled with hot glue.

Small squares of plywood siliconed to the center of the load cell for mounting feet. A thin layer of silicone makes them anti-skid. The rings and feet raise the board enough to get all the components underneath as shown. Same total height as the old scale. 1.25". The rings are mounted inboard so it looks like the board is floating.

I usually use a free, zero I/O, colourful hi-res web page for the HMI but in this case the project needed a local display as well.

I used a $6 hi-res very bright OLED SSD1306 128X32 display. This is a small 0.91" display so to make it readable from 6 ft I used the largest font. Large OLED displays would be even better but they are not inexpensive. Dark 1.0 mm lexan is used in front of the display and dark foam rubber behind it. This hides the board except for the OLED display. When it's off all you see is black. The lexan is inset into the slot so you don't see the edges.

Make sure and use the u8g2 library not Adafruit and the u8g2_font_logisoso32_tr for a large, hi-res, smooth font.

Typical display commands to print " Inside".

  u8g2.clearBuffer();          // clear the internal memory
  u8g2.setFont(u8g2_font_logisoso32_tr); // choose a suitable font
  u8g2.drawStr(0,32," Inside");  // write something to the internal memory
  u8g2.sendBuffer();          // transfer internal memory to the display

I followed this video:

I have 9 NodeMCU controllers doing various home automation tasks and saving $1,000+/year. So far they all have a battery backed DS3231 real time clock that is set to internet time at 3 am to maintain accuracy and correct for daylight savings time or standard time.

This time I used ESP-NOW to send time, date, inside temp and outside temp directly from another NodeMCU instead. Sending data this way does not use the router. I will use this method from now on.

Details on ESP-Now are here.

Read more »

MPEG-4 Video - 16.63 MB - 10/04/2021 at 18:21


night light and display.MP4

Photoresistor used to turn ON or OFF built in blue LED night light or initiate display routine.

MPEG-4 Video - 17.68 MB - 10/04/2021 at 18:20


  • Record weight to EEPROM

    nodemcu12ecanada07/23/2022 at 00:37 0 comments

    On a power failure the recorded weight and zero offset was lost or defaulted to an old value put in the program.

    To prevent this it now reads the previous weight and zero offset stored in the EEPROM on boot only.

    NodeMCU "EEPROM" is actually flash memory configured to act like an EEPROM. Flash memory has a limited number of cycles for writing.

    Writing is only guaranteed for 10,000 cycles so only write when needed. In this case only once per day. 

    It may or may not last 100,000 cycles or more.

    The float weightrecord value is broken into two 8 bit integers to be stored. One value to the left of the decimal point and the other to the right. After the values are read they are combined back to a float value as shown.

    In the setup I added:


            epromrd1 =; // read previous weight stored in EEPROM on boot
            epromrd2 =; 
            weightrecord = (epromrd1*10.0 + epromrd2)/10.0; // calculate weightrecord from EEPROM on boot

    In the loop I added EEPROM.write commands  

    New weightrecord written to EEPROM once between 5 and 9 am if above 165 lbs (me). 

        if((hr==4)&&(mn==0)){  // set save and read bits once a day at 4 a.m.
          savebit = 1;
          readbit = 1;

      if ((hr>4)&&(hr<9)&&(weightlbsdisplay > 165.0)){ 
            weightrecord = weightlbsdisplay;

             epromwt1 = weightrecord; // break weightrecord into before and after decimal integers, 
             epromwt2 = (weightrecord*10) - (epromwt1*10);
             if (savebit == 1){ // save weightrecord to EEPROM reads on boot so latest weight not lost on power failure
              EEPROM.commit(); // copy entire contents to EEPROM, only writes if data is different

    Similar additions were made for saving and reading the zero offset.

    The 548503 or thereabouts zero offset is broken into three 8-bit numbers. 54, 85, 03 for EEPROM storage. 

    255 is the max number stored in an EEPROM memory location. Up to 512 memory locations.

    For more info about using the EEPROM commands with NodeMCU or ESP32 go to:

View project log

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates