Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
The Smart Mirror is something cool that is simple and easy to make despite how complicated it seems. In essence, the mirror displays the time and weather forecast for the next few days. All this is done by placing a monitor behind a one-way mirror, and casting an image to the monitor from the BeagleBone.
How It's MadeThe frame, mirror, and monitor was made by hand with the use of wood. Although the back is a bit bulky, it can always be altered in any fashion one would like. I ended up cutting a few corners on the mirror by not actually using a one-way mirror. Instead, I used an acrylic panel with reflective film over it to save a lot of money, as one-way mirrors can be costly. After hooking up the monitor to the frame, the hard part was done, and it was time to move onto the software side of things.
I used the BeagleBone black as an ordinary linux computer, running a specific webpage I designed using simpleweatherjs, which updates every few minutes. Although the entire product is not done yet, it functions pretty well and does the job. Currently, the webpage only functions with the use of an ethernet cable, but soon it will be configured to be used with wi-fi with the attachment of a wifi usb adapter.
Below includes the HTML, CSS, and JavaScript files for this project. Additional files, such as the icons for each weather condition can be found at http://simpleweatherjs.com/
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0">
<title>Magic Mirror App</title>
<link href="http://fonts.googleapis.com/css?family=Montserrat:400,700,inherit,400" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="css/standardize.css">
<link rel="stylesheet" href="css/index.css">
<script>
function startTime() {
var today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
m = checkTime(m);
s = checkTime(s);
var hours =
["12","1","2","3","4","5","6","7","8","9","10","11","12","1","2","3","4","5","6","7","8","9","10","11"];
var days = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
var months =
["January","February","March","April","May","June","July","August","September","October","November","December"];
var ampm = "";
if(today.getHours<12)
{
ampm = "AM";
}
else
{
ampm = "PM";
}
var blinkSec = " ";
if(s%2 != 0)
{
blinkSec= ".";
}
else
{
blinkSec= "..";
}
document.getElementById('txt').innerHTML =
hours[h] + ":" + m + " " + ampm;
document.getElementById('sec').innerHTML = blinkSec;
document.getElementById('date').innerHTML =
days[today.getDay()] + ", " + months[today.getMonth()] + " " + today.getDate() + ", " + today.getFullYear();
var t = setTimeout(startTime, 500);
}
function checkTime(i) {
if (i < 10) {i = "0" + i}; // add zero in front of numbers < 10
return i;
}
</script>
</head>
<body class="body page-index clearfix" onload="startTime()" style = "background-color: black;">
<div class="time">
<div id="sec" style="color: red;text-align: center; font-family: helvetica;font-size: 30px;"></div>
<div id="txt" style="color: white; text-align: center; font-family: helvetica; font-weight: normal; font-size: 90px;"></div>
<div id="date" style="color: white;text-align: center; font-family: helvetica;font-size: 30px;"></div>
</div>
<div class="container clearfix">
<p class="location"></p>
<p class="temperature"></p>
<div class="climate_bg">
</div>
<div class="info_bg">
<img class="dropicon" src="images/Droplet.svg">
<p class="humidity"></p>
<img class="windicon" src="images/Wind.svg">
<div class="windspeed"></div>
</div>
<p class="highlowtemp"></p>
<div class="conditioncontainer">
<p class="condition"></p>
</div>
<p class="heatwind"></p>
</div>
<div class="forecastonecontainer">
<p class="dateone"></p>
<div class="weatheronecontainer">
<div class="forecasticonone"></div>
<div class="conditiononecontainer">
<div class = "forecastone"></div>
</div>
<div class="highonecontainer">
<div class="highone"></div>
</div>
<div class="lowonecontainer">
<div class="lowone"></div>
</div>
</div>
</div>
<div class="forecasttwocontainer">
<p class="datetwo"></p>
<div class="weathertwocontainer">
<div class="forecasticontwo"></div>
<div class="conditiontwocontainer">
<div class = "forecasttwo"></div>
</div>
<div class="hightwocontainer">
<div class="hightwo"></div>
</div>
<div class="lowtwocontainer">
<div class="lowtwo"></div>
</div>
</div>
</div>
<div class="forecastthreecontainer">
<p class="datethree"></p>
<div class="weatherthreecontainer">
<div class="forecasticonthree"></div>
<div class="conditionthreecontainer">
<div class = "forecastthree"></div>
</div>
<div class="highthreecontainer">
<div class="highthree"></div>
</div>
<div class="lowthreecontainer">
<div class="lowthree"></div>
</div>
</div>
</div>
<div class="forecastfourcontainer">
<p class="datefour"></p>
<div class="weatherfourcontainer">
<div class="forecasticonfour"></div>
<div class="conditionfourcontainer">
<div class = "forecastfour"></div>
</div>
<div class="highfourcontainer">
<div class="highfour"></div>
</div>
<div class="lowfourcontainer">
<div class="lowfour"></div>
</div>
</div>
</div>
<p class="lastupdated"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.simpleWeather/3.1.0/jquery.simpleWeather.min.js"></script>
<script src="js/weather.js"></script>
</body>
</html>
body {
background-color: #000000;
font: 400 1em/1.38 Montserrat;
color: #ffffff;
}
.info_bg p {
margin-bottom: -.2em;
}
.time{
position:absolute;
left:2%;
}
.lastupdated{
position: absolute;
width: 400px;
top:560px;
right: 2.9%;
text-align: center;
}
.conditioncontainer{
position:relative;
left: 221px;
top: 120px;
width: 173px;
height: 65px;
display: table;
}
.condition {
position: relative;
display: table-cell;
width: 173px;
height: 50px;
color: black;
font-size: 18px;
vertical-align: middle;
text-align: center;
z-index: 7;
word-wrap: normal;
}
.climate_bg {
position: absolute;
top: -2px;
left: 220px;
z-index: 6;
width: 175px;
height: 191px;
border-top-right-radius: 10px;
background-color: white;
}
.weathericon {
display: block;
position: absolute;
top: -10px;
left: .46993865%;
z-index: 5;
width: 173px;
height: auto;
overflow: hidden;
}
.container {
position: absolute;
top: 28px;
right: 3%;
z-index: 9;
width: 398px;
height: 260px;
border-radius: 10px;
border-style: solid;
border-width: 3px;
border-color: white;
background-color: black;
}
.forecastfourcontainer {
position:absolute;
width: 398px;
height: 60px;
border-width: 2px;
border-color: white;
border-style: solid;
border-radius: 10px;
z-index: 9;
top: 490px;
right: 2.9%;
opacity: 0.95;
}
.datefour {
position:relative;
width: 70px;
font-size: 20px;
left: 10px;
top: 14px;
}
.weatherfourcontainer {
position:relative;
background-color: white;
height: 60px;
width:328px;
left: 68px;
top:-29px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
opacity: .95;
}
.conditionfourcontainer{
position:relative;
width: 157px;
height:60px;
top:-86px;
left: 50px;
display: table;
}
.forecasticonfour {
width: 80px;
height: auto;
position: relative;
top:-9px;
left: -15px;
color: black;
}
.forecastfour {
position: relative;
width:170px;
height: 20px;
font-size: 18px;
left: 5px;
color: black;
word-wrap: normal;
display: table-cell;
vertical-align:middle;
}
.highfourcontainer{
position:relative;
display:table;
background-color: black;
border-top-width: 2px;
border-bottom-width: 2px;
border-color: white;
border-style: solid;
top: -146px;
left: 208px;
width: 60px;
height: 60px;
}
.highfour{
position: relative;
display: table-cell;
vertical-align: middle;
text-align: center;
font-size: 17px;
color: white;
width: 50px;
}
.lowfourcontainer{
position:relative;
display:table;
background-color: black;
border-top-width: 2px;
border-bottom-width: 2px;
border-right-width: 2px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
border-color: white;
border-style: solid;
top: -206px;
left: 268px;
width: 60px;
height: 60px;
}
.lowfour{
position: relative;
display: table-cell;
vertical-align: middle;
text-align: center;
font-size: 17px;
color: white;
width: 50px;
}
.forecastthreecontainer {
position:absolute;
width: 398px;
height: 60px;
border-width: 2px;
border-color: white;
border-style: solid;
border-radius: 10px;
z-index: 9;
top: 425px;
right: 2.9%;
opacity: 0.95;
}
.datethree {
position:relative;
width: 70px;
font-size: 20px;
left: 10px;
top: 14px;
}
.weatherthreecontainer {
position:relative;
background-color: white;
height: 60px;
width:328px;
left: 68px;
top:-29px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
opacity: .95;
}
.conditionthreecontainer{
position:relative;
width: 157px;
height:60px;
top:-86px;
left: 50px;
display: table;
}
.forecasticonthree {
width: 80px;
height: auto;
position: relative;
top:-9px;
left: -15px;
color: black;
}
.forecastthree {
position: relative;
width:170px;
height: 20px;
font-size: 18px;
left: 5px;
color: black;
word-wrap: normal;
display: table-cell;
vertical-align:middle;
}
.highthreecontainer{
position:relative;
display:table;
background-color: black;
border-top-width: 2px;
border-bottom-width: 2px;
border-color: white;
border-style: solid;
top: -146px;
left: 208px;
width: 60px;
height: 60px;
}
.highthree{
position: relative;
display: table-cell;
vertical-align: middle;
text-align: center;
font-size: 17px;
color: white;
width: 50px;
}
.lowthreecontainer{
position:relative;
display:table;
background-color: black;
border-top-width: 2px;
border-bottom-width: 2px;
border-right-width: 2px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
border-color: white;
border-style: solid;
top: -206px;
left: 268px;
width: 60px;
height: 60px;
}
.lowthree{
position: relative;
display: table-cell;
vertical-align: middle;
text-align: center;
font-size: 17px;
color: white;
width: 50px;
}
.forecasttwocontainer {
position:absolute;
width: 398px;
height: 60px;
border-width: 2px;
border-color: white;
border-style: solid;
border-radius: 10px;
z-index: 9;
top: 360px;
right: 2.9%;
opacity: 0.95;
}
.datetwo {
position:relative;
width: 70px;
font-size: 20px;
left: 10px;
top: 14px;
}
.weathertwocontainer {
position:relative;
background-color: white;
height: 60px;
width:328px;
left: 68px;
top:-29px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
opacity: .95;
}
.conditiontwocontainer{
position:relative;
width: 157px;
height:60px;
top:-86px;
left: 50px;
display: table;
}
.forecasticontwo {
width: 80px;
height: auto;
position: relative;
top:-9px;
left: -15px;
color: black;
}
.forecasttwo {
position: relative;
width:170px;
height: 20px;
font-size: 18px;
left: 5px;
color: black;
word-wrap: normal;
display: table-cell;
vertical-align:middle;
}
.hightwocontainer{
position:relative;
display:table;
background-color: black;
border-top-width: 2px;
border-bottom-width: 2px;
border-color: white;
border-style: solid;
top: -146px;
left: 208px;
width: 60px;
height: 60px;
}
.hightwo{
position: relative;
display: table-cell;
vertical-align: middle;
text-align: center;
font-size: 17px;
color: white;
width: 50px;
}
.lowtwocontainer{
position:relative;
display:table;
background-color: black;
border-top-width: 2px;
border-bottom-width: 2px;
border-right-width: 2px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
border-color: white;
border-style: solid;
top: -206px;
left: 268px;
width: 60px;
height: 60px;
}
.lowtwo{
position: relative;
display: table-cell;
vertical-align: middle;
text-align: center;
font-size: 17px;
color: white;
width: 50px;
}
.forecastonecontainer {
position:absolute;
width: 398px;
height: 60px;
border-width: 2px;
border-color: white;
border-style: solid;
border-radius: 10px;
z-index: 9;
top: 295px;
right: 2.9%;
opacity: 0.95;
}
.dateone {
position:relative;
width: 70px;
font-size: 20px;
left: 10px;
top: 14px;
}
.weatheronecontainer {
position:relative;
background-color: white;
height: 60px;
width:328px;
left: 68px;
top:-29px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
opacity: .95;
}
.forecasticonone {
width: 80px;
height: auto;
position: relative;
top:-9px;
left: -15px;
color: black;
}
.conditiononecontainer{
position:relative;
width: 157px;
height:60px;
top:-86px;
left: 50px;
display: table;
}
.forecastone {
position: relative;
width:170px;
height: 20px;
font-size: 18px;
left: 5px;
color: black;
word-wrap: normal;
display: table-cell;
vertical-align:middle;
}
.highonecontainer{
position:relative;
display:table;
background-color: black;
border-top-width: 2px;
border-bottom-width: 2px;
border-color: white;
border-style: solid;
top: -146px;
left: 208px;
width: 60px;
height: 60px;
}
.highone{
position: relative;
display: table-cell;
vertical-align: middle;
text-align: center;
font-size: 17px;
color: white;
width: 50px;
}
.lowonecontainer{
position:relative;
display:table;
background-color: black;
border-top-width: 2px;
border-bottom-width: 2px;
border-right-width: 2px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
border-color: white;
border-style: solid;
top: -206px;
left: 268px;
width: 60px;
height: 60px;
}
.lowone{
position: relative;
display: table-cell;
vertical-align: middle;
text-align: center;
font-size: 17px;
color: white;
width: 50px;
}
.dropicon {
display: block;
position: absolute;
top: 15px;
left: -.9110429448%;
z-index: 3;
width: 41px;
height: auto;
overflow: hidden;
}
.not-available, .failed {
position: absolute;
top: 464px;
left: 0;
right: 0;
z-index: 10;
width: 248px;
min-height: 24px;
margin: 0 auto;
font: 0.625em/1.38 'Trebuchet MS';
color: rgb(0, 0, 0);
}
.humidity {
position: absolute;
top: 23px;
left: 29px;
z-index: 2;
width: 46px;
min-height: 29px;
font-size: 1em;
line-height: 1.38;
text-align: center;
color: #ffffff;
}
.info_bg {
position: absolute;
top: 189px;
left: 220px;
width: 175px;
z-index: 4;
height: 68px;
border-bottom-right-radius: 10px;
border-bottom-style: solid;
border-right-style: solid;
border-right-width: 3px;
border-bottom-width: 3px;
border-color: white;
background-color: #1ab1ed;
}
.location {
position: absolute;
top: 110px;
text-align: center;
z-index: 8;
width: 223px;
min-height: 59px;
font-size: 1.313em;
font-weight: 400;
line-height: 1.38;
text-transform: uppercase;
color: rgb(255, 255, 255);
}
.temperature {
position: absolute;
top: 20px;
left: 10px;
z-index: 7;
width: 223px;
text-align: center;
min-height: 28px;
font-size: 4.25em;
font-weight: 700;
line-height: 1.38;
color: rgb(255, 255, 255);
}
.windicon {
display: block;
position: absolute;
top: 10px;
left: 43.1173312883%;
z-index: 1;
width: 50px;
height: auto;
overflow: hidden;
}
.highlowtemp {
position: absolute;
top: 150px;
width: 223px;
text-align: center;
font-size: 25px;
color: white;
}
.heatwind {
position: relative;
top: 137px;
width: 220px;
text-align: center;
font-size: 24px;
}
.windspeed {
position: absolute;
top: 15px;
left: 113px;
width: 50px;
min-height: 29px;
font-size: 1em;
line-height: 1.38;
text-align: center;
color: #ffffff;
}
.windspeed p {
margin-bottom: -.2em;
}
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition(function (position) {
loadWeather(position.coords.latitude + ',' + position.coords.longitude);
});
} else{
loadWeather('Sugar Land, Texas', '' );
}
$(document).ready(function() {
loadWeather();
setInterval(loadWeather('Sugar Land, Texas', '' ), 10000);
});
function loadWeather(location, woeid){
$.simpleWeather({
location: location,
woeid: woeid,
unit: 'f',
success: function(weather){
city = weather.city;
temp = weather.temp+'°';
wcode = '<img class="weathericon" src= "images/weathericons/' + weather.code + '.svg">';
wind = '<p>' + weather.wind.speed + '</p><p>' + weather.units.speed + '</p>';
humidity = weather.humidity + ' %';
highlow = '↑ ' + weather.high + '° ' + '↓ ' + weather.low + '°';
current = weather.currently;
heatindexwindchill = '<img src= "http://www.weatherjon.org/meteo/homepage/blocks/radarUS/icons/dark/heatIndex.png" style="width:25px;height:25px;">' + ' ' + weather.heatindex + '° ' + '<img src= "http://pngimg.com/upload/snowflakes_PNG7576.png" style="width:25px;height:25px;">' + ' ' + weather.wind.chill + '°';
dateone = weather.forecast[1].day;
forecasticonone = '<img class="forecasticoneone" src= "images/weathericons/' + weather.forecast[1].code + '.svg">'
forecastone = weather.forecast[1].text ;
highone = '↑ ' + weather.forecast[1].high+ '°';
lowone = '↓ ' + weather.forecast[1].low+ '°';
datetwo = weather.forecast[2].day;
forecasticontwo = '<img class="forecasticoneone" src= "images/weathericons/' + weather.forecast[2].code + '.svg">'
forecasttwo = weather.forecast[2].text ;
hightwo = '↑ ' + weather.forecast[2].high+ '°';
lowtwo = '↓ ' + weather.forecast[2].low+ '°';
datethree = weather.forecast[3].day;
forecasticonthree = '<img class="forecasticoneone" src= "images/weathericons/' + weather.forecast[3].code + '.svg">'
forecastthree = weather.forecast[3].text ;
highthree = '↑ ' + weather.forecast[3].high+ '°';
lowthree = '↓ ' + weather.forecast[3].low+ '°';
datefour = weather.forecast[4].day;
forecasticonfour = '<img class="forecasticoneone" src= "images/weathericons/' + weather.forecast[4].code + '.svg">'
forecastfour = weather.forecast[4].text ;
highfour = '↑ ' + weather.forecast[4].high+ '°';
lowfour = '↓ ' + weather.forecast[4].low+ '°';
lastupdated = 'Last updated on ' + weather.updated;
$(".location").text(city);
$(".temperature").html(temp);
$(".climate_bg").html(wcode);
$(".windspeed").html(wind);
$(".humidity").text(humidity);
$(".highlowtemp").html(highlow);
$(".condition").text(current);
$(".heatwind").html(heatindexwindchill);
$(".dateone").html(dateone);
$(".forecasticonone").html(forecasticonone);
$(".forecastone").html(forecastone);
$(".highone").html(highone);
$(".lowone").html(lowone);
$(".datetwo").html(datetwo);
$(".forecasticontwo").html(forecasticontwo);
$(".forecasttwo").html(forecasttwo);
$(".hightwo").html(hightwo);
$(".lowtwo").html(lowtwo);
$(".datethree").html(datethree);
$(".forecasticonthree").html(forecasticonthree);
$(".forecastthree").html(forecastthree);
$(".highthree").html(highthree);
$(".lowthree").html(lowthree);
$(".datefour").html(datefour);
$(".forecasticonfour").html(forecasticonfour);
$(".forecastfour").html(forecastfour);
$(".highfour").html(highfour);
$(".lowfour").html(lowfour);
$(".lastupdated").html(lastupdated);
},
error: function(error) {
$("error").html('<p>' + error + '</p>');
}
});
}
Comments