-----------------------------------------------------------------------------------------------------------------
Have you ever wanted a smart vanity mirror that could allow you to view your appearance and displays information that may be relevant for daily use (i.e., calendar date, time, temperature, weather forecast etc.)?
This project will teach you the basic steps and theory of how to develop one and also provide you with ideas on how to improve on the final product!
-----------------------------------------------------------------------------------------------------------------
Although there are existing projects centered around developing smart mirrors, many of the projects have large monitors, mirrors, and frames that make it difficult for the vanity to be portable. Additionally, the mirrors made in the existing projects are not intended to be vanity mirrors, so they tend to lack a lighting component and those that do include lighting strips use them for backlighting and not for enabling the user to have better visibility of their image.
As such, this project will attempt to remedy those gaps in this space and improve upon the existing projects by including the following features:
- Clean, aesthetic finish
- Portable size
- LED lighting projected towards user with button to turn on/off
- Touchscreen functionality and modules for users to interact with
- Backup toggle/Navigation button in case touchscreen functionality does not cooperate
- Internet connection: video player, music, weather
While this project can be useful for a variety of users, the features listed above will make the device particularly useful to students and people that move frequently as its portable size allows for it to be used on many surfaces as opposed to being mounted on a wall or to a table and its Wi-Fi connectivity means it can be utilized in a variety of places.
Challenges, Redirection, and Final ProcessThroughout the course of this project, there were an abundance of unprecedented challenges that lead to the redirection of this project and the change in final features the device incorporated.
Challenges and Redirection
1) Discontinuation of the DarkSky API
The first challenge began with the discontinuation of the DarkSky API that was intended to be used for the weather data retrieval as seen in this project: https://www.hackster.io/mprocter12/smart-mirror-using-beaglebone-black-e379a3. However, this difficulty was remedied by using PyOWM (OpenWeatherMap API) to retrieve weather data. This solution was reached by analyzing this project and the steps utilized by its creator: https://www.hackster.io/irene-kwon/all-in-one-morning-updates-with-pocketbeagle-e50b00.
2) Difficulties downloading Magic Mirror
The primary challenge of this project was the failure in installing and integrating the MagicMirror software. MagicMirror is a repository that contains multiple files to make it easy for anyone to develop a smart mirror with many widgets and features. Unfortunately, it was difficult to install and get running on the BeagleBone Black and since this was a key part of the project, it caused a lag in steps.
Below are some of the steps I attempted when trying to install and run MagicMirror:
- Cloned MagicMirror from GitHub
- Ran into "ENOSPC" and partitioned device to create more space
- Ran into "npm install" error that could not be resolved as command kept terminating and not installing
- Used 'sudo npm install" in attempt to bypass error
- Ran into "getaddrinfo EAI_AGAIN registry.npmjs.org:443” error
- Updated kernel in attempt to resolve error but both 4-19 and 5-4 updated kernel versions did not resolve error
- Tried to install electron using "npm install electron" and "sudo npm start" but did not work
3) Lack of adhesive on mirror tile
The reflective feature was a core function that was intended to be included in the device; however, the part that was delivered was an acrylic mirror tile that did not have an adhesive. This made it difficult to integrate the mirror with the LCD display. This problem potentially could have been resolved by lifting up the LCD screen glass and sliding the cut acrylic mirror tile underneath it; however, this poses risk of damage to the LCD and may be difficult for a beginner to enact.
Build Instructions / Final Device Process
Connecting to Wi-Fi
Having a stable Wi-Fi connection is integral to the success of this project as the important data being used is being retrieved directly from it
To connect to the Wi-Fi:
- Insert the Wi-Fi adapter into a 4-port USB hub
- Enter the cloud9 IDE terminal (192.168.7.2:300)
- In terminal window, change into appropriate directories (var/lib/cloud9/ENGI301/Project1/code)
- Connect to Wi-Fi using "sudo connmanctl" and "enable Wi-Fi"
For more detailed information on how to ensure that the BeagleBone Black is connected to Wi-Fi, see the Helpful Resources Section at the bottom of the page
Setting up the LCD Screen
To set up the LCD screen and connect it to the BeagleBone Black:
- Connect BeagleBone Black to computer by inserting miniUSB side of cable into USB Client port and USB side of cable into Computer port
- Connect HDMI adapter to HDMI port of BeagleBone. Connect one end of Male to Male HDMI Cable into female end of HDMI adapter and the other end of Male to Male HDMI Cable into the HDMI port of the LCD
- Connect USB cable into USB port of BeagleBone Black and end of cable into 4-port USB hub
- Connect microUSB end of cable into "Touch" port of LCD and USB end into 4-port USB hub
- Connect wall adapter of USB hub into standard power outlet outputting 100-240V
After this step, the device set-up should be complete and look like this:
Retrieving the Weather Data
Retrieving the weather data was not difficult after the initial pause due to the discontinuation of Dark Sky API.
To get the weather data, simply open an account with OWM and replace the API key in the SmartMirror.py code with your key. Next, research the city ID for the region you wish to obtain the weather for and substitute that into SmartMirror.py.
After this is complete, the script below should function by converting the data from OWM to Fahrenheit and making a combined string that can be outputted.
#Import necessary packages for retrieving weather data
from pyowm import OWM
#-------------------------------------------------------------------------------
# Get weather data for city
#-------------------------------------------------------------------------------
# Retrieve weather information from OpenWeatherMap API
API_key = '7c564fe1392176d69668415db351e21b' #insert your unique API key
owm = OWM(API_key)
my_city_id = 4699066 #insert unique city ID
obs = owm.weather_at_id(my_city_id)
w = obs.get_weather() # Get current, low, and high temperature
temp = w.get_temperature('fahrenheit') #Covert from Kelvin to Farenheit
#Create Farenheit symbol
m_symbol = '\xb0' + 'F'
#Set up strings for displaying the daily forecast
curr = "Current Temp: {0} {1}".format(temp['temp'], m_symbol)
high = "Daily High: {0} {1}".format(temp['temp_max'], m_symbol)
low = "Daily Low: {0} {1}".format(temp['temp_min'], m_symbol)
#Combined string with headline
weather = "Todays Weather\n{0}\n{1}\n{2}\n".format(curr,high,low)
Retrieving News Headlines
To retrieve the new headlines:
- Clone code from https://proxiesapi-com.medium.com/scraping-the-new-york-times-with-python-and-beautiful-soup-6e5f3bc58e39
- Install lxml and wheel
{Use these resources for guidance:
- https://stackoverflow.com/questions/24398302/bs4-featurenotfound-couldnt-find-a-tree-builder-with-the-features-you-requeste
- https://stackoverflow.com/questions/34819221/why-is-python-setup-py-saying-invalid-command-bdist-wheel-on-travis-ci
- https://lxml.de/installation.html
If you have difficulty, try installing the encoded versions
}
- Modified code to say “story-wrapper” instead of "assetWrapper" and to find <h3> instead of <h2> because <h3> had more tags and titles
- Also enabled counter to limit list to only top 10 headlines
#Import necessary packages for retrieving news data
import requests
from bs4 import BeautifulSoup
import json
import datetime
import textwrap
#-------------------------------------------------------------------------------
# Get news updates
#-------------------------------------------------------------------------------
url = "https://www.nytimes.com/" #news website url
headers = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9'}
r = requests.get(url, headers=headers) #Retrieve data from New York Times
now = datetime.datetime.now() #Retreives current date and time
now = now.strftime('%A, %B %d, %I:%M %p') #convert date and tijme to string
#Initialize varizbles
r_html = r.text
article = []
count = 0 #Initialize counter
soup=BeautifulSoup(r_html,'lxml') #Parses html
for item in soup.select('.story-wrapper'): #Search for story wrapper key word in NYT text
try:
headline = item.find('h3').get_text() #Search for h3 heading to locate headlines
article.append(headline) #Adds headlines to list
count += 1
except Exception as e:
pass
if count > 10: #Breaks loop after the first 10 headlines
break
#Set up strings for displaying the news headlines
header = ('%s\n%s\n\nHeadlines\n' %(now, url)) #creates header with date, time, website url, and title
H1 = article[1] #Separates each element of list into individual variable
H2 = article[2]
H3 = article[3]
H4 = article[4]
H5 = article[5]
H6 = article[6]
H7 = article[7]
H8 = article[8]
H9 = article[9]
H10 = article[10]
#Combined string with header
news = "{0}\n{1}\n{2}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n{8}\n{9}\n{10}\n".format(header,H1,H2,H3,H4,H5,H6,H7,H8,H9,H10)
Displaying on the LCD Screen
Once the relevant data can be retrieved from the internet, it is important to determine how this will be communicated with the user. For simplicity and to utilize the touchscreen capability of the LCD, I used pyqt5 to create a Graphical User Interface (GUI) that can be interacted with.
This system works using the script below:
#Import necessary packages for creating GUI
import sys
from PyQt5.QtWidgets import *
#-------------------------------------------------------------------------------
# Main Script - Display Weather and News on LCD display
#-------------------------------------------------------------------------------
def window():
app = QApplication(sys.argv) #calls the constructor and initializes QT application
window = QWidget() #intializes window
b1 = QPushButton("Weather") #Creates second button for weather data
b2 = QPushButton("News") #Creates second button for news data
vbox = QVBoxLayout() #Creates vertically aligned box
vbox.addWidget(b1) #adds weather button to the home box
vbox.addWidget(b2) #adds news button to the home box
#Displays weather when 'Weather' button is clicked
def on_b1_clicked():
alert = QMessageBox() #Creates pop up message where data is displayed
alert.setText(weather) #Outputs the temperature data
alert.exec_() #Runs the alert until it is closed out
b1.clicked.connect(on_b1_clicked)
#Displays headlines when 'News' button is clicked
def on_b2_clicked():
alert = QMessageBox() #Creates pop up message where data is displayed
alert.setText(news) #Outputs the headlines
alert.exec_() #Runs the alert until it is closed out
b2.clicked.connect(on_b2_clicked)
window.setLayout(vbox)
window.resize(250,250) #Resizes the Home pop-up box from default size to a larger size
window.setWindowTitle("Home")
window.show()
sys.exit(app.exec_()) #Runs the application until it is closed out
if __name__ == '__main__':
window()
The function of the script is to create a home window that allows the user to navigate to the weather an/or news using buttons and view the information using alert messages.
To assemble device hardware:
- Connect BeagleBone Black to computer by inserting miniUSB side of cable into USB Client port and USB side of cable into Computer port
- Connect HDMI adapter to HDMI port of BeagleBone. Connect one end of Male to Male HDMI Cable into female end of HDMI adapter and the other end of Male to Male HDMI Cable into the HDMI port of the LCD
- Connect USB cable into USB port of BeagleBone Black and end of cable into 4-port USB hub
- Connect microUSB end of cable into "Touch" port of LCD and USB end into 4-port USB hub
- Connect Wi-Fi adapter into 4-port USB hub
- Connect wall adapter of USB hub into standard power outlet outputting 100-240V
To initialize the Beagle Bone Black:
- Begin by flashing the SD card that will be used in the BeagleBone
- Enter the cloud9 IDE terminal (192.168.7.2:300)
- In terminal window, change into appropriate directories (var/lib/cloud9/ENGI301/Project1/code)
- Connect to Wi-Fi using "sudo connmanctl" and "enable Wi-Fi"
- Update using "sudo apt-get update"
- Install PyOWM for weather data by entering "sudo pip3 install pyowm"
- Install BeautifulSoup by entering "sudo pip3 install beautifulsoup4"
- Install pyqt GUI by entering "sudo apt-get install python3-pyqt5"
To execute code and operate device:
- Assemble device using instructions in above section
- Turn on/start computer and BeagleBone Black
- Download SmartMirror.py (main code) and RunSmartMirror (run script) from this repository and upload to cloud9
- In terminal window, change into appropriate directories (var/lib/cloud9/ENGI301/Project1/code)
- Change settings of run script to make executable (chmod 755 RunSmartMirror)
- Ensure hardware connections are in place and correct using instructions in the section above and the linked Hackster.io page
- Enter ./RunSmartMirror to run the SmartMirror.py program since it is a set path in the run script
# Run Smart Mirror in /var/lib/cloud9/ENGI301/Project1/code
# Steps:
# - Connect and enable wifi
# - Open new cloud9 terminal window
# - Change to relevant directory: cd ENGI301/Project1/code
# - Enter command: ./RunSmartMirror
# --------------------------------------------------------------------------
#Changes into relevant directories
cd /var/lib/cloud9/ENGI301/Project1/code
#Configures LCD display
export DISPLAY=':0.0'
#Sets python path for running file
PYTHONPATH=/var/lib/cloud9/ENGI301/Project1/code python3 SmartMirror.py
- Observe the window on the LCD display for a Home button with Weather and News buttons
- Interact with button of choice for updates: Click the "Weather" to receive forecast and "News" to receive news for the day via alert messages
- Close alert messages by clicking "Ok" and then close window by clicking red "X" in upper-right corner of the window
- To run program again, repeat steps 7-10
A video of the device functioning can be found here:
Future ImprovementsWhile the final mirror produced did not have all the original features it was intended to due to complications, this project can be iterated on and improved by discovering ways to add new features that can create a pleasurable user experience and result in a polished product.
Existing features to improve on:
1) Expand weather forecast data
- Adjust code to allow for forecast data for multiple days at a time (up to 1 week), display representative icons, and show other relevant parameters such as pressure and chance of rain
2) Python Graphical User Interface (GUI)
- Add dark mode theme for users who want the windows and alert message screens not to be glaring and improve user experience
- Configure back button to easily navigate back to home window without having to close out of alert messages to make use of system more seamless
New features to incorporate:
1) Mirror film
- This feature will allow the device to fulfill its primary function of being a mirror.
2) A clean, aesthetic chassis
- This will house the internal components (wiring) of the device and make the final product truly portable
3) Integrated LED strips
- This will also allow the device to better fulfill its intended purpose of being a smart vanity as the light projected at the user will increase visibility and make it easier to assess their face
4) Power Button/Ability to function only from a power outlet
- This feature will also increase the device's portability as it will allow it to be transported easily similar to the existing standard smart mirrors.
- This also makes the device more utilitarian as it does not require a computer to function.
5) Speaker system
- This feature will make the device more fun and potentially more appealing to users as they will be able to incorporate their music into the use of the system.
Ultimately, this mirror can be personalized such that its features are useful to the user. As such, the ideas mentioned above are just starters as you can brainstorm and incorporate other features that you believe are need in your mirror.
Helpful ResourcesThroughout this project, many resources were helpful in understanding the concepts, troubleshooting, and path rerouting when a component or system did not function as intended. Thanks to the creators of these resources. These resources may be useful for anyone who is thinking of recreating this project and can be found below:
Existing Smart Mirror Projects on Hackster:
- https://www.hackster.io/mprocter12/smart-mirror-using-beaglebone-black-e379a3
- https://www.hackster.io/eben-kouao/smart-mirror-touchscreen-with-face-recognition-6c84cc
- https://www.hackster.io/SrivishnuTech/make-your-own-smart-mirror-for-under-80-using-raspberry-pi-a87460
- https://www.hackster.io/irene-kwon/all-in-one-morning-updates-with-pocketbeagle-e50b00
Existing Code Libraries that can be used for modifications/testing:
- https://github.com/MichMich/MagicMirror
- https://proxiesapi-com.medium.com/scraping-the-new-york-times-with-python-and-beautiful-soup-6e5f3bc58e39
- https://github.com/pyqt/examples
Documentation Guides:
- https://www.fis.gatech.edu/how-to-configure-bbw-wifi/
- https://pyowm.readthedocs.io/en/latest/
- https://elinux.org/Beagleboard:BeagleBoneBlack_Debian
Thank you for reading this guide and following the journey. I hope you are inspired to create and develop something awesome!
Comments