CHRONO-LABELER: Food-Dating & Labeling Device for Bluetooth Mini Printers
by blopa1961 in Circuits > Arduino
102 Views, 0 Favorites, 0 Comments
CHRONO-LABELER: Food-Dating & Labeling Device for Bluetooth Mini Printers
Versión en Español disponible AQUI
This project allows you to make date and time labels using an Arduino ESP32 with a Bluetooth mini printer, without the need for a smartphone or PC.
Target use:
How many times have you thrown away food because you don't know how long it has been in the fridge?
Disclaimer and terms of use:
No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
In other words: use at YOUR OWN RISK.
License:
Attribution Non-commercial (by-nc)
The license of use of this software is exclusively PERSONAL, that is, you cannot sell this product if you make it.
Supplies
ESP32 Mini
3 high brightess LEDs (1 blue for WiFi mode, 1 yellow for NTP status and 1 green for printing)
3 resistors 1K (metalfilm preferred because of size)
1 resistor 10K
1 button (7mm of height used, see the photo)
a piece of perf board
a strip of Dupont pins
Description:
I designed the Chrono-Labeler to solve a common kitchen headache: forgetting exactly when leftovers or meal-prep containers were placed in the fridge. This device pairs with cheap, portable Bluetooth thermal printers to create instant, legible date labels.
After analyzing available printers in the market, I found out that many Bluetooth mini printers have DRM locks (a chip inside the roll) to force the use of their brand's labels (Niimbot) or try to charge annual subscriptions higher than the printer's cost to use the most basic of functions like printing a date (Phomemo). Of those printers I didn't buy the Niimbot D110 because of the negative comments I found on Reddit, but I bought and immediately returned the Phomemo D30 (because you need to pay for a 30 dollar per year subscription to be able to print a simple date!).
At last I bought a TP-110 and a TP-220, branded G&G or TPL indistinctly (they are the same products in both brands). Both printers work with a subset of the TSPL 2 printer language.
I tried the printers with the Print-Label Android software (after finding out there's fake software called "Print Label" without the dash). Print-Label is acceptable, but if you have to open your smartphone, load the APP, enable Bluetooth, connect to the printer, choose the printing profile (label size, font, etc.) each time; it takes several minutes to achieve a simple sticker...
...and I only wanted to know how long the chicken has been in the fridge!!...
I develop Arduino (and PIC) devices and know the ESP32. Since it has WiFi I can get the time from the Internet via NTP (I don't even need a DS3231 RTC). I can build a WEB page to configure the SSID and the printer parameters. It also has Bluetooth, which solves the printer connection.
This is my first Arduino ESP32 Bluetooth development, how hard can it be... duh!
Thus, all the hardware I need is 1 button and a couple of LEDs to make a minimalist version of a sticker print server...
I thought... piece of cake! I can connect to the ESP32 by WiFi and load the default print parameters and I only have to press <THE BUTTON> each time I need a dated sticker.
The "piece of cake" took me more than 2 months of fulltime work, hacking to capture Bluetooth packets with Wireshark and more than 2500 lines of code between Arduino and HTML. Yes, I know, I learned a lot ;)
Even though the development would have been the same, I didn't find a reasonably priced Serial-TTL printer in my country (Argentina); this is the reason why this device uses Bluetooth. I also discovered that common Serial-TTL printers like the Adafruit Nano cannot print labels, either because they can't handle the (label) paper thickness or because the print head is so deep inside the printer that in case of labels they would start to print from the middle of the label...
Future developments:
- The first change I'd like to make is replacing the font rendering routines, because Adafruit GFX fonts do not contain Spanish characters. Even though accents are not used while printing dates, with these fonts it's not possible to label soufflés, piñatas or résumés from the main page.
- Change the buffer printing routine to asynchronous (timer) so I can remove all the delay() statements from the program. It's not difficult to do, but a lot of flags and checks would be necessary to block other routines from accessing the buffer in various parts of the program (even with the good ESP32's RAM capacity there's not enough memory for a second buffer when building WEB pages in Strings, mainly because of fragmentation). The program is working and as Murphy said, "if it works don't touch it "...
- Now that all of these printer's UUIDs have been listed, it would be interesting to add routines to access the printer's technical data, for example the battery level (in the source code you will see a comment with these printers' UUIDs for model, firmware version, etc.).
- Maybe add a Chrono Labeler version with a DS3231 that would not require an Internet connection.
- Another possible development would be to adapt the software to the Mi17-446 ("kitty") printer, which has similar functions to the TP-220 and is cheaper; but it uses the ESC/POS printer language and thus is not compatible with TSPL. I already bought one, we'll see...
- It would also be possible to put the Chrono Labeler inside the printer to add a "print date" button, and maybe replace the lithium battery by a capacitor to leave the printer connected and on 24/7.
Hardware:
Well, I talked about a minimalist solution, so the hardware is made up of an ESP32 Mini, 3 high brightness LEDs (1 blue, 1 yellow, 1 green) with their respective 1K resistors and 1 button with a 10K pullup to 3.3V, mounted on a perforated board...
I even included the STL for the case if you want to 3D print it (infill 100%).
Development ("log"):
To those not interested in Bluetooth technical topics I suggest you skip ahead to the next Step.
During research and development my first success was to print a bitmap using SPP (Serial Port Profile) with the BluetoothSerial routines that are part of Arduino, but I soon discovered that they are deprecated and will not be a part of future releases.
Said routines work in "Bluetooth Classic", which is a different protocol from the one currently in use, called "BLE" (Bluetooth Low Energy).
Furthermore, newer Espressif chips, namely the S, C or H series like the ESP32-C3 or ESP32-S3 have BLE only and do not work with Bluetooth Classic devices.
The printers I used work in both modes, Classic and BLE, for which reason each has 2 names and 2 MAC addresses (their BLE names end up in "-BLE"). You can get a printout of their BLE names and MAC addresses by double clicking the paper feed button.
So the next step was to port the development to BLE using the Arduino routines: BLEDevice, BLEUtils y BLEClient.
This is where I hit the wall for the first time, because even though I could obtain the printer's UUIDs (see the UUID and characteristics comments in the source code), I was unable to print the bitmap that was working fine in the SPP version of my program.
Hours of debugging passed until I found out that since my initial test was based on the Wireshark capture of the Bluetooth packets sent by my old Android 7 tablet and captured by HCI snoop, I was actually analyzing Bluetooth Classic 640 byte packets (of the bitmap transfer). Those of you who have BLE development experience would know for sure that BLE packets have a data limit of 251 bytes (against the Bluetooth Classic of about 1K), duh, I didn't know.
I also discovered that contrary to SPP, in BLE mode you have to give the printer time to process what it received or there will be a buffer overrun (and loss of data). This is the reason why my software now has the BLE inter-packet delay option in the configuration (and also the reason for more debugging time during the research).
A reset delay is also necessary when changing connections, buy this will not affect you if using a single printer.
Beautiful, now that it works with BLE I stop sweating and continue with the development... I try to print with the printer off... it hangs! Back to R&D... I discover that BLEDevice is BLOCKING, which means it has no time limits if there's no Bluetooth answer... luckily there's a library called NimBLE-Arduino which implements BLE with timeout... I port the software to NimBLE. Done!
Now to print texts to see how they come out... They DON'T! And they don't print because TP-110 and TP-220 printers do not implement the whole TSPL 2 language, only BITMAP; there's no TSPL "TEXT" command in the firmware.
More development, create a RAM buffer and build the texts using Adafruit GFX fonts. Fortunately somebody already did it, there's a library called Thermal Printer Library written by "bitbank2" (Larry Bank) which implements font rendering; so, I import the library part that renders the fonts... letters come "dirty" at the bottom (!)... I find the bug, fix it and add a change that lets me use white or black backgrounds indistinctly.
In a future Chrono Labeler release the idea is to replace this routine with those in U8g2, which contain all Spanish language characters.
It is said that all projects reach 90% completion in 90% of the available development time, and the remaining 10% takes ANOTHER 90% of development time... projects automatically get more and more complex while they advance... because, now that I have a working buffer... wouldn't it be nice to be able to SEE how my print will come out? WYSIWYG!
I "only" have to add a BMP header to the buffer and paste it into my WEB page right? Again I found myself some brand new trouble... BMP bitmaps have to be 32 bit aligned, I can't force the printer width to be 32 bit aligned and I don't have enough RAM for another buffer... furthermore, it seems that a Microsoft engineer was smoking something when he defined BMP headers and stuck a beautiful 16 bit variable at the beginning of a structure that has to be 32 bit aligned... That is where I had to learn (after more hours of debugging) what #pragma pack means in Arduino...
Finally I wrote the bitmap 32 bit alignment routine inside the same buffer and I added "preview" to all Chrono Labeler's WEB pages, including configuration pages (so you can see how the output will come out while configuring). Yes, I had to rewrite all the HTML pages for this to happen.
I would now only need to understand the printer init escape codes, which I copied from the Wireshark captures because they are undocumented (but work).
Compiling:
The software was developed using Arduino IDE 2.3.8
Add the following URL to your 'Additional Boards Manager URLs' in the Arduino IDE file/Preferences menu:
https://dl.espressif.com/dl/package_esp32_index.json
Then install "esp32" by Espressif Systems in Boards Manager, and "NimBLE-Arduino" in Library Manager.
There are thousands of tutorials on how to setup Arduino IDE, so I will not elaborate on the subject, Google it if you need to.
Download the source code from the link below, copy the files to a folder with the same name as the .ino, create the Fonts subfolder and copy the fonts there.
Select "ESP32 Dev Module" as the target device, set it to 240 MHz, partition scheme "No OTA (2MB APP/2MB SPIFFS)" and upload speed to 921600.
Done, you can now send the sketch to your ESP32 mini.
Source Code:
The full source code is available in github >>>>>> HERE <<<<<<
Spanish version also available >>>>>> HERE <<<<<<
How to Use:
Connect Chrono Labeler to local WiFi (SSID and pass), pair the printer via Bluetooth and configure your desired date and time format. Then you will only need to press THE BUTTON every time you want a label with date and time.
Once connected to your Intranet you can access the Chrono Labeler by IP (if fixed)
or by mDNS visiting: http://chronolabeler.local
From the main WEB page you can print any text (without accents for the time being).
If you leave the first text line blank you will get a date and time sticker, exactly the same as if you had pressed <THE BUTTON>. If the "Print" button is grayed out, make sure you pair the printer first.
What? How to access Chrono Labeler's WiFi configuration page? Easy: