Skip to content

chriskoz/BottleScale

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BottleScale

A basic IoT scale that monitors the weight of a gas bottle (e.g. a CO2 tank for a kegerator or aquarium) and reports the current weight and the estimated amount of gas remaining over MQTT.

An ESP8266 reads a set of load cells through an HX711 amplifier, publishes two values to an MQTT broker, and then drops into deep sleep to conserve power. It wakes on a fixed interval, takes a fresh reading, publishes, and sleeps again.

The scale installed under a CO2 bottle in a kegerator

Purpose

  • Continuously track how much CO2 (or any gas) is left in a bottle without manual weighing.
  • Publish readings to a home-automation / dashboard system (Adafruit IO, Mosquitto, Home Assistant, etc.) via MQTT.
  • Spend almost all of its time in ESP8266 deep sleep, so it sips power between readings.

The firmware assumes pounds (lbs). Kilograms work fine too — the calibration factor is just linearly related (1 lb = 0.453592 kg), so pick your unit and set the calibration factor to match.

How it works

On each wake cycle the device:

  1. Boots out of deep sleep and initializes the HX711 scale.
  2. Checks the TARE button:
    • If not pressed, it loads the previously saved zero offset from EEPROM.
    • If pressed, it re-tares the scale (zeroes it) and saves the new offset to EEPROM.
  3. Connects to WiFi (10 checks per attempt, up to 5 attempts), then connects to the MQTT broker (up to MQTT_CONNECT_ATTEMPTS attempts).
  4. Reads the scale, computes estimatedRemaining = FULL_BOTTLE_WEIGHT - currentReading, and publishes both values to their MQTT topics.
  5. Enters deep sleep for SLEEP_TIME seconds (default 15 minutes) and repeats.

If either WiFi or the MQTT broker can't be reached, the device gives up rather than retrying indefinitely: it logs the failure, skips publishing, and goes straight back to sleep to try again on the next cycle. This bounds how long a wake cycle can draw current for when the network is down.

Build photos

Four load cells mounted on the printed scale body around a central HX711 breakout An Adafruit Feather HUZZAH ESP8266 wired inside a printed enclosure, with the tare button on the lid
Scale body — four load cells mounted around the printed disc, wired into the HX711 breakout in the centre. Electronics — Feather HUZZAH ESP8266 in its enclosure. The tare button is mounted on the lid.

The finished enclosure and scale platform installed in the bottom of the kegerator

Installed: the electronics enclosure sits alongside the scale platform, which the CO2 bottle stands on.

Hardware

Component Notes
ESP8266 board e.g. Adafruit Feather HUZZAH with ESP8266. The 3.3 V rail powers the HX711.
HX711 load cell amplifier 24-bit ADC breakout for the load cells. Runs at 2.7 V–5 V, so 3.3 V is fine.
4 × half-bridge load cells The common 50 kg "bathroom scale" type. All four wire together into a single full Wheatstone bridge feeding the HX711 — see wiring.
Tactile push button Momentary button used to trigger a re-tare.
Power source USB (as built). Deep sleep keeps average current low, so battery should be viable — though it hasn't been tested on one.

Deep sleep wiring note: For the ESP8266 to wake itself from ESP.deepSleep(), GPIO16 (D0) must be connected to the RST pin. Without this jumper the device will not wake up after the first sleep.

Load cell wiring

Four half-bridge cells combine into one full bridge. Each cell has three wires (red, black, white). Wire them so that opposite cells form the two halves of the bridge:

Bridge signal HX711 pin
Excitation + E+
Excitation − E−
Signal + A+
Signal − A−

If your readings run backwards (weight increasing reads negative), that's expected and normal — it just means the cells deflect the other way. Use a negative CALIBRATION_FACTOR to correct it rather than rewiring. The default here is -9500 for exactly this reason.

3D-printed enclosure

The scale body — the disc the load cells mount to — lives in hardware/:

  • BottleScale.skp — SketchUp source model (editable).
  • BottleScale.stl — exported mesh, ready to slice and print.

The electronics enclosure shown in the photos is a generic third-party ESP8266 case and is not included in this repo.

Required libraries

Install these through the Arduino Library Manager (or manually):

Library Source
ESP8266 board support (ESP8266WiFi, EEPROM) esp8266/Arduino board package
HX711 bogde/HX711
PubSubClient knolleary/pubsubclient

Pinout

Defined at the top of BottleScale/BottleScale.ino:

Signal ESP8266 GPIO #define
HX711 DOUT (data) GPIO14 DOUT
HX711 SCK / CLK (clock) GPIO12 CLK
TARE button GPIO13 TARE_PIN

The TARE button uses the internal pull-up (INPUT_PULLUP); wire the button between GPIO13 and GND. A HIGH reading means "not pressed" (use the saved offset); pulling the pin LOW by pressing the button triggers a re-tare.

The HX711 also needs power — connect its VCC to the ESP8266 3.3 V pin and GND to ground.

Configuration

Edit the #define values near the top of BottleScale/BottleScale.ino before flashing. The committed file ships with <PLACEHOLDER> values:

Setting Purpose
WIFI_SSID / WIFI_PASSWORD Your WiFi credentials.
MQTT_SERVER / MQTT_PORT MQTT broker address and port (default 1883).
MQTT_USER / MQTT_PASSWORD MQTT broker credentials. Leave as empty strings for an anonymous local broker.
MQTT_TOPIC_SCALE_READING Topic for the raw weight reading.
MQTT_TOPIC_EST_REMAINING Topic for the estimated gas remaining.
MQTT_CONNECT_ATTEMPTS How many times to try the broker before giving up and sleeping (default 5, 2 s apart).
CALIBRATION_FACTOR Load-cell calibration (default -9500). Adjust for your cells and unit.
FULL_BOTTLE_WEIGHT Weight of gas in a full bottle (default 5 lb), used for the "remaining" estimate.
SLEEP_TIME Deep-sleep interval in seconds (default 900 = 15 min, max ~70 min).
OFFSET_EEPROM_ADDR EEPROM address where the tare offset is stored (default 0).

The source includes commented-out MQTT settings for Adafruit IO as an alternative to a local Mosquitto broker — uncomment whichever set you use.

⚠️ Don't commit your credentials

This sketch keeps WiFi and MQTT credentials inline as #defines, which makes it very easy to commit real secrets by accident. Before you push anything:

git diff -- BottleScale/BottleScale.ino

and confirm the placeholders are still placeholders. To have git ignore your local edits to the file entirely:

git update-index --skip-worktree BottleScale/BottleScale.ino

Security

This project makes no attempt at transport security, which is worth understanding before you deploy it:

  • MQTT runs in plaintext on port 1883. Credentials and readings are sent unencrypted. Anyone on your network can read them.
  • No TLS, no certificate validation. WiFiClient is used rather than WiFiClientSecure.
  • Credentials are compiled into the firmware. Anyone who can read the flash can recover your WiFi password.

This is fine for a device on a trusted home LAN talking to a local broker. Do not point this at a public broker over the internet as-is — if you need that, switch to WiFiClientSecure on port 8883 and use a broker-specific token rather than your real credentials.

Calibration

  1. With no bottle on the scale, hold the TARE button while resetting the device to zero it.
  2. Place a known weight on the scale and compare the reported reading.
  3. Adjust CALIBRATION_FACTOR up or down until the reading matches the known weight, then re-flash.

For an interactive way to find the factor, SparkFun's HX711 calibration example lets you nudge the value with +/- over the serial monitor until the reading matches your known weight. Run it with the same DOUT/CLK pins as above (GPIO14 / GPIO12), then copy the resulting factor into this sketch.

Build & flash

  1. Install the ESP8266 board package and the libraries listed above in the Arduino IDE.
  2. Open BottleScale/BottleScale.ino.
  3. Fill in your WiFi, MQTT, and calibration settings.
  4. Select your ESP8266 board and port, then upload.
  5. Open the Serial Monitor at 9600 baud to watch the boot/connect/publish/sleep cycle.

Known issues

Contributions welcome — these are known and unfixed:

  • estimatedRemaining depends on how you tared. The firmware computes FULL_BOTTLE_WEIGHT - currentReading. That only yields "gas remaining" if the scale was tared with a full bottle in place. If you tared with an empty cylinder on the scale, then currentReading is already the gas remaining and this value is the gas consumed. Check which convention your tare matches before trusting the number.

License

This repository is dual-licensed:

Path License
Firmware (BottleScale/) and documentation MIT
3D models (hardware/) CC BY-SA 4.0

The HX711 library by bogde is a separate GPL-licensed dependency, not included here — install it via the Arduino Library Manager. The calibration procedure references SparkFun's beerware-licensed example, linked above rather than vendored.

About

An IOT scale for kegerator CO2 bottles

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages