From 072cf0b6ed50b4c83a510a68bb692594b0c9589b Mon Sep 17 00:00:00 2001 From: Yucel Aydogan Date: Mon, 13 Jun 2016 18:16:03 -0400 Subject: [PATCH 01/39] RSS Service (#161) * Create rss-service * RSS service * Support for RSS service * RSS service * Update index.html * RSS service * minor updates * Added rss-service * Randomize the news * Revert "Randomize the news" This reverts commit ef9467859f62cbba9ccf9c5d63de3023cf70f129. * RSS fixes * RSS fixes * RSS fixes * removing rss-service.js * Fixing an unpextec line issue after merge * RSS display fixes * RSS display fixes * RSS display fixes --- config.example.js | 5 ++++ css/main.css | 20 ++++++++++++- index.html | 13 +++++++++ js/controller.js | 19 +++++++++++++ js/services/rss.js | 60 +++++++++++++++++++++++++++++++++++++++ scripts/install.sh | 0 speech/_snowboydetect.so | Bin 7 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 js/services/rss.js mode change 100755 => 100644 scripts/install.sh mode change 100755 => 100644 speech/_snowboydetect.so diff --git a/config.example.js b/config.example.js index 9b7de2d5d..1164d72bc 100644 --- a/config.example.js +++ b/config.example.js @@ -71,6 +71,7 @@ var config = { }, traffic: { key : "", // Bing Maps API Key + reload_interval : 5, // Number of minutes the information is refreshed // An array of tips that you would like to display travel time for trips : [{ @@ -81,6 +82,10 @@ var config = { /*startTime: "", endTime: ""*/ // Optional starttime and endtime when the traffic information should be displayed on screen. The format can be either hh:mm or hh:mm am/pm }] + }, + rss: { + feeds : [], // RSS feeds list - e.g. ["rss1.com", "rss2.com"] + refreshInterval : 120 // Number of minutes the information is refreshed } }; diff --git a/css/main.css b/css/main.css index 88f098d9e..e7c86dabc 100644 --- a/css/main.css +++ b/css/main.css @@ -356,4 +356,22 @@ ul.calendar { .xkcd { -webkit-filter: invert(100%); - max-width: 100%; } + max-width: 100%; +} + +.news { + height: 75px; + margin-bottom: 5px; +} + +.news-title { + font-family: 'Open Sans', sans-serif; + font-size: 12px; + margin-bottom: 5px; +} + +.news-content { + font-family: 'Open Sans', sans-serif; + font-size: 20px; + margin-bottom: 55px; +} diff --git a/index.html b/index.html index 40cc53544..6e1cdf3f2 100644 --- a/index.html +++ b/index.html @@ -37,6 +37,7 @@ + @@ -156,6 +157,18 @@

{{ 'commands.title' | translate }}

+
+
+
+ + Source: {{news.title}}, Last Updated: {{news.lastUpdated.format('MMM DD, h:mm a')}} +
+
+ {{news.content}} +
+
+
+
diff --git a/js/controller.js b/js/controller.js index 5123aebdd..28e46d614 100644 --- a/js/controller.js +++ b/js/controller.js @@ -16,12 +16,14 @@ ReminderService, SearchService, SoundCloudService, + RssService, $rootScope, $scope, $timeout, $interval, tmhDynamicLocale, $translate) { var _this = this; $scope.listening = false; $scope.debug = false; $scope.focus = "default"; $scope.user = {}; + $scope.shownews = true; $scope.commands = []; /*$translate('home.commands').then(function (translation) { $scope.interimResult = translation; @@ -169,6 +171,23 @@ $interval(refreshComic, 12*60*60000); // 12 hours + var refreshRss = function () { + console.log ("Refreshing RSS"); + $scope.news = null; + RssService.refreshRssList(); + }; + + var updateNews = function() { + $scope.shownews = false; + setTimeout(function(){ $scope.news = RssService.getNews(); $scope.shownews = true; }, 1000); + }; + + refreshRss(); + $interval(refreshRss, config.rss.refreshInterval * 60000); + + updateNews(); + $interval(updateNews, 8000); // cycle through news every 8 seconds + var addCommand = function(commandId, commandFunction){ var voiceId = 'commands.'+commandId+'.voice'; var textId = 'commands.'+commandId+'.text'; diff --git a/js/services/rss.js b/js/services/rss.js new file mode 100644 index 000000000..bb2e9d9b6 --- /dev/null +++ b/js/services/rss.js @@ -0,0 +1,60 @@ +(function(annyang) { + 'use strict'; + + function RssService($http) { + var service = {}; + service.feed = []; + service.currentFeed = 0; + + service.init = function() { + service.feed = []; + service.currentFeed = 0; + var currentTime = new moment(); + + angular.forEach(config.rss.feeds, function(url) { + $http.jsonp('http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=50&callback=JSON_CALLBACK&q=' + encodeURIComponent(url)).then(function(response) { + for (var i=0; i < response.data.responseData.feed.entries.length; i++){ + var feedEntry = { + title : response.data.responseData.feed.title, + content: response.data.responseData.feed.entries[i].title, + lastUpdated : currentTime, + }; + //console.log(feedEntry); + service.feed.push(feedEntry); + } + }); + }); + return service.feed; + }; + + service.refreshRssList = function() { + return service.init(); + }; + + service.getNews = function() { + if (service.feed == null) { + return null; + } + switch (config.rss.mode) { + case 'random': + service.currentFeed = Math.floor(Math.random() * service.feed.length); + break; + + case 'sequence': + default: + if (service.currentFeed == (service.feed.length-1)){ + service.currentFeed = 0; + } + else { + service.currentFeed = service.currentFeed + 1; + } + }; + return service.feed[service.currentFeed]; + } ; + + return service; + } + + angular.module('SmartMirror') + .factory('RssService', RssService); +}(window.annyang)); diff --git a/scripts/install.sh b/scripts/install.sh old mode 100755 new mode 100644 diff --git a/speech/_snowboydetect.so b/speech/_snowboydetect.so old mode 100755 new mode 100644 From ac20ffd76209e854da800e7218ae9fdb9f434aef Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Tue, 14 Jun 2016 17:44:19 -0700 Subject: [PATCH 02/39] Removing ding as a result of #287 The ding was causing a freeze in a rewind. This is a temporary workaround to stop the keyword spotter from hanging after a few utterances. --- speech/kws.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/speech/kws.py b/speech/kws.py index 41275fb81..0ebf8ff03 100644 --- a/speech/kws.py +++ b/speech/kws.py @@ -16,7 +16,7 @@ def interrupt_callback(): def hotword_detected_callback(): print("!Hotword Detected") - snowboydecoder.play_audio_file(snowboydecoder.DETECT_DING) + #snowboydecoder.play_audio_file(snowboydecoder.DETECT_DING) if len(sys.argv) < 2: print("Error: need to specify model name and sensitivity") From 854c9fb52304741665162fb380de419253edcae7 Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Fri, 17 Jun 2016 18:22:02 -0700 Subject: [PATCH 03/39] adding installer and a small sound-cloud visualization tweek --- index.html | 2 +- js/services/soundcloud.js | 2 +- scripts/install.sh | 131 -------------------------- scripts/pi-install.sh | 190 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+), 133 deletions(-) delete mode 100644 scripts/install.sh create mode 100755 scripts/pi-install.sh diff --git a/index.html b/index.html index 6e1cdf3f2..e6636d3b8 100644 --- a/index.html +++ b/index.html @@ -107,7 +107,7 @@

{{user.name}}

-
+

{{scTrack}}

diff --git a/js/services/soundcloud.js b/js/services/soundcloud.js index 73067094b..e313029e7 100644 --- a/js/services/soundcloud.js +++ b/js/services/soundcloud.js @@ -76,7 +76,7 @@ var canvas = document.getElementById('visualizer'); var canvasCtx = canvas.getContext("2d"); - var WIDTH = 150; + var WIDTH = 300; var HEIGHT = 150; canvasCtx.fillStyle = 'rgb(0, 0, 0)'; diff --git a/scripts/install.sh b/scripts/install.sh deleted file mode 100644 index 6bb428076..000000000 --- a/scripts/install.sh +++ /dev/null @@ -1,131 +0,0 @@ -#!/bin/bash - -# Any subsequent(*) commands which fail will cause the shell script to exit immediately -set -e - -# Supported versions of node: v4.x, v5.x -NODE_VERSION="v4.*\|v5.*" - -# Terminal Colors -red=$'\e[1;31m' -grn=$'\e[1;32m' -yel=$'\e[1;33m' -blu=$'\e[1;34m' -mag=$'\e[1;35m' -cyn=$'\e[1;36m' -end=$'\e[0m' - -# Ensure we are using sudo -if [ "$(whoami)" != "root" ]; -then - echo "This script requires root permissions, try: sudo ./${0##*/} " - exit 0 -fi - -cat << "EOF" - ________ _____ ______ ________ ________ _________ -|\ ____\|\ _ \ _ \|\ __ \|\ __ \|\___ ___\ -\ \ \___|\ \ \\\__\ \ \ \ \|\ \ \ \|\ \|___ \ \_| - \ \_____ \ \ \\|__| \ \ \ __ \ \ _ _\ \ \ \ - \|____|\ \ \ \ \ \ \ \ \ \ \ \ \\ \| \ \ \ - ____\_\ \ \__\ \ \__\ \__\ \__\ \__\\ _\ \ \__\ - |\_________\|__| \|__|\|__|\|__|\|__|\|__| \|__| - \|_________| - - _____ ______ ___ ________ ________ ________ ________ -|\ _ \ _ \|\ \|\ __ \|\ __ \|\ __ \|\ __ \ -\ \ \\\__\ \ \ \ \ \ \|\ \ \ \|\ \ \ \|\ \ \ \|\ \ - \ \ \\|__| \ \ \ \ \ _ _\ \ _ _\ \ \\\ \ \ _ _\ - \ \ \ \ \ \ \ \ \ \\ \\ \ \\ \\ \ \\\ \ \ \\ \ - \ \__\ \ \__\ \__\ \__\\ _\\ \__\\ _\\ \_______\ \__\\ _\ - \|__| \|__|\|__|\|__|\|__|\|__|\|__|\|_______|\|__|\|__| - -EOF - -printf "%sThis script will install the smart-mirror and it's dependencies.\n" - -# Ensure the use would like to start the install -read -r -p "Would you like to continue? [y/N] " response -if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]] -then - printf "%sExcellent! ${red}Please do not exit this script until it is complete.${end}\n" -else - exit 1 -fi - -printf "%s\n" -read -r -p "[Requires Reboot] Would you like to automoticlly rotate your monitor? [y/N]" rotateResponse -if [[ $rotateResponse =~ ^([yY][eE][sS]|[yY])$ ]] -then - # Rotate Display (replace the display_rotate line with display_rotate=1) - sed -i -e '$a\ -\ -#Rotate the display (smart-mirror)\ -display_rotate=1' /boot/config.txt -fi - -printf "%s\nChecking for node...\n" -node --version | grep ${NODE_VERSION} -if [[ $? != 0 ]] ; -then - # Install Node - printf "%s{blu}Downloading node${end}\n" - wget https://nodejs.org/dist/v4.0.0/node-v4.0.0-linux-armv7l.tar.gz - tar -xvf node-v4.0.0-linux-armv7l.tar.gz - cd node-v4.0.0-linux-armv7l - - # Copy to /usr/local - printf "%s{blu}Installing node${end}\n" - sudo cp -R * /usr/local/ - - # Clean up after ourselvs - cd .. - rm node-v4.0.0-linux-armv7l.tar.gz - rm -R node-v4.0.0-linux-armv7l - printf "%s$(tput setaf 10)node is now installed!${end}\n" -else - printf "%s$(tput setaf 10)node is already installed, great job!${end}\n" -fi - -# Getting the code -printf "%s\n{blu}Cloning Git Repo${end}\n" -cd /home/$SUDO_USER -sudo -u $SUDO_USER git clone https://github.com/evancohen/smart-mirror.git -printf "%s\n$(tput setaf 10)smart-mirror code is now downloaded${end}\n" - -cd smart-mirror - -printf "%s{blu}generating config template${end}\n" -sudo -u $SUDO_USER cp config.example.js config.js - -# Install package to hide the mouse when inactive -printf "%s\n{blu}Installing unclutter${end}\n" -sudo apt-get install unclutter - -# Apply LXDE unclutter autostart -sed -i -e '$a\ -\ -#Hide the mouse when inactive (smart-mirror)\ -unclutter -idle 0.1 -root' /etc/xdg/lxsession/LXDE-pi/autostart - -printf "%s\n{blu}Installing smart-mirror dependencies...${end}\n" -printf "%s${yel}This may take a while. Go grab a beer :)${end}\n" -sudo -u $SUDO_USER npm install - -# The mirror is now installed, yay! -cat << "EOF" - - | The smart-mirror is now installed! - / \ - / _ \ Once you fill out your config you can start the mirror with: - |.o '.| npm start - |'._.'| - | | To lean more, check out the documentation at: - ,'| | |`. docs.smart-mirror.io - / | | | \ - |,-'--|--'-.| - -EOF -# ASCII art found on http://textart.io/ - -exit 0 \ No newline at end of file diff --git a/scripts/pi-install.sh b/scripts/pi-install.sh new file mode 100755 index 000000000..49ecd8b89 --- /dev/null +++ b/scripts/pi-install.sh @@ -0,0 +1,190 @@ +#!/bin/bash + +# Any subsequent(*) commands which fail will cause the shell script to exit immediately +set -e + +# Supported versions of node: v4.x, v5.x +NODE_MINIMUM_VERSION="v4.0.0" +NODE_STABLE_VERSION="6.x" + +# Compare node versions. +function check_version() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; } +# Check to see if a command exists (if something is installed) +function command_exists () { type "$1" &> /dev/null ;} + +# Terminal Colors +red=$'\e[1;31m' +grn=$'\e[1;32m' +yel=$'\e[1;33m' +blu=$'\e[1;34m' +mag=$'\e[1;35m' +cyn=$'\e[1;36m' +end=$'\e[0m' + +# Ensure we are using sudo +if [ "$(whoami)" != "root" ]; +then + echo "This script requires root permissions, try: sudo ./${0##*/} " + exit 0 +fi + +cat << "EOF" + ________ _____ ______ ________ ________ _________ +|\ ____\|\ _ \ _ \|\ __ \|\ __ \|\___ ___\ +\ \ \___|\ \ \\\__\ \ \ \ \|\ \ \ \|\ \|___ \ \_| + \ \_____ \ \ \\|__| \ \ \ __ \ \ _ _\ \ \ \ + \|____|\ \ \ \ \ \ \ \ \ \ \ \ \\ \| \ \ \ + ____\_\ \ \__\ \ \__\ \__\ \__\ \__\\ _\ \ \__\ + |\_________\|__| \|__|\|__|\|__|\|__|\|__| \|__| + \|_________| + + _____ ______ ___ ________ ________ ________ ________ +|\ _ \ _ \|\ \|\ __ \|\ __ \|\ __ \|\ __ \ +\ \ \\\__\ \ \ \ \ \ \|\ \ \ \|\ \ \ \|\ \ \ \|\ \ + \ \ \\|__| \ \ \ \ \ _ _\ \ _ _\ \ \\\ \ \ _ _\ + \ \ \ \ \ \ \ \ \ \\ \\ \ \\ \\ \ \\\ \ \ \\ \ + \ \__\ \ \__\ \__\ \__\\ _\\ \__\\ _\\ \_______\ \__\\ _\ + \|__| \|__|\|__|\|__|\|__|\|__|\|__|\|_______|\|__|\|__| + +EOF + +ARCH=$(uname -m) +# Check processor archetecture. +if [$ARCH != "armv7l" ]; then + printf "%s${red} Unupported device!${end} The smart-mirror only works on the Pi 2 and 3" + exit; +fi + +printf "%sThis script will install the smart-mirror and it's dependencies.\n" + +# Ensure the use would like to start the install +read -r -p "Would you like to continue? [y/N] " response +if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then + printf "%sExcellent! ${red}Please do not exit this script until it is complete.${end}\n" +else + exit 1 +fi + +# # Rotate the monitor +# printf "%s\n" +# read -r -p "Would you like to rotate your monitor? [y/N]" rotateResponse +# if [[ $rotateResponse =~ ^([yY][eE][sS]|[yY])$ ]]; then +# # Rotate Display (replace the display_rotate line with display_rotate=1) +# sed -i -e '$a\ +# \ +# #Rotate the display (smart-mirror)\ +# display_rotate=1' /boot/config.txt +# fi + +# Sound configuration +printf "%s\n${blu}Would you like to install and auto-configure sound and audio capture dependencies (reccomended)?${end}\n" +read -r -p "If you have an existing sound setup you can skip this [y/N] " response +if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then + ## TODO: is pulseaudio-module-jack actually required? + printf "%s\n${blu}Installing audio dependencies${end}\n" + sudo apt-get install pulseaudio pulseaudio-module-zeroconf pulseaudio-module-jack +fi + +# Install native dependencies +printf "%s\n${blu}Installing non-audio native dependencies${end}\n" +sudo apt-get install curl wget git python-pyaudio python3-pyaudio sox unclutter + +# Check if we need to install or upgrade Node.js. +printf "%s\n${blu}Checking current Node installation${end}\n" +NODE_INSTALL=false +if command_exists node; then + NODE_CURRENT=$(node -v) + printf "%sMinimum Node version: $NODE_MINIMUM_VERSION\n" + printf "%sInstalled Node version: $NODE_CURRENT\n" + if check_version $NODE_MINIMUM_VERSION $NODE_CURRENT; then + NODE_INSTALL=true + # If Node is already running then abort + if pgrep "node" > /dev/null; then + printf "%s${red}A node process is currently running. Unable to upgrade for you.${end}\n" + printf "Exit all Node processes and then restart this installer." + exit; + fi + printf "%sLooks like you need an upgrade. Taking care of that for you.\n" + fi +else + printf "%sNo Node installation found. Installing it for you.\n"; + NODE_INSTALL=true +fi +# Upgrade node if it is out of date +if $NODE_INSTALL; then + printf "%sInstalling Node...\n" + curl -sL https://deb.nodesource.com/setup_$NODE_STABLE_VERSION | sudo -E bash - + sudo apt-get install -y nodejs + printf "%sNode installation complete.\n" +fi + +#Install magic mirror +cd /home/"$SUDO_USER" +if [ -d "$HOME/smart-mirror" ]; then + printf "%s${red}Looks like the smart mirror is already installed.${end}\n" + printf "%sPlease rename or remove the ${mag}smart-mirror${end} folder and re-run the installer.\n" + printf "%sIf you want to upgrade your smart mirror run ${cyn}git pull${end} from the ~/smart-mirror directory.\n" + exit; +fi + +# Getting the code +printf "%s\n${blu}Cloning smart-mirror Git Repo${end}\n" +if sudo -u "$SUDO_USER" git clone https://github.com/evancohen/smart-mirror.git; then + printf "%s${grn}smart-mirror code is now downloaded${end}\n" +else + printf "%s${red}Unable to clone smart-mirror :( ${end}\n" + exit; +fi + +# Generate config and install dependencies +cd smart-mirror || exit +printf "%s\n${blu}generating config template...${end}\n" +sudo -u "$SUDO_USER" cp config.example.js config.js + +# Install smart-mirror dependencies +printf "%s\n${blu}Installing smart-mirror dependencies...${end}\n" +printf "%s${yel}This may take a while. Go grab a beer :)${end}\n" +if sudo -u "$SUDO_USER" npm install; then + printf "%s${grn}Dependency installation complete!${end}\n" +else + printf "%s${red}Unable to install dependencies :( ${end}\n" + exit; +fi + +# Apply LXDE unclutter autostart (if we haven't already) +if ! grep -q '(smart-mirror)' /etc/xdg/lxsession/LXDE/autostart; then + sed -i -e '$a\ +\ +#Hide the mouse when inactive (smart-mirror)\ +unclutter -idle 0.1 -root' /etc/xdg/lxsession/LXDE/autostart +fi + +# Disable the screensaver (if we haven't already) +if ! grep -q '(smart-mirror)' /home/"$SUDO_USER"/.config/lxsession/LXDE-pi/autostart; then + sed -i -e '$a\ +\ +#Disable screen saver (smart-mirror)\ +@xset s 0 0\ +@xset s noblank\ +@xset s noexpose\ +@xset dpms 0 0 0' /home/"$SUDO_USER"/.config/lxsession/LXDE-pi/autostart +fi + + +# The mirror is now installed, yay! +cat << "EOF" + + | The smart-mirror is now installed! + / \ + / _ \ Once you fill out your config you can start the mirror with: + |.o '.| > npm start + |'._.'| Or if you are running over SSH: + | | > DISPLAY=:0 npm start + ,'| | |`. + / | | | \ To lean more, check out the documentation at: + |,-'--|--'-.| http://docs.smart-mirror.io + +EOF +# ASCII art found on http://textart.io/ + +exit 0 \ No newline at end of file From eeb45c69ff7c90ab71c6368a1e37830d2440a8e4 Mon Sep 17 00:00:00 2001 From: Joel Hawksley Date: Mon, 20 Jun 2016 16:29:44 -0600 Subject: [PATCH 04/39] [SPELLING] tempreture > temperature (#298) * [SPELLING] tempreture > temperature * [SPELLING] forcast > forecast --- config.example.js | 6 +++--- css/icesnow.css | 6 +++--- css/main.css | 4 ++-- index.html | 6 +++--- sass/icesnow.scss | 2 +- sass/main.scss | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/config.example.js b/config.example.js index 1164d72bc..94c1db4aa 100644 --- a/config.example.js +++ b/config.example.js @@ -31,10 +31,10 @@ var config = { }, */ - // forcast.io + // forecast.io forecast : { - key : "", // Your forcast.io api key - units : "auto" // See forcast.io documentation if you are getting the wrong units + key : "", // Your forecast.io api key + units : "auto" // See forecast.io documentation if you are getting the wrong units }, // Philips Hue hue : { diff --git a/css/icesnow.css b/css/icesnow.css index 2a212d483..73a1cae43 100644 --- a/css/icesnow.css +++ b/css/icesnow.css @@ -115,7 +115,7 @@ ul.calendar { text-align: right; width: 230px; } -.weather-today .tempreture { +.weather-today .temperature { font-size: 60px; } .weather-week-descriptor { @@ -132,7 +132,7 @@ ul.calendar { display: inline-block; margin-right: 10px; width: 40px; } - .weather-week .tempreture { + .weather-week .temperature { display: inline-block; width: 60px; } @@ -284,7 +284,7 @@ body { Weather */ -.weather-today .tempreture { +.weather-today .temperature { font-size: 80px; } .weather-week-descriptor span.ng-binding { diff --git a/css/main.css b/css/main.css index e7c86dabc..ad0d6b058 100644 --- a/css/main.css +++ b/css/main.css @@ -130,7 +130,7 @@ ul.calendar { text-align: right; width: 230px; } -.weather-today .tempreture { +.weather-today .temperature { font-size: 60px; } .weather-week-descriptor { @@ -147,7 +147,7 @@ ul.calendar { display: inline-block; margin-right: 10px; width: 40px; } - .weather-week .tempreture { + .weather-week .temperature { display: inline-block; width: 50px; } diff --git a/index.html b/index.html index e6636d3b8..9b8e61166 100644 --- a/index.html +++ b/index.html @@ -69,7 +69,7 @@
- {{currentForecast.temperature}}° + {{currentForecast.temperature}}°
{{hourlyForecast.summary}} @@ -80,8 +80,8 @@ {{forecast.day}} - {{forecast.temperatureMin}}° - {{forecast.temperatureMax}}° + {{forecast.temperatureMin}}° + {{forecast.temperatureMax}}°
diff --git a/sass/icesnow.scss b/sass/icesnow.scss index a53db7242..18f773372 100644 --- a/sass/icesnow.scss +++ b/sass/icesnow.scss @@ -54,7 +54,7 @@ Weather */ -.weather-today .tempreture { +.weather-today .temperature { font-size: 80px; } diff --git a/sass/main.scss b/sass/main.scss index f9a82b62a..18f952242 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -143,7 +143,7 @@ ul.calendar { width: 230px; } -.weather-today .tempreture { +.weather-today .temperature { font-size: 60px; } @@ -163,7 +163,7 @@ ul.calendar { margin-right: 10px; width: 40px; } - .tempreture { + .temperature { display: inline-block; width: 60px; } From 056f6ff69fa6da68dd4088653fcaf84f39561605 Mon Sep 17 00:00:00 2001 From: Joel Hawksley Date: Wed, 22 Jun 2016 19:01:38 -0600 Subject: [PATCH 05/39] [CLEANUP] Remove SCSS (#302) --- css/icesnow.css.map | 7 - css/main.css.map | 7 - sass/icesnow.scss | 114 -------------- sass/main.scss | 370 -------------------------------------------- 4 files changed, 498 deletions(-) delete mode 100644 css/icesnow.css.map delete mode 100644 css/main.css.map delete mode 100644 sass/icesnow.scss delete mode 100644 sass/main.scss diff --git a/css/icesnow.css.map b/css/icesnow.css.map deleted file mode 100644 index 7fa9c801a..000000000 --- a/css/icesnow.css.map +++ /dev/null @@ -1,7 +0,0 @@ -{ -"version": 3, -"mappings": "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", -"sources": ["../sass/icesnow.scss","../sass/main.scss"], -"names": [], -"file": "icesnow.css" -} diff --git a/css/main.css.map b/css/main.css.map deleted file mode 100644 index 19c7a95da..000000000 --- a/css/main.css.map +++ /dev/null @@ -1,7 +0,0 @@ -{ -"version": 3, -"mappings": "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", -"sources": ["../sass/main.scss"], -"names": [], -"file": "main.css" -} diff --git a/sass/icesnow.scss b/sass/icesnow.scss deleted file mode 100644 index 18f773372..000000000 --- a/sass/icesnow.scss +++ /dev/null @@ -1,114 +0,0 @@ -@import "main"; - -@import url(https://fonts.googleapis.com/css?family=Work+Sans:300,400,500); - -body { - font-family: 'Work Sans', sans-serif; - font-weight: 300; -} - -.top-left { - float: right; - text-align: right; - display: -webkit-flex; - -webkit-flex-direction: column; - flex-direction: column; - float: right; - width: 420px; - .date { - -webkit-flex: 2; - flex: 2; - -webkit-order: 2; - order: 2; - width: 220px; - position: relative; - left: 200px; - } - ul.calendar { - -webkit-flex: 3; - flex: 3; - -webkit-order: 3; - order: 3; - } - .time { - -webkit-flex: 1; - flex: 1; - -webkit-order: 1; - order: 1; - } -} - -.top-right { - float: left; - text-align: left; - width: 265px; - .weather { - text-align: left; - width: 100%; - } -} - -/* - -Weather - -*/ - -.weather-today .temperature { - font-size: 80px; -} - -.weather-week-descriptor span.ng-binding { - &:first-child { - font-size: 21px; - } - text-align: left; - word-spacing: normal; - display: inline-block; -} - -.weather-week-day { - margin-bottom: 5px; -} - -.weather { - .weather-today .icon, .weather-week-day .icon-small { - display: none; - } - .weather-today canvas, .weather-week-day canvas { - display: inline-block; - } - .weather-week-descriptor span { - padding-bottom: 7px; - margin-bottom: 7px; - display: block; - border-bottom: 2px solid #aaa; - &:last-child { - border-bottom: 0; - } - } -} - -/* -Calc -*/ - -.top-left ul.calendar { - font-size: 17px; - margin-top: 80px; - .day { - display: none; - } - .event-details .details { - color: #999; - } -} - -/* middle */ - -.middle-center { - justify-content: flex-end; - h1 { - font-size: 90px; - } -} \ No newline at end of file diff --git a/sass/main.scss b/sass/main.scss deleted file mode 100644 index 18f952242..000000000 --- a/sass/main.scss +++ /dev/null @@ -1,370 +0,0 @@ -@font-face { - font-family: "HelveticaNeue-UltraLight"; - src: url("../fonts/HelveticaNeue-UltraLight.ttf"); - /* EOT file for IE */ -} - -body { - background-color: black; - color: #fff; - font-family: 'HelveticaNeue-UltraLight', 'Open Sans', sans-serif; - font-weight: 300; - position: relative; -} - -h1, h2, h3, h4, h5 { - font-weight: 300; -} - -h1 { - font-size: 120px; -} - -dt { - font-weight: 600; -} - -/* Colors */ - -.light-grey { - color: #ccc; -} - -.grey { - color: #999; -} - -/* Displays */ - -.sleep-cover { - background-color: black; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 999; -} - -.container { - z-index: -1; - /* so things are still selectable */ - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; -} - -.listening, .interim-result { - font-family: 'Open Sans', sans-serif; -} - -.top-left { - float: left; -} - -.date { - font-size: 42px; -} - -.time { - font-size: 110px; -} - -.top-right { - float: right; -} - -.middle-center { - display: flex; - flex: 1; - align-items: stretch; - align-self: flex-start; - flex-direction: column; - width: 100%; - text-align: center; - justify-content: center; -} - -.bottom-center { - font-family: 'Open Sans', sans-serif; - width: 100%; - text-align: center; - margin-bottom: 20px; -} - -.commands { - width: 450px; - text-align: left; - margin-left: auto; - margin-right: auto; -} - -ul.calendar { - list-style: none; - font-size: 22px; - margin-left: 10px; - padding: 0; -} - -.calendar { - .event { - margin-bottom: 10px; - } - span { - display: inline-block; - &.day { - font-weight: bold; - width: 128px; - vertical-align: top; - } - &.summary { - max-width: 400px; - } - } - .event-details .details { - font-size: 12px; - padding-left: 135px; - font-family: 'Open Sans', sans-serif; - font-weight: lighter; - } -} - -.weather { - margin-left: auto; - display: inline-block; - text-align: right; - width: 230px; -} - -.weather-today .temperature { - font-size: 60px; -} - -.weather-week-descriptor { - font-family: 'Open Sans', sans-serif; - font-size: 12px; - margin-left: auto; - margin-bottom: 10px; - text-align: justify; -} - -.weather-week { - margin-right: 10px; - font-size: 22px; - .day { - display: inline-block; - margin-right: 10px; - width: 40px; - } - .temperature { - display: inline-block; - width: 60px; - } -} - -.weather { - .weather-today canvas, .weather-week-day canvas { - display: none; - } -} - -.traffic-information { - text-align: right; - margin-top: 10px; - margin-right: 10px; -} - -.time-to { - font-weight: bold; -} - -@keyframes reduce-dashoffset { - to { stroke-dashoffset: 0; } -} - -@keyframes increase-dashoffset { - from { stroke-dashoffset: 0; } -} - -.timer { - font-size: 120px; - position: relative; -} - -.timer-circle { - $size: 3.25em; - $stroke: 0.1em; - $pi: 3.1415926535; - - width: $size; - height: $size; - transform: rotate(-90deg) scaleY(-1); - margin: 20px auto; - display: block; - - .background, - .progress { - r: $size / 2 - $stroke; - cx: $size / 2; - cy: $size / 2; - fill: none; - stroke: #222; - stroke-width: $stroke; - } - - .progress { - stroke-dasharray: $pi * $size; - stroke-dashoffset: $pi * $size; - - stroke: white; - stroke-linecap: round; - animation-name: increase-dashoffset; - animation-timing-function: linear; - animation-fill-mode: forwards; - } - - &.finish .progress { - // animation-name: reduce-dashoffset; - // animation-duration: 1500ms; - // animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.335); - } -} - -.timer-countdown { - position: absolute; - top: 50%; - left: 50%; - transform: translateY(-50%) translateX(-50%); -} - -.timer-duration { - @extend .timer-countdown; - top: 75%; - font-size: 25%; -} - -.contents { - max-width: 100%; -} - -.gif { - height: 100%; -} - -.map { - height: 1080px; -} - -.contents-box { - text-align: center; - width: 100%; - position: relative; - overflow: hidden; - &:after { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - -webkit-box-shadow: inset 0 0 10px 10px #000; - -moz-box-shadow: inset 0 0 10px 10px #000; - box-shadow: inset 0 0 10px 10px #000; - overflow: hidden; - } -} - -.color-block { - height: 200px; - width: 200px; - display: inline-block; - margin: 10px; - margin-bottom: 20px; -} - -.debug-info { - width: 500px; -} - -/* Animations */ - -.fade { - &.ng-hide { - opacity: 0; - } - &.ng-hide-remove, &.ng-hide-add { - display: block !important; - } - &.ng-hide-remove { - transition: all ease 1500ms; - } - &.ng-hide-add { - transition: all ease 500ms; - } -} - -.animate-grow { - max-height: 1280px !important; - &.ng-hide-add, &.ng-hide-remove { - transition: all linear 500ms; - } - &.ng-hide { - max-height: 0 !important; - } -} - -.dimmed { - color: #aaa; -} - -.xxsmall, .xsmall, .small { - font-family: "HelveticaNeue-Medium", sans-serif; - letter-spacing: 0; -} - -.xxsmall { - font-size: 15px; - .wi { - line-height: 15px; - } -} - -.xsmall { - font-size: 20px; -} - -.small { - font-size: 25px; -} - -.icon { - position: relative; - top: -10px; - display: inline-block; - font-size: 45px; - padding-right: 5px; - font-weight: 100; - margin-right: 10px; -} - -.icon-small { - position: relative; - display: inline-block; - font-size: 20px; - padding-left: 0px; - padding-right: -10px; - font-weight: 100; - width: 20px; -} - -.xkcd { - -webkit-filter: invert(100%); - max-width: 100%; -} From b083f6010d555723eece030176a0b6dfc866131d Mon Sep 17 00:00:00 2001 From: Joel Hawksley Date: Fri, 24 Jun 2016 06:45:34 -0600 Subject: [PATCH 06/39] [FEATURE] Add minutely summary to weather week descriptor (#304) --- index.html | 1 + js/controller.js | 2 ++ js/services/weather.js | 9 ++++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 9b8e61166..aa161091d 100644 --- a/index.html +++ b/index.html @@ -72,6 +72,7 @@ {{currentForecast.temperature}}°
+ {{minutelyForecast.summary}} {{hourlyForecast.summary}} {{weeklyForecast.summary}}
diff --git a/js/controller.js b/js/controller.js index 28e46d614..c4a69d981 100644 --- a/js/controller.js +++ b/js/controller.js @@ -73,9 +73,11 @@ $scope.currentForecast = WeatherService.currentForecast(); $scope.weeklyForecast = WeatherService.weeklyForecast(); $scope.hourlyForecast = WeatherService.hourlyForecast(); + $scope.minutelyForecast = WeatherService.minutelyForecast(); console.log("Current", $scope.currentForecast); console.log("Weekly", $scope.weeklyForecast); console.log("Hourly", $scope.hourlyForecast); + console.log("Minutely", $scope.minutelyForecast); var skycons = new Skycons({"color": "#aaa"}); skycons.add("icon_weather_current", $scope.currentForecast.iconAnimation); diff --git a/js/services/weather.js b/js/services/weather.js index ee37f4a1e..42ed4177e 100644 --- a/js/services/weather.js +++ b/js/services/weather.js @@ -16,7 +16,14 @@ }); }; - //Returns the current forecast along with high and low tempratures for the current day + service.minutelyForecast = function(){ + if(service.forecast === null){ + return null; + } + return service.forecast.data.minutely; + } + + //Returns the current forecast along with high and low tempratures for the current day service.currentForecast = function() { if(service.forecast === null){ return null; From f152f874c67a4bbacc40b1be58a59fa98b7061a7 Mon Sep 17 00:00:00 2001 From: The One Date: Tue, 28 Jun 2016 19:50:59 +0200 Subject: [PATCH 07/39] add Hyperion support (#229) * add Hyperion support * Merge Hyperion and Hue Services --- config.example.js | 45 +++++++--- index.html | 5 +- js/controller.js | 6 +- js/services/hue.js | 125 -------------------------- js/services/light.js | 202 +++++++++++++++++++++++++++++++++++++++++++ locales/de.json | 15 ++-- locales/en.json | 13 ++- package.json | 1 + 8 files changed, 259 insertions(+), 153 deletions(-) delete mode 100644 js/services/hue.js create mode 100644 js/services/light.js diff --git a/config.example.js b/config.example.js index 94c1db4aa..f007ea3ba 100644 --- a/config.example.js +++ b/config.example.js @@ -36,20 +36,37 @@ var config = { key : "", // Your forecast.io api key units : "auto" // See forecast.io documentation if you are getting the wrong units }, - // Philips Hue - hue : { - ip : "", // The IP address of your hue base - uername : "", // The username used to control your hue - groups : [{ - id : 0, // The group id 0 will change all the lights on the network - name : "all" - }, { - id : 1, - name : "bedroom" - }, { - id : 2, - name : "kitchen" - }] + // lights + light : { + settings : { + hue_ip : "", // The IP address of your hue base + hue_username : "" // The username used to control your hue + }, + setup : [ + { + name : "parlor", // Single word room name for speech recognition + targets : [ + { + type : "hyperion", + ip : "", // The IP address of your hyperion + port : "19444" // The port of your hyperion + }, + { + type : "hue", // Philips Hue + id : 1 // The group id (0 will change all the lights on the network) + } + ] + }, + { + name : "bath", + targets : [ + { + type : "hue", + id : 2 + } + ] + } + ] }, // Calendar (An array of iCals) calendar: { diff --git a/index.html b/index.html index aa161091d..cccfc4a1b 100644 --- a/index.html +++ b/index.html @@ -22,6 +22,7 @@ + @@ -29,7 +30,7 @@ - + @@ -44,7 +45,7 @@ - + diff --git a/js/controller.js b/js/controller.js index c4a69d981..d04d3dafb 100644 --- a/js/controller.js +++ b/js/controller.js @@ -7,7 +7,7 @@ WeatherService, FitbitService, MapService, - HueService, + LightService, CalendarService, ComicService, GiphyService, @@ -340,9 +340,9 @@ console.debug("It is", moment().format('h:mm:ss a')); }); - // Turn lights off + // Control light addCommand('light_action', function(state, action) { - HueService.performUpdate(state + " " + action); + LightService.performUpdate(state + " " + action); }); //Show giphy image diff --git a/js/services/hue.js b/js/services/hue.js deleted file mode 100644 index 96ab095a9..000000000 --- a/js/services/hue.js +++ /dev/null @@ -1,125 +0,0 @@ -(function() { - 'use strict'; - - function HueService($http, $translate) { - var service = {}; - //Updates a group of Hue lights (Assumes that one group is configured) - //You can change the group to 0 to perform the updates to all lights - service.performUpdate = function(spokenWords) { - var spokenWordsArray = spokenWords.toLowerCase().split(" "); - //deturmine the updates that we need to perform to the lights - var update = deturmineUpdates(spokenWordsArray); - // Deturmine which light to swith on/off - var light = deturmineLight(spokenWordsArray); - //Parse the update string and see what actions we need to perform - console.log("Updating hue group [" + light + "]:", update); - - $http.put('http://' + config.hue.ip + '/api/' + config.hue.uername + "/groups/" + light + "/action", update) - .success(function (data, status, headers) { - console.log(data); - }) - } - - //Detect any kind of target color - function deturmineUpdates(spokenWords){ - var update = {}; - - update["transitiontime"] = 10; - - for(var i = 0; i < spokenWords.length; i++){ - - //Check for color updates - if($translate.instant('lights.colors.red') == spokenWords[i]){ - update["xy"] = [0.674,0.322]; - } else if($translate.instant('lights.colors.dark_green') == spokenWords[i]){ - update["xy"] = [0.408,0.517]; - } else if($translate.instant('lights.colors.green') == spokenWords[i]){ - update["xy"] = [0.408,0.517]; - } else if($translate.instant('lights.colors.blue') == spokenWords[i]){ - update["xy"] = [0.168,0.041]; - } else if($translate.instant('lights.colors.yellow') == spokenWords[i]){ - update["xy"] = [0.4317,0.4996]; - } else if($translate.instant('lights.colors.orange') == spokenWords[i]){ - update["xy"] = [0.5562,0.4084]; - } else if($translate.instant('lights.colors.pink') == spokenWords[i]){ - update["xy"] = [0.3824,0.1601]; - } else if($translate.instant('lights.colors.purple') == spokenWords[i]){ - update["xy"] = [0.2725,0.1096]; - } else if($translate.instant('lights.colors.white') == spokenWords[i]){ - update["xy"] = [0.3227,0.329]; - } else if($translate.instant('lights.colors.movie') == spokenWords[i]){ - update["xy"] = [0.3227,0.329]; - update["sat"] = 0; - update["bri"] = 15; - } else if($translate.instant('lights.colors.colorloop') == spokenWords[i]){ - update["effect"] = "colorloop"; - } else if($translate.instant('lights.colors.stop') == spokenWords[i]){ - update["effect"] = "none"; - update["xy"] = [0.3227,0.329]; - update["sat"] = 0; - update["bri"] = 255; - } - - //check for a brightness adjustment - if(spokenWords[i] == '10'){ - update["bri"] = 26; - } else if(spokenWords[i] == '20'){ - update["bri"] = 51; - } else if(spokenWords[i] == '25'){ - update["bri"] = 64; - } else if(spokenWords[i] == '30'){ - update["bri"] = 77; - } else if(spokenWords[i] == '40'){ - update["bri"] = 102; - } else if(spokenWords[i] == '50'){ - update["bri"] = 128; - } else if(spokenWords[i] == '60'){ - update["bri"] = 153; - } else if(spokenWords[i] == '70'){ - update["bri"] = 179; - } else if(spokenWords[i] == '75'){ - update["bri"] = 191; - } else if(spokenWords[i] == '80'){ - update["bri"] = 204; - } else if(spokenWords[i] == '90'){ - update["bri"] = 230; - } else if(spokenWords[i] == '100'){ - update["bri"] = 255; - } else if($translate.instant('lights.intensity.increase') == spokenWords[i]){ - update["bri_inc"] = 51; // 20% - } else if($translate.instant('lights.intensity.decrease') == spokenWords[i]){ - update["bri_inc"] = -51; // 20% - } else if($translate.instant('lights.intensity.max') == spokenWords[i]){ - update["bri"] = 254; - } - - //are we turning the lights on or off? - if($translate.instant('lights.action.on') == spokenWords[i]){ - update["on"] = true; - update["bri"] = 250; - } else if($translate.instant('lights.action.off') == spokenWords[i]){ - update["on"] = false; - } - } - return update; - } - - // Detect light - // TODO make this return an array of groups to update - function deturmineLight(spokenWords){ - for(var i = 0; i < spokenWords.length; i++){ - for (var j = 0; j < config.hue.groups.length; j++){ - if (spokenWords[i] == config.hue.groups[j].name){ - return j; - } - } - } - return 0; - } - return service; - } - - angular.module('SmartMirror') - .factory('HueService', HueService); - -}()); diff --git a/js/services/light.js b/js/services/light.js new file mode 100644 index 000000000..3bbfd664f --- /dev/null +++ b/js/services/light.js @@ -0,0 +1,202 @@ +(function() { + 'use strict'; + + var Hyperion = require('hyperion-client'); + + function LightService($http, $translate) { + var service = {}; + + // update lights + service.performUpdate = function(spokenWords){ + // split string into separate words and remove empty ones + var spokenWords = spokenWords.toLowerCase().split(" ").filter(Boolean); + + // what locations are defined in the config + var definedLocations = []; + for(var i = 0; i < config.light.setup.length; i++){ + definedLocations.push(config.light.setup[i].name.toLowerCase()); + } + + var SaidParameter = {}; + SaidParameter['locations'] = []; + SaidParameter['on'] = true; + + // what has been said + for(var i = 0; i < spokenWords.length; i++){ + var index = definedLocations.indexOf(spokenWords[i]); + if(index > -1){ + SaidParameter['locations'].push(index); + } + + // turn lights on or off? + if($translate.instant('lights.action.off') == spokenWords[i]){ + SaidParameter['on'] = false; + } + + // Choose Color + if($translate.instant('lights.colors.red') == spokenWords[i]){ + SaidParameter['colorRGB'] = [255, 0, 0]; + SaidParameter['colorHSV'] = [0, 255, 254]; + } else if($translate.instant('lights.colors.green') == spokenWords[i]){ + SaidParameter['colorRGB'] = [0, 255, 0]; + SaidParameter['colorHSV'] = [25500, 255, 254]; + } else if($translate.instant('lights.colors.blue') == spokenWords[i]){ + SaidParameter['colorRGB'] = [0, 0, 255]; + SaidParameter['colorHSV'] = [46920, 255, 254]; + } else if($translate.instant('lights.colors.yellow') == spokenWords[i]){ + SaidParameter['colorRGB'] = [255, 255, 0]; + SaidParameter['colorHSV'] = [10920, 255, 254]; + } else if($translate.instant('lights.colors.orange') == spokenWords[i]){ + SaidParameter['colorRGB'] = [255, 127, 0]; + SaidParameter['colorHSV'] = [5460, 255, 254]; + } else if($translate.instant('lights.colors.pink') == spokenWords[i]){ + SaidParameter['colorRGB'] = [255, 0, 255]; + SaidParameter['colorHSV'] = [54610, 255, 254]; + } else if($translate.instant('lights.colors.purple') == spokenWords[i]){ + SaidParameter['colorRGB'] = [127, 0, 127]; + SaidParameter['colorHSV'] = [54610, 255, 127]; + } else if($translate.instant('lights.colors.white') == spokenWords[i]){ + SaidParameter['colorRGB'] = [255, 255, 255]; + SaidParameter['colorHSV'] = [0, 0, 254]; + } + + // Adjust brightness + if(spokenWords[i] == '100%' || $translate.instant('lights.intensity.max').includes(spokenWords[i])){ + SaidParameter['brightness'] = 1.0; + } else if(spokenWords[i] == '10%'){ + SaidParameter['brightness'] = 0.1; + } else if(spokenWords[i] == '20%'){ + SaidParameter['brightness'] = 0.2; + } else if(spokenWords[i] == '25%' || $translate.instant('lights.intensity.quarter').includes(spokenWords[i])){ + SaidParameter['brightness'] = 0.25; + } else if(spokenWords[i] == '30%'){ + SaidParameter['brightness'] = 0.3; + } else if(spokenWords[i] == '40%'){ + SaidParameter['brightness'] = 0.3; + } else if(spokenWords[i] == '50%' || $translate.instant('lights.intensity.half').includes(spokenWords[i])){ + SaidParameter['brightness'] = 0.5; + } else if(spokenWords[i] == '60%'){ + SaidParameter['brightness'] = 0.6; + } else if(spokenWords[i] == '70%'){ + SaidParameter['brightness'] = 0.7; + } else if(spokenWords[i] == '75%' || $translate.instant('lights.intensity.threequarter').includes(spokenWords[i])){ + SaidParameter['brightness'] = 0.75; + } else if(spokenWords[i] == '80%'){ + SaidParameter['brightness'] = 0.8; + } else if(spokenWords[i] == '90%'){ + SaidParameter['brightness'] = 0.9; + } + + // special mode + if($translate.instant('lights.action.nightmode').includes(spokenWords[i])){ + SaidParameter['colorRGB'] = [255, 0, 0]; + SaidParameter['colorHSV'] = [0, 255, 254]; + SaidParameter['brightness'] = 0.1 + } + + // reset all LED + if($translate.instant('lights.action.reset').includes(spokenWords[i])){ + localStorage.clear() + } + + } + + // if spoken words contain no location, use all defined locations + if(SaidParameter['locations'].length == 0){ + for(var i = 0; i < definedLocations.length; i++){ + SaidParameter['locations'].push(i); + } + } + + var SavedSettings = []; + + // get remaining info from local storage + for(var j = 0 ; j < SaidParameter['locations'].length; j++){ + var i = SaidParameter['locations'][j]; + var SavedSetting = {}; + // read settings from storage or use default + if(localStorage.getItem('Light_Setup_' + i) == null){ + SavedSetting['colorRGB'] = [255, 255, 255]; + SavedSetting['colorHSV'] = [0, 0, 254]; + SavedSetting['brightness'] = 0.4 + } + else{ + SavedSetting = JSON.parse(localStorage.getItem('Light_Setup_' + i)); + } + + // overwrite settings with spoken info + for(var key in SaidParameter){ + if(SaidParameter.hasOwnProperty(key)) { + SavedSetting[key] = SaidParameter[key]; + } + } + + // save new values in local storage + localStorage.setItem('Light_Setup_' + i, JSON.stringify(SavedSetting)); + + SavedSetting['location'] = i; + + SavedSettings.push(SavedSetting); + } + + SavedSettings.map(updateLights); + } + + function updateLights(setting){ + var index = setting['location']; + for(var i = 0; i < config.light.setup[index].targets.length; i++){ + if(config.light.setup[index].targets[i].type == "hyperion"){ + updateHyperion(i, index, setting); + } + else if(config.light.setup[index].targets[i].type == "hue"){ + updateHue(i, index, setting); + } + } + } + + function updateHyperion(i, index, setting){ + // Convert color and brightness + for(var j = 0; j < setting['colorRGB'].length; j++){ + setting['colorRGB'][j] = Math.round(setting['colorRGB'][j] * setting['brightness']); + } + // Connect to the configured Hyperion client + var hyperion = new Hyperion(config.light.setup[index].targets[i].ip, config.light.setup[index].targets[i].port); + + hyperion.on('connect', function(){ + if(setting['on']){ + hyperion.setColor(setting['colorRGB']); + } + else{ + hyperion.clearall(); + } + }); + + hyperion.on('error', function(error){ + console.error('error:', error); + }); + } + + function updateHue(i, index, setting){ + var update = {}; + update["transitiontime"] = 10; + + update['on'] = setting['on']; + if(setting['on']){ + update['hue'] = setting['colorHSV'][0]; + update['sat'] = setting['colorHSV'][1]; + update['bri'] = Math.round(setting['colorHSV'][2] * setting['brightness']); + } + + $http.put('http://' + config.light.settings.hue_ip + '/api/' + config.light.settings.hue_username + "/groups/" + config.light.setup[index].targets[i].id + "/action", update) + .success(function (data, status, headers) { + console.log(data); + }) + } + + return service; + } + + angular.module('SmartMirror') + .factory('LightService', LightService); + +}()); diff --git a/locales/de.json b/locales/de.json index 4d7f7ff17..52da8c617 100644 --- a/locales/de.json +++ b/locales/de.json @@ -31,11 +31,16 @@ "intensity": { "increase": "heller", "decrease": "dunkler", - "max": "maximal" + "max": "maximal", + "half": "halber", + "quarter": "viertel", + "threequarter": "dreiviertel" }, "action": { "on": "an", - "off": "aus" + "off": "aus", + "nightmode": "nachtmodus", + "reset": "zurücksetzen" } }, "commands": { @@ -181,9 +186,9 @@ "description": "Replays the current song on SoundCloud" }, "light_action": { - "text": "Schalte das (state) Licht (action)", - "voice": "(Schalte) (das) :state (die) Licht(er) *action", - "description": "(Schalte) (das) :state (die) Licht(er) *action" + "text": "Schalte (das|die) Licht(er) (action)", + "voice": "(Schalte) (das) (die) Licht(er) *action", + "description": "Steuert Farbe und Helligkeit von Lichtern" } } } diff --git a/locales/en.json b/locales/en.json index dbb1a84e8..4fb96fa0e 100644 --- a/locales/en.json +++ b/locales/en.json @@ -31,11 +31,16 @@ "intensity": { "increase": "increase", "decrease": "decrease", - "max": "max" + "max": "max", + "half": "half", + "quarter": "quarter", + "threequarter": ["three-quarter", "three-fourth"] }, "action": { "on": "on", - "off": "off" + "off": "off", + "nightmode": "nightmode", + "reset": "reset" } }, "commands": { @@ -181,9 +186,9 @@ "description": "Replays the current song on SoundCloud" }, "light_action": { - "text": "Turn the (state) light (action)", + "text": "Turn (state) light(s) (action)", "voice": "(turn) (the) :state (the) light(s) *action", - "description": "(turn) (the) :state (the) light(s) *action" + "description": "Control color and brightness of lights" } } } diff --git a/package.json b/package.json index 0fbe3712a..cdb0bd366 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "express": "^4.13.4", "fitbit-oauth2": "0.0.1", "fs": "0.0.2", + "hyperion-client": "1.0.3", "electron-json-storage": "2.0.0" } } From 7ecb922fc63ef9a7eea80b13ead093f97f82b797 Mon Sep 17 00:00:00 2001 From: justbill2020 Date: Tue, 28 Jun 2016 18:32:19 -0500 Subject: [PATCH 08/39] Motion detect (#311) * pir-hdmi Based on dev branch... Added python code to detect PIR on pin 11 on raspberry pi. Spawns process in main.js... pulls vars from config.js file. in response to #286 * found an issue in py code... updated pin number and expanded python code... tested and it works great... * PIRHDMI v1.11 removed dash causing unhandled exception... Added variables to config.example.js file (config.pirhdmi.Debug and config.pirhdmi.Enable) if config.pirhdmi is not in config.js this will default to disabled. * motion v1.12 Changed branch name and removed all pir-hdmi files and references to be consistent with motion. * Update config.example.js * update config.example.js and main.js minor syntax errors. * update main.js minor syntax issues... i'm slowly running out of coffee... * . . * . . * . . * 1.14 1.14 * 1.15 1.15 * 1.16 1.15 * 1.16a * 1.16a --- config.example.js | 9 +++++- main.js | 26 +++++++++++++++- motion/motiondetect.py | 71 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 motion/motiondetect.py diff --git a/config.example.js b/config.example.js index f007ea3ba..07210cbc6 100644 --- a/config.example.js +++ b/config.example.js @@ -3,7 +3,14 @@ var config = { // Lenguage for the mirror language : "en-US", - // Keyword Spotting (Hotword Detection) + // PIR Detection + motion : { + pin : 26, //Default pirPin is GPIO pin 26. + screentimeout : 5.0, //Default timeout is 5 minutes must be a float number. + enable : true, // Enable or disable this functionality + debug : true // send debug info to dev console, if debug timeout is 30 seconds (not yet working) + }, + // Keyword Spotting (Hotword Detection) speech : { keyword : "Smart Mirror", model : "smart_mirror.pmdl", // The name of your model diff --git a/main.js b/main.js index b429846a2..e4373b838 100644 --- a/main.js +++ b/main.js @@ -95,6 +95,27 @@ kwsProcess.stdout.on('data', function (data) { console.log(data.toString()) }) +// Get motion config +if(typeof config.motion == 'undefined'){ + config.motion = {} +} +var motionpin = config.motion.pin || 26 +var motiondebug = config.motion.debug || true +var screentimeout = config.motion.screentimeout || 5.0 +var motionenable = config.motion.enable || false + +// Initilize the motion process +if (motionEnable == true){ +var MotionProcess = spawn('python', ['./motion/motiondetect.py', motionpin, screentimeout, motiondebug], {detached: false}) +// Handle messages from python script +MotionProcess.stderr.on('data', function (data) { + var message = data.toString() + console.log(message) +}) +MotionProcess.stdout.on('data', function (data) { + console.log(data.toString()) +}) +} // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. @@ -108,4 +129,7 @@ app.on('window-all-closed', function () { // No matter how the app is quit, we should clean up after ourselvs app.on('will-quit', function () { kwsProcess.kill() -}) \ No newline at end of file + if (motionEnable==true){ + MotionProcess.kill() + } +}) diff --git a/motion/motiondetect.py b/motion/motiondetect.py new file mode 100644 index 000000000..e0e4e20fc --- /dev/null +++ b/motion/motiondetect.py @@ -0,0 +1,71 @@ +import RPi.GPIO as GPIO +import time +from threading import Timer +import subprocess +import sys +import signal + +isDebug = True +interrupted = False + + +def signal_handler(signal, frame): + global interrupted + interrupted = True + exit(0) +if len(sys.argv) < 2: + motionPin = 26 + ScreenTimeOut = float(0.5) + +else: + motionPin = int(sys.argv[1]) + ScreenTimeOut = round(float(sys.argv[2]), 2) + +print motionPin +print ScreenTimeOut + +def debugging(msg): + global isDebug + if isDebug: + print msg + + +GPIO.setmode(GPIO.BCM) +GPIO.setup(motionPin, GPIO.IN) +timer = False +monitor_is_on = True + +def monitor_off(): + global monitor_is_on + debugging("monitor off") + subprocess.Popen('tvservice -o', shell=True) + monitor_is_on = False + +def monitor_on(): + global monitor_is_on + debugging("monitor on") + subprocess.Popen('tvservice -p', shell=True) + subprocess.Popen('fbset -depth 8 && fbset -depth 16 && xrefresh', shell=True) + monitor_is_on = True + +signal.signal(signal.SIGINT, signal_handler) + +while True: + debugging("Waiting for movement") + time.sleep(0.5) + movement = GPIO.input(motionPin) + if movement: + debugging(" movement active") + if timer: + debugging(" cancel timer") + timer.cancel() + timer = False + if not monitor_is_on: + debugging(" calling monitor on") + monitor_on() + else: + debugging(" movement inactive") + if not timer: + debugging(" starting timer") + timer = Timer(60*ScreenTimeOut, monitor_off) + timer.start() From 221a068fb2d517e991efe975ba2b4fa825feccf0 Mon Sep 17 00:00:00 2001 From: Joel Hawksley Date: Wed, 29 Jun 2016 16:14:45 -0600 Subject: [PATCH 09/39] [FEATURE] Reload weather every two minutes. (#313) Add option for number of minutes the information is refreshed. Forecast.io limits requests to 1000/day: a 2min interval = 720 calls/day --- config.example.js | 3 ++- js/controller.js | 51 ++++++++++++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/config.example.js b/config.example.js index 07210cbc6..76d3fa8dd 100644 --- a/config.example.js +++ b/config.example.js @@ -41,7 +41,8 @@ var config = { // forecast.io forecast : { key : "", // Your forecast.io api key - units : "auto" // See forecast.io documentation if you are getting the wrong units + units : "auto", // See forecast.io documentation if you are getting the wrong units + reload_interval : 2, // Number of minutes the information is refreshed. Forecast.io limits requests to 1000/day: a 2min interval = 720 calls/day }, // lights light : { diff --git a/js/controller.js b/js/controller.js index d04d3dafb..d153ee8ec 100644 --- a/js/controller.js +++ b/js/controller.js @@ -66,6 +66,32 @@ SoundCloudService.init(); var refreshMirrorData = function() { + CalendarService.getCalendarEvents().then(function(response) { + $scope.calendar = CalendarService.getFutureEvents(); + }, function(error) { + console.log(error); + }); + + if ($scope.fitbitEnabled) { + setTimeout(function() { refreshFitbitData(); }, 5000); + } + }; + + var refreshFitbitData = function() { + console.log('refreshing fitbit data'); + FitbitService.profileSummary(function(response){ + $scope.fbDailyAverage = response; + }); + + FitbitService.todaySummary(function(response){ + $scope.fbToday = response; + }); + }; + + refreshMirrorData(); + $interval(refreshMirrorData, 1500000); + + var refreshWeatherData = function() { //Get our location and then get the weather for our location GeolocationService.getLocation({enableHighAccuracy: true}).then(function(geoposition){ console.log("Geoposition", geoposition); @@ -93,31 +119,10 @@ }, function(error){ console.log(error); }); - - CalendarService.getCalendarEvents().then(function(response) { - $scope.calendar = CalendarService.getFutureEvents(); - }, function(error) { - console.log(error); - }); - - if ($scope.fitbitEnabled) { - setTimeout(function() { refreshFitbitData(); }, 5000); - } - }; - - var refreshFitbitData = function() { - console.log('refreshing fitbit data'); - FitbitService.profileSummary(function(response){ - $scope.fbDailyAverage = response; - }); - - FitbitService.todaySummary(function(response){ - $scope.fbToday = response; - }); }; - refreshMirrorData(); - $interval(refreshMirrorData, 1500000); + refreshWeatherData(); + $interval(refreshWeatherData, config.forecast.reload_interval * 60000); var greetingUpdater = function () { if(typeof config.greeting != 'undefined' && !Array.isArray(config.greeting) && typeof config.greeting.midday != 'undefined') { From 227855f4212d9727b442493870e87fb865174c64 Mon Sep 17 00:00:00 2001 From: Kris Date: Thu, 30 Jun 2016 10:17:43 +1200 Subject: [PATCH 10/39] Auto-Sleep / Auto-Wake Functionality + HDMI Power Control (#128) * config file is now in the root * auto-wake/auto-sleep functionality * auto wake on any voice command * add HDMI power control * auto-wake/auto-sleep functionality * add HDMI power control * Move all logic out of controller * Move all logic out of controller * Remove old methods & update config. * move screen on/off voice logic to service * remove $scope from service * remove $scope from service * add scope default focus states for screen events * move exec to service * move exec to service * cleanup rebase * fix screen on * rebase + add binary config option * small fixes * remove logic from controller * remove camelcase + config.js * fix config typo and use moment() for time check * remove sys and log stdout msg * try undo whitespaces --- config.example.js | 6 ++++++ index.html | 1 + js/controller.js | 24 +++++++++++++++++++++ js/services/autosleep.js | 45 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 js/services/autosleep.js diff --git a/config.example.js b/config.example.js index 76d3fa8dd..c2666825b 100644 --- a/config.example.js +++ b/config.example.js @@ -111,6 +111,12 @@ var config = { rss: { feeds : [], // RSS feeds list - e.g. ["rss1.com", "rss2.com"] refreshInterval : 120 // Number of minutes the information is refreshed + }, + auto_timer: { + auto_sleep: 2400000, // How long the screen will stay awake before going to sleep (40 Mins) + auto_wake: '07:00:00', // When to automatically wake the screen up (7:00AM) + 'wake_cmd': '/opt/vc/bin/tvservice -p', // The binary and arguments used on your system to wake the screen + 'sleep_cmd': '/opt/vc/bin/tvservice -o', // The binary and arguments used on your system to sleep the screen } }; diff --git a/index.html b/index.html index cccfc4a1b..3adeb0151 100644 --- a/index.html +++ b/index.html @@ -39,6 +39,7 @@ + diff --git a/js/controller.js b/js/controller.js index d153ee8ec..49e46c0e6 100644 --- a/js/controller.js +++ b/js/controller.js @@ -3,6 +3,7 @@ function MirrorCtrl( SpeechService, + AutoSleepService, GeolocationService, WeatherService, FitbitService, @@ -43,6 +44,14 @@ //Update the time function updateTime(){ $scope.date = new moment(); + + // Auto wake at a specific time + if (typeof config.auto_timer !== 'undefined' && typeof config.auto_timer.auto_wake !== 'undefined' && config.auto_timer.auto_wake == moment().format('HH:mm:ss')) { + console.debug('Auto-wake', config.auto_timer.auto_wake); + $scope.focus = "default"; + AutoSleepService.wake(); + AutoSleepService.startAutoSleepTimer(); + } } // Reset the command text @@ -53,6 +62,8 @@ }; _this.init = function() { + AutoSleepService.startAutoSleepTimer(); + var tick = $interval(updateTime, 1000); updateTime(); GeolocationService.getLocation({enableHighAccuracy: true}).then(function(geoposition){ @@ -228,6 +239,19 @@ // Go back to default view addCommand('wake_up', defaultView); + // Turn off HDMI output + addCommand('screen off', function() { + console.debug('turning screen off'); + AutoSleepService.sleep(); + }); + + // Turn on HDMI output + addCommand('screen on', function() { + console.debug('turning screen on'); + AutoSleepService.wake(); + $scope.focus = "default" + }); + // Hide everything and "sleep" addCommand('debug', function() { console.debug("Boop Boop. Showing debug info..."); diff --git a/js/services/autosleep.js b/js/services/autosleep.js new file mode 100644 index 000000000..ed60587ca --- /dev/null +++ b/js/services/autosleep.js @@ -0,0 +1,45 @@ +(function() { + 'use strict'; + + function AutoSleepService($interval) { + var service = {}; + var autoSleepTimer; + + service.exec = require('child_process').exec; + + service.startAutoSleepTimer = function() { + if (typeof config.auto_timer !== 'undefined' && typeof config.auto_timer.auto_sleep !== 'undefined' && typeof config.auto_timer.auto_wake !== 'undefined') { + service.stopAutoSleepTimer(); + autoSleepTimer = $interval(service.sleep, config.auto_timer.auto_sleep); + console.debug('Starting auto-sleep timer', config.auto_timer.auto_sleep); + } + }; + + service.stopAutoSleepTimer = function() { + console.debug('Stopping auto-sleep timer'); + $interval.cancel(autoSleepTimer); + }; + + service.wake = function() { + service.exec(config.auto_timer.wake_cmd, service.puts); + }; + + service.sleep = function() { + service.exec(config.auto_timer.sleep_cmd, service.puts); + }; + + service.puts = function (error, stdout, stderr) { + if (error) { + console.debug('auto-sleep error', error); + } + + console.debug('autosleep stdout:', stdout) + }; + + return service; + } + + angular.module('SmartMirror') + .factory('AutoSleepService', AutoSleepService); + +}()); \ No newline at end of file From 995d668e3623c7b1c91b49d53325387e3e11d479 Mon Sep 17 00:00:00 2001 From: Joel Hawksley Date: Wed, 29 Jun 2016 16:18:10 -0600 Subject: [PATCH 11/39] [FEATURE] Group events by day for simpler display. (#314) --- css/main.css | 12 +++++++++++- index.html | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/css/main.css b/css/main.css index ad0d6b058..70a6d5ff2 100644 --- a/css/main.css +++ b/css/main.css @@ -113,16 +113,26 @@ ul.calendar { .calendar span { display: inline-block; } .calendar span.day { + .calendar .day { + display: none; font-weight: bold; + position: absolute; width: 128px; vertical-align: top; } .calendar span.summary { + margin-left: 150px; max-width: 400px; } .calendar .event-details .details { font-size: 12px; - padding-left: 135px; + padding-left: 150px; font-family: 'Open Sans', sans-serif; font-weight: lighter; } +.day-marker { + margin-top: 30px; +} +.day-marker .day { + display: block; +} .weather { margin-left: auto; diff --git a/index.html b/index.html index 3adeb0151..39ddaf94b 100644 --- a/index.html +++ b/index.html @@ -57,7 +57,7 @@
{{date.format('dddd')}}, {{date.format('LL')}}
{{date.format('LT')}}
    -
  • +
  • {{event.start.format('dddd') | uppercase}} {{event.SUMMARY}} From 52521fd165dbf7b16b3492765ec7ef0cf664f279 Mon Sep 17 00:00:00 2001 From: Joel Hawksley Date: Wed, 29 Jun 2016 16:59:10 -0600 Subject: [PATCH 12/39] Fix broken development branch. (#319) * [FIX] Fix typo in main.js that prevents app from booting * [FIX] Remove errant line from CSS that broke layout --- css/main.css | 1 - main.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/css/main.css b/css/main.css index 70a6d5ff2..c7c85206e 100644 --- a/css/main.css +++ b/css/main.css @@ -112,7 +112,6 @@ ul.calendar { margin-bottom: 10px; } .calendar span { display: inline-block; } - .calendar span.day { .calendar .day { display: none; font-weight: bold; diff --git a/main.js b/main.js index e4373b838..ff4025c2b 100644 --- a/main.js +++ b/main.js @@ -102,7 +102,7 @@ if(typeof config.motion == 'undefined'){ var motionpin = config.motion.pin || 26 var motiondebug = config.motion.debug || true var screentimeout = config.motion.screentimeout || 5.0 -var motionenable = config.motion.enable || false +var motionEnable = config.motion.enable || false // Initilize the motion process if (motionEnable == true){ From 4cbb99abb0813fd794f621234fe3ea056ff63492 Mon Sep 17 00:00:00 2001 From: Joel Hawksley Date: Wed, 29 Jun 2016 17:03:32 -0600 Subject: [PATCH 13/39] [CLEANUP] Config keys should be camelCased (#320) [Resolves #315] --- config.example.js | 20 ++++++++++---------- js/controller.js | 8 ++++---- js/services/autosleep.js | 10 +++++----- js/services/geolocation.js | 10 +++++----- js/services/light.js | 2 +- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/config.example.js b/config.example.js index c2666825b..171ea686d 100644 --- a/config.example.js +++ b/config.example.js @@ -2,7 +2,7 @@ var config = { // Lenguage for the mirror language : "en-US", - + // PIR Detection motion : { pin : 26, //Default pirPin is GPIO pin 26. @@ -32,23 +32,23 @@ var config = { //use this only if you want to hardcode your geoposition (used for weather) /* - geo_position: { + geoPosition: { latitude: 78.23423423, longitude: 13.123124142 }, */ - + // forecast.io forecast : { key : "", // Your forecast.io api key units : "auto", // See forecast.io documentation if you are getting the wrong units - reload_interval : 2, // Number of minutes the information is refreshed. Forecast.io limits requests to 1000/day: a 2min interval = 720 calls/day + refreshInterval : 2, // Number of minutes the information is refreshed. Forecast.io limits requests to 1000/day: a 2min interval = 720 calls/day }, // lights light : { settings : { - hue_ip : "", // The IP address of your hue base - hue_username : "" // The username used to control your hue + hueIp : "", // The IP address of your hue base + hueUsername : "" // The username used to control your hue }, setup : [ { @@ -97,7 +97,7 @@ var config = { traffic: { key : "", // Bing Maps API Key - reload_interval : 5, // Number of minutes the information is refreshed + refreshInterval : 5, // Number of minutes the information is refreshed // An array of tips that you would like to display travel time for trips : [{ mode : "Driving", // Possibilities: Driving / Transit / Walking @@ -112,9 +112,9 @@ var config = { feeds : [], // RSS feeds list - e.g. ["rss1.com", "rss2.com"] refreshInterval : 120 // Number of minutes the information is refreshed }, - auto_timer: { - auto_sleep: 2400000, // How long the screen will stay awake before going to sleep (40 Mins) - auto_wake: '07:00:00', // When to automatically wake the screen up (7:00AM) + autoTimer: { + autoSleep: 2400000, // How long the screen will stay awake before going to sleep (40 Mins) + autoWake: '07:00:00', // When to automatically wake the screen up (7:00AM) 'wake_cmd': '/opt/vc/bin/tvservice -p', // The binary and arguments used on your system to wake the screen 'sleep_cmd': '/opt/vc/bin/tvservice -o', // The binary and arguments used on your system to sleep the screen } diff --git a/js/controller.js b/js/controller.js index 49e46c0e6..ff7318624 100644 --- a/js/controller.js +++ b/js/controller.js @@ -46,8 +46,8 @@ $scope.date = new moment(); // Auto wake at a specific time - if (typeof config.auto_timer !== 'undefined' && typeof config.auto_timer.auto_wake !== 'undefined' && config.auto_timer.auto_wake == moment().format('HH:mm:ss')) { - console.debug('Auto-wake', config.auto_timer.auto_wake); + if (typeof config.autoTimer !== 'undefined' && typeof config.autoTimer.auto_wake !== 'undefined' && config.autoTimer.auto_wake == moment().format('HH:mm:ss')) { + console.debug('Auto-wake', config.autoTimer.auto_wake); $scope.focus = "default"; AutoSleepService.wake(); AutoSleepService.startAutoSleepTimer(); @@ -133,7 +133,7 @@ }; refreshWeatherData(); - $interval(refreshWeatherData, config.forecast.reload_interval * 60000); + $interval(refreshWeatherData, config.forecast.refreshInterval * 60000); var greetingUpdater = function () { if(typeof config.greeting != 'undefined' && !Array.isArray(config.greeting) && typeof config.greeting.midday != 'undefined') { @@ -169,7 +169,7 @@ if(typeof config.traffic != 'undefined'){ refreshTrafficData(); - $interval(refreshTrafficData, config.traffic.reload_interval * 60000); + $interval(refreshTrafficData, config.traffic.refreshInterval * 60000); } var refreshComic = function () { diff --git a/js/services/autosleep.js b/js/services/autosleep.js index ed60587ca..73b877f60 100644 --- a/js/services/autosleep.js +++ b/js/services/autosleep.js @@ -8,10 +8,10 @@ service.exec = require('child_process').exec; service.startAutoSleepTimer = function() { - if (typeof config.auto_timer !== 'undefined' && typeof config.auto_timer.auto_sleep !== 'undefined' && typeof config.auto_timer.auto_wake !== 'undefined') { + if (typeof config.autoTimer !== 'undefined' && typeof config.autoTimer.autoSleep !== 'undefined' && typeof config.autoTimer.auto_wake !== 'undefined') { service.stopAutoSleepTimer(); - autoSleepTimer = $interval(service.sleep, config.auto_timer.auto_sleep); - console.debug('Starting auto-sleep timer', config.auto_timer.auto_sleep); + autoSleepTimer = $interval(service.sleep, config.autoTimer.autoSleep); + console.debug('Starting auto-sleep timer', config.autoTimer.autoSleep); } }; @@ -21,11 +21,11 @@ }; service.wake = function() { - service.exec(config.auto_timer.wake_cmd, service.puts); + service.exec(config.autoTimer.wake_cmd, service.puts); }; service.sleep = function() { - service.exec(config.auto_timer.sleep_cmd, service.puts); + service.exec(config.autoTimer.sleep_cmd, service.puts); }; service.puts = function (error, stdout, stderr) { diff --git a/js/services/geolocation.js b/js/services/geolocation.js index bdae63aba..60572f7bd 100644 --- a/js/services/geolocation.js +++ b/js/services/geolocation.js @@ -23,14 +23,14 @@ var deferred = $q.defer(); // Use geo postion from config file if it is defined - if(typeof config.geo_position != 'undefined' - && typeof config.geo_position.latitude != 'undefined' - && typeof config.geo_position.longitude != 'undefined'){ + if(typeof config.geoPosition != 'undefined' + && typeof config.geoPosition.latitude != 'undefined' + && typeof config.geoPosition.longitude != 'undefined'){ deferred.resolve({ coords: { - latitude: config.geo_position.latitude, - longitude: config.geo_position.longitude, + latitude: config.geoPosition.latitude, + longitude: config.geoPosition.longitude, }, }); diff --git a/js/services/light.js b/js/services/light.js index 3bbfd664f..860c88559 100644 --- a/js/services/light.js +++ b/js/services/light.js @@ -187,7 +187,7 @@ update['bri'] = Math.round(setting['colorHSV'][2] * setting['brightness']); } - $http.put('http://' + config.light.settings.hue_ip + '/api/' + config.light.settings.hue_username + "/groups/" + config.light.setup[index].targets[i].id + "/action", update) + $http.put('http://' + config.light.settings.hueIp + '/api/' + config.light.settings.hueUsername + "/groups/" + config.light.setup[index].targets[i].id + "/action", update) .success(function (data, status, headers) { console.log(data); }) From 82aa9181a151aa01e24711f4078694cf223cc351 Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Wed, 29 Jun 2016 20:07:30 -0700 Subject: [PATCH 14/39] resolving merge conflicts --- css/main.css | 470 +++++++++++++++++++++++++++++++-------------------- main.js | 37 ++-- 2 files changed, 303 insertions(+), 204 deletions(-) diff --git a/css/main.css b/css/main.css index c7c85206e..f0f2ab8f6 100644 --- a/css/main.css +++ b/css/main.css @@ -1,93 +1,118 @@ @font-face { - font-family: "HelveticaNeue-UltraLight"; - src: url("../fonts/HelveticaNeue-UltraLight.ttf"); - /* EOT file for IE */ } + font-family: "HelveticaNeue-UltraLight"; + src: url("../fonts/HelveticaNeue-UltraLight.ttf"); + /* EOT file for IE */ +} + +[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { + display: none !important; +} + body { - background-color: black; - color: #fff; - font-family: 'HelveticaNeue-UltraLight', 'Open Sans', sans-serif; - font-weight: 300; - position: relative; } + background-color: black; + color: #fff; + font-family: 'HelveticaNeue-UltraLight', 'Open Sans', sans-serif; + font-weight: 300; + position: relative; +} -h1, h2, h3, h4, h5 { - font-weight: 300; } +h1, +h2, +h3, +h4, +h5 { + font-weight: 300; +} h1 { - font-size: 120px; } + font-size: 120px; +} dt { - font-weight: 600; } + font-weight: 600; +} /* Colors */ .light-grey { - color: #ccc; } + color: #ccc; +} .grey { - color: #999; } + color: #999; +} /* Displays */ .sleep-cover { - background-color: black; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 999; } + background-color: black; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 999; +} .container { - z-index: -1; - /* so things are still selectable */ - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - transition: all 0.3s ease;} + z-index: -1; + /* so things are still selectable */ + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + transition: all 0.3s ease; +} .listening { - box-shadow: inset 0px -40px 40px -40px #fff -} + box-shadow: inset 0px -40px 40px -40px #fff +} .not-listening { - box-shadow: inset 0px 0px 0px 0px #fff -} + box-shadow: inset 0px 0px 0px 0px #fff +} .interim-result { - font-family: 'Open Sans', sans-serif; } + font-family: 'Open Sans', sans-serif; +} .top-left { - float: left; } + float: left; +} .date { - font-size: 42px; } + font-size: 42px; +} .time { - font-size: 110px; } + font-size: 110px; +} .top-right { - float: right; } + float: right; +} .middle-center { - display: flex; - flex: 1; - align-items: stretch; - align-self: flex-start; - flex-direction: column; - width: 100%; - text-align: center; - justify-content: center; } + display: flex; + flex: 1; + align-items: stretch; + align-self: flex-start; + flex-direction: column; + width: 100%; + text-align: center; + justify-content: center; +} .bottom-center { - font-family: 'Open Sans', sans-serif; - width: 100%; - text-align: center; - margin-bottom: 20px; } + font-family: 'Open Sans', sans-serif; + width: 100%; + text-align: center; + margin-bottom: 20px; +} .bottom-left { font-family: 'Open Sans', sans-serif; @@ -97,71 +122,93 @@ dt { } .commands { - width: 450px; - text-align: left; - margin-left: auto; - margin-right: auto; } + width: 450px; + text-align: left; + margin-left: auto; + margin-right: auto; +} ul.calendar { - list-style: none; - font-size: 22px; - margin-left: 10px; - padding: 0; } + list-style: none; + font-size: 22px; + margin-left: 10px; + padding: 0; +} .calendar .event { - margin-bottom: 10px; } + margin-bottom: 10px; +} + .calendar span { - display: inline-block; } - .calendar .day { + display: inline-block; +} + +.calendar .day { display: none; font-weight: bold; position: absolute; width: 128px; - vertical-align: top; } - .calendar span.summary { + vertical-align: top; +} + +.calendar span.summary { margin-left: 150px; - max-width: 400px; } + max-width: 400px; +} + .calendar .event-details .details { - font-size: 12px; - padding-left: 150px; - font-family: 'Open Sans', sans-serif; - font-weight: lighter; } + font-size: 12px; + padding-left: 150px; + font-family: 'Open Sans', sans-serif; + font-weight: lighter; +} + .day-marker { - margin-top: 30px; + margin-top: 30px; } .day-marker .day { - display: block; + display: block; } .weather { - margin-left: auto; - display: inline-block; - text-align: right; - width: 230px; } + margin-left: auto; + display: inline-block; + text-align: right; + width: 230px; +} .weather-today .temperature { - font-size: 60px; } + font-size: 60px; +} .weather-week-descriptor { - font-family: 'Open Sans', sans-serif; - font-size: 12px; - margin-left: auto; - margin-bottom: 10px; - text-align: justify; } + font-family: 'Open Sans', sans-serif; + font-size: 12px; + margin-left: auto; + margin-bottom: 10px; + text-align: justify; +} .weather-week { - margin-right: 10px; - font-size: 22px; } - .weather-week .day { + margin-right: 10px; + font-size: 22px; +} + +.weather-week .day { display: inline-block; margin-right: 10px; - width: 40px; } - .weather-week .temperature { + width: 40px; +} + +.weather-week .temperature { display: inline-block; - width: 50px; } + width: 50px; +} -.weather .weather-today canvas, .weather .weather-week-day canvas { - display: none; } +.weather .weather-today canvas, +.weather .weather-week-day canvas { + display: none; +} .fitbit { height: 100%; @@ -195,77 +242,102 @@ ul.calendar { } .traffic-information { - text-align: right; - margin-top: 10px; - margin-right: 10px; } + text-align: right; + margin-top: 10px; + margin-right: 10px; +} .time-to { - font-weight: bold; } + font-weight: bold; +} @keyframes reduce-dashoffset { - to { - stroke-dashoffset: 0; } } + to { + stroke-dashoffset: 0; + } + +} + @keyframes increase-dashoffset { - from { - stroke-dashoffset: 0; } } + from { + stroke-dashoffset: 0; + } + +} + .timer { - font-size: 120px; - position: relative; } + font-size: 120px; + position: relative; +} .timer-circle { - width: 3.25em; - height: 3.25em; - transform: rotate(-90deg) scaleY(-1); - margin: 20px auto; - display: block; } - .timer-circle .background, - .timer-circle .progress { + width: 3.25em; + height: 3.25em; + transform: rotate(-90deg) scaleY(-1); + margin: 20px auto; + display: block; +} + +.timer-circle .background, +.timer-circle .progress { r: 1.525em; cx: 1.625em; cy: 1.625em; stroke-width: 0.1em; fill: none; - stroke: #222; } - .timer-circle .progress { + stroke: #222; +} + +.timer-circle .progress { stroke-dasharray: 10.2101761239em; stroke-dashoffset: 10.2101761239em; stroke-linecap: round; animation-name: increase-dashoffset; animation-timing-function: linear; animation-fill-mode: forwards; - stroke: white; } + stroke: white; +} -.timer-countdown, .timer-duration { - position: absolute; - top: 50%; - left: 50%; - transform: translateY(-50%) translateX(-50%); } +.timer-countdown, +.timer-duration { + position: absolute; + top: 50%; + left: 50%; + transform: translateY(-50%) translateX(-50%); +} .timer-duration { - top: 75%; - font-size: 25%; } + top: 75%; + font-size: 25%; +} .contents { - max-width: 100%; } + max-width: 100%; +} .gif { - height: 100%; } + height: 100%; +} .map { - height: 1080px; } + height: 1080px; +} .reminders-container { - width: 250px; - text-align: left; - margin-left: auto; - margin-right: auto; } + width: 250px; + text-align: left; + margin-left: auto; + margin-right: auto; +} .contents-box { - text-align: center; - width: 100%; - position: relative; - overflow: hidden; } - .contents-box:after { + text-align: center; + width: 100%; + position: relative; + overflow: hidden; +} + +.contents-box:after { content: ''; position: absolute; top: 0; @@ -275,7 +347,8 @@ ul.calendar { -webkit-box-shadow: inset 0 0 10px 10px #000; -moz-box-shadow: inset 0 0 10px 10px #000; box-shadow: inset 0 0 10px 10px #000; - overflow: hidden; } + overflow: hidden; +} .video { width: 100%; @@ -284,92 +357,119 @@ ul.calendar { /* If you want to make the video black and white -webkit-filter: grayscale(100%); filter: grayscale(100%); - */ -} + */} .sc-container { - margin:auto; - -webkit-filter: grayscale(70%); - filter: grayscale(70%); - font-family: bold; + margin: auto; + -webkit-filter: grayscale(70%); + filter: grayscale(70%); + font-family: bold; } + .scWaveform { - background-color: #000000; - width: 500px; - -webkit-filter: invert(100%); - filter: invert(100%); + background-color: #000000; + width: 500px; + -webkit-filter: invert(100%); + filter: invert(100%); } .color-block { - height: 200px; - width: 200px; - display: inline-block; - margin: 10px; - margin-bottom: 20px; } + height: 200px; + width: 200px; + display: inline-block; + margin: 10px; + margin-bottom: 20px; +} .debug-info { - width: 500px; } + width: 500px; +} /* Animations */ .fade.ng-hide { - opacity: 0; } -.fade.ng-hide-remove, .fade.ng-hide-add { - display: block !important; } + opacity: 0; +} + +.fade.ng-hide-remove, +.fade.ng-hide-add { + display: block !important; +} + .fade.ng-hide-remove { - transition: all ease 1500ms; } + transition: all ease 1500ms; +} + .fade.ng-hide-add { - transition: all ease 500ms; } + transition: all ease 500ms; +} .animate-grow { - max-height: 1280px !important; } - .animate-grow.ng-hide-add, .animate-grow.ng-hide-remove { - transition: all linear 500ms; } - .animate-grow.ng-hide { - max-height: 0 !important; } + max-height: 1280px !important; +} + +.animate-grow.ng-hide-add, +.animate-grow.ng-hide-remove { + transition: all linear 500ms; +} + +.animate-grow.ng-hide { + max-height: 0 !important; +} .dimmed { - color: #aaa; } + color: #aaa; +} -.xxsmall, .xsmall, .small { - font-family: "HelveticaNeue-Medium", sans-serif; - letter-spacing: 0; } +.xxsmall, +.xsmall, +.small { + font-family: "HelveticaNeue-Medium", sans-serif; + letter-spacing: 0; +} .xxsmall { - font-size: 15px; } - .xxsmall .wi { - line-height: 15px; } + font-size: 15px; +} + +.xxsmall .wi { + line-height: 15px; +} .xsmall { - font-size: 20px; } + font-size: 20px; +} .small { - font-size: 25px; } + font-size: 25px; +} .icon { - position: relative; - top: -10px; - display: inline-block; - font-size: 45px; - padding-right: 5px; - font-weight: 100; - margin-right: 10px; } + position: relative; + top: -10px; + display: inline-block; + font-size: 45px; + padding-right: 5px; + font-weight: 100; + margin-right: 10px; +} .icon-small { - position: relative; - display: inline-block; - font-size: 20px; - padding-left: 0px; - padding-right: -10px; - font-weight: 100; - width: 20px; } + position: relative; + display: inline-block; + font-size: 20px; + padding-left: 0px; + padding-right: -10px; + font-weight: 100; + width: 20px; +} .xkcd { - -webkit-filter: invert(100%); - max-width: 100%; + -webkit-filter: invert(100%); + max-width: 100%; } .news { - height: 75px; + height: 75px; margin-bottom: 5px; } diff --git a/main.js b/main.js index ff4025c2b..d02fa9a1b 100644 --- a/main.js +++ b/main.js @@ -96,25 +96,24 @@ kwsProcess.stdout.on('data', function (data) { }) // Get motion config -if(typeof config.motion == 'undefined'){ - config.motion = {} -} -var motionpin = config.motion.pin || 26 -var motiondebug = config.motion.debug || true -var screentimeout = config.motion.screentimeout || 5.0 -var motionEnable = config.motion.enable || false +if(typeof config.motion != 'undefined'){ + var motionpin = config.motion.pin || 26 + var motiondebug = config.motion.debug || true + var screentimeout = config.motion.screentimeout || 5.0 + var motionenable = config.motion.enable || false -// Initilize the motion process -if (motionEnable == true){ -var MotionProcess = spawn('python', ['./motion/motiondetect.py', motionpin, screentimeout, motiondebug], {detached: false}) -// Handle messages from python script -MotionProcess.stderr.on('data', function (data) { - var message = data.toString() - console.log(message) -}) -MotionProcess.stdout.on('data', function (data) { - console.log(data.toString()) -}) + // Initilize the motion process + if (motionenable){ + var MotionProcess = spawn('python', ['./motion/motiondetect.py', motionpin, screentimeout, motiondebug], {detached: false}) + // Handle messages from python script + MotionProcess.stderr.on('data', function (data) { + var message = data.toString() + console.log(message) + }) + MotionProcess.stdout.on('data', function (data) { + console.log(data.toString()) + }) + } } // This method will be called when Electron has finished // initialization and is ready to create browser windows. @@ -129,7 +128,7 @@ app.on('window-all-closed', function () { // No matter how the app is quit, we should clean up after ourselvs app.on('will-quit', function () { kwsProcess.kill() - if (motionEnable==true){ + if (motionenable){ MotionProcess.kill() } }) From 4a0e61d85e725c5fcb7cde88d4c1c70299ae3353 Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Wed, 29 Jun 2016 20:09:25 -0700 Subject: [PATCH 15/39] making sense out of all these refreshes. fixing #313 --- index.html | 2 +- js/controller.js | 57 +++++++++++++++++++++++++++------------------- js/services/rss.js | 26 +++++++++++---------- 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/index.html b/index.html index 39ddaf94b..99c18fb39 100644 --- a/index.html +++ b/index.html @@ -161,7 +161,7 @@

    {{ 'commands.title' | translate }}

    -
    +
    Source: {{news.title}}, Last Updated: {{news.lastUpdated.format('MMM DD, h:mm a')}} diff --git a/js/controller.js b/js/controller.js index ff7318624..6441e717f 100644 --- a/js/controller.js +++ b/js/controller.js @@ -33,12 +33,12 @@ $scope.layoutName = 'main'; $scope.fitbitEnabled = false; - if (typeof config.fitbit != 'undefined') { + if (typeof config.fitbit !== 'undefined') { $scope.fitbitEnabled = true; } //set lang - moment.locale((typeof config.language != 'undefined')?config.language.substring(0, 2).toLowerCase(): 'en'); + moment.locale((typeof config.language !== 'undefined')?config.language.substring(0, 2).toLowerCase(): 'en'); console.log('moment local', moment.locale()); //Update the time @@ -61,6 +61,17 @@ }); }; + /** + * Register a refresh callback for a given interval (in seconds) + */ + var registerRefreshInterval = function(callback, interval){ + //Load the data initially + callback(); + if(typeof interval !== 'undefined'){ + $interval(callback, interval * 60000); + } + } + _this.init = function() { AutoSleepService.startAutoSleepTimer(); @@ -133,10 +144,10 @@ }; refreshWeatherData(); - $interval(refreshWeatherData, config.forecast.refreshInterval * 60000); + $interval(refreshWeatherData, ((config.forecast.refreshInterval)? config.forecast.refreshInterval : 2) * 60000); var greetingUpdater = function () { - if(typeof config.greeting != 'undefined' && !Array.isArray(config.greeting) && typeof config.greeting.midday != 'undefined') { + if(typeof config.greeting !== 'undefined' && !Array.isArray(config.greeting) && typeof config.greeting.midday !== 'undefined') { var hour = moment().hour(); var greetingTime = "midday"; @@ -154,8 +165,10 @@ $scope.greeting = config.greeting[Math.floor(Math.random() * config.greeting.length)]; } }; - greetingUpdater(); - $interval(greetingUpdater, 120000); + + if(typeof config.greeting !== 'undefined'){ + registerRefreshInterval(greetingUpdater, 120000); + } var refreshTrafficData = function() { TrafficService.getDurationForTrips().then(function(tripsWithTraffic) { @@ -167,9 +180,8 @@ }); }; - if(typeof config.traffic != 'undefined'){ - refreshTrafficData(); - $interval(refreshTrafficData, config.traffic.refreshInterval * 60000); + if(typeof config.traffic !== 'undefined'){ + registerRefreshInterval(refreshTrafficData, config.traffic.refreshInterval); } var refreshComic = function () { @@ -180,15 +192,14 @@ console.log(error); }); }; + + registerRefreshInterval(refreshComic, 12*60); // 12 hours - refreshComic(); var defaultView = function() { console.debug("Ok, going to default view..."); $scope.focus = "default"; } - - $interval(refreshComic, 12*60*60000); // 12 hours - + var refreshRss = function () { console.log ("Refreshing RSS"); $scope.news = null; @@ -196,15 +207,15 @@ }; var updateNews = function() { - $scope.shownews = false; - setTimeout(function(){ $scope.news = RssService.getNews(); $scope.shownews = true; }, 1000); + registerRefreshInterval(function(){ + $scope.news = RssService.getNews(); + }, 5); }; - refreshRss(); - $interval(refreshRss, config.rss.refreshInterval * 60000); - - updateNews(); - $interval(updateNews, 8000); // cycle through news every 8 seconds + if(typeof config.rss !== 'undefined'){ + registerRefreshInterval(refreshRss, config.rss.refreshInterval); + registerRefreshInterval(updateNews, 8); + } var addCommand = function(commandId, commandFunction){ var voiceId = 'commands.'+commandId+'.voice'; @@ -212,7 +223,7 @@ var descId = 'commands.'+commandId+'.description'; $translate([voiceId, textId, descId]).then(function (translations) { SpeechService.addCommand(translations[voiceId], commandFunction); - if (translations[textId] != '') { + if (translations[textId] !== '') { var command = {"text": translations[textId], "description": translations[descId]}; $scope.commands.push(command); } @@ -461,7 +472,7 @@ $timeout.cancel(resetCommandTimeout); }, result : function(result){ - if(typeof result != 'undefined'){ + if(typeof result !== 'undefined'){ $scope.interimResult = result[0]; resetCommandTimeout = $timeout(restCommand, 5000); } @@ -486,7 +497,7 @@ .controller('MirrorCtrl', MirrorCtrl); function themeController($scope) { - $scope.layoutName = (typeof config.layout != 'undefined' && config.layout)?config.layout:'main'; + $scope.layoutName = (typeof config.layout !== 'undefined' && config.layout)?config.layout:'main'; } angular.module('SmartMirror') diff --git a/js/services/rss.js b/js/services/rss.js index bb2e9d9b6..8045755f7 100644 --- a/js/services/rss.js +++ b/js/services/rss.js @@ -11,19 +11,21 @@ service.currentFeed = 0; var currentTime = new moment(); - angular.forEach(config.rss.feeds, function(url) { - $http.jsonp('http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=50&callback=JSON_CALLBACK&q=' + encodeURIComponent(url)).then(function(response) { - for (var i=0; i < response.data.responseData.feed.entries.length; i++){ - var feedEntry = { - title : response.data.responseData.feed.title, - content: response.data.responseData.feed.entries[i].title, - lastUpdated : currentTime, - }; - //console.log(feedEntry); - service.feed.push(feedEntry); - } + if (typeof config.rss != 'undefined'){ + angular.forEach(config.rss.feeds, function(url) { + $http.jsonp('http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=50&callback=JSON_CALLBACK&q=' + encodeURIComponent(url)).then(function(response) { + for (var i=0; i < response.data.responseData.feed.entries.length; i++){ + var feedEntry = { + title : response.data.responseData.feed.title, + content: response.data.responseData.feed.entries[i].title, + lastUpdated : currentTime, + }; + //console.log(feedEntry); + service.feed.push(feedEntry); + } + }); }); - }); + } return service.feed; }; From d6ec61c7a509c1623d2a995b7a8f8491eba64af3 Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Wed, 29 Jun 2016 20:14:32 -0700 Subject: [PATCH 16/39] fixing weather refresh --- js/controller.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/controller.js b/js/controller.js index 6441e717f..f7d7b9223 100644 --- a/js/controller.js +++ b/js/controller.js @@ -143,8 +143,9 @@ }); }; - refreshWeatherData(); - $interval(refreshWeatherData, ((config.forecast.refreshInterval)? config.forecast.refreshInterval : 2) * 60000); + if(typeof config.forecast !== 'undefined'){ + registerRefreshInterval(refreshWeatherData, config.forecast.refreshInterval || 2); + } var greetingUpdater = function () { if(typeof config.greeting !== 'undefined' && !Array.isArray(config.greeting) && typeof config.greeting.midday !== 'undefined') { From fd05157e8babedf8b1a215262e758645bb869e11 Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Wed, 29 Jun 2016 20:18:06 -0700 Subject: [PATCH 17/39] adding refresh fallback values to all refreshable services --- js/controller.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/js/controller.js b/js/controller.js index f7d7b9223..55c34eb5b 100644 --- a/js/controller.js +++ b/js/controller.js @@ -182,7 +182,7 @@ }; if(typeof config.traffic !== 'undefined'){ - registerRefreshInterval(refreshTrafficData, config.traffic.refreshInterval); + registerRefreshInterval(refreshTrafficData, config.traffic.refreshInterval || 5); } var refreshComic = function () { @@ -208,14 +208,12 @@ }; var updateNews = function() { - registerRefreshInterval(function(){ - $scope.news = RssService.getNews(); - }, 5); + $scope.news = RssService.getNews(); }; if(typeof config.rss !== 'undefined'){ - registerRefreshInterval(refreshRss, config.rss.refreshInterval); - registerRefreshInterval(updateNews, 8); + registerRefreshInterval(refreshRss, config.rss.refreshInterval || 30); + registerRefreshInterval(updateNews, 2); } var addCommand = function(commandId, commandFunction){ From b601ca1f3040ccd602c7060026ad9591331d9450 Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Thu, 30 Jun 2016 23:49:34 -0700 Subject: [PATCH 18/39] taking a crack at #327 --- js/controller.js | 17 ++++++++--------- js/services/weather.js | 3 ++- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/js/controller.js b/js/controller.js index 55c34eb5b..c39d39499 100644 --- a/js/controller.js +++ b/js/controller.js @@ -62,7 +62,7 @@ }; /** - * Register a refresh callback for a given interval (in seconds) + * Register a refresh callback for a given interval (in minutes) */ var registerRefreshInterval = function(callback, interval){ //Load the data initially @@ -87,17 +87,15 @@ var playing = false, sound; SoundCloudService.init(); - var refreshMirrorData = function() { + var refreshCalendar = function() { CalendarService.getCalendarEvents().then(function(response) { $scope.calendar = CalendarService.getFutureEvents(); }, function(error) { console.log(error); }); - - if ($scope.fitbitEnabled) { - setTimeout(function() { refreshFitbitData(); }, 5000); - } }; + + registerRefreshInterval(refreshCalendar, 25); var refreshFitbitData = function() { console.log('refreshing fitbit data'); @@ -110,8 +108,9 @@ }); }; - refreshMirrorData(); - $interval(refreshMirrorData, 1500000); + if($scope.fitbitEnabled){ + registerRefreshInterval(refreshFitbitData, 5); + } var refreshWeatherData = function() { //Get our location and then get the weather for our location @@ -168,7 +167,7 @@ }; if(typeof config.greeting !== 'undefined'){ - registerRefreshInterval(greetingUpdater, 120000); + registerRefreshInterval(greetingUpdater, 60); } var refreshTrafficData = function() { diff --git a/js/services/weather.js b/js/services/weather.js index 42ed4177e..35b2ba737 100644 --- a/js/services/weather.js +++ b/js/services/weather.js @@ -8,9 +8,10 @@ service.init = function(geoposition) { geoloc = geoposition; + var language = (typeof config.language !== 'undefined')?config.language.substr(0, 2) : "en" return $http.jsonp('https://api.forecast.io/forecast/'+config.forecast.key+'/'+ geoposition.coords.latitude+','+geoposition.coords.longitude+'?units=' + - config.forecast.units + "&lang="+ config.language.substr(0, 2) + "&callback=JSON_CALLBACK") + config.forecast.units + "&lang=" + language + "&callback=JSON_CALLBACK") .then(function(response) { return service.forecast = response; }); From 47d0ffbe8aee702b19552b4cdd9f537943066fc2 Mon Sep 17 00:00:00 2001 From: Joel Hawksley Date: Fri, 1 Jul 2016 17:02:59 -0600 Subject: [PATCH 19/39] [FEATURE] Use Today/Tomorrow/Day name for calendar entries (#329) [Resolves #316] --- index.html | 2 +- js/controller.js | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 99c18fb39..dfd58e01c 100644 --- a/index.html +++ b/index.html @@ -59,7 +59,7 @@
    • - {{event.start.format('dddd') | uppercase}} + {{event.start.calendar() | uppercase}} {{event.SUMMARY}}
      {{event.start.format('LLL')}}
      diff --git a/js/controller.js b/js/controller.js index c39d39499..488d82805 100644 --- a/js/controller.js +++ b/js/controller.js @@ -38,7 +38,17 @@ } //set lang - moment.locale((typeof config.language !== 'undefined')?config.language.substring(0, 2).toLowerCase(): 'en'); + moment.locale( + (typeof config.language !== 'undefined')?config.language.substring(0, 2).toLowerCase(): 'en', + { + calendar : { + sameDay : '[Today]', + nextDay : '[Tomorrow]', + nextWeek : 'dddd' + } + } + ); + console.log('moment local', moment.locale()); //Update the time From 4f8892824f1064bdebad548979f48e868c4cff7e Mon Sep 17 00:00:00 2001 From: Joel Hawksley Date: Fri, 1 Jul 2016 17:58:21 -0600 Subject: [PATCH 20/39] [FEATURE] Optionally show calendar names above events (#328) --- config.example.js | 3 ++- css/main.css | 8 ++++++++ index.html | 3 ++- js/controller.js | 2 ++ js/services/calendar.js | 8 ++++++++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/config.example.js b/config.example.js index 171ea686d..0344b4974 100644 --- a/config.example.js +++ b/config.example.js @@ -80,7 +80,8 @@ var config = { calendar: { icals : [], // Be sure to wrap your URLs in quotes maxResults: 9, // Number of calender events to display (Defaults is 9) - maxDays: 365 // Number of days to display (Default is one year) + maxDays: 365, // Number of days to display (Default is one year) + showCalendarNames: false // Show calendar names above events }, // Giphy giphy: { diff --git a/css/main.css b/css/main.css index f0f2ab8f6..9f2750e52 100644 --- a/css/main.css +++ b/css/main.css @@ -163,6 +163,14 @@ ul.calendar { font-weight: lighter; } +.calendar-name { + display: none; +} + +.show-calendar-names .calendar-name { + display: block; +} + .day-marker { margin-top: 30px; } diff --git a/index.html b/index.html index dfd58e01c..6d473efe0 100644 --- a/index.html +++ b/index.html @@ -56,10 +56,11 @@
      {{date.format('dddd')}}, {{date.format('LL')}}
      {{date.format('LT')}}
      -
        +
        • {{event.start.calendar() | uppercase}} +
          {{event.calendarName}}
          {{event.SUMMARY}}
          {{event.start.format('LLL')}}
          diff --git a/js/controller.js b/js/controller.js index 488d82805..08770a969 100644 --- a/js/controller.js +++ b/js/controller.js @@ -33,6 +33,8 @@ $scope.layoutName = 'main'; $scope.fitbitEnabled = false; + $scope.config = config; + if (typeof config.fitbit !== 'undefined') { $scope.fitbitEnabled = true; } diff --git a/js/services/calendar.js b/js/services/calendar.js index 8e9186f21..7fae0ffa4 100644 --- a/js/services/calendar.js +++ b/js/services/calendar.js @@ -60,6 +60,12 @@ var cur_event = null; for (var i = 0; i < cal_array.length; i++) { var ln = cal_array[i]; + + // Extract calendar name + if (ln.startsWith('X-WR-CALNAME')) { + var calendarName = ln.split(':')[1]; + } + //If we encounted a new Event, create a blank event object + set in event options. if (!in_event && ln == 'BEGIN:VEVENT') { var in_event = true; @@ -68,6 +74,7 @@ //If we encounter end event, complete the object and add it to our events array then clear it for reuse. if (in_event && ln == 'END:VEVENT') { in_event = false; + cur_event.calendarName = calendarName; if(!contains(events, cur_event)) { events.push(cur_event); } @@ -127,6 +134,7 @@ var startDate = moment(dt); var endDate = moment(dt); endDate.add(event_duration, 'minutes'); + recuring_event.calendarName = calendarName; recuring_event.start = startDate; recuring_event.end = endDate; if(!contains(events, recuring_event)) { From bb6fde86bac43eabd31e21fa046ac79a2ffe2cb8 Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Fri, 1 Jul 2016 21:45:51 -0700 Subject: [PATCH 21/39] fixing calendar issue for days 7+ out --- index.html | 24 +----------------------- js/controller.js | 9 ++++----- 2 files changed, 5 insertions(+), 28 deletions(-) diff --git a/index.html b/index.html index 6d473efe0..4cae613bd 100644 --- a/index.html +++ b/index.html @@ -51,7 +51,7 @@ - +
          {{date.format('dddd')}}, {{date.format('LL')}}
          @@ -198,28 +198,6 @@

          {{ 'commands.title' | translate }}

          - -
          - -
          -
          - - - - - - -
          - -
          -
            -
          • - {{ result.date | date : 'EEE MMM, yyyy hh:mm:ss a' }} - {{ result.content }} -
          • -
          -
          -
          diff --git a/js/controller.js b/js/controller.js index 08770a969..8ebf640b4 100644 --- a/js/controller.js +++ b/js/controller.js @@ -19,6 +19,8 @@ SoundCloudService, RssService, $rootScope, $scope, $timeout, $interval, tmhDynamicLocale, $translate) { + + // Local Scope Vars var _this = this; $scope.listening = false; $scope.debug = false; @@ -26,12 +28,8 @@ $scope.user = {}; $scope.shownews = true; $scope.commands = []; - /*$translate('home.commands').then(function (translation) { - $scope.interimResult = translation; - });*/ $scope.interimResult = $translate.instant('home.commands'); $scope.layoutName = 'main'; - $scope.fitbitEnabled = false; $scope.config = config; @@ -46,7 +44,8 @@ calendar : { sameDay : '[Today]', nextDay : '[Tomorrow]', - nextWeek : 'dddd' + nextWeek : 'dddd', + sameElse : 'L' } } ); From 5b28d37ae3b8c6b1d8fa5545d11ca55a7a70b4f1 Mon Sep 17 00:00:00 2001 From: Kurt Du Bois Date: Sun, 3 Jul 2016 16:18:14 +0200 Subject: [PATCH 22/39] Fixed the discontinued google feed api as defined in #332. --- js/services/rss.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/js/services/rss.js b/js/services/rss.js index 8045755f7..af433836c 100644 --- a/js/services/rss.js +++ b/js/services/rss.js @@ -13,16 +13,15 @@ if (typeof config.rss != 'undefined'){ angular.forEach(config.rss.feeds, function(url) { - $http.jsonp('http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=50&callback=JSON_CALLBACK&q=' + encodeURIComponent(url)).then(function(response) { - for (var i=0; i < response.data.responseData.feed.entries.length; i++){ + $http.jsonp('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20xml%20where%20url%20%3D%20\'' + encodeURIComponent(url) + '\'&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=JSON_CALLBACK').then(function(response) { + for (var i=0; i < response.data.query.results.rss.channel.item.length; i++){ var feedEntry = { - title : response.data.responseData.feed.title, - content: response.data.responseData.feed.entries[i].title, + title : response.data.query.results.rss.channel.title, + content: response.data.query.results.rss.channel.item[i].title, lastUpdated : currentTime, }; - //console.log(feedEntry); service.feed.push(feedEntry); - } + } }); }); } @@ -49,7 +48,7 @@ } else { service.currentFeed = service.currentFeed + 1; - } + } }; return service.feed[service.currentFeed]; } ; From 2a7af14048c495dbcffef483e31295060ea2fab8 Mon Sep 17 00:00:00 2001 From: Kurt Du Bois Date: Mon, 4 Jul 2016 04:11:15 +0200 Subject: [PATCH 23/39] Add the stock-ticker information on screen. (#331) * Added the stock-information. * Updated the stock names to be an array. Fixed a small issue where stock information would not be shown if traffic info was not filled in. * Small configuration example update. * Added a check if the config names are filled in. If not, nothing should happen. --- config.example.js | 3 +++ css/main.css | 10 +++++----- index.html | 7 +++++++ js/controller.js | 23 ++++++++++++++++++----- js/services/stock.js | 27 +++++++++++++++++++++++++++ 5 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 js/services/stock.js diff --git a/config.example.js b/config.example.js index 0344b4974..e4f3bd7e0 100644 --- a/config.example.js +++ b/config.example.js @@ -113,6 +113,9 @@ var config = { feeds : [], // RSS feeds list - e.g. ["rss1.com", "rss2.com"] refreshInterval : 120 // Number of minutes the information is refreshed }, + stock: { + names: [] // The names of the stock quotes you with to show in the official format. (e.g.: 'YHOO','AAPL','GOOG') + }, autoTimer: { autoSleep: 2400000, // How long the screen will stay awake before going to sleep (40 Mins) autoWake: '07:00:00', // When to automatically wake the screen up (7:00AM) diff --git a/css/main.css b/css/main.css index 9f2750e52..cec80595c 100644 --- a/css/main.css +++ b/css/main.css @@ -54,7 +54,7 @@ dt { .container { z-index: -1; - /* so things are still selectable */ + /* so things are still selectable */ position: fixed; top: 0; left: 0; @@ -140,7 +140,7 @@ ul.calendar { } .calendar span { - display: inline-block; + display: inline-block; } .calendar .day { @@ -148,7 +148,7 @@ ul.calendar { font-weight: bold; position: absolute; width: 128px; - vertical-align: top; + vertical-align: top; } .calendar span.summary { @@ -160,7 +160,7 @@ ul.calendar { font-size: 12px; padding-left: 150px; font-family: 'Open Sans', sans-serif; - font-weight: lighter; + font-weight: lighter; } .calendar-name { @@ -249,7 +249,7 @@ ul.calendar { width: 450px; } -.traffic-information { +.traffic-information, .stock-information { text-align: right; margin-top: 10px; margin-right: 10px; diff --git a/index.html b/index.html index 4cae613bd..de98fa054 100644 --- a/index.html +++ b/index.html @@ -40,6 +40,7 @@ + @@ -99,6 +100,12 @@ {{traffic.duration.humanize()}}
    +
    +
    + + {{quote.resource.fields.issuer_name}}: ${{quote.resource.fields.price | number : 3}} +
    +
    diff --git a/js/controller.js b/js/controller.js index 8ebf640b4..3bfe3326a 100644 --- a/js/controller.js +++ b/js/controller.js @@ -18,6 +18,7 @@ SearchService, SoundCloudService, RssService, + StockService, $rootScope, $scope, $timeout, $interval, tmhDynamicLocale, $translate) { // Local Scope Vars @@ -105,7 +106,7 @@ console.log(error); }); }; - + registerRefreshInterval(refreshCalendar, 25); var refreshFitbitData = function() { @@ -192,7 +193,7 @@ }; if(typeof config.traffic !== 'undefined'){ - registerRefreshInterval(refreshTrafficData, config.traffic.refreshInterval || 5); + registerRefreshInterval(refreshTrafficData, config.traffic.refreshInterval || 5); } var refreshComic = function () { @@ -203,14 +204,14 @@ console.log(error); }); }; - + registerRefreshInterval(refreshComic, 12*60); // 12 hours var defaultView = function() { console.debug("Ok, going to default view..."); $scope.focus = "default"; } - + var refreshRss = function () { console.log ("Refreshing RSS"); $scope.news = null; @@ -218,9 +219,21 @@ }; var updateNews = function() { - $scope.news = RssService.getNews(); + $scope.news = RssService.getNews(); }; + var getStock = function() { + StockService.getStockQuotes().then(function(result) { + $scope.stock = result.list.resources; + }, function(error) { + console.log(error); + }); + } + + if (typeof config.stock !== 'undefined' && config.stock.names.length) { + registerRefreshInterval(getStock, 30); + } + if(typeof config.rss !== 'undefined'){ registerRefreshInterval(refreshRss, config.rss.refreshInterval || 30); registerRefreshInterval(updateNews, 2); diff --git a/js/services/stock.js b/js/services/stock.js new file mode 100644 index 000000000..0a954af71 --- /dev/null +++ b/js/services/stock.js @@ -0,0 +1,27 @@ +(function(annyang) { + 'use strict'; + + function StockService($window, $http, $q) { + var service = {}; + + service.getStockQuotes = function() { + var deferred = $q.defer(); + if (config.stock.names.length) { + var url = 'http://finance.yahoo.com/webservice/v1/symbols/'+config.stock.names.join(',').toUpperCase()+'/quote?format=json&view=detail'; + + $http.get(url).then(function(response) { + deferred.resolve(response.data); + }, function(error) { + deferred.reject('Unknown error'); + }); + } + + return deferred.promise; + } + + return service; + } + + angular.module('SmartMirror') + .factory('StockService', StockService); +}(window.annyang)); From aafb40c79f70c50ea73b8feeda8180146bdca24d Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Wed, 6 Jul 2016 16:28:11 -0700 Subject: [PATCH 24/39] experamental on-device model trainer (#330) --- package.json | 1 + scripts/train-model.js | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 scripts/train-model.js diff --git a/package.json b/package.json index cdb0bd366..d77dfc3da 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "install": "bower install", "start": "electron main.js ", "microphone-debug" : "electron scripts/microphone-debug/main.js", + "train-model" : "electron scripts/train-model.js", "wiredep": "wiredep -s index.html" }, "repository": { diff --git a/scripts/train-model.js b/scripts/train-model.js new file mode 100644 index 000000000..c16646d32 --- /dev/null +++ b/scripts/train-model.js @@ -0,0 +1,51 @@ +'use strict'; + +const electron = require('electron'); +// Module to control application life. +const app = electron.app; +// Module to create native browser window. +const BrowserWindow = electron.BrowserWindow; + +// Keep a global reference of the window object, if you don't, the window will +// be closed automatically when the JavaScript object is garbage collected. +let mainWindow; + +function createWindow () { + // Create the browser window. + mainWindow = new BrowserWindow({width: 1000, height: 800, webPreferences : {nodeIntegration: false}}); + + // and load the index.html of the app. + mainWindow.loadURL('https://snowboy.kitt.ai/hotword/47'); + + // Open the DevTools. + //mainWindow.webContents.openDevTools(); + + // Emitted when the window is closed. + mainWindow.on('closed', function() { + // Dereference the window object, usually you would store windows + // in an array if your app supports multi windows, this is the time + // when you should delete the corresponding element. + mainWindow = null; + }); +} + +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. +app.on('ready', createWindow); + +// Quit when all windows are closed. +app.on('window-all-closed', function () { + // On OS X it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (process.platform !== 'darwin') { + app.quit(); + } +}); + +app.on('activate', function () { + // On OS X it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (mainWindow === null) { + createWindow(); + } +}); From ec4b365bbe124af2faff4b3f9e7dcfb9090ad6ae Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Wed, 6 Jul 2016 21:06:24 -0700 Subject: [PATCH 25/39] resolving conflicts and preparing for merge --- config.example.js | 9 ++++ index.html | 11 +++++ js/controller.js | 10 ++++- js/services/fitbit.js | 94 +++++++++++++++++++++++++++++++++++------- js/services/traffic.js | 9 +++- 5 files changed, 116 insertions(+), 17 deletions(-) diff --git a/config.example.js b/config.example.js index e4f3bd7e0..a82f46ca4 100644 --- a/config.example.js +++ b/config.example.js @@ -107,6 +107,15 @@ var config = { name : "work", // Name of your destination ex: "work" /*startTime: "", endTime: ""*/ // Optional starttime and endtime when the traffic information should be displayed on screen. The format can be either hh:mm or hh:mm am/pm + }, + { + mode : "Driving", // Possibilities: Driving / Transit / Walking + origin : "", // Start of your trip. Human readable address. + via : "", // Set an intermediate goal for getting an alternate route for example + destination : "", // Destination of your trip. Human readable address. + name : "work", // Name of your destination ex: "work" + /*startTime: "", + endTime: ""*/ // Optional starttime and endtime when the traffic information should be displayed on screen. The format can be either hh:mm or hh:mm am/pm }] }, rss: { diff --git a/index.html b/index.html index de98fa054..8252f4940 100644 --- a/index.html +++ b/index.html @@ -192,6 +192,17 @@

    {{ 'commands.title' | translate }}

    Today's active minutes: {{(fbToday.summary.veryActiveMinutes) + (fbToday.summary.fairlyActiveMinutes)}}
    Calories burned: {{fbToday.summary.caloriesOut}}

    +
    Your sleep last night
    +
    {{(fbSleep.sleep[0].minutesAsleep/60 | number:2 )}} hours / {{fbSleep.sleep[0].minutesAwake }} min awake // {{(fbSleep.sleep[0].efficiency)}} %
    +
    Awake/restless: {{fbSleep.sleep[0].awakeCount}} / {{fbSleep.sleep[0].restlessCount}}
    +

    +
    Device status
    +
    +
    + {{device.deviceVersion}} {{device.battery}} synced +
    +
    +

    Latest badges
    diff --git a/js/controller.js b/js/controller.js index 3bfe3326a..7e1645bd7 100644 --- a/js/controller.js +++ b/js/controller.js @@ -114,10 +114,18 @@ FitbitService.profileSummary(function(response){ $scope.fbDailyAverage = response; }); - + FitbitService.todaySummary(function(response){ $scope.fbToday = response; }); + + FitbitService.sleepSummary(function(response){ + $scope.fbSleep = response; + }); + + FitbitService.deviceSummary(function(response){ + $scope.fbDevices = response; + }); }; if($scope.fitbitEnabled){ diff --git a/js/services/fitbit.js b/js/services/fitbit.js index 583db1286..edd1c5609 100644 --- a/js/services/fitbit.js +++ b/js/services/fitbit.js @@ -33,6 +33,24 @@ } }; + service.getToday = function(){ + var today = new Date(); + var dd = today.getDate(); + var mm = today.getMonth()+1; //January is 0! + var yyyy = today.getFullYear(); + + // Add padding for the date, (we want 0x where x is the day or month number if its less than 10) + if(dd<10) { + dd='0'+dd; + } + + if(mm<10) { + mm='0'+mm + } + + return yyyy+'-'+mm+'-'+dd; + } + // Instantiate a fitbit client. // var fitbit = {}; @@ -146,21 +164,7 @@ return null; } - var today = new Date(); - var dd = today.getDate(); - var mm = today.getMonth()+1; //January is 0! - var yyyy = today.getFullYear(); - - // Add padding for the date, (we want 0x where x is the day or month number if its less than 10) - if(dd<10) { - dd='0'+dd - } - - if(mm<10) { - mm='0'+mm - } - - today = yyyy+'-'+mm+'-'+dd; + today = service.getToday(); // Make an API call to get the users activities for today fitbit.request({ @@ -171,7 +175,37 @@ console.log(err); } var result = JSON.parse(body); + console.log(result); + // If the token arg is not null, then a refresh has occured and + // we must persist the new token. + if (token) { + persist.write(tfile, token, function(err) { + if (err) console.log(err); + }); + } + return callback(result); + }); + + + } + + service.sleepSummary = function(callback) { + if(service.today === null){ + return null; + } + + today = service.getToday(); + // Make an API call to get the users sleep summary for today + fitbit.request({ + uri: "https://api.fitbit.com/1/user/-/sleep/date/" + today + ".json", + method: 'GET', + }, function(err, body, token) { + if (err) { + console.log(err); + } + var result = JSON.parse(body); + console.log(result); // If the token arg is not null, then a refresh has occured and // we must persist the new token. if (token) { @@ -181,8 +215,38 @@ } return callback(result); }); + + } + service.deviceSummary = function(callback) { + if(service.today === null){ + return null; + } + + // Make an API call to get the users device status + fitbit.request({ + uri: "https://api.fitbit.com/1/user/-/devices.json", + method: 'GET', + }, function(err, body, token) { + if (err) { + console.log(err); + } + var result = JSON.parse(body); + console.log(result); + // If the token arg is not null, then a refresh has occured and + // we must persist the new token. + if (token) { + persist.write(tfile, token, function(err) { + if (err) console.log(err); + }); + } + return callback(result); + }); + + + } + return service; } diff --git a/js/services/traffic.js b/js/services/traffic.js index 6420ef87e..f601d0f1c 100644 --- a/js/services/traffic.js +++ b/js/services/traffic.js @@ -37,6 +37,7 @@ } else { trip.duration = moment.duration(response.data.resourceSets[0].resources[0].travelDurationTraffic, 'seconds') } + deferred.resolve(trip); }, function(error) { // Most of the time this is because an address can't be found @@ -54,7 +55,13 @@ // Depending on the mode of transport different paramaters are required. function getEndpoint(trip){ - var endpoint = BING_MAPS + trip.mode + "?wp.0=" + trip.origin + "&wp.1="+trip.destination; + var waypoints = 1; + var intermediateGoal = ""; + if (typeof trip.via !== 'undefined' && trip.via != "") { + waypoints = 2; + intermediateGoal = "&wp.1=" + trip.via; + } + var endpoint = BING_MAPS + trip.mode + "?wp.0=" + trip.origin + intermediateGoal + "&wp."+ waypoints + "="+trip.destination; if(trip.mode == "Driving"){ endpoint += "&avoid=minimizeTolls"; } else if(trip.mode == "Transit"){ From 8a6515a7117722c4d9a6617415232a4c9dc450f4 Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Wed, 6 Jul 2016 21:14:45 -0700 Subject: [PATCH 26/39] simplifying example config --- config.example.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/config.example.js b/config.example.js index a82f46ca4..8720e8408 100644 --- a/config.example.js +++ b/config.example.js @@ -103,15 +103,7 @@ var config = { trips : [{ mode : "Driving", // Possibilities: Driving / Transit / Walking origin : "", // Start of your trip. Human readable address. - destination : "", // Destination of your trip. Human readable address. - name : "work", // Name of your destination ex: "work" - /*startTime: "", - endTime: ""*/ // Optional starttime and endtime when the traffic information should be displayed on screen. The format can be either hh:mm or hh:mm am/pm - }, - { - mode : "Driving", // Possibilities: Driving / Transit / Walking - origin : "", // Start of your trip. Human readable address. - via : "", // Set an intermediate goal for getting an alternate route for example + via : "", // [Optional] Set an intermediate goal for getting an alternate route for example destination : "", // Destination of your trip. Human readable address. name : "work", // Name of your destination ex: "work" /*startTime: "", From 086d031a075a037dbc6337bff3f3fe5264d48324 Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Sun, 10 Jul 2016 13:05:35 -0700 Subject: [PATCH 27/39] checking in bash boot script fixes #109 (#339) --- scripts/bash-start.sh | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 scripts/bash-start.sh diff --git a/scripts/bash-start.sh b/scripts/bash-start.sh new file mode 100755 index 000000000..b4c53b1c6 --- /dev/null +++ b/scripts/bash-start.sh @@ -0,0 +1,4 @@ +#!/bin/bash +export DISPLAY=:0 +export XAUTHORITY=/home/pi/.Xauthority +cd /home/pi/smart-mirror && npm start From 9edd1abd3fdf4111c97b778618da5b84d30bf03f Mon Sep 17 00:00:00 2001 From: Kurt Du Bois Date: Mon, 11 Jul 2016 11:02:12 +0200 Subject: [PATCH 28/39] Attempt to improve the RSS functionality. --- js/controller.js | 15 +++++++++------ js/services/rss.js | 28 ++++++++++++++++------------ 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/js/controller.js b/js/controller.js index 8ebf640b4..e11c496cd 100644 --- a/js/controller.js +++ b/js/controller.js @@ -105,7 +105,7 @@ console.log(error); }); }; - + registerRefreshInterval(refreshCalendar, 25); var refreshFitbitData = function() { @@ -192,7 +192,7 @@ }; if(typeof config.traffic !== 'undefined'){ - registerRefreshInterval(refreshTrafficData, config.traffic.refreshInterval || 5); + registerRefreshInterval(refreshTrafficData, config.traffic.refreshInterval || 5); } var refreshComic = function () { @@ -203,22 +203,25 @@ console.log(error); }); }; - + registerRefreshInterval(refreshComic, 12*60); // 12 hours var defaultView = function() { console.debug("Ok, going to default view..."); $scope.focus = "default"; } - + var refreshRss = function () { console.log ("Refreshing RSS"); $scope.news = null; - RssService.refreshRssList(); + RssService.refreshRssList().then(function() { + $scope.news = RssService.getNews(); + }); + }; var updateNews = function() { - $scope.news = RssService.getNews(); + $scope.news = RssService.getNews(); }; if(typeof config.rss !== 'undefined'){ diff --git a/js/services/rss.js b/js/services/rss.js index af433836c..fde83e0b6 100644 --- a/js/services/rss.js +++ b/js/services/rss.js @@ -1,7 +1,7 @@ (function(annyang) { 'use strict'; - function RssService($http) { + function RssService($http, $q) { var service = {}; service.feed = []; service.currentFeed = 0; @@ -12,24 +12,28 @@ var currentTime = new moment(); if (typeof config.rss != 'undefined'){ + var promises = []; angular.forEach(config.rss.feeds, function(url) { - $http.jsonp('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20xml%20where%20url%20%3D%20\'' + encodeURIComponent(url) + '\'&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=JSON_CALLBACK').then(function(response) { - for (var i=0; i < response.data.query.results.rss.channel.item.length; i++){ - var feedEntry = { - title : response.data.query.results.rss.channel.title, - content: response.data.query.results.rss.channel.item[i].title, + promises.push($http.jsonp('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20xml%20where%20url%20%3D%20\'' + encodeURIComponent(url) + '\'&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=JSON_CALLBACK')); + }); + + return $q.all(promises).then(function(response) { + for (var i=0; i < response['0'].data.query.results.rss.channel.item.length; i++){ + var feedEntry = { + title : response['0'].data.query.results.rss.channel.title, + content: response['0'].data.query.results.rss.channel.item[i].title, lastUpdated : currentTime, - }; - service.feed.push(feedEntry); - } - }); + }; + service.feed.push(feedEntry); + } }); } - return service.feed; }; service.refreshRssList = function() { - return service.init(); + return service.init().then(function(entries) { + return entries; + }); }; service.getNews = function() { From ac82b6c35d536305cd24221ebfbbcf01244cf857 Mon Sep 17 00:00:00 2001 From: David Ehlen Date: Tue, 12 Jul 2016 10:59:38 +0200 Subject: [PATCH 29/39] Added localization and made use of ng-show to hide fitbit data when not present --- index.html | 26 ++++++++++++++------------ js/controller.js | 4 ++-- locales/de.json | 35 +++++++++++++++++++++++++++++------ locales/en.json | 23 +++++++++++++++++++++++ locales/es.json | 23 +++++++++++++++++++++++ locales/fr.json | 23 +++++++++++++++++++++++ locales/ko.json | 23 +++++++++++++++++++++++ 7 files changed, 137 insertions(+), 20 deletions(-) diff --git a/index.html b/index.html index 8252f4940..a782fe506 100644 --- a/index.html +++ b/index.html @@ -185,25 +185,27 @@

    {{ 'commands.title' | translate }}

    -
    Fitbit stats for {{fbDailyAverage.fullName}}
    -
    Your daily average steps: {{fbDailyAverage.averageDailySteps}}
    -
    Today's steps: {{fbToday.summary.steps}}
    -
    Today's distance: {{fbToday.summary.distances[0].distance}} KM
    -
    Today's active minutes: {{(fbToday.summary.veryActiveMinutes) + (fbToday.summary.fairlyActiveMinutes)}}
    -
    Calories burned: {{fbToday.summary.caloriesOut}}
    +
    {{'fitbit.statsFor' | translate}} {{fbDailyAverage.fullName}}
    +
    {{'fitbit.averageSteps' | translate}}: {{fbDailyAverage.averageDailySteps}}
    +
    {{'fitbit.todaysSteps' | translate}}: {{fbToday.summary.steps}}
    +
    {{'fitbit.todaysDistance' | translate}}: {{fbToday.summary.distances[0].distance}} km
    +
    {{'fitbit.todaysActiveMinutes' | translate}}: {{(fbToday.summary.veryActiveMinutes) + (fbToday.summary.fairlyActiveMinutes)}} min
    +
    {{'fitbit.caloriesBurned' | translate}}: {{fbToday.summary.caloriesOut}} kcal

    -
    Your sleep last night
    -
    {{(fbSleep.sleep[0].minutesAsleep/60 | number:2 )}} hours / {{fbSleep.sleep[0].minutesAwake }} min awake // {{(fbSleep.sleep[0].efficiency)}} %
    -
    Awake/restless: {{fbSleep.sleep[0].awakeCount}} / {{fbSleep.sleep[0].restlessCount}}
    +
    {{'fitbit.sleepLastNight' | translate}}
    +
    {{(fbSleep.sleep[0].minutesAsleep/60 | number:2 )}} {{'fitbit.hours' | translate}} / {{fbSleep.sleep[0].minutesAwake }} min {{'fitbit.awake' | translate}} // {{(fbSleep.sleep[0].efficiency)}} % {{'fitbit.efficient' | translate}}
    +
    {{'fitbit.awake' | translate}}/{{'fitbit.restless' | translate}}: {{fbSleep.sleep[0].awakeCount}} / {{fbSleep.sleep[0].restlessCount}}

    -
    Device status
    +
    {{'fitbit.deviceStatus' | translate}}
    - {{device.deviceVersion}} {{device.battery}} synced + {{device.deviceVersion}}
    + {{'fitbit.battery' | translate}}: {{device.battery}}
    + {{'fitbit.synched' | translate}}: {{device.lastSyncTime | date: 'dd.MM.yyyy HH:mm:ss'}}

    -
    Latest badges
    +
    {{'fitbit.latestBadges' | translate}}
    diff --git a/js/controller.js b/js/controller.js index 7e1645bd7..3e3a917f4 100644 --- a/js/controller.js +++ b/js/controller.js @@ -129,7 +129,7 @@ }; if($scope.fitbitEnabled){ - registerRefreshInterval(refreshFitbitData, 5); + registerRefreshInterval(refreshFitbitData, 60); } var refreshWeatherData = function() { @@ -425,7 +425,7 @@ //Show fitbit stats (registered only if fitbit is configured in the main config) if ($scope.fitbitEnabled) { - SpeechService.addCommand('show my walking', function() { + addCommand('show_my_walking', function() { refreshFitbitData(); }); } diff --git a/locales/de.json b/locales/de.json index 52da8c617..e3314d2a3 100644 --- a/locales/de.json +++ b/locales/de.json @@ -43,6 +43,24 @@ "reset": "zurücksetzen" } }, + "fitbit": { + "statsFor": "Fitbit Statistiken für", + "averageSteps": "Durschnittliche Schritte pro Tag", + "todaysSteps": "Heutige Schritte", + "todaysDistance": "Heutige Distanz", + "todaysActiveMinutes": "Heutige aktive Minuten", + "caloriesBurned": "Verbrannte Kalorien", + "latestBadges": "Letzte Badges", + "sleepLastNight": "Schlaf letzte Nacht", + "hours": "Stunden", + "awake": "wach", + "efficient": "effizient", + "restless": "ruhelos", + "deviceStatus": "Gerätestatus", + "battery": "Batterie", + "synched": "Synchronisiert am", + "latestBadges": "Letzte Badges" + }, "commands": { "title" : "Zur Verfügung stehende Befehle", "list": { @@ -88,7 +106,7 @@ "map_zoom_out": { "text": "verkleinern", "voice": "(Karte) verkleinern", - "description": "Verkleinert die aktulle Karte" + "description": "Verkleinert die aktulle Karte." }, "map_zoom_point": { "text": "vergrößere ________", @@ -123,7 +141,7 @@ "image_comic_dilbert": { "text": "Dilbert Comic", "voice": "Dilbert", - "description": "Dilbert Comic" + "description": "Zeigt den aktuellsten Dilbert Comic." }, "reminder_insert": { "text": "Erinnere mich an ________", @@ -168,27 +186,32 @@ "sc_play": { "text": "SoundCloud play ________", "voice": "SoundCloud play *query", - "description": "Play a song on SoundCloud" + "description": "Spielt einen Song auf Soundcloud" }, "sc_pause": { "text": "SoundCloud pause/stop", "voice": "SoundCloud (pause)(post)(stop)(stock)", - "description": "Stop/pause SoundCoud playback" + "description": "Stoppt/Pausiert die SoundCoud Wiedergabe" }, "sc_resume": { "text": "SoundCloud play", "voice": "SoundCloud (play)(resume)", - "description": "Resumes playback" + "description": "Setzt Soundcloud Wiedergabe fort" }, "sc_replay": { "text": "SoundCloud replay", "voice": "SoundCloud replay", - "description": "Replays the current song on SoundCloud" + "description": "Spielt den aktuellen Soundcloud Song erneut" }, "light_action": { "text": "Schalte (das|die) Licht(er) (action)", "voice": "(Schalte) (das) (die) Licht(er) *action", "description": "Steuert Farbe und Helligkeit von Lichtern" + }, + "show_my_walking": { + "text": "Zeig meine Schritte", + "voice": "Zeig meine Schritte", + "description": "Aktualisiert Fitbit Daten." } } } diff --git a/locales/en.json b/locales/en.json index 4fb96fa0e..3813bdfd3 100644 --- a/locales/en.json +++ b/locales/en.json @@ -43,6 +43,24 @@ "reset": "reset" } }, + "fitbit": { + "statsFor": "Fitbit stats for", + "averageSteps": "Daily average steps", + "todaysSteps": "Todays steps", + "todaysDistance": "Todays distance", + "todaysActiveMinutes": "Todays active minutes", + "caloriesBurned": "Burned calories", + "latestBadges": "Latest badges", + "sleepLastNight": "Sleep last night", + "hours": "hours", + "awake": "awake", + "efficient": "efficient", + "restless": "restless", + "deviceStatus": "Device Status", + "battery": "Battery", + "synched": "Synched on", + "latestBadges": "Latest Badges" + }, "commands": { "title" : "Available Commands", "list": { @@ -189,6 +207,11 @@ "text": "Turn (state) light(s) (action)", "voice": "(turn) (the) :state (the) light(s) *action", "description": "Control color and brightness of lights" + }, + "show_my_walking": { + "text": "Show my walking", + "voice": "Show my walking", + "description": "Refreshes the fitbit data." } } } diff --git a/locales/es.json b/locales/es.json index 7c30ee8b8..145e8a1f7 100644 --- a/locales/es.json +++ b/locales/es.json @@ -38,6 +38,24 @@ "off": "apagar" } }, + "fitbit": { + "statsFor": "Fitbit stats for", + "averageSteps": "Daily average steps", + "todaysSteps": "Todays steps", + "todaysDistance": "Todays distance", + "todaysActiveMinutes": "Todays active minutes", + "caloriesBurned": "Burned calories", + "latestBadges": "Latest badges", + "sleepLastNight": "Sleep last night", + "hours": "hours", + "awake": "awake", + "efficient": "efficient", + "restless": "restless", + "deviceStatus": "Device Status", + "battery": "Battery", + "synched": "Synched on", + "latestBadges": "Latest Badges" + }, "commands": { "title" : "Listado de Órdenes", "list": { @@ -184,6 +202,11 @@ "text": "[estado] las luces a [acción]", "voice": ":state las luces a *action", "description": "Cambia el estado de las luces" + }, + "show_my_walking": { + "text": "Show my walking", + "voice": "Show my walking", + "description": "Refreshes the fitbit data." } } } diff --git a/locales/fr.json b/locales/fr.json index df5d85162..8cd0eca09 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -38,6 +38,24 @@ "off": "éteins" } }, + "fitbit": { + "statsFor": "Fitbit stats for", + "averageSteps": "Daily average steps", + "todaysSteps": "Todays steps", + "todaysDistance": "Todays distance", + "todaysActiveMinutes": "Todays active minutes", + "caloriesBurned": "Burned calories", + "latestBadges": "Latest badges", + "sleepLastNight": "Sleep last night", + "hours": "hours", + "awake": "awake", + "efficient": "efficient", + "restless": "restless", + "deviceStatus": "Device Status", + "battery": "Battery", + "synched": "Synched on", + "latestBadges": "Latest Badges" + }, "commands": { "title" : "Commandes disponibles", "list": { @@ -184,6 +202,11 @@ "text": "(Allume|Éteins) (la|les) lumières (action)", "voice": ":state (les) (la) lumière(s) (*action)", "description": ":state (les) (la) lumière(s) (*action)" + }, + "show_my_walking": { + "text": "Show my walking", + "voice": "Show my walking", + "description": "Refreshes the fitbit data." } } } diff --git a/locales/ko.json b/locales/ko.json index b0b01ec0b..843f10588 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -38,6 +38,24 @@ "off": "끄다" } }, + "fitbit": { + "statsFor": "Fitbit stats for", + "averageSteps": "Daily average steps", + "todaysSteps": "Todays steps", + "todaysDistance": "Todays distance", + "todaysActiveMinutes": "Todays active minutes", + "caloriesBurned": "Burned calories", + "latestBadges": "Latest badges", + "sleepLastNight": "Sleep last night", + "hours": "hours", + "awake": "awake", + "efficient": "efficient", + "restless": "restless", + "deviceStatus": "Device Status", + "battery": "Battery", + "synched": "Synched on", + "latestBadges": "Latest Badges" + }, "commands": { "title" : "사용 가능한 명령", "list": { @@ -184,6 +202,11 @@ "text": "불 (흰/빨간/파란)색으로 (켜/꺼)줘", "voice": "불 :state *action (해)줘", "description": "불 :state *action (해)줘" + }, + "show_my_walking": { + "text": "Show my walking", + "voice": "Show my walking", + "description": "Refreshes the fitbit data." } } } From 33a7aa2e207be527ec025466a3eaa3c9842ce979 Mon Sep 17 00:00:00 2001 From: David Ehlen Date: Tue, 12 Jul 2016 11:10:48 +0200 Subject: [PATCH 30/39] Made descriptions consistent, changed some wording or localizations --- locales/de.json | 22 +++++++++++----------- locales/en.json | 38 +++++++++++++++++++------------------- locales/es.json | 48 ++++++++++++++++++++++++------------------------ locales/fr.json | 30 +++++++++++++++--------------- locales/ko.json | 28 ++++++++++++++-------------- 5 files changed, 83 insertions(+), 83 deletions(-) diff --git a/locales/de.json b/locales/de.json index 52da8c617..45d5c3d5f 100644 --- a/locales/de.json +++ b/locales/de.json @@ -6,7 +6,7 @@ "time_to" : "Zeit bis {{name}}: " }, "reminders": { - "empty": "Keine Erinnerungen" + "empty": "Keine Erinnerungen." }, "timer": { "one": "Eine", @@ -88,7 +88,7 @@ "map_zoom_out": { "text": "verkleinern", "voice": "(Karte) verkleinern", - "description": "Verkleinert die aktulle Karte" + "description": "Verkleinert die aktuelle Karte." }, "map_zoom_point": { "text": "vergrößere ________", @@ -98,7 +98,7 @@ "map_zoom_reset": { "text": "Normalansicht", "voice": "(Karte) Normalansicht", - "description": "Setzt die Ansicht zurück" + "description": "Setzt die Ansicht zurück." }, "video_search": { "text": "Zeige mir ________", @@ -108,12 +108,12 @@ "video_stop": { "text": "Stop video", "voice": "stop (the) video", - "description": "Stops the playback of video content." + "description": "Stopt die Video Wiedergabe." }, "image_giphy": { "text": "Bild von ________", "voice": "Bild von *img", - "description": "Zeigt ein Giphy Bild" + "description": "Zeigt ein Giphy Bild." }, "image_comic": { "text": "Zeige Comic", @@ -123,7 +123,7 @@ "image_comic_dilbert": { "text": "Dilbert Comic", "voice": "Dilbert", - "description": "Dilbert Comic" + "description": "Zeigt den aktuellsten Dilbert Comic." }, "reminder_insert": { "text": "Erinnere mich an ________", @@ -168,27 +168,27 @@ "sc_play": { "text": "SoundCloud play ________", "voice": "SoundCloud play *query", - "description": "Play a song on SoundCloud" + "description": "Spielt einen Song auf SoundCloud." }, "sc_pause": { "text": "SoundCloud pause/stop", "voice": "SoundCloud (pause)(post)(stop)(stock)", - "description": "Stop/pause SoundCoud playback" + "description": "Stoppt/Pausiert die SoundCoud Wiedergabe." }, "sc_resume": { "text": "SoundCloud play", "voice": "SoundCloud (play)(resume)", - "description": "Resumes playback" + "description": "Setzt die Soundcloud Wiedergabe fort." }, "sc_replay": { "text": "SoundCloud replay", "voice": "SoundCloud replay", - "description": "Replays the current song on SoundCloud" + "description": "Spielt den aktuellen Song erneut auf Soundcloud." }, "light_action": { "text": "Schalte (das|die) Licht(er) (action)", "voice": "(Schalte) (das) (die) Licht(er) *action", - "description": "Steuert Farbe und Helligkeit von Lichtern" + "description": "Steuert Farbe und Helligkeit von Lichtern." } } } diff --git a/locales/en.json b/locales/en.json index 4fb96fa0e..42f2842f5 100644 --- a/locales/en.json +++ b/locales/en.json @@ -6,7 +6,7 @@ "time_to" : "Time to {{name}}: " }, "reminders": { - "empty": "Empty list" + "empty": "Empty list." }, "timer": { "one": "One", @@ -53,22 +53,22 @@ "home": { "text": "Go home", "voice": "Go home", - "description": "Takes you back to the home screen" + "description": "Takes you back to the home screen." }, "sleep": { "text": "Go to sleep", "voice": "Go to sleep", - "description": "Go to sleep" + "description": "Go to sleep." }, "wake_up": { "text": "Wake up", "voice": "Wake up", - "description": "Wake up" + "description": "Wake up." }, "debug": { "text": "Show debug information", "voice": "Show debug information", - "description": "Show debug information" + "description": "Show debug information." }, "map_show": { "text": "Show map", @@ -83,22 +83,22 @@ "map_zoom_in": { "text": "Zoom in", "voice": "(map) zoom in", - "description": "Zooms in the current map" + "description": "Zooms in the current map." }, "map_zoom_out": { "text": "Zoom out", "voice": "(map) zoom out", - "description": "Zooms out the current map" + "description": "Zooms out the current map." }, "map_zoom_point": { "text": "Zoom to ________", "voice": "(map) zoom (to) *value", - "description": "Zooms to indicated point" + "description": "Zooms to indicated point." }, "map_zoom_reset": { "text": "Reset zoom", "voice": "(map) reset zoom", - "description": "Resets zoom" + "description": "Resets zoom." }, "video_search": { "text": "Show me ________", @@ -113,7 +113,7 @@ "image_giphy": { "text": "Giphy ________", "voice": "giphy *img", - "description": "Shows a giphy image" + "description": "Shows a Giphy image." }, "image_comic": { "text": "Show xkcd", @@ -123,7 +123,7 @@ "image_comic_dilbert": { "text": "Show Dilbert comic", "voice": "Show Dilbert (comic)", - "description": "Show Dilbert comic." + "description": "Show the most recent Dilbert comic." }, "reminder_insert": { "text": "Remind me to ________", @@ -138,12 +138,12 @@ "reminder_show": { "text": "Show me reminders", "voice": "Show me reminders", - "description": "Display the reminders list" + "description": "Display the reminders list." }, "time_show": { "text": "what time is it", "voice": "what time is it", - "description": "what time is it" + "description": "Shows the current time." }, "timer_start": { "text": "Timer for ________", @@ -163,32 +163,32 @@ "timer_resume": { "text": "Resume timer", "voice": "resume (the) timer", - "description": "Resume timer" + "description": "Resume timer." }, "sc_play": { "text": "SoundCloud play ________", "voice": "SoundCloud play *query", - "description": "Play a song on SoundCloud" + "description": "Play a song on SoundCloud." }, "sc_pause": { "text": "SoundCloud pause/stop", "voice": "SoundCloud (pause)(post)(stop)(stock)", - "description": "Stop/pause SoundCoud playback" + "description": "Stop/pause SoundCoud playback." }, "sc_resume": { "text": "SoundCloud play", "voice": "SoundCloud (play)(resume)", - "description": "Resumes playback" + "description": "Resumes playback." }, "sc_replay": { "text": "SoundCloud replay", "voice": "SoundCloud replay", - "description": "Replays the current song on SoundCloud" + "description": "Replays the current song on SoundCloud." }, "light_action": { "text": "Turn (state) light(s) (action)", "voice": "(turn) (the) :state (the) light(s) *action", - "description": "Control color and brightness of lights" + "description": "Control color and brightness of lights." } } } diff --git a/locales/es.json b/locales/es.json index 7c30ee8b8..48530d259 100644 --- a/locales/es.json +++ b/locales/es.json @@ -6,7 +6,7 @@ "time_to" : "Tiempo al {{name}}: " }, "reminders": { - "empty": "No recuerdo" + "empty": "No recuerdo." }, "timer": { "one": "Uno", @@ -43,62 +43,62 @@ "list": { "text": "¿Qué digo?", "voice": "Que digo", - "description": "Lista de los comandos de voz" + "description": "Lista de los comandos de voz." }, "home": { "text": "Vuelve", "voice": "Vuelve", - "description": "Vuelve al menú principal" + "description": "Vuelve al menú principal." }, "sleep": { "text": "Duerme", "voice": "Duerme", - "description": "Duerme el sistema" + "description": "Duerme el sistema." }, "wake_up": { "text": "Despierta", "voice": "Despierta", - "description": "Despierta el sistema" + "description": "Despierta el sistema." }, "debug": { "text": "Opciones", "voice": "Opciones", - "description": "Muestra información de depuración" + "description": "Muestra información de depuración." }, "map_show": { "text": "Muestra el mapa", "voice": "Muestra el mapa", - "description": "Muestra el mapa de tu posición actual" + "description": "Muestra el mapa de tu posición actual." }, "map_location": { "text": "Muestra el mapa", "voice": "Muestra el mapa de *location", - "description": "Muestra el mapa de la posición indicada" + "description": "Muestra el mapa de la posición indicada." }, "map_zoom_in": { "text": "Centra el mapa", "voice": "Centra (el mapa)", - "description": "Centra el mapa" + "description": "Centra el mapa." }, "map_zoom_out": { "text": "Amplia el mapa", "voice": "Amplia (el mapa)", - "description": "Amplia el mapa" + "description": "Amplia el mapa." }, "map_zoom_point": { "text": "Apunta el mapa a _______", "voice": "Apunta (el mapa) a *value", - "description": "Apunta el mapa a un punto en concreto" + "description": "Apunta el mapa a un punto en concreto." }, "map_zoom_reset": { "text": "Resetea el mapa", "voice": "Resetea (el) (mapa)", - "description": "Resetea (el) (mapa)" + "description": "Resetea (el) (mapa)." }, "video_search": { "text": "Busca imagen de _______", "voice": "Busca imagen de *term", - "description": "Busca una imagen" + "description": "Busca una imagen." }, "video_stop": { "text": "Stop video", @@ -108,12 +108,12 @@ "image_giphy": { "text": "Busca animacion de _______", "voice": "Busca animacion de *img", - "description": "Busca animacion de algún tema" + "description": "Busca animacion de algún tema." }, "image_comic": { "text": "Comic", "voice": "Comic (del dia)", - "description": "Muestra el comic del día" + "description": "Muestra el comic del día." }, "image_comic_dilbert": { "text": "Comic Dilbert", @@ -123,22 +123,22 @@ "reminder_insert": { "text": "Recuerdame hacer _______", "voice": "Recuerdame hacer *task", - "description": "Recuerdame hacer una tarea" + "description": "Recuerdame hacer una tarea." }, "reminder_clear": { "text": "Limpia la tareas pendientes", "voice": "Limpia la tareas pendientes", - "description": "Limpia la tareas pendientes" + "description": "Limpia la tareas pendientes." }, "reminder_show": { "text": "Muéstrame la lista de retiro", "voice": "Muéstrame la lista de retiro", - "description": "Muestra la lista de retiro" + "description": "Muestra la lista de retiro." }, "time_show": { "text": "¿Qué hora es?", "voice": "que hora es", - "description": "Muestra la hora actual" + "description": "Muestra la hora actual." }, "timer_start": { "text": "Temporizador a _______", @@ -163,27 +163,27 @@ "sc_play": { "text": "SoundCloud play ________", "voice": "SoundCloud play *query", - "description": "Play a song on SoundCloud" + "description": "Play a song on SoundCloud." }, "sc_pause": { "text": "SoundCloud pause/stop", "voice": "SoundCloud (pause)(post)(stop)(stock)", - "description": "Stop/pause SoundCoud playback" + "description": "Stop/pause SoundCoud playback." }, "sc_resume": { "text": "SoundCloud play", "voice": "SoundCloud (play)(resume)", - "description": "Resumes playback" + "description": "Resumes playback." }, "sc_replay": { "text": "SoundCloud replay", "voice": "SoundCloud replay", - "description": "Replays the current song on SoundCloud" + "description": "Replays the current song on SoundCloud." }, "light_action": { "text": "[estado] las luces a [acción]", "voice": ":state las luces a *action", - "description": "Cambia el estado de las luces" + "description": "Cambia el estado de las luces." } } } diff --git a/locales/fr.json b/locales/fr.json index df5d85162..92036d799 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -6,7 +6,7 @@ "time_to" : "Temps de {{name}}: " }, "reminders": { - "empty": "Aucun rappel" + "empty": "Aucun rappel." }, "timer": { "one": "Une", @@ -48,22 +48,22 @@ "home": { "text": "Accueil", "voice": "Accueil", - "description": "Vous ramène à l'écran d'accueil" + "description": "Vous ramène à l'écran d'accueil." }, "sleep": { "text": "Bonne nuit", "voice": "Bonne nuit", - "description": "Va te coucher" + "description": "Va te coucher." }, "wake_up": { "text": "Réveille toi", "voice": "Réveille toi", - "description": "Réveille Toi" + "description": "Réveille Toi." }, "debug": { "text": "Débogage", "voice": "Débogage", - "description": "Afficher les informations de débogage" + "description": "Afficher les informations de débogage." }, "map_show": { "text": "Affiche carte", @@ -78,22 +78,22 @@ "map_zoom_in": { "text": "Zoom avant", "voice": "Zoom (avant) (sur la carte)", - "description": "Zoom avant sur la carte actuelle" + "description": "Zoom avant sur la carte actuelle." }, "map_zoom_out": { "text": "Zoom arrière", "voice": "Zoom arrière (sur la carte)", - "description": "Zoom arrière sur la carte actuelle" + "description": "Zoom arrière sur la carte actuelle." }, "map_zoom_point": { "text": "Zoom vers ________", "voice": "Zoom (vers) *value", - "description": "Zoom vers le point indiqué" + "description": "Zoom vers le point indiqué." }, "map_zoom_reset": { "text": "Réinitialise zoom", "voice": "Réinitialise le zoom", - "description": "Réinitilalise la fonction zoom" + "description": "Réinitilalise la fonction zoom." }, "video_search": { "text": "(Re)cherche une image de ________", @@ -108,7 +108,7 @@ "image_giphy": { "text": "(Re)cherche une image animée de ________", "voice": "(Re)cherche une image animée de *img", - "description": "Affiche une image de giphy" + "description": "Affiche une image de giphy." }, "image_comic": { "text": "Montre(-moi) le dernier xkcd ", @@ -163,27 +163,27 @@ "sc_play": { "text": "SoundCloud play ________", "voice": "SoundCloud play *query", - "description": "Play a song on SoundCloud" + "description": "Play a song on SoundCloud." }, "sc_pause": { "text": "SoundCloud pause/stop", "voice": "SoundCloud (pause)(post)(stop)(stock)", - "description": "Stop/pause SoundCoud playback" + "description": "Stop/pause SoundCoud playback." }, "sc_resume": { "text": "SoundCloud play", "voice": "SoundCloud (play)(resume)", - "description": "Resumes playback" + "description": "Resumes playback." }, "sc_replay": { "text": "SoundCloud replay", "voice": "SoundCloud replay", - "description": "Replays the current song on SoundCloud" + "description": "Replays the current song on SoundCloud." }, "light_action": { "text": "(Allume|Éteins) (la|les) lumières (action)", "voice": ":state (les) (la) lumière(s) (*action)", - "description": ":state (les) (la) lumière(s) (*action)" + "description": ":state (les) (la) lumière(s) (*action)." } } } diff --git a/locales/ko.json b/locales/ko.json index b0b01ec0b..3bbb30817 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -6,7 +6,7 @@ "time_to" : "{{name}} 에 시간: " }, "reminders": { - "empty": "더 리콜 없습니다" + "empty": "더 리콜 없습니다." }, "timer": { "one": "일", @@ -53,12 +53,12 @@ "sleep": { "text": "잠자러가", "voice": "잠자러가", - "description": "잠자러가" + "description": "잠자러가." }, "wake_up": { "text": "일어나", "voice": "일어나", - "description": "일어나" + "description": "일어나." }, "debug": { "text": "디버그 정보 보여 줘", @@ -133,57 +133,57 @@ "reminder_show": { "text": "나에게 리콜 목록을 표시", "voice": "나에게 리콜 목록을 표시", - "description": "리콜 목록을 표시합니다" + "description": "리콜 목록을 표시합니다." }, "time_show": { "text": "지금 몇 시", "voice": "지금 몇 시", - "description": "지금 몇 시" + "description": "지금 몇 시." }, "timer_start": { "text": "______ 타이머 (설정)", "voice": "*duration 타이머 (설정)", - "description": "*duration 타이머 (설정)" + "description": "*duration 타이머 (설정)." }, "timer_show": { "text": "타이머 보여줄래", "voice": "타이머 보여줄래", - "description": "타이머 보여줄래" + "description": "타이머 보여줄래." }, "timer_stop": { "text": "타이머 정지", "voice": "타이머 정지", - "description": "타이머 정지" + "description": "타이머 정지." }, "timer_resume": { "text": "타이머 재시작", "voice": "타이머 재시작", - "description": "타이머 재시작" + "description": "타이머 재시작." }, "sc_play": { "text": "SoundCloud play ________", "voice": "SoundCloud play *query", - "description": "Play a song on SoundCloud" + "description": "Play a song on SoundCloud." }, "sc_pause": { "text": "SoundCloud pause/stop", "voice": "SoundCloud (pause)(post)(stop)(stock)", - "description": "Stop/pause SoundCoud playback" + "description": "Stop/pause SoundCoud playback." }, "sc_resume": { "text": "SoundCloud play", "voice": "SoundCloud (play)(resume)", - "description": "Resumes playback" + "description": "Resumes playback." }, "sc_replay": { "text": "SoundCloud replay", "voice": "SoundCloud replay", - "description": "Replays the current song on SoundCloud" + "description": "Replays the current song on SoundCloud." }, "light_action": { "text": "불 (흰/빨간/파란)색으로 (켜/꺼)줘", "voice": "불 :state *action (해)줘", - "description": "불 :state *action (해)줘" + "description": "불 :state *action (해)줘." } } } From 162a64f8ff263ed36b1b33957ab96ad52e97e369 Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Tue, 12 Jul 2016 17:37:35 -0700 Subject: [PATCH 31/39] Switching to use Dependency CI --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4b13f424b..cdda94879 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Smart Mirror -[![Join the chat at https://gitter.im/evancohen/smart-mirror](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/evancohen/smart-mirror?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Stories in Progress](https://img.shields.io/waffle/label/evancohen/smart-mirror/in%20progress.svg)] (https://waffle.io/evancohen/smart-mirror) [![Suggestions](https://img.shields.io/waffle/label/evancohen/smart-mirror/suggestion.svg?label=suggestions)] (https://github.com/evancohen/smart-mirror/issues?q=is%3Aissue+is%3Aopen+label%3Asuggestion) [![devDependency Status](https://david-dm.org/evancohen/smart-mirror/dev-status.svg)](https://david-dm.org/evancohen/smart-mirror#info=devDependencies) +[![Join the chat at https://gitter.im/evancohen/smart-mirror](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/evancohen/smart-mirror?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Stories in Progress](https://img.shields.io/waffle/label/evancohen/smart-mirror/in%20progress.svg)] (https://waffle.io/evancohen/smart-mirror) [![Suggestions](https://img.shields.io/waffle/label/evancohen/smart-mirror/suggestion.svg?label=suggestions)] (https://github.com/evancohen/smart-mirror/issues?q=is%3Aissue+is%3Aopen+label%3Asuggestion) [![Dependency Status](https://dependencyci.com/github/evancohen/smart-mirror/badge)](https://dependencyci.com/github/evancohen/smart-mirror) -Check out the [smart mirror documentation](http://docs.smart-mirror.io) for installation instructions and troubleshooting. +Check out the [smart mirror documentation](http://docs.smart-mirror.io) for more information, installation instructions, and troubleshooting. #### Gitter: A live chat to get help and discuss mirror related issues: https://gitter.im/evancohen/smart-mirror. Usually there are a few folks hanging around in the lobby, but if there arent you are probubly better off [filing an issue](https://github.com/evancohen/smart-mirror/issues/new). From 5320ed851bdd3cbd4f2a2cc7efde3c022eb09a5b Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Sat, 16 Jul 2016 16:06:34 -0700 Subject: [PATCH 32/39] reverting #311 because of IPC issues --- config.example.js | 11 ++----- main.js | 23 -------------- motion/motiondetect.py | 71 ------------------------------------------ 3 files changed, 2 insertions(+), 103 deletions(-) delete mode 100644 motion/motiondetect.py diff --git a/config.example.js b/config.example.js index 8720e8408..a164d5728 100644 --- a/config.example.js +++ b/config.example.js @@ -2,15 +2,8 @@ var config = { // Lenguage for the mirror language : "en-US", - - // PIR Detection - motion : { - pin : 26, //Default pirPin is GPIO pin 26. - screentimeout : 5.0, //Default timeout is 5 minutes must be a float number. - enable : true, // Enable or disable this functionality - debug : true // send debug info to dev console, if debug timeout is 30 seconds (not yet working) - }, - // Keyword Spotting (Hotword Detection) + + // Keyword Spotting (Hotword Detection) speech : { keyword : "Smart Mirror", model : "smart_mirror.pmdl", // The name of your model diff --git a/main.js b/main.js index d02fa9a1b..fc990baf0 100644 --- a/main.js +++ b/main.js @@ -95,26 +95,6 @@ kwsProcess.stdout.on('data', function (data) { console.log(data.toString()) }) -// Get motion config -if(typeof config.motion != 'undefined'){ - var motionpin = config.motion.pin || 26 - var motiondebug = config.motion.debug || true - var screentimeout = config.motion.screentimeout || 5.0 - var motionenable = config.motion.enable || false - - // Initilize the motion process - if (motionenable){ - var MotionProcess = spawn('python', ['./motion/motiondetect.py', motionpin, screentimeout, motiondebug], {detached: false}) - // Handle messages from python script - MotionProcess.stderr.on('data', function (data) { - var message = data.toString() - console.log(message) - }) - MotionProcess.stdout.on('data', function (data) { - console.log(data.toString()) - }) - } -} // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. @@ -128,7 +108,4 @@ app.on('window-all-closed', function () { // No matter how the app is quit, we should clean up after ourselvs app.on('will-quit', function () { kwsProcess.kill() - if (motionenable){ - MotionProcess.kill() - } }) diff --git a/motion/motiondetect.py b/motion/motiondetect.py deleted file mode 100644 index e0e4e20fc..000000000 --- a/motion/motiondetect.py +++ /dev/null @@ -1,71 +0,0 @@ -import RPi.GPIO as GPIO -import time -from threading import Timer -import subprocess -import sys -import signal - -isDebug = True -interrupted = False - - -def signal_handler(signal, frame): - global interrupted - interrupted = True - exit(0) -if len(sys.argv) < 2: - motionPin = 26 - ScreenTimeOut = float(0.5) - -else: - motionPin = int(sys.argv[1]) - ScreenTimeOut = round(float(sys.argv[2]), 2) - -print motionPin -print ScreenTimeOut - -def debugging(msg): - global isDebug - if isDebug: - print msg - - -GPIO.setmode(GPIO.BCM) -GPIO.setup(motionPin, GPIO.IN) -timer = False -monitor_is_on = True - -def monitor_off(): - global monitor_is_on - debugging("monitor off") - subprocess.Popen('tvservice -o', shell=True) - monitor_is_on = False - -def monitor_on(): - global monitor_is_on - debugging("monitor on") - subprocess.Popen('tvservice -p', shell=True) - subprocess.Popen('fbset -depth 8 && fbset -depth 16 && xrefresh', shell=True) - monitor_is_on = True - -signal.signal(signal.SIGINT, signal_handler) - -while True: - debugging("Waiting for movement") - time.sleep(0.5) - movement = GPIO.input(motionPin) - if movement: - debugging(" movement active") - if timer: - debugging(" cancel timer") - timer.cancel() - timer = False - if not monitor_is_on: - debugging(" calling monitor on") - monitor_on() - else: - debugging(" movement inactive") - if not timer: - debugging(" starting timer") - timer = Timer(60*ScreenTimeOut, monitor_off) - timer.start() From b8f64ed4b22f25953eac3265ee7794b23bcd5dba Mon Sep 17 00:00:00 2001 From: Joel Hawksley Date: Mon, 18 Jul 2016 08:10:25 -0600 Subject: [PATCH 33/39] [CALENDAR] Polish day/multi-day formatting. (#347) [Resolves #317] --- css/main.css | 11 ++++++----- index.html | 13 ++++++++++--- js/controller.js | 2 ++ js/services/calendar.js | 11 +++++++++++ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/css/main.css b/css/main.css index cec80595c..37df928ec 100644 --- a/css/main.css +++ b/css/main.css @@ -146,19 +146,16 @@ ul.calendar { .calendar .day { display: none; font-weight: bold; - position: absolute; - width: 128px; vertical-align: top; } .calendar span.summary { - margin-left: 150px; - max-width: 400px; + font-size: 25px; + max-width: 400px; } .calendar .event-details .details { font-size: 12px; - padding-left: 150px; font-family: 'Open Sans', sans-serif; font-weight: lighter; } @@ -174,8 +171,12 @@ ul.calendar { .day-marker { margin-top: 30px; } + .day-marker .day { display: block; + font-size: 15px; + letter-spacing: 2px; + margin-bottom: 10px; } .weather { diff --git a/index.html b/index.html index a782fe506..b55233be6 100644 --- a/index.html +++ b/index.html @@ -58,12 +58,19 @@
    {{date.format('dddd')}}, {{date.format('LL')}}
    {{date.format('LT')}}
      -
    • +
    • - {{event.start.calendar() | uppercase}} + + {{event.startName}} + - {{event.endName}} +
      {{event.calendarName}}
      {{event.SUMMARY}} -
      {{event.start.format('LLL')}}
      +
      + {{event.start.format('M/D')}} {{event.start.format('LT')}} - {{event.end.format('M/D')}} {{event.end.format('LT')}} + {{event.start.format('LT')}} - {{event.end.format('LT')}} +
      +
      All day
    diff --git a/js/controller.js b/js/controller.js index 89b89c2e6..d7c9c75ed 100644 --- a/js/controller.js +++ b/js/controller.js @@ -43,6 +43,8 @@ (typeof config.language !== 'undefined')?config.language.substring(0, 2).toLowerCase(): 'en', { calendar : { + lastWeek : '[Last] dddd', + lastDay : '[Yesterday]', sameDay : '[Today]', nextDay : '[Tomorrow]', nextWeek : 'dddd', diff --git a/js/services/calendar.js b/js/services/calendar.js index 7fae0ffa4..80d6035ca 100644 --- a/js/services/calendar.js +++ b/js/services/calendar.js @@ -96,12 +96,21 @@ //If the type is a start date, proccess it and store details if (type.startsWith('DTSTART')) { cur_event.start = makeDate(type, val); + cur_event.startName = makeDate(type, val).calendar().toUpperCase(); } //If the type is an end date, do the same as above else if (type.startsWith('DTEND')) { cur_event.end = makeDate(type, val); + + // Subtract one second so that single-day events endon the same day + cur_event.endName = makeDate(type, val).subtract(1, 'seconds').calendar().toUpperCase(); } + + if (cur_event.startName && cur_event.endName) { + cur_event.label = cur_event.startName + " - " + cur_event.endName; + } + //Convert timestamp else if (type == 'DTSTAMP') { //val = makeDate(type, val); @@ -136,7 +145,9 @@ endDate.add(event_duration, 'minutes'); recuring_event.calendarName = calendarName; recuring_event.start = startDate; + recuring_event.startName = startDate.calendar().toUpperCase(); recuring_event.end = endDate; + recuring_event.endName = endDate.subtract(1, 'seconds').calendar().toUpperCase(); if(!contains(events, recuring_event)) { events.push(recuring_event); } From 023f0867534aecdbe17a7152113ceb9fb6fb8558 Mon Sep 17 00:00:00 2001 From: Kurt Du Bois Date: Thu, 21 Jul 2016 20:19:52 +0200 Subject: [PATCH 34/39] Added scrobbler support. (#346) * Initial checkin of the last.fm scrobbler service. * Added the conversion of the data. * Fixed conversion issue: now it is converted in the service. Added the call to the voice command. Updated the translations. (this has to be fixed for other languages. * Some updates: - Show on the bottom left - No voice command - Dealing with error cases --- config.example.js | 5 +++++ css/main.css | 20 ++++++++++++++++---- index.html | 19 ++++++++++++++----- js/controller.js | 11 +++++++++++ js/services/scrobbler.js | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 js/services/scrobbler.js diff --git a/config.example.js b/config.example.js index a164d5728..18f8a8eb7 100644 --- a/config.example.js +++ b/config.example.js @@ -115,6 +115,11 @@ var config = { autoWake: '07:00:00', // When to automatically wake the screen up (7:00AM) 'wake_cmd': '/opt/vc/bin/tvservice -p', // The binary and arguments used on your system to wake the screen 'sleep_cmd': '/opt/vc/bin/tvservice -o', // The binary and arguments used on your system to sleep the screen + }, + lastfm: { + key: "", // Your last.fm api key + user: "", // Your last.fm username + refreshInterval : 0.6 // Number of minutes between checks for playing track } }; diff --git a/css/main.css b/css/main.css index 37df928ec..d5323cb44 100644 --- a/css/main.css +++ b/css/main.css @@ -114,13 +114,21 @@ dt { margin-bottom: 20px; } -.bottom-left { +.bottom-left, .bottom-right { font-family: 'Open Sans', sans-serif; position: absolute; - bottom: 20px; + bottom: 50px; + width: 50%; +} + +.bottom-left { left: 20px; } +.bottom-right { + right: 20px; +} + .commands { width: 450px; text-align: left; @@ -250,6 +258,11 @@ ul.calendar { width: 450px; } +.playing-track img { + float: left; + margin-right: 5px; +} + .traffic-information, .stock-information { text-align: right; margin-top: 10px; @@ -478,7 +491,6 @@ ul.calendar { } .news { - height: 75px; margin-bottom: 5px; } @@ -492,4 +504,4 @@ ul.calendar { font-family: 'Open Sans', sans-serif; font-size: 20px; margin-bottom: 55px; -} +} \ No newline at end of file diff --git a/index.html b/index.html index b55233be6..1c10c075c 100644 --- a/index.html +++ b/index.html @@ -41,6 +41,7 @@ + @@ -112,14 +113,12 @@ {{quote.resource.fields.issuer_name}}: ${{quote.resource.fields.price | number : 3}}
    -
    +

    {{greeting}}

    -

    {{user.name}}

    -
    @@ -190,8 +189,8 @@

    {{ 'commands.title' | translate }}

    -
    -
    +
    +
    {{'fitbit.statsFor' | translate}} {{fbDailyAverage.fullName}}
    {{'fitbit.averageSteps' | translate}}: {{fbDailyAverage.averageDailySteps}}
    {{'fitbit.todaysSteps' | translate}}: {{fbToday.summary.steps}}
    @@ -220,6 +219,16 @@

    {{ 'commands.title' | translate }}

    +
    + +
    {{track.artist}}
    +
    {{track.title}}
    +
    {{track.album}}
    +
    Playing
    +
    +
    +
    +
    diff --git a/js/controller.js b/js/controller.js index d7c9c75ed..7b196966e 100644 --- a/js/controller.js +++ b/js/controller.js @@ -19,6 +19,7 @@ SoundCloudService, RssService, StockService, + ScrobblerService, $rootScope, $scope, $timeout, $interval, tmhDynamicLocale, $translate) { // Local Scope Vars @@ -252,6 +253,16 @@ registerRefreshInterval(updateNews, 2); } + var getScrobblingTrack = function(){ + ScrobblerService.getCurrentTrack().then(function(track) { + $scope.track = track; + }); + } + + if(typeof config.lastfm.key !== 'undefined' && config.lastfm.user !== 'undefined'){ + registerRefreshInterval(getScrobblingTrack, config.lastfm.refreshInterval || 0.6) + } + var addCommand = function(commandId, commandFunction){ var voiceId = 'commands.'+commandId+'.voice'; var textId = 'commands.'+commandId+'.text'; diff --git a/js/services/scrobbler.js b/js/services/scrobbler.js new file mode 100644 index 000000000..8d4a7a39f --- /dev/null +++ b/js/services/scrobbler.js @@ -0,0 +1,40 @@ +(function(annyang) { + 'use strict'; + + function ScrobblerService($http, $q) { + var service = {}; + + service.getCurrentTrack = function () { + var deferred = $q.defer(); + if (config.lastfm.user && config.lastfm.key) { + var url = "http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user="+config.lastfm.user+"&api_key="+config.lastfm.key+"&limit=1&format=json"; + + $http.get(url).then(function(response) { + if (response.data.error){ + // If there is an error with the request (excluding network errors) + console.log("Scrobbler Error: ", response.data.message); + deferred.reject(response); + } else if (typeof response.data.recenttracks.track[0]["@attr"] == "object"){ + // If there is a track currently playing + var track = response.data.recenttracks.track[0]; + deferred.resolve({ + title: track.name, + artist: track.artist["#text"] || "Unknown", + album: track.album["#text"] || "", + cover: track.image[1]["#text"], + }); + } else { + // Either there was a network error or there is no song currently playing + deferred.reject(response); + } + }); + } + return deferred.promise; + } + + return service; + } + + angular.module('SmartMirror') + .factory('ScrobblerService', ScrobblerService); +}(window.annyang)); From 83dd214b3cf52c5f72c38825f1d9835c73de4c4d Mon Sep 17 00:00:00 2001 From: Kurt Du Bois Date: Fri, 22 Jul 2016 18:33:50 +0200 Subject: [PATCH 35/39] Updated the stock information to the yahoo yql service. (#354) Added the change percentage. --- index.html | 4 ++-- js/controller.js | 6 +++--- js/services/stock.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 1c10c075c..98061ac8f 100644 --- a/index.html +++ b/index.html @@ -111,7 +111,7 @@
    - {{quote.resource.fields.issuer_name}}: ${{quote.resource.fields.price | number : 3}} + {{quote.Name}}: ${{quote.LastTradePriceOnly | number : 3}} ({{quote.Change}}%)
    @@ -200,7 +200,7 @@

    {{ 'commands.title' | translate }}

    {{'fitbit.sleepLastNight' | translate}}
    {{(fbSleep.sleep[0].minutesAsleep/60 | number:2 )}} {{'fitbit.hours' | translate}} / {{fbSleep.sleep[0].minutesAwake }} min {{'fitbit.awake' | translate}} // {{(fbSleep.sleep[0].efficiency)}} % {{'fitbit.efficient' | translate}}
    -
    {{'fitbit.awake' | translate}}/{{'fitbit.restless' | translate}}: {{fbSleep.sleep[0].awakeCount}} / {{fbSleep.sleep[0].restlessCount}}
    +
    {{'fitbit.awake' | translate}}/{{'fitbit.restless' | translate}}: {{fbSleep.sleep[0].awakeCount}} / {{fbSleep.sleep[0].restlessCount}}

    {{'fitbit.deviceStatus' | translate}}
    diff --git a/js/controller.js b/js/controller.js index 7b196966e..3476c4626 100644 --- a/js/controller.js +++ b/js/controller.js @@ -117,7 +117,7 @@ FitbitService.profileSummary(function(response){ $scope.fbDailyAverage = response; }); - + FitbitService.todaySummary(function(response){ $scope.fbToday = response; }); @@ -238,11 +238,11 @@ var getStock = function() { StockService.getStockQuotes().then(function(result) { - $scope.stock = result.list.resources; + $scope.stock = result.query.results.quote; }, function(error) { console.log(error); }); - } + } if (typeof config.stock !== 'undefined' && config.stock.names.length) { registerRefreshInterval(getStock, 30); diff --git a/js/services/stock.js b/js/services/stock.js index 0a954af71..7eb4cf2e3 100644 --- a/js/services/stock.js +++ b/js/services/stock.js @@ -7,7 +7,7 @@ service.getStockQuotes = function() { var deferred = $q.defer(); if (config.stock.names.length) { - var url = 'http://finance.yahoo.com/webservice/v1/symbols/'+config.stock.names.join(',').toUpperCase()+'/quote?format=json&view=detail'; + var url = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quote%20where%20symbol%20in%20('+"'" + config.stock.names.join("','") + "'"+')&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&format=json'; $http.get(url).then(function(response) { deferred.resolve(response.data); From 7f451de4be43d20c35f4ea48fccbfadf700d879b Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Fri, 22 Jul 2016 16:58:58 -0700 Subject: [PATCH 36/39] Performance improvements (#352) * only add fitbit dependencies if the user has fitbit in their config * using ng-if for binding intensive elements. 7% perf improvement :smile: * improve performance of digest binding * only add fitbit dependencies if the user has fitbit in their config * rebasing calendar fixes onto performance * using ng-bind for calendar * replacing missing closing parenthasese * replacing missing closing parenthasese and bonus char * lastfm config object should be optional --- index.html | 71 +++++++++++++++++------------------ js/controller.js | 2 +- js/services/fitbit.js | 86 +++++++++++++++++++++---------------------- main.js | 5 ++- 4 files changed, 81 insertions(+), 83 deletions(-) diff --git a/index.html b/index.html index 98061ac8f..57a3c05c5 100644 --- a/index.html +++ b/index.html @@ -56,20 +56,20 @@
    -
    {{date.format('dddd')}}, {{date.format('LL')}}
    -
    {{date.format('LT')}}
    +
    ,
    +
    • - {{event.startName}} - - {{event.endName}} + + - -
      {{event.calendarName}}
      - {{event.SUMMARY}} +
      +
      - {{event.start.format('M/D')}} {{event.start.format('LT')}} - {{event.end.format('M/D')}} {{event.end.format('LT')}} - {{event.start.format('LT')}} - {{event.end.format('LT')}} + - + -
      All day
      @@ -81,20 +81,20 @@
      - {{currentForecast.temperature}}° +
      - {{minutelyForecast.summary}} - {{hourlyForecast.summary}} - {{weeklyForecast.summary}} + + +
      - {{forecast.day}} + - {{forecast.temperatureMin}}° - {{forecast.temperatureMax}}° + +
      @@ -104,21 +104,21 @@
    - {{ 'traffic.time_to' | translate:traffic }} - {{traffic.duration.humanize()}} + +
    - {{quote.Name}}: ${{quote.LastTradePriceOnly | number : 3}} ({{quote.Change}}%) + : $
    -

    {{greeting}}

    +

    @@ -127,7 +127,7 @@

    {{greeting}}

    -

    {{scTrack}}

    +

    @@ -140,48 +140,43 @@

    {{scTrack}}

    -
    {{dilbert.title}}
    +
    • - {{reminder}} +
    -
    +
    -
    {{timer.countdown | secondsToDateTime | date:"mm:ss"}}
    -
    {{timer.duration | secondsToDateTime | date:"mm:ss"}}
    +
    +
    -
    -

    {{ 'commands.title' | translate }}

    +
    +

    -
    {{command['text']}}
    -
    {{command['description']}}
    +
    +
    Show my walking
    Refreshes fitbit data.
    - - We are using node , - Chrome , - and Electron . -
    -
    +
    - Source: {{news.title}}, Last Updated: {{news.lastUpdated.format('MMM DD, h:mm a')}} + Source: , Last Updated:
    - {{news.content}} +
    @@ -190,7 +185,7 @@

    {{ 'commands.title' | translate }}

    -
    +
    {{'fitbit.statsFor' | translate}} {{fbDailyAverage.fullName}}
    {{'fitbit.averageSteps' | translate}}: {{fbDailyAverage.averageDailySteps}}
    {{'fitbit.todaysSteps' | translate}}: {{fbToday.summary.steps}}
    diff --git a/js/controller.js b/js/controller.js index 3476c4626..46f87be50 100644 --- a/js/controller.js +++ b/js/controller.js @@ -259,7 +259,7 @@ }); } - if(typeof config.lastfm.key !== 'undefined' && config.lastfm.user !== 'undefined'){ + if(typeof config.lastfm !== 'undefined' && typeof config.lastfm.key !== 'undefined' && config.lastfm.user !== 'undefined'){ registerRefreshInterval(getScrobblingTrack, config.lastfm.refreshInterval || 0.6) } diff --git a/js/services/fitbit.js b/js/services/fitbit.js index edd1c5609..2c7f34c5b 100644 --- a/js/services/fitbit.js +++ b/js/services/fitbit.js @@ -1,10 +1,5 @@ (function() { 'use strict'; - - var express = require('express'); - var app = express(); - var fs = require( 'fs' ); - var Fitbit = require( 'fitbit-oauth2' ); function FitbitService($http) { @@ -56,53 +51,58 @@ var fitbit = {}; if (typeof config.fitbit != 'undefined') { fitbit = new Fitbit(config.fitbit); - } - // In a browser, http://localhost:4000/fitbit to authorize a user for the first time. - // - app.get('/fitbit', function (req, res) { - res.redirect(fitbit.authorizeURL()); - }); + var express = require('express'); + var app = express(); + var fs = require( 'fs' ); + var Fitbit = require( 'fitbit-oauth2' ); - // Callback service parsing the authorization token and asking for the access token. This - // endpoint is refered to in config.fitbit.authorization_uri.redirect_uri. See example - // config below. - // - app.get('/fitbit_auth_callback', function (req, res, next) { - var code = req.query.code; - fitbit.fetchToken( code, function(err, token) { - if (err) return next(err); + // In a browser, http://localhost:4000/fitbit to authorize a user for the first time. + // + app.get('/fitbit', function (req, res) { + res.redirect(fitbit.authorizeURL()); + }); - // persist the token - persist.write(tfile, token, function(err) { + // Callback service parsing the authorization token and asking for the access token. This + // endpoint is refered to in config.fitbit.authorization_uri.redirect_uri. See example + // config below. + // + app.get('/fitbit_auth_callback', function (req, res, next) { + var code = req.query.code; + fitbit.fetchToken( code, function(err, token) { if (err) return next(err); - res.redirect('/fb-profile'); - }); - }); - }); - // Call an API. fitbit.request() mimics nodejs request() library, automatically - // adding the required oauth2 headers. The callback is a bit different, called - // with ( err, body, token ). If token is non-null, this means a refresh has happened - // and you should persist the new token. - // - app.get( '/fb-profile', function(req, res, next) { - fitbit.request({ - uri: "https://api.fitbit.com/1/user/-/profile.json", - method: 'GET', - }, function(err, body, token) { - if (err) return next(err); - var profile = JSON.parse(body); - // if token is not null, a refesh has happened and we need to persist the new token - if (token) + // persist the token persist.write(tfile, token, function(err) { if (err) return next(err); - res.send('
    ' + JSON.stringify(profile, null, 2) + '
    '); + res.redirect('/fb-profile'); }); - else - res.send('
    ' + JSON.stringify(profile, null, 2) + '
    '); + }); + }); + + // Call an API. fitbit.request() mimics nodejs request() library, automatically + // adding the required oauth2 headers. The callback is a bit different, called + // with ( err, body, token ). If token is non-null, this means a refresh has happened + // and you should persist the new token. + // + app.get( '/fb-profile', function(req, res, next) { + fitbit.request({ + uri: "https://api.fitbit.com/1/user/-/profile.json", + method: 'GET', + }, function(err, body, token) { + if (err) return next(err); + var profile = JSON.parse(body); + // if token is not null, a refesh has happened and we need to persist the new token + if (token) + persist.write(tfile, token, function(err) { + if (err) return next(err); + res.send('
    ' + JSON.stringify(profile, null, 2) + '
    '); + }); + else + res.send('
    ' + JSON.stringify(profile, null, 2) + '
    '); + }); }); - }); + } // Only start up express and enable the fitbit service to start making API calls if the fitbit config is present in config.js. if (typeof config.fitbit != 'undefined') { diff --git a/main.js b/main.js index fc990baf0..c79e3e659 100644 --- a/main.js +++ b/main.js @@ -11,6 +11,9 @@ const BrowserWindow = electron.BrowserWindow const powerSaveBlocker = electron.powerSaveBlocker powerSaveBlocker.start('prevent-display-sleep') +// Launching the mirror in dev mode +const DevelopmentMode = process.argv[2] == "dev"; + // Load the smart mirror config var config; try{ @@ -59,7 +62,7 @@ function createWindow () { mainWindow.loadURL('file://' + __dirname + '/index.html') // Open the DevTools if run with "npm start dev" - if(process.argv[2] == "dev"){ + if(DevelopmentMode){ mainWindow.webContents.openDevTools(); } From 6385727093ea263ff7d8f8a096253aec468619c5 Mon Sep 17 00:00:00 2001 From: Kurt Du Bois Date: Sat, 23 Jul 2016 10:27:05 +0200 Subject: [PATCH 37/39] Fixed issue with an individual stock quote not rendering. (#357) --- js/controller.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/js/controller.js b/js/controller.js index 46f87be50..f2e1aa925 100644 --- a/js/controller.js +++ b/js/controller.js @@ -238,11 +238,17 @@ var getStock = function() { StockService.getStockQuotes().then(function(result) { - $scope.stock = result.query.results.quote; + var stock = []; + if (result.query.results.quote instanceof Array) { + stock = stock.concat(result.query.results.quote); + } else { + stock.push(result.query.results.quote); + } + $scope.stock = stock; }, function(error) { console.log(error); }); - } + } if (typeof config.stock !== 'undefined' && config.stock.names.length) { registerRefreshInterval(getStock, 30); From ffc54a75022885190d6b8d722f4187e929ab30fb Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Mon, 25 Jul 2016 21:37:20 -0700 Subject: [PATCH 38/39] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d77dfc3da..cac0865f1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "smart-mirror", - "version": "0.0.2", + "version": "0.0.3", "description": "The fairest of them all", "main": "main.js", "scripts": { From 18577f4856f9bf55ea158bb08d8444df85e0d963 Mon Sep 17 00:00:00 2001 From: Evan Cohen Date: Mon, 25 Jul 2016 21:39:47 -0700 Subject: [PATCH 39/39] Removing PulseAudio --- scripts/pi-install.sh | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/scripts/pi-install.sh b/scripts/pi-install.sh index 49ecd8b89..a9bd19f68 100755 --- a/scripts/pi-install.sh +++ b/scripts/pi-install.sh @@ -76,17 +76,8 @@ fi # display_rotate=1' /boot/config.txt # fi -# Sound configuration -printf "%s\n${blu}Would you like to install and auto-configure sound and audio capture dependencies (reccomended)?${end}\n" -read -r -p "If you have an existing sound setup you can skip this [y/N] " response -if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then - ## TODO: is pulseaudio-module-jack actually required? - printf "%s\n${blu}Installing audio dependencies${end}\n" - sudo apt-get install pulseaudio pulseaudio-module-zeroconf pulseaudio-module-jack -fi - # Install native dependencies -printf "%s\n${blu}Installing non-audio native dependencies${end}\n" +printf "%s\n${blu}Installing native dependencies${end}\n" sudo apt-get install curl wget git python-pyaudio python3-pyaudio sox unclutter # Check if we need to install or upgrade Node.js. @@ -187,4 +178,4 @@ cat << "EOF" EOF # ASCII art found on http://textart.io/ -exit 0 \ No newline at end of file +exit 0