This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License
I got the idea for this project to when I moved my charging station to the garage and wanted some kind of notification when it completed a cycle (see my note about LiPo safety.) That got me thinking Internet of Things and wondering what would be a simple and inexpensive way to get an email when the charger’s buzzer went off.
An Arduino seemed like a logical place to start because they’re relatively cheap and easy to use but I shelved that idea when I realized they require a third-party service like those from Adafruit, Temboo or PushingBox in order to send emails, something that would add an unwanted layer of complexity to what should be a dirt simple project. Meh. (As an aside, if your heart is set on using an Arduino, Adafruit has a great tutorial for building a simple IoT doorbell that could be modified to perform other notification tasks.)
After scrapping the idea of using an Arduino I turned my attention to the Raspberry Pi. Specifically, the little Raspberry Pi Zero. The Pi is similar to the Arduino in that it has programmable general purpose input-output ports or ‘GPIO’ ports, but unlike Arduinos the Pi is a full-on single board computer. When you install the free Raspbian OS with Pixel, you get a lovely GUI that includes a desktop, a web browser, a RealVNC server, and the ability to send and receive emails.
At just $5 the Raspberry Pi Zero is the cheapest and the smallest member of the Pi family and is based on the Broadcom BCM2835. To keep the cost down the Zero lacks the hardware to connect to the Internet but, for just a few dollars more you can add WiFi and BT via the Zero-size Red Bear IoT pHAT add-on board (available unassembled or pre-soldered from Adafruit).
The IoT pHAT provides both 802.11n WiFi and Bluetooth and gives you the option of using an onboard WiFi antenna or adding an external antenna via an IPX / U.FL connector. (A slide switch selects between the two.) Because the Zero will be living in my garage I opted to use a 2.4GHz stub antenna I had laying around. The stub significantly boosted its range and the WiFi performance is now excellent from every location in the house.
In the above photo the pHAT’s antenna selector is shown in the ‘onboard’ position — the antenna itself is on the left of the Red Bear logo.
The first order of business is deciding what event(s) you want to monitor and then figuring out a means of detection that is compatible with the Raspberry Pi. If the device to be monitored has a self-contained two-pin piezoelectric buzzer that provides audible alerts (this is the most common type) then the easiest way for the Pi to detect those events is by connecting the buzzer’s power input pin to a GPIO pin on the Pi. (I tested this on my Turnigy REAKTOR 300W 20A and IMAX B6 balance chargers from HobbyKing.com and both worked perfectly for me.)
|PLEASE READ: For those considering this project I’m making a couple of assumptions: One, the device in question uses a 2-pin piezoelectric buzzer. And two, the buzzer operates on between 3.3 and 5 volts. Also, be aware that few battery chargers like those discussed here are meant to be serviced. Disassembly of your precious charger can be tricky at best and at worst may cause severe damage so yeah, you have been warned. See DISCLAIMER below. This will also likely void your warranty so there’s that too. =)|
How It Works
|The MintyMailer’s script is a simple if-then-else loop I wrote in Python that polls three of the Pi’s GPIO ports — two are assigned to button presses and one looks at the status of the charger. A fourth port drives the LED status indicator. When the buzzer goes off an email is sent and the script is latched into standby and then waits for a manual reset.|
GPIO ports 2, 4 and 20 are configured as INPUTS while GPIO port 21 is configured as an OUTPUT. GPIO 4 Is connected to the (+) side of a battery charger’s piezoelectric alarm buzzer and when the buzzer receives power GPIO 4 sees that as a logic HIGH. Conversely, when the buzzer is unpowered the port sees that as a logic LOW. The script looks for these state changes and any transition from LOW to HIGH is considered an ‘event’. Once an event is detected, an email is sent, the LED is lit and all subsequent events [like continuous beeping] are ignored until the START/RESET button on GPIO 2 is pressed.
When the mailer is first run the LED slowly flashes 5 times to indicate the script has loaded. After that the LED will remain OFF until the START/RESET button has been pressed. To work correctly, START/RESET can’t be pressed until the charger has started a cycle. This is because most LiPo chargers beep with each key press — something that would be seen as an event and cause a false trigger. (It’s worth noting that the mailer can’t work if the charger’s alarm has been silenced.)
After a cycle has started (balance, fast charge, discharge, etc.) it’s time to press the START/RESET button. The LED will then blink once every 2 seconds as a heartbeat to show the script is actively awaiting an event. When an event is detected the LED momentarily goes ON, and then flashes rapidly to indicate an email is in the process of being sent. Once the email is sent the LED will remain ON continuously until the START/RESET button is pressed again. (A planned mod is to swap out the white LED I’m using now for an RGB LED that would change color to indicate various states).
After the script has loaded you can manually trigger an event and send an email by pressing the TEST button on GPIO 20.
There are two ways to terminate the script:
- In headless mode (i.e. no keyboard), press and hold the START/RESET button. While still holding the START/RESET button, press and hold the TEST button. Continue pressing both the buttons until the LED flashes rapidly and then goes dark. When the LED is OFF the script has been unloaded.
- If a keyboard is attached pressing Ctrl+C will terminate and unload the script.
As you can see from the connection diagram the ‘MintyMailer’ is extremely simple and [aside from some moderately delicate soldering] the trickiest part was drilling clean holes in the candy tin (tip: use a step drill bit and drill progressively larger holes using a wood block to support the metal from behind.)
If you look through the photos you’ll see that I kept the mods as simple as possible by soldered leads directly to the Pi. 30AWG Multistrand silicone wire was used throughout because it’s thin and bendy and heat-resistant, plus it’s easy to snake around inside a cramped chassis. 3.5mm And 2.5mm mono audio jacks and cables (not shown in diagram) were used to connect the devices and provide power to the Pi, respectively.
Power is supplied to the Zero by an unused iPad charger I had laying around. The charger provides an honest 5VDC @ 2.5A and has the ubiquitous USB Type-A female jack. Originally I was going to connect to the charger with a USB 2.0 A male to Micro B male cable, but cutting a hole large enough to pass a USB connector through that paper-thin metal box seemed like a bad idea.
My solution was to cut off the Micro B connector and replace it with the 2.5mm mono audio plug shown. By going this route I have the option of using the audio jack when the case is closed, or using the Zero’s female Micro B USB connector if I need to power it when the case is open. Finally, the Pi and IoT pHAT are secured to the inside of the candy tin using squares of VHB tape. (VHB is non-conductive, easy to reposition and thick enough to keep the board well above the metal box.)
It all makes for a tidy package and even with the cover closed there is plenty of air circulation to keep things cool.
I really enjoyed cobbling the MintyMailer together and I have to admit it’s liberating having the option of being emailed instead of listening for a buzzer.
This was my very first foray into both Raspberry Pi and Python and I’m impressed with how smoothly it all went, with much of the credit going to the wealth of information available within the Pi ecosystem.
There are probably countless uses for a device like this (perhaps especially as an aid for the hearing impaired) and I hope the project inspires others to build something similar. If you do, please share a link to your project because I’d really like to see it.
A Word About LiPo Safety
If handled improperly or if they are damaged in some way LiPo batteries can be a fire hazard. This is especially true during a charge/discharge cycle and as such batteries should never be left unattended while connected to a charger. My personal charging station is located on a steel rack away from combustibles and a smart smoke alarm [that is audible throughout the house] is positioned overhead and a fire extinguisher is nearby. As a final precaution my batteries are always stored and charged in ammo boxes or fireproof bags designed specifically for LiPo batteries.
Getting Started With The Raspberry Pi
My Parts List (your spending may vary)
|DISCLAIMER: THE CONTENTS OF THIS ARTICLE ARE PROVIDED BY THE PROVIDER “AS IS” AND “WITH ALL FAULTS.” THE PROVIDER MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE SAFETY, SUITABILITY, LACK OF VIRUSES, INACCURACIES, TYPOGRAPHICAL ERRORS, OR OTHER HARMFUL COMPONENTS OF THIS SOFTWARE PRODUCT. THERE ARE INHERENT DANGERS IN THE USE OF ANY SOFTWARE AND YOU ARE SOLELY RESPONSIBLE FOR DETERMINING WHETHER THIS SOFTWARE PRODUCT IS COMPATIBLE WITH YOUR EQUIPMENT AND OTHER SOFTWARE INSTALLED ON YOUR EQUIPMENT. YOU ARE ALSO SOLELY RESPONSIBLE FOR THE PROTECTION OF YOUR EQUIPMENT AND BACKUP OF YOUR DATA, AND THE PROVIDER WILL NOT BE LIABLE FOR ANY DAMAGES PHYSICAL OR OTHERWISE YOU MAY SUFFER IN CONNECTION WITH USING, MODIFYING, OR DISTRIBUTING THIS SOFTWARE PRODUCT OR THE INFORMATION PROVIDED IN THIS ARTICLE.|
Download the Python source (ZIP format)
#! /usr/local/bin/python # # # # MIT License Copyright (c)2017 Crady von Pawlak # # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # This work is also licensed under a Creative Commons Attribution-NonCommercial 4.0 International License # https://creativecommons.org/licenses/by-nc/4.0/ # # # MintyMailer(CC)2017 Crady von Pawlak / CradyLab(tm) # rel 1.0 # Written in Python 3 for Raspberry Pi in Raspbian Jessie with Pixel # Developed with Raspberry Pi 3 Model B v1.2 and Raspberry Pi Zero with Red Bear IoT pHAT # Tested with Turnigy REAKTOR 300W 20A and IMAX B6 balance chargers from HobbyKing.com # # # To launch the script on boot-up, place it in the Documents folder and then add the following to the last line of the .bashrc file: # python Documents/charger_alerts.py # # # Usage: # # Pin 7 of the Raspberry Pi (GPIO 4) is configured as an input and connected to the (+) side of a battery charger's # piezoelectric alarm buzzer. When the buzzer is silent GPIO 4 sees a LOW. Any 'beep' from the buzzer is conversely # seen as a HIGH. # # The script works by looking for these state changes and any transition from LOW to HIGH is considered # an 'event'. Once an event is detected an email is sent, the LED is lit continuously and all subsequent events (i.e. # continuous beeping) are ignored until the START/RESET button is pressed. # # After Loading # # When the script is first run the LED will slowly flash 5 times to indicate it has successfully loaded. After that the # LED will remain OFF until the START/RESET button has been pressed. # # To work correctly, START/RESET must not be pressed until the charger has started a cycle. This is because most LiPo # chargers beep with each key press - something that would be seen as an event and cause a false trigger (note that the # alerter cannot work if the charger's alarm has been silenced.) # # After the battery charger's cycle has started (balance, fast charge, discharge, etc.) it's time to press the START/RESET # button. The LED will then blink continuously once every 2 seconds to show the script is actively waiting for an event. # # When an event has been detected the LED will go ON, and then flash rapidly to indicate an email is in the process of # being sent. Once an email is sent the LED will then remain ON until the START/RESET button is pressed again. # # Test Emails # # After the script has loaded you can trigger an event and force the script to send an email by pressing the TEST button. # import smtplib from email.mime.text import MIMEText import sys from time import sleep import os, RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) # define GPIO pins GPIO.setup(2,GPIO.IN) # Physical pin 3 (has internal 1.8K pullup resistor) - START / RESET button GPIO.setup(4,GPIO.IN,pull_up_down=GPIO.PUD_DOWN) # Physical pin 7 - SIGNAL connect to (+) of piezo buzzer GPIO.setup(20,GPIO.IN,pull_up_down=GPIO.PUD_UP) # Physical pin 38 - TEST button GPIO.setup(21,GPIO.OUT) # Physical pin 40 - LED anode via 1K resistor # ChargerState values # 0 = Awaiting START / RESET press # 1 = Awaiting event # 2 = Email sent # 3 = dummy value to keep loop going ChargerState = 0 Heartbeat = 0 GPIO.output(21,0) # Set LED to 'off' state ############################################## Emailer # define email content recipients = ["SomeEmailAddress@somedomain.com"] # Recipient email addresses sender = "SomeEmailAddress@somedomain.com" # Sender email address subject = "LiPo Charger" body = """ Cycle completed. =) """ msg = MIMEText(body) msg['Subject'] = subject msg['From'] = sender msg['To'] = ", ".join(recipients) # Send email function def SendAlert(): session = smtplib.SMTP('smtp.gmail.com', 587) # Email server (Gmail as example) session.starttls() session.login(sender, 'YourEmailPassword') # Email password send_it = session.sendmail(sender, recipients, msg.as_string()) session.quit() return ############################################## Emailer # LED heartbeat def DoHeartbeat(): global ChargerState if (ChargerState != 1): sleep(0.15) return else: global Heartbeat if (Heartbeat == 14): # Briefly flash LED approx. every 2S GPIO.output(21,1) sleep(0.06) # LED on for 60ms GPIO.output(21,0) Heartbeat = 0 sleep(0.15) Heartbeat = Heartbeat + 1 return # Flash LED at 2Hz def Flash_LED_At_2Hz(): LED_blinks = 0 while(LED_blinks < 5): # Briefly flash LED at 2Hz GPIO.output(21,1) sleep(0.5) GPIO.output(21,0) sleep(0.5) LED_blinks = LED_blinks + 1 GPIO.output(21,0) # Leave LED OFF return # Flash LED at 10Hz def Flash_LED_At_10Hz(): LED_blinks = 0 while(LED_blinks < 5): # Briefly flash LED at 10Hz GPIO.output(21,1) sleep(0.1) GPIO.output(21,0) sleep(0.1) LED_blinks = LED_blinks + 1 GPIO.output(21,0) # Leave LED OFF return # Flash LED at 30Hz def Flash_LED_At_30Hz(): LED_blinks = 0 while(LED_blinks < 15): # briefly flash LED at 30Hz GPIO.output(21,1) sleep(0.033) GPIO.output(21,0) sleep(0.033) LED_blinks = LED_blinks + 1 GPIO.output(21,1) # Leave LED ON return # Exit function - unloads program def KillTheScript(): Flash_LED_At_30Hz() # Flash LED quickly so we know exit has started GPIO.output(21,0) # Turn off LED print ("Charger emailer terminated") sys.exit() # Exit script Flash_LED_At_2Hz() # Slowly blink the LED 5 times to indicate program is loaded and ready print ("Emailer loaded. Press START when charger cycle has begun.") while ChargerState != 3: # Loop indefinitely if (GPIO.input(4) == 1): # Detect if piezo buzzer energized if (ChargerState == 1): # Test program the status GPIO.output(21,1) # Turn on LED to show email is sending SendAlert() # Send email ChargerState = 2 # Update status to 'Email sent' print ("Email sent") Flash_LED_At_30Hz() # Indicate email has been sent then stay on until reset #elif (GPIO.input(2) == 0 and GPIO.input(20) == 1 and ChargerState == 0): # START / RESET has been pressed #ChargerState = 1 # Update status to 'Awaiting event' #Flash_LED_At_10Hz() # Flash LED #print ("Started. Awaiting event ...") elif (GPIO.input(2) == 0 and GPIO.input(20) == 1 and ChargerState != 1): # START / RESET has been pressed ChargerState = 1 # Update status to 'Awaiting event' Flash_LED_At_10Hz() # Flash LED print ("Reset. Awaiting event ...") elif (GPIO.input(20) == 0 and GPIO.input(2) == 1): # TEST button has been pressed GPIO.output(21,1) # Turn on LED to show email is sending SendAlert() # Send test email ChargerState = 2 # Update status to 'Email sent' print ("Test email sent") Flash_LED_At_30Hz() # Indicate an email has been sent then stay on until reset elif (GPIO.input(20) == 0 and GPIO.input(21) == 0): # Both buttons are being pressed simultaneously # (press and hold RESET then TEST buttons) print ("Hold BOTH buttons until LED is off") GPIO.output(21,0) # Turn on LED off #ChargerState = 3 KillTheScript() else: DoHeartbeat() # Nothing happening? Pause for 150ms to reduce CPU load then resume loop # That's it! =)
Did you find this post helpful or informative? If so please consider donating to CradyLab™