Sometimes, a product is so simple, so obvious, you wonder why no one has created it yet. That's kind of the story here... Everyday at work, I listened to countless people complaining that the coffee pot was empty. The collective voice of the people rang out with demands of change! They wanted to know if the coffee pot was empty before they went to the kitchen to get some, to know if they needed to stop somewhere on their way to work because no one had started a new brew. Lucky for them, we live in the dawning of the age of IoT, and I just happen to be a herald.
Given that my office uses insulated, metal pots rather than the typical glass ones, I elected to measure the weight of the pot rather than see how much coffee is left using optical sensors. Note, this will not work for coffee makers with an exposed hot plate! To accomplish this, I hacked into a cheap digital kitchen scale to pirate data about the weight of an object and publish that data to the internet using PubNub. However, thanks to the embedded nature of modern electronics, this is easier said than done.
Difficulty: e a s y ..
Don't fret; difficult does not mean impossible... so grab your tool kit, boys and girls. It's time to create something!
Step 1: Parts and Tools
- Digital Kitchen Scale - On Amazon
- Screw Drivers & Pliers - To open up the scale
- Wire Cutters & Strippers - To cut and strip wire
- Soldering Iron - To solder with
- Hookup Wire - Very small gauge is fine for this low current application
- Multimeter - To measure voltage / resistance
- Hot Glue Gun - Useful for coating connections and holding things down
Circuitry Components
- ESP8266 - Our connection to the internet
- 2 x 4.7k ohm Resistors - Pullups for the I2C lines
- 3 x 10k ohm ressistors - Pullups for buttons
- 1 x 0.1uF Ceramic Capacitor - Decoupling Cap for the ESP8266
- LCD Reader Circuit - Everything described here...
- 5V Source - This can be an unused USB charger
The circuitry used to read data from the kitchen scale as well as the process used to read the LCD screen is somewhat involved, and a separate Instructable has been written detailing this process.
Additional Items
- Computer - For programming and such
- AVR Programmer - I use the pocket programmer from Sparkfun
- 3.3V USB to Serial Converter - I use this breakout from Sparkfun
Software and Services
- PubNub - Data Streaming Service. Free Sandbox for developers!
- AVR Development Environment - Documentation at Atmel
- ESP8266 Development Environment - Toolchain Wiki
- Project Source Code Repository - Hosted on GitHub
Step 2: Project Overview
Taking a step back, the whole project works like this. The digital scale collects measurements and displays information on its LCD screen. That data is read directly by an ATmega328p and then sent to the ESP8266 on the I2C bus. From there, it is published on the internet to any user subscribed to the channel via PubNub.
There are a lot of moving parts here, so let's figure out everything that needs to be created:
- Digital Scale should read weight of coffee pot
- Circuitry to get the weight read by digital scale
- Internet connectivity to publish weight data using PubNub
- Web interface to display that information to anyone
Step 3: Learn to Read
Well, sort of... we need to teach a microcontroller how to directly read an LCD screen. What... why... how? All of these questions and more will be answered! Actually, this step is rather involved so, I have created a separated Instructable detailing this process in it's entirety.
So take some time to read through my guide on Direct Reading of LCD using AVR General Purpose IO. When you get back, you should have a working circuit which can read the weight value displayed on the scale LCD. We will modify this circuit and the firmware in the next few steps!
Step 4: Circuit Design
There are a few additions to the circuit used in the companion Instructable. Namely, the addition of the ESP8266, I2C bus, and some new abilities. The ATmega328p has complete control over the scale. It directly drives the active low mode buttons, reads the LCD screen, and can even disable power to the scale using a transistor. This chip also communicates with the ESP8266 via the I2C bus (also known as TWI).
In addition, the mega328 is responsible for resetting the ESP8266 if it requests such an event due to network issues or some other error state. The ESP8266 has the job of publishing our scale data to the internet using PubNub. Take note, this entire circuit is operating at 3.3V DC!
There isn't too much else going on in this circuit. I think it should be pretty straight forward to anyone who can read a schematic. Again, I can't stress enough that this circuit runs on 3.3V DC. The ATmega328p has a pretty wide input voltage range, but the ESP8266 and scale do not. The open pins on PORTC can be used for additional analog sensors. The most obvious choice would be a temperature sensor, but this would require a probe to go down into the coffee for the pot in our office, and that would most likely go unused.
An ideal source voltage is 5V (fed only into the 3.3V regulator input),
and I have elected to use an old USB phone charger, just make sure it can source at least 500mA (most can).
Cut off the USB micro end of the cable (the part that goes into your phone) and strip back the insulation. It can be tricky to do this without cutting the internal wires... just keep trying. Peel back the shielding (uninsulated wire) to reveal the power and data lines. You can safely cut off the green and white wires (data lines). We only care about the red (5V) and black (GND) ones.
Step 5: Firmware - ATmega328p
The firmware for this chip can be found in the atmega328p directory of the source code repository. This code is written in C, should be compiled using AVR-GCC, and can be flashed to the chip using Atmel Studio or AVRDUDE and an external AVR programmer. This is NOT Arduino code. There are a few changes to the code used in the LCD Reader Instructable, so I will briefly touch on those points.
On boot, the following actions will take place:
- Initialize I/O pins and hardware peripherals
- Enable the ESP8266
- Enable the scale, ensure in weight mode with grams as the unit
- Enable I2C bus
- Enter Main Loop
The main loop does the following things about once per second:
- Read the LCD
- Decode the LCD data into a weight in grams
- Reset the ESP8266, if requested
- Keep the scale awake (every 45 seconds)
To keep the scale awake, the unit button is pressed a couple of times. Otherwise, the scale enters a clock display mode that cannot be easily exited. Although this chip is the main controller, it acts as a slave on the I2C bus. This was done primarily because the ESP8266 module in use does not have access to the actual I2C hardware pins, and a “bit-bang” master is much easier to implement than a slave.
When an I2C Read is initiated, the scale digits are transmitted on the bus. The first byte represents the upper two digits, while the second byte represents the lower two digits. For example, a weight of 1234 grams would be sent as [12] [34]. As the mega328 is never expecting an I2C write, such an event signals a reset request by the ESP8266. At this time, the mega328 will pull the reset line of the ESP8266 low for a few milliseconds and then release it. This is used as a rudimentary way to overcome error states in the ESP8266.
Step 6: Firmware - ESP8266
The firmware for this module can be found in the esp8266 directory of the source code repository. This code is written in C, should be compiled using the Espressif SDK and XTensa Tools GCC, and can be flashed to the chip using esptool and a 3.3V USB to Serial Converter. This is NOT Arduino code.
The code presented is built off of another Instructable I previously wrote. Again, I encourage you to take some time to read through that guide, as it shows how to set up the development environment, flash the chip, and details the code in use as well as how to write your own PubNub library.
On boot, the following actions take place:
- Initialize UART and I/O pins
- Connect to WiFi network
- Connect to PubNub
- Enable a recurring 1 ms timer
The 1ms timer can serve as a main loop, as it is repeated every 1ms. It is here that we will request information about the scale or request a reset from the Atmel ATmega328p. The entire I2C bit-bang implementation is also handled here by using various state flags and setting the clock and data lines HI or LO accordingly. After both data bytes representing the scale digits have been read, the values are concatenated and used to build a JSON string to be published in the publishMsg() function.
// Publish the value using PubNub
static void publishMsg (void)
{
// Check values for I2C line error...
if (TWI_msg[0] > 99 || TWI_msg[1] > 99) {
TWI_fullMsg = 10000;
}
// Ignore very small values
else if (TWI_msg[0] == 0 && TWI_msg[1] < 50) {
TWI_fullMsg = 0;
}
// Record full value and round to nearest 10
else {
int mod = TWI_msg[1] % 10;
TWI_msg[1] /= 10;
if (mod > 4)
++TWI_msg[1];
TWI_msg[1] *= 10;
TWI_fullMsg = (uint16_t)TWI_msg[1] + 100 * (uint16_t)TWI_msg[0];
}
// Only publish if this is a new value or it's been a while...
if((TWI_fullMsg != TWI_lastMsg) || TIME_TO_PUBLISH) {
char buf[40] = { 0, };
sprintf(buf, "{"columns":[["Coffee","%d"]]}", TWI_fullMsg);
pubnub_publish(channel, buf);
TWI_lastMsg = TWI_fullMsg;
stat_flag &= ~REQUEST_PUBLISH;
}
}
Notice, data is only published if it is new! It doesn't make sense to constantly send out irrelevant or repeated bytes. However, a counter does ensure that at least one message is published every few minutes, serving as a heartbeat signal. You will have to enter your own PubNub keys and personal WiFi credentials into the source code. This is discussed in the getting started guide I wrote.
Step 7: The Build
With the circuit designed and firmware loaded, it's time to build the final product! The scale is pretty thin, but with some clever placement we can fit all of the new components into the original casing so it looks nice. The first step is to cut a small hole in the front of the scale for a reset button. This allows a user to reset the scale if it is acting strange...
I elected to hand solder everything onto a small perf board, but a custom PCB with surface mount components would be a better option.
If you recall from the LCD Reader Instructable, there is a lot of empty space available inside of the scale, just not a lot of vertical room.
After dremeling out the battery compartment plastic, the soldered circuit fit perfectly near the back of the scale, with wires running forward to the LCD screen and the ESP8266. The WiFi module should be placed as far forward as possible - less RF signal interference from the coffee pot!
It is really important that the scale is supported only by the four load cells - this is how it works! If any weight is supported by the circuitry or any other parts we added, the scale will not be accurate. I actually had to cut a small hole in the bottom case to make clearance for the top of the ATmega328p - another reason surface mount parts on a PCB would be better.
Step 8: Creating a Web Interface
All of this streaming data is useless without a way to access it, so I built a really simple web page that displays the coffee pot level using EON, a PubNub JavaScript framework for IoT dashboards. The webpage utilizes HTML, CSS for styling, and JavaScript to handle the PubNub interactions. The full source code can be found in the gh-pages branch of the project repository.
The first step is to initialize PubNub and create an EON chart.
var pubnub = PUBNUB.init({
publish_key: 'YOUR_PUBLISH_KEY',
subscribe_key: 'YOUR_SUBSCRIBE_KEY'
});
var channel = "javamon";
eon.chart({
pubnub:pubnub,
channel: channel,
message: function(m){
// Do cool stuff here!
});
The chart will then update with any new data published by the scale on the selected channel. The interface is also responsible for translating the raw weight into a percentage level from 0 to 100. At first, I was doing this in the scale itself, but a change in the coffee pot would require a firmware update with new conversion factors. Putting this calculation in the JavaScript means a couple of variable updates to the accessible web page code will take care of it.
In addition, the interface will alert users if either the pot is off of the scale or some unknown object is on the scale. This is done by comparing the scale weight to the known weight of the empty coffee pot.
There was a major flaw in my original design - it was possible for the webpage to take up to two minutes before displaying any data as it waited on a publish event to take place. This was solved with the addition of PubNub Storage and Playback. This feature allowed me to look at the history of messages published to my channel in order to populate the graph before any new publish events took place. I am only looking at messages published in the last five minutes, and if none are found, then scale is in an error state. JavaMon is live in the PubNub office right now - check out the web page!
Step 9: Wrapping Up
And there you have it - an IoT coffee pot level monitor! This project was a lot of fun for me, and I hope it was for you, too. As always, let me know if you have any questions or comments - I always appreciate your feedback!