Merge pull request #28 from MichMich/develop

sync changes
This commit is contained in:
sam detweiler
2019-11-19 17:15:00 -08:00
committed by GitHub
47 changed files with 4057 additions and 2095 deletions

View File

@@ -17,6 +17,7 @@
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2017,
"ecmaFeatures": {
"globalReturn": true
}

6
.gitignore vendored
View File

@@ -11,7 +11,9 @@ coverage
.grunt
.lock-wscript
build/Release
node_modules
/node_modules/**/*
fonts/node_modules/**/*
vendor/node_modules/**/*
jspm_modules
.npm
.node_repl_history
@@ -81,3 +83,5 @@ Temporary Items
*.orig
*.rej
*.bak
!/tests/node_modules/**/*

View File

@@ -1,3 +1,4 @@
dist: trusty
language: node_js
node_js:
- "8"

View File

@@ -3,21 +3,52 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
### Added
- new upgrade script to help users consume regular updates installers/upgrade-script.sh
- new script to help setup pm2, without install installers/fixuppm2.sh
### Updated
- updated raspberry.sh installer script to handle new platform issues, split node/npm, pm2, and screen saver changes
- improve handling for armv6l devices, where electron support has gone away, add optional serveronly config option
---
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror² core.
## [2.9.0] - Unreleased (Develop Branch)
## [2.10.0] - Unreleased (Develop Branch)
*This release is scheduled to be released on 2019-10-01.*
*This release is scheduled to be released on 2020-01-01.*
### Added
- Timestamps in log output
### Updated
### Fixed
- Fixed issue in weatherforecast module where predicted amount of rain was not using the decimal symbol specified in config.js.
## [2.9.0] - 2019-10-01
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md).
### Added
- Spanish translation for "PRECIP".
- Adding a Malay (Malaysian) translation for MagicMirror².
- Add test check URLs of vendors 200 and 404 HTTP CODE.
- Add tests for new weather module and helper to stub ajax requests.
### Updated
- Updatenotification module: Display update notification for a limited (configurable) time.
- Enabled e2e/vendor_spec.js tests.
- The css/custom.css will be rename after the next release. We've add into `run-start.sh` a instruction by GIT to ignore with `--skip-worktree` and `rm --cached`. [#1540](https://github.com/MichMich/MagicMirror/issues/1540)
- Disable sending of notification CLOCK_SECOND when displaySeconds is false.
### Fixed
- Updatenotification module: Properly handle race conditions, prevent crash.
- Send `NEWS_FEED` notification also for the first news messages which are shown.
- Fixed issue where weather module would not refresh data after a network or API outage. [#1722](https://github.com/MichMich/MagicMirror/issues/1722)
- Fixed weatherforecast module not displaying rain amount on fallback endpoint.
- Notifications CLOCK_SECOND & CLOCK_MINUTE being from startup instead of matched against the clock and avoid drifting.
## [2.8.0] - 2019-07-01

View File

@@ -1,7 +1,7 @@
The MIT License (MIT)
=====================
Copyright © 2016-2017 Michael Teeuw
Copyright © 2016-2019 Michael Teeuw
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation

View File

@@ -177,14 +177,19 @@ For more available modules, check out out the wiki page [MagicMirror² 3rd Party
If you want to update your MagicMirror² to the latest version, use your terminal to go to your Magic Mirror folder and type the following command:
```bash
git pull && npm install
```
bash -c "$(curl -sL https://raw.githubusercontent.com/MichMich/MagicMirror/master/installers/upgrade-script.sh)"
```
This will do a test run
If you changed nothing more than the config or the modules, this should work without any problems.
Type `git status` to see your changes, if there are any, you can reset them with `git reset --hard`. After that, git pull should be possible.
If the test update looks good then run this command
```
bash -c "$(curl -sL https://raw.githubusercontent.com/MichMich/MagicMirror/master/installers/upgrade-script.sh)" apply
```
If there are changes you have made, they will be listed, and u will have the opportunity to save your work
The script will also update the dependencies of any active modules
If there are update issues, please come to the forums for help
## Community
The community around the MagicMirror² is constantly growing. We even have a [forum](https://forum.magicmirror.builders) now where you can share your ideas, ask questions, help others and get inspired by other builders. We would love to see you there!

View File

@@ -24,6 +24,11 @@ var config = {
language: "en",
timeFormat: 24,
units: "metric",
// serverOnly: true/false/"local" ,
// local for armv6l processors, default
// starts serveronly and then starts chrome browser
// false, default for all NON-armv6l devices
// true, force serveronly mode, because you want to.. no UI on this device
modules: [
{

View File

@@ -1,14 +0,0 @@
/*****************************************************
* Magic Mirror *
* Custom CSS *
* *
* By Michael Teeuw http://michaelteeuw.nl *
* MIT Licensed. *
* *
* Add any custom CSS below. *
* Changes to this files will be ignored by GIT. *
*****************************************************/
body {
}

View File

@@ -0,0 +1,15 @@
const config = require('../config/config.js');const fs=require('fs');
for(let m of config.modules){
if(!(m.disabled || false)){
try {
let f=fs.statSync(m.module);
if(f.isDirectory()){
f1=fs.statSync(m.module+'/package.json');
if (f1.isFile()){
console.log(m.module);
}
}
}
catch (ex) {}
}
}

161
installers/fixuppm2.sh Executable file
View File

@@ -0,0 +1,161 @@
#!/bin/bash
# Define the tested version of Node.js.
NODE_TESTED="v5.1.0"
NPM_TESTED="V6.0.0"
USER=`whoami`
PM2_FILE=pm2_MagicMirror.json
mac=$(uname -s)
if [ $mac == 'Darwin' ]; then
cmd=greadlink
else
cmd=readlink
fi
if [ -d ~/MagicMirror ]; then
# put the log where the script is located
logdir=$(dirname $($cmd -f "$0"))
# if the script was execute from the web
if [[ $logdir != *"MagicMirror/installers"* ]]; then
# use the MagicMirror/installers folder
cd ~/MagicMirror/installers >/dev/null
logdir=$(pwd)
cd - >/dev/null
fi
logfile=$logdir/pm2_setup.log
date +"pm2 setup starting - %a %b %e %H:%M:%S %Z %Y" >>$logfile
node_installed=$(which node)
if [ "$node_installed." == "." ]; then
# node not installed
echo Installing node >>$logfile
if [ $mac == 'Darwin' ]; then
brew install node
else
NODE_STABLE_BRANCH="10.x"
curl -sL https://deb.nodesource.com/setup_$NODE_STABLE_BRANCH | sudo -E bash -
sudo apt-get install -y nodejs
fi
fi
node_version=$(node -v)
echo node version $node_version >>$logfile
npm_installed=$(which npm)
if [ "$npm_installed." == "." ]; then
# npm not installed
echo Installing npm >>$logfile
if [ $mac != 'Darwin' ]; then
sudo apt-get install -y npm
fi
fi
# get latest
echo force installing latest npm version via npm >>$logfile
#sudo npm i -g npm
npm_version=$(npm -v)
echo npm version $npm_version >>$logfile
# assume pm2 will be found on the path
pm2cmd=pm2
up=""
if [ $mac == 'Darwin' ]; then
up="--unsafe-perm"
launchctl=launchctl
launchctl_path=$(which $launchctl)
`export PATH=$PATH:${launchctl_path%/$launchctl}`
fi
# check to see if already installed
pm2_installed=$(which $pm2cmd)
if [ "$pm2_installed." != "." ]; then
# does it work?
echo pm2 installed >> $logfile
pm2_fails=$(pm2 list | grep -i -m 1 "App Name" | wc -l )
if [ $pm2_fails != 1 ]; then
# uninstall it
echo pm2 installed, but does not work, uninstalling >> $logfile
sudo npm uninstall $up -g pm2
# force reinstall
pm2_installed=
fi
fi
# in not installed
if [ "$pm2_installed." == "." ]; then
# install it.
echo pm2 not installed, installing >>$logfile
result=$(sudo npm install $up -g pm2)
# if this is a mac
if [ $mac == 'Darwin' ]; then
echo this is a mac, fixup for path >>$logfile
# get the location of pm2 install
# parse the npm install output to get the command
pm2cmd=`echo $result | awk -F - '{print $1}' | tr -d '[:space:]'`
c='/pm2'
# get the path only
echo ${pm2cmd%$c} >installers/pm2path
fi
fi
# remove MagicMirror if defined
$pm2cmd delete MagicMirror >/dev/null 2>&1
cd ~/MagicMirror
echo get the pm2 platform specific startup command >>$logfile
# get the platform specific pm2 startup command
v=$($pm2cmd startup | tail -n 1)
if [ $mac != 'Darwin' ]; then
# check to see if we can get the OS package name (Ubuntu)
if [ $(which lsb_release| wc -l) >0 ]; then
# fix command
# if ubuntu 18.04, pm2 startup gets something wrong
if [ $(lsb_release -r | grep -m1 18.04 | wc -l) > 0 ]; then
v=$(echo $v | sed 's/\/bin/\/bin:\/bin/')
fi
fi
fi
echo command = $v >>$logfile
# execute the command returned
$v 2>/dev/null >>$logfile
echo pm2 startup done >>$logfile
# if the user is no pi, we have to fixup the pm2 json file
echo configure the pm2 config file for MagicMirror >>$logfile
if [ "$USER" != "pi" ]; then
echo the user is not pi >>$logfile
# go to the installers folder`
cd installers
# edit the startup script for the right user
echo change mm.sh >>$logfile
if [ ! -e mm_temp.sh ]; then
echo save copy of mm.sh >> $logfile
cp mm.sh mm_temp.sh
fi
if [ $(grep pi mm_temp.sh | wc -l) -gt 0 ]; then
echo change hard coded pi username >> $logfile
sed 's/pi/'$USER'/g' mm_temp.sh >mm.sh
else
echo change relative home path to hard coded path >> $logfile
hf=$(echo $HOME |sed 's/\//\\\//g')
sed 's/\~/'$hf'/g' mm_temp.sh >mm.sh
fi
# edit the pms config file for the right user
echo change $PM2_FILE >>$logfile
sed 's/pi/'$USER'/g' $PM2_FILE > pm2_MagicMirror_new.json
# make sure to use the updated file
PM2_FILE=pm2_MagicMirror_new.json
# if this is a mac
if [ $mac == 'Darwin' ]; then
# copy the path file to the system paths list
sudo cp ./pm2path /etc/paths.d
# change the name of the home path for mac
sed 's/home/Users/g' $PM2_FILE > pm2_MagicMirror_new1.json
# make sure to use the updated file
PM2_FILE=pm2_MagicMirror_new1.json
fi
echo now using this config file $PM2_FILE >>$logfile
# go back one cd level
cd - >/dev/null
fi
echo start MagicMirror via pm2 now >>$logfile
# tell pm2 to start the app defined in the config file
$pm2cmd start $HOME/MagicMirror/installers/$PM2_FILE
# tell pm2 to save that configuration, for start at boot
echo save MagicMirror pm2 config now >>$logfile
$pm2cmd save
date +"pm2 setup completed - %a %b %e %H:%M:%S %Z %Y" >>$logfile
else
echo It appears MagicMirror has not been installed on this system
echo please run the installer, "raspberry.sh" first
fi

382
installers/raspberry.sh Normal file → Executable file
View File

@@ -1,5 +1,4 @@
#!/bin/bash
# This is an installer script for MagicMirror2. It works well enough
# that it can detect if you have Node installed, run a binary script
# and then download and run MagicMirror2.
@@ -18,117 +17,169 @@ echo ' \$$$$$$ |'
echo ' \______/'
echo -e "\e[0m"
doInstall=1
true=1
false=0
# Define the tested version of Node.js.
NODE_TESTED="v5.1.0"
NPM_TESTED="V6.0.0"
USER=`whoami`
PM2_FILE=~/MagicMirror/installers/pm2_MagicMirror.json
PM2_FILE=pm2_MagicMirror.json
force_arch=
pm2setup=$false
trim() {
local var="$*"
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
echo -n "$var"
}
mac=$(uname -s)
if [ $mac == 'Darwin' ]; then
echo this is a mac | tee -a $logfile
cmd=greadlink
else
cmd=readlink
fi
# put the log where the script is located
logdir=$(dirname $($cmd -f "$0"))
# if the script was execute from the web
if [[ $logdir != *"MagicMirror/installers"* ]]; then
# use the MagicMirror/installers folder, if setup
if [ -d MagicMirror ]; then
cd ~/MagicMirror/installers >/dev/null
logdir=$(pwd)
cd - >/dev/null
else
# use the users home folder if initial install
logdir=$HOME
fi
fi
logfile=$logdir/install.log
echo install log being saved to $logfile
# Determine which Pi is running.
date +"install starting - %a %b %e %H:%M:%S %Z %Y" >>$logfile
ARM=$(uname -m)
echo installing on $ARM processor system >>$logfile
# Check the Raspberry Pi version.
if [ "$ARM" != "armv7l" ]; then
read -p "this appears not to be a Raspberry Pi 2 or 3, do you want to continue installtion (y/N)?" choice
read -p "this appears not to be a Raspberry Pi 2 or 3, do you want to continue installation (y/N)?" choice
if [[ $choice =~ ^[Nn]$ ]]; then
echo user stopped install on $ARM hardware >>$logfile
echo -e "\e[91mSorry, your Raspberry Pi is not supported."
echo -e "\e[91mPlease run MagicMirror on a Raspberry Pi 2 or 3."
echo -e "\e[91mIf this is a Pi Zero, you are in the same boat as the original Raspberry Pi. You must run in server only mode."
exit;
fi
#if [ "$ARM" == "armv6l" ]; then
# echo forcing armv71 architecture for pi 0 >>$logfile
# force_arch=-'--arch=armv7l'
#fi
fi
# Define helper methods.
function command_exists () { type "$1" &> /dev/null ;}
function verlte() { [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ];}
function verlt() { [ "$1" = "$2" ] && return 1 || verlte $1 $2 ;}
# Update before first apt-get
echo -e "\e[96mUpdating packages ...\e[90m"
sudo apt-get update || echo -e "\e[91mUpdate failed, carrying on installation ...\e[90m"
if [ $mac != 'Darwin' ]; then
echo -e "\e[96mUpdating packages ...\e[90m" | tee -a $logfile
sudo apt-get update || echo -e "\e[91mUpdate failed, carrying on installation ...\e[90m" | tee -a $logfile
fi
if [ $mac != 'Darwin' ]; then
# Installing helper tools
echo -e "\e[96mInstalling helper tools ...\e[90m"
echo -e "\e[96mInstalling helper tools ...\e[90m" | tee -a $logfile
sudo apt-get --assume-yes install curl wget git build-essential unzip || exit
fi
# Check if we need to install or upgrade Node.js.
echo -e "\e[96mCheck current Node installation ...\e[0m"
echo -e "\e[96mCheck current Node installation ...\e[0m" | tee -a $logfile
NODE_INSTALL=false
if command_exists node; then
echo -e "\e[0mNode currently installed. Checking version number.";
echo -e "\e[0mNode currently installed. Checking version number." | tee -a $logfile
NODE_CURRENT=$(node -v)
echo -e "\e[0mMinimum Node version: \e[1m$NODE_TESTED\e[0m"
echo -e "\e[0mInstalled Node version: \e[1m$NODE_CURRENT\e[0m"
echo -e "\e[0mMinimum Node version: \e[1m$NODE_TESTED\e[0m" | tee -a $logfile
echo -e "\e[0mInstalled Node version: \e[1m$NODE_CURRENT\e[0m" | tee -a $logfile
if verlte $NODE_CURRENT $NODE_TESTED; then
echo -e "\e[96mNode should be upgraded.\e[0m"
echo -e "\e[96mNode should be upgraded.\e[0m" | tee -a $logfile
NODE_INSTALL=true
# Check if a node process is currenlty running.
# If so abort installation.
if pgrep "node" > /dev/null; then
echo -e "\e[91mA Node process is currently running. Can't upgrade."
echo "Please quit all Node processes and restart the installer."
echo -e "\e[91mA Node process is currently running. Can't upgrade." | tee -a $logfile
echo "Please quit all Node processes and restart the installer." | tee -a $logfile
exit;
fi
else
echo -e "\e[92mNo Node.js upgrade necessary.\e[0m"
echo -e "\e[92mNo Node.js upgrade necessary.\e[0m" | tee -a $logfile
fi
else
echo -e "\e[93mNode.js is not installed.\e[0m";
echo -e "\e[93mNode.js is not installed.\e[0m" | tee -a $logfile
NODE_INSTALL=true
fi
# Install or upgrade node if necessary.
if $NODE_INSTALL; then
echo -e "\e[96mInstalling Node.js ...\e[90m"
echo -e "\e[96mInstalling Node.js ...\e[90m" | tee -a $logfile
# Fetch the latest version of Node.js from the selected branch
# The NODE_STABLE_BRANCH variable will need to be manually adjusted when a new branch is released. (e.g. 7.x)
# Only tested (stable) versions are recommended as newer versions could break MagicMirror.
if [ $mac == 'Darwin' ]; then
brew install node
else
NODE_STABLE_BRANCH="10.x"
curl -sL https://deb.nodesource.com/setup_$NODE_STABLE_BRANCH | sudo -E bash -
sudo apt-get install -y nodejs
echo -e "\e[92mNode.js installation Done!\e[0m"
fi
echo -e "\e[92mNode.js installation Done! version=$(node -v)\e[0m" | tee -a $logfile
fi
# Check if we need to install or upgrade npm.
echo -e "\e[96mCheck current NPM installation ...\e[0m"
echo -e "\e[96mCheck current NPM installation ...\e[0m" | tee -a $logfile
NPM_INSTALL=false
if command_exists npm; then
echo -e "\e[0mNPM currently installed. Checking version number.";
echo -e "\e[0mNPM currently installed. Checking version number." | tee -a $logfile
NPM_CURRENT='V'$(npm -v)
echo -e "\e[0mMinimum npm version: \e[1m$NPM_TESTED\e[0m"
echo -e "\e[0mInstalled npm version: \e[1m$NPM_CURRENT\e[0m"
echo -e "\e[0mMinimum npm version: \e[1m$NPM_TESTED\e[0m" | tee -a $logfile
echo -e "\e[0mInstalled npm version: \e[1m$NPM_CURRENT\e[0m" | tee -a $logfile
if verlte $NPM_CURRENT $NPM_TESTED; then
echo -e "\e[96mnpm should be upgraded.\e[0m"
echo -e "\e[96mnpm should be upgraded.\e[0m" | tee -a $logfile
NPM_INSTALL=true
# Check if a node process is currently running.
# If so abort installation.
if pgrep "npm" > /dev/null; then
echo -e "\e[91mA npm process is currently running. Can't upgrade."
echo "Please quit all npm processes and restart the installer."
echo -e "\e[91mA npm process is currently running. Can't upgrade." | tee -a $logfile
echo "Please quit all npm processes and restart the installer." | tee -a $logfile
exit;
fi
else
echo -e "\e[92mNo npm upgrade necessary.\e[0m"
echo -e "\e[92mNo npm upgrade necessary.\e[0m" | tee -a $logfile
fi
else
echo -e "\e[93mnpm is not installed.\e[0m";
echo -e "\e[93mnpm is not installed.\e[0m" | tee -a $logfile
NPM_INSTALL=true
fi
# Install or upgrade node if necessary.
if $NPM_INSTALL; then
echo -e "\e[96mInstalling npm ...\e[90m"
echo -e "\e[96mInstalling npm ...\e[90m" | tee -a $logfile
# Fetch the latest version of npm from the selected branch
# The NODE_STABLE_BRANCH variable will need to be manually adjusted when a new branch is released. (e.g. 7.x)
@@ -137,108 +188,299 @@ if $NPM_INSTALL; then
#NODE_STABLE_BRANCH="9.x"
#curl -sL https://deb.nodesource.com/setup_$NODE_STABLE_BRANCH | sudo -E bash -
#
# if this is a mac, npm was installed with node
if [ $mac != 'Darwin' ]; then
sudo apt-get install -y npm
echo -e "\e[92mnpm installation Done!\e[0m"
fi
# update to the latest.
echo upgrading npm to latest >> $logfile
sudo npm i -g npm
echo -e "\e[92mnpm installation Done! version=V$(npm -v)\e[0m" | tee -a $logfile
fi
# Install MagicMirror
cd ~
if [ $doInstall == 1 ]; then
if [ -d "$HOME/MagicMirror" ] ; then
echo -e "\e[93mIt seems like MagicMirror is already installed."
echo -e "To prevent overwriting, the installer will be aborted."
echo -e "Please rename the \e[1m~/MagicMirror\e[0m\e[93m folder and try again.\e[0m"
echo -e "\e[93mIt seems like MagicMirror is already installed." | tee -a $logfile
echo -e "To prevent overwriting, the installer will be aborted." | tee -a $logfile
echo -e "Please rename the \e[1m~/MagicMirror\e[0m\e[93m folder and try again.\e[0m" | tee -a $logfile
echo ""
echo -e "If you want to upgrade your installation run \e[1m\e[97mgit pull\e[0m from the ~/MagicMirror directory."
echo -e "If you want to upgrade your installation run \e[1m\e[97mgit pull\e[0m from the ~/MagicMirror directory." | tee -a $logfile
echo ""
exit;
fi
echo -e "\e[96mCloning MagicMirror ...\e[90m"
echo -e "\e[96mCloning MagicMirror ...\e[90m" | tee -a $logfile
if git clone --depth=1 https://github.com/MichMich/MagicMirror.git; then
echo -e "\e[92mCloning MagicMirror Done!\e[0m"
echo -e "\e[92mCloning MagicMirror Done!\e[0m" | tee -a $logfile
else
echo -e "\e[91mUnable to clone MagicMirror."
echo -e "\e[91mUnable to clone MagicMirror." | tee -a $logfile
exit;
fi
cd ~/MagicMirror || exit
echo -e "\e[96mInstalling dependencies ...\e[90m"
if npm install; then
echo -e "\e[92mDependencies installation Done!\e[0m"
echo -e "\e[96mInstalling dependencies ...\e[90m" | tee -a $logfile
if npm install $force_arch; then
echo -e "\e[92mDependencies installation Done!\e[0m" | tee -a $logfile
else
echo -e "\e[91mUnable to install dependencies!"
echo -e "\e[91mUnable to install dependencies!" | tee -a $logfile
exit;
fi
# Use sample config for start MagicMirror
echo setting up initial config.js | tee -a $logfile
cp config/config.js.sample config/config.js
fi
# Check if plymouth is installed (default with PIXEL desktop environment), then install custom splashscreen.
echo -e "\e[96mCheck plymouth installation ...\e[0m"
echo -e "\e[96mCheck plymouth installation ...\e[0m" | tee -a $logfile
if command_exists plymouth; then
THEME_DIR="/usr/share/plymouth/themes"
echo -e "\e[90mSplashscreen: Checking themes directory.\e[0m"
echo -e "\e[90mSplashscreen: Checking themes directory.\e[0m" | tee -a $logfile
if [ -d $THEME_DIR ]; then
echo -e "\e[90mSplashscreen: Create theme directory if not exists.\e[0m"
echo -e "\e[90mSplashscreen: Create theme directory if not exists.\e[0m" | tee -a $logfile
if [ ! -d $THEME_DIR/MagicMirror ]; then
sudo mkdir $THEME_DIR/MagicMirror
fi
if sudo cp ~/MagicMirror/splashscreen/splash.png $THEME_DIR/MagicMirror/splash.png && sudo cp ~/MagicMirror/splashscreen/MagicMirror.plymouth $THEME_DIR/MagicMirror/MagicMirror.plymouth && sudo cp ~/MagicMirror/splashscreen/MagicMirror.script $THEME_DIR/MagicMirror/MagicMirror.script; then
echo -e "\e[90mSplashscreen: Theme copied successfully.\e[0m"
echo -e "\e[90mSplashscreen: Theme copied successfully.\e[0m" | tee -a $logfile
if sudo plymouth-set-default-theme -R MagicMirror; then
echo -e "\e[92mSplashscreen: Changed theme to MagicMirror successfully.\e[0m"
echo -e "\e[92mSplashscreen: Changed theme to MagicMirror successfully.\e[0m" | tee -a $logfile
else
echo -e "\e[91mSplashscreen: Couldn't change theme to MagicMirror!\e[0m"
echo -e "\e[91mSplashscreen: Couldn't change theme to MagicMirror!\e[0m" | tee -a $logfile
fi
else
echo -e "\e[91mSplashscreen: Copying theme failed!\e[0m"
echo -e "\e[91mSplashscreen: Copying theme failed!\e[0m" | tee -a $logfile
fi
else
echo -e "\e[91mSplashscreen: Themes folder doesn't exist!\e[0m"
echo -e "\e[91mSplashscreen: Themes folder doesn't exist!\e[0m" | tee -a $logfile
fi
else
echo -e "\e[93mplymouth is not installed.\e[0m";
echo -e "\e[93mplymouth is not installed.\e[0m" | tee -a $logfile
fi
# Use pm2 control like a service MagicMirror
read -p "Do you want use pm2 for auto starting of your MagicMirror (y/N)?" choice
if [[ $choice =~ ^[Yy]$ ]]; then
#
# check if this is a mac
#
mac=$(uname -s)
echo install and setup pm2 | tee -a $logfile
# assume pm2 will be found on the path
pm2cmd=pm2
# check to see if already installed
pm2_installed=$(which $pm2cmd)
up=""
if [ $mac == 'Darwin' ]; then
up="--unsafe-perm"
launchctl=launchctl
launchctl_path=$(which $launchctl)
`export PATH=$PATH:${launchctl_path%/$launchctl}`
fi
sudo npm install $up -g pm2
if [[ "$(ps --no-headers -o comm 1)" =~ systemd ]]; then #Checking for systemd
pm2 startup systemd -u $USER --hp /home/$USER
# check to see if already installed
pm2_installed=$(which $pm2cmd)
if [ "$pm2_installed." != "." ]; then
# does it work?
pm2_fails=$(pm2 list | grep -i -m 1 "App Name" | wc -l )
if [ $pm2_fails != 1 ]; then
# uninstall it
echo pm2 installed, but does not work, uninstalling >> $logfile
sudo npm uninstall $up -g pm2 >> $logfile
# force reinstall
pm2_installed=
fi
fi
# if not installed
if [ "$pm2_installed." == "." ]; then
# install it.
echo pm2 not installed, installing >>$logfile
result=$(sudo npm install $up -g pm2)
echo pm2 install result $result >>$logfile
# if this is a mac
if [ $mac == 'Darwin' ]; then
echo this is a mac, fixup for path >>$logfile
# get the location of pm2 install
# parse the npm install output to get the command
pm2cmd=`echo $result | awk -F - '{print $1}' | tr -d '[:space:]'`
c='/pm2'
# get the path only
echo ${pm2cmd%$c} >installers/pm2path
fi
fi
echo get the pm2 platform specific startup command >>$logfile
# get the platform specific pm2 startup command
v=$($pm2cmd startup | tail -n 1)
if [ $mac != 'Darwin' ]; then
# check to see if we can get the OS package name (Ubuntu)
if [ $(which lsb_release| wc -l) >0 ]; then
# fix command
# if ubuntu 18.04, pm2 startup gets something wrong
if [ $(lsb_release -r | grep -m1 18.04 | wc -l) > 0 ]; then
v=$(echo $v | sed 's/\/bin/\/bin:\/bin/')
fi
fi
fi
echo startup command = $v >>$logfile
# execute the command returned
$v 2>&1 >>$logfile
echo pm2 startup command done >>$logfile
# if the user is no pi, we have to fixup the pm2 json file
echo configure the pm2 config file for MagicMirror >>$logfile
if [ "$USER" != "pi" ]; then
echo the user is not pi >>$logfile
# go to the installers folder`
cd installers
# edit the startup script for the right user
echo change mm.sh >>$logfile
if [ ! -e mm_temp.sh ]; then
echo save copy of mm.sh >> $logfile
cp mm.sh mm_temp.sh
fi
if [ $(grep pi mm_temp.sh | wc -l) -gt 0 ]; then
echo change hard coded pi username >> $logfile
sed 's/pi/'$USER'/g' mm_temp.sh >mm.sh
else
sudo su -c "env PATH=$PATH:/usr/bin pm2 startup linux -u $USER --hp /home/$USER"
echo change relative home path to hard coded path >> $logfile
hf=$(echo $HOME |sed 's/\//\\\//g')
sed 's/\~/'$hf'/g' mm_temp.sh >mm.sh
fi
if [ "USER" != "pi" ]; then
sed 's/pi/'$USER'/g' mm.sh >mm.sh
sed 's/pi/'$USER'/g' $PM2_FILE > ~/MagicMirror/installers/pm2_MagicMirror_new.json
PM2_FILE=~/MagicMirror/installers/pm2_MagicMirror_new.json
# edit the pms config file for the right user
echo change $PM2_FILE >>$logfile
sed 's/pi/'$USER'/g' $PM2_FILE > pm2_MagicMirror_new.json
# make sure to use the updated file
PM2_FILE=pm2_MagicMirror_new.json
# if this is a mac
if [ $mac == 'Darwin' ]; then
# copy the path file to the system paths list
sudo cp ./pm2path /etc/paths.d
# change the name of the home path for mac
sed 's/home/Users/g' $PM2_FILE > pm2_MagicMirror_new1.json
# make sure to use the updated file
PM2_FILE=pm2_MagicMirror_new1.json
fi
pm2 start $PM2_FILE
pm2 save
echo now using this config file $PM2_FILE >>$logfile
# go back one cd level
cd - >/dev/null
fi
echo start MagicMirror via pm2 now >>$logfile
# tell pm2 to start the app defined in the config file
$pm2cmd start $HOME/MagicMirror/installers/$PM2_FILE
# tell pm2 to save that configuration, for start at boot
echo save MagicMirror pm2 config now >>$logfile
$pm2cmd save
pm2setup=$true
fi
# Disable Screensaver
if [ -d "/etc/xdg/lxsession" ]; then
choice=n
read -p "Do you want to disable the screen saver? (y/N)?" choice
if [[ $choice =~ ^[Yy]$ ]]; then
# if this is a mac
if [ $mac == 'Darwin' ]; then
# get the current setting
setting=$(defaults -currentHost read com.apple.screensaver idleTime)
# if its on
if [ $setting != 0 ] ; then
# turn it off
echo disable screensaver via mac profile >> $logfile
defaults -currentHost write com.apple.screensaver idleTime 0
else
echo mac profile screen saver already disabled >> $logfile
fi
else
# find out if some screen saver running
# get just the running processes and args
# just want the program name (1st token)
# find the 1st with 'saver' in it (should only be one)
# parse with path char, get the last field ( the actual pgm name)
screen_saver_running=$(ps -A -o args | awk '{print $1}' | grep -m1 [s]aver | awk -F\/ '{print $NF}');
# if we found something
if [ "$screen_saver_running." != "." ]; then
# some screensaver running
case "$screen_saver_running" in
mate-screensaver) echo 'mate screen saver' >>$logfile
#killall mate-screensaver >/dev/null 2>&1
#$ms -d >/dev/null 2>&1
gsettings set org.mate.screensaver lock-enabled false 2>/dev/null
gsettings set org.mate.screensaver idle-activation-enabled false 2>/dev/null
gsettings set org.mate.screensaver lock_delay 0 2>/dev/null
echo " $screen_saver_running disabled" >> $logfile
DISPLAY=:0 mate-screensaver >/dev/null 2>&1 &
;;
gnome-screensaver) echo 'gnome screen saver' >>$logfile
gnome_screensaver-command -d >/dev/null 2>&1
echo " $screen_saver_running disabled" >> $logfile
;;
xscreensaver) echo 'xscreensaver running' | tee -a $logfile
if [ $(grep -m1 'mode:' ~/.xscreensaver | awk '{print $2}') != 'off' ]; then
sed -i 's/$xsetting/mode: off/' ~/.xscreensaver
echo " xscreensaver set to off" >> $logfile
else
echo " xscreensaver already disabled" >> $logfile
fi
;;
gsd-screensaver | gsd-screensaver-proxy)
setting=$(gsettings get org.gnome.desktop.screensaver lock-enabled)
setting1=$(gsettings get org.gnome.desktop.session idle-delay)
if [ "$setting $setting1" != 'false uint32 0' ]; then
echo disable screensaver via gsettings was $setting and $setting1>> $logfile
gsettings set org.gnome.desktop.screensaver lock-enabled false
gsettings set org.gnome.desktop.screensaver idle-activation-enabled false
gsettings set org.gnome.desktop.session idle-delay 0
else
echo gsettings screen saver already disabled >> $logfile
fi
;;
*) echo "some other screensaver $screen_saver_running" found | tee -a $logfile
echo "please configure it manually" | tee -a $logfile
;;
esac
elif [ -d "/etc/xdg/lxsession" ]; then
currently_set=$(grep -m1 '\-dpms' /etc/xdg/lxsession/LXDE-pi/autostart)
if [ "$currently_set." == "." ]; then
echo disable screensaver via lxsession >> $logfile
# turn it off for the future
sudo su -c "echo -e '@xset s noblank\n@xset s off\n@xset -dpms' >> /etc/xdg/lxsession/LXDE-pi/autostart"
# turn it off now
export DISPLAY=:0; xset s noblank;xset s off;xset -dpms
else
echo lxsession screen saver already disabled >> $logfile
fi
elif [ $(which gsettings | wc -l) == 1 ]; then
setting=$(gsettings get org.gnome.desktop.screensaver lock-enabled)
setting1=$(gsettings get org.gnome.desktop.session idle-delay)
if [ "$setting $setting1" != 'false uint32 0' ]; then
echo disable screensaver via gsettings was $setting and $setting1>> $logfile
gsettings set org.gnome.desktop.screensaver lock-enabled false
gsettings set org.gnome.desktop.screensaver idle-activation-enabled false
gsettings set org.gnome.desktop.session idle-delay 0
else
echo gsettings screen saver already disabled >> $logfile
fi
elif [ -e "/etc/lightdm/lightdm.conf" ]; then
# if screen saver NOT already disabled?
if [ $(grep 'xserver-command=X -s 0 -dpms' /etc/lightdm/lightdm.conf | wc -l) == 0 ]; then
echo install screensaver via lightdm.conf >> $logfile
sudo sed -i '/^\[Seat:\*\]/a xserver-command=X -s 0 -dpms' /etc/lightdm/lightdm.conf
else
echo screensaver via lightdm already disabled >> $logfile
fi
else
echo " "
echo -e "unable to disable screen saver, /etc/xdg/lxsession does not exist"
echo -e "unable to disable screen saver, /etc/xdg/lxsession does not exist" | tee -a $logfile
fi
fi
fi
echo " "
if [ $pm2setup -eq $true ]; then
rmessage="pm2 start MagicMirror"
else
rmessage="DISPLAY=:0 npm start"
fi
echo -e "\e[92mWe're ready! Run \e[1m\e[97m$rmessage\e[0m\e[92m from the ~/MagicMirror directory to start your MagicMirror.\e[0m" | tee -a $logfile
echo " "
echo -e "\e[92mWe're ready! Run \e[1m\e[97mDISPLAY=:0 npm start\e[0m\e[92m from the ~/MagicMirror directory to start your MagicMirror.\e[0m"
echo " "
echo " "
date +"install completed - %a %b %e %H:%M:%S %Z %Y" >>$logfile

357
installers/upgrade-script.sh Executable file
View File

@@ -0,0 +1,357 @@
#!/bin/bash
# only DO npm installs when flag is set to 1
# test when set to 0
true=1
false=0
doinstalls=$false
force=$false
justActive=$true
test_run=$true
stashed=$false
keyFile=package.json
forced_arch=
git_active_lock='./.git/index.lock'
lf=$'\n'
git_user_name=
git_user_email=
trim() {
local var="$*"
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
echo -n "$var"
}
# is this a mac
mac=$(uname -s)
# get the processor architecture
arch=$(uname -m)
if [ $mac == 'Darwin' ]; then
cmd=greadlink
else
cmd=readlink
fi
if [ -d ~/MagicMirror ]; then
# put the log where the script is located
logdir=$(dirname $($cmd -f "$0"))
# if the script was execute from the web
if [[ $logdir != *"MagicMirror/installers"* ]]; then
# use the MagicMirror/installers folder
cd ~/MagicMirror/installers >/dev/null
logdir=$(pwd)
cd - >/dev/null
fi
logfile=$logdir/upgrade.log
echo >>$logfile
date +"Upgrade started - %a %b %e %H:%M:%S %Z %Y" >>$logfile
# because of how its executed from the web, p0 gets overlayed with parm
# check to see if a parm was passed .. easy apply without editing
p0=$0
# if not 'bash', and some parm specified
if [ $0 != 'bash' -a "$1." != "." ]; then
# then executed locally
# get the parm
p0=$1
fi
# lowercase it.. watch out, mac stuff doesn't work with tr, etc
p0=$(echo $p0 | cut -c 1-5 | awk '{print tolower($0)}' )
if [ $p0 == 'apply' ]; then
echo user requested to apply changes >>$logfile
doinstalls=$true
test_run=$false
elif [ $p0 == 'force' ]; then
echo user requested to force apply changes >>$logfile
doinstalls=$true
force=$true
test_run=$false
fi
if [ $test_run == $true ]; then
echo doing test run = true | tee -a $logfile
else
echo doing test run = false | tee -a $logfile
fi
# if we want just the modules listed in config.js now
if [ $justActive == $true ]; then
if [ ! -f ~/MagicMirror/installers/dumpactivemodules.js ]; then
echo downloading dumpactivemodules script >> $logfile
curl -sL https://raw.githubusercontent.com/MichMich/MagicMirror/develop/installers/dumpactivemodules.js > ~/MagicMirror/installers/dumpactivemodules.js
fi
fi
echo update log will be in $logfile
# used for parsing the array of module names
SAVEIFS=$IFS # Save current IFS
IFS=$'\n'
echo | tee -a $logfile
# if the git lock file exists and git is not running
if [ -f git_active_lock ]; then
# check to see if git is actually running
git_running=`ps -ef | grep git | grep -v color | grep -v 'grep git' | wc -l`
# if not running
if [ git_running == $false ]; then
# clean up the dangling lock file
echo erasing abandonded git lock file >> $logfile
rm git_active_lock >/dev/null 2>&1
else
# git IS running, we can't proceed
echo it appears another instance of git is running | tee -a $logfile
# if this is an actual run
if [ $doinstalls == $true ]; then
# force it back to test run
doinstalls = $false
test_run=$true
echo forcing test run mode | tee -a $logfile
echo please resolve git running already and start the update again | tee -a $logfile
fi
fi
fi
# change to MagicMirror folder
cd ~/MagicMirror
# save custom.css
cd css
echo "saving custom.css" | tee -a $logfile
cp -p custom.css save_custom.css
cd - >/dev/null
save_alias=$(alias git 2>/dev/null)
lang=$(locale | grep LANGUAGE | awk -F= '{print $2}')
# make sure git respones are in english, so code works
if [ "$lang." != "en_US.UTF-8." ]; then
echo not english or locale not set, set git alias >>$logfile
if [ "$LC_ALL." == "." ]; then
alias git='LANGUAGE=en_US.UTF-8 git' >>$logfile
else
alias git='LC_ALL=en_US.UTF-8 git' >>$logfile
fi
#alias >>$logfile
fi
# get the git remote name
remote=$(git remote 2>/dev/null | awk '{print $1}')
# if remote name set
if [ "$remote." != "." ]; then
echo remote name = $remote >>$logfile
# get the local and remote package.json versions
local_version=$(grep -m1 version package.json | awk -F\" '{print $4}')
remote_version=$(curl -s https://raw.githubusercontent.com/MichMich/MagicMirror/master/package.json | grep -m1 version | awk -F\" '{print $4}')
# only change if they are different
if [ "$local_version." != "$remote_version." -o $force == $true -o $test_run == $true ]; then
echo upgrading from version $local_version to $remote_version | tee -a $logfile
# get the latest upgrade
echo fetching latest revisions | tee -a $logfile
if git fetch $remote; then
# need to get the current branch
current_branch=$(git branch | grep "*" | awk '{print $2}')
echo current branch = $current_branch >>$logfile
$(git status 2>&1)>>$logfile
# get the names of the files that are different locally
diffs=$(git status 2>&1 | grep modified | awk -F: '{print $2}')
# split names into an array
diffs=($diffs) # split to array $diffs
# if there are different files (array size greater than zero)
if [ ${#diffs[@]} -gt 0 ]; then
package_lock=0
echo there are "${#diffs[@]}" local files that are different than the master repo | tee -a $logfile
echo | tee -a $logfile
for file in "${diffs[@]}"
do
echo "$file" | tee -a $logfile
if [ $(echo $file | grep '\-lock.json$' | wc -l) -eq 1 ]; then
package_lock=$true
fi
done
echo | tee -a $logfile
if [ $package_lock -eq 1 ]; then
echo "any *-lock.json files do not need to be saved"
fi
read -p "do you want to save these files for later (Y/n)?" choice
echo save/restore files selection = $choice >> $logfile
if [[ $choice =~ ^[Yy]$ ]]; then
git_user=$(git config --global --get user.email)
if [ "git_user." == "." ]; then
git_user_name="-c user.name=upgrade_script"
git_user_email="-c user.email=script@upgrade.com"
fi
git git_user_name git_user_email stash >>$logfile
stashed=$true
else
for file in "${diffs[@]}"
do
f="$(trim "$file")"
echo restoring $f from repo >> $logfile
if [ $test_run == $false ]; then
git checkout HEAD -- $f | tee -a $logfile
else
echo skipping restore for $f, doing test run | tee -a $logfile
fi
done
fi
else
echo no files different from github version >> $logfile
fi
# lets test merge, in memory, no changes to working directory or local repo
test_merge_output=$(git merge-tree `git merge-base $current_branch HEAD` HEAD $current_branch | grep "^<<<<<<<\|changed in both")
echo "test merge result rc='$test_merge_output' , if empty, no conflicts" >> $logfile
# if there were no conflicts reported
if [ "$test_merge_output." == "." ]; then
if [ $test_run == $false ]; then
# go ahead and merge now
echo "executing merge, apply specified" >> $logfile
# get the text output of merge
merge_output=$(git merge $remote/$current_branch 2>&1)
# and its return code
merge_result=$?
# make any long line readable
merge_output=$(echo $merge_output | tr '|' '\n'| sed "s/create/\\${lf}create/g" | sed "s/mode\ change/\\${lf}mode\ change/g")
echo -e "merge result rc= $merge_result\n $merge_output">> $logfile
else
echo "skipping merge, only test run" >> $logfile
merge_output=''
merge_result=0
fi
# if no merge errors
if [ $merge_result == 0 ]; then
# some updates applied
if [ "$merge_output." != 'Already up to date.' -o $test_run == $true ]; then
# update any dependencies for base
if [ $doinstalls == $true ]; then
# if this is a pi zero
echo processor architecture is $arch >> $logfile
#if [ "$arch" == "armv6l" ]; then
# # force to look like pi 2
# echo forcing architecture armv7l >>$logfile
# forced_arch='--arch=armv7l'
#fi
echo "updating MagicMirror runtime, please wait" | tee -a $logfile
npm install $forced_arch 2>&1 | tee -a $logfile
done_update=`date +"completed - %a %b %e %H:%M:%S %Z %Y"`
echo npm install $done_update on base >> $ logfile
fi
# process updates for modules after base changed
cd modules
if [ $justActive == $true ]; then
# get the list of ACTIVE modules with package.json files
mtype=active
modules=$(node ../installers/dumpactivemodules.js)
else
# get the list of INSTALLED modules with package.json files
mtype=installed
modules=$(find -maxdepth 2 -name 'package.json' -printf "%h\n" | cut -d'/' -f2 )
fi
modules=($modules) # split to array $modules
# if the array has entries in it
if [ ${#modules[@]} -gt 0 ]; then
echo >> $logfile
echo "processing dependency changes for $mtype modules with package.json files" | tee -a $logfile
echo
for module in "${modules[@]}"
do
echo "processing for module" $module please wait | tee -a $logfile
echo '----------------------------------' | tee -a $logfile
# change to that directory
cd $module
# process its dependencies
if [ $doinstalls == $true ]; then
npm install $forced_arch 2>&1| tee -a $logfile
else
echo skipped processing for $module, doing test run | tee -a $logfile
fi
# return to modules folder
cd .. >/dev/null
echo "processing complete for module" $module | tee -a $logfile
echo
done
else
echo "no modules found needing npm refresh" | tee -a $logfile
fi
# return to Magic Mirror folder
cd .. >/dev/null
else
echo "no changes detected for modules, skipping " | tee -a $logfile
fi
else
echo there were merge errors | tee -a $logfile
echo $merge_output | tee -a %logfile
echo you should examine and resolve them | tee -a $logfile
echo using the command git log --oneline --decorate | tee -a $logfile
git log --oneline --decorate | tee -a $logfile
fi
else
echo "there are merge conflicts to be resolved, no changes have been applied" | tee -a $logfile
echo $test_merge_output | tee -a $logfile
fi
else
echo "MagicMirror git fetch failed" | tee -a $logfile
fi
else
echo "local version $local_version already same as master $remote_version" | tee -a $logfile
fi
else
echo "Unable to determine upstream git repository" | tee -a $logfile
fi
# should be in MagicMirror base
cd css
# restore custom.css
echo "restoring custom.css" | tee -a $logfile
cp -p save_custom.css custom.css
rm save_custom.css
cd - >/dev/null
if [ "$lang." != "en_US.UTF-8." ]; then
if [ "$save_alias." != "." ]; then
echo restoring git alias >>$logfile
$save_alias >/dev/null
else
echo removing git alias >>$logfile
unalias git >/dev/null
fi
fi
IFS=$SAVEIFS # Restore IFS
if [ $stashed == $true ]; then
if [ $test_run == $true ]; then
echo test run, restoring files stashed | tee -a $logfile
git git_user_name git_user_email stash pop >> $logfile
else
echo we stashed a set of files that appear changed from the latest repo versions. you should review them | tee -a $logfile
git stash show --name-only > installers/stashed_files
echo see installers/stashed_files for the list
echo
echo you can use git checkout "stash@{0}" -- filename to extract one file from the stash
echo
echo or git stash pop to restore them all
echo
echo WARNING..
echo WARNING.. either will overlay the file just installed by the update
echo WARNING..
fi
fi
# return to original folder
cd - >/dev/null
date +"Upgrade ended - %a %b %e %H:%M:%S %Z %Y" >>$logfile
else
echo It appears MagicMirror has not been installed on this system
echo please run the installer, "raspberry.sh" first
fi

View File

@@ -11,6 +11,9 @@ var Utils = require(__dirname + "/utils.js");
var defaultModules = require(__dirname + "/../modules/default/defaultmodules.js");
var path = require("path");
// add timestamps in front of log messages
require('console-stamp')(console, 'HH:MM:ss.l');
// Get version number.
global.version = JSON.parse(fs.readFileSync("package.json", "utf8")).version;
console.log("Starting MagicMirror: v" + global.version);

View File

@@ -203,7 +203,7 @@ var MM = (function() {
*/
var updateModuleContent = function(module, newHeader, newContent) {
var moduleWrapper = document.getElementById(module.identifier);
if (moduleWrapper === null) return;
if (moduleWrapper === null) {return;}
var headerWrapper = moduleWrapper.getElementsByClassName("module-header");
var contentWrapper = moduleWrapper.getElementsByClassName("module-content");

View File

@@ -41,26 +41,40 @@ Module.register("clock",{
// Schedule update interval.
var self = this;
self.second = 0;
self.minute = 0;
self.lastDisplayedMinute = null;
setInterval(function() {
if (self.config.displaySeconds || self.lastDisplayedMinute !== moment().minute()) {
self.second = moment().second();
self.minute = moment().minute();
//Calculate how many ms should pass until next update depending on if seconds is displayed or not
var delayCalculator = function(reducedSeconds) {
if (self.config.displaySeconds) {
return 1000 - moment().milliseconds();
} else {
return ((60 - reducedSeconds) * 1000) - moment().milliseconds();
}
};
//A recursive timeout function instead of interval to avoid drifting
var notificationTimer = function() {
self.updateDom();
}
if (self.second === 59) {
self.second = 0;
if (self.minute === 59){
self.minute = 0;
} else {
self.minute++;
}
self.sendNotification("CLOCK_MINUTE", self.minute);
} else {
self.second++;
//If seconds is displayed CLOCK_SECOND-notification should be sent (but not when CLOCK_MINUTE-notification is sent)
if (self.config.displaySeconds) {
self.second = (self.second + 1) % 60;
if (self.second !== 0) {
self.sendNotification("CLOCK_SECOND", self.second);
setTimeout(notificationTimer, delayCalculator(0));
return;
}
}, 1000);
}
//If minute changed or seconds isn't displayed send CLOCK_MINUTE-notification
self.minute = (self.minute + 1) % 60;
self.sendNotification("CLOCK_MINUTE", self.minute);
setTimeout(notificationTimer, delayCalculator(0));
};
//Set the initial timeout with the amount of seconds elapsed as reducedSeconds so it will trigger when the minute changes
setTimeout(notificationTimer, delayCalculator(self.second));
// Set locale.
moment.locale(config.language);

View File

@@ -327,6 +327,11 @@ Module.register("newsfeed",{
self.updateDom(self.config.animationSpeed);
// Broadcast NewsFeed if needed
if (self.config.broadcastNewsFeeds) {
self.sendNotification("NEWS_FEED", {items: self.newsItems});
}
timer = setInterval(function() {
self.activeItem++;
self.updateDom(self.config.animationSpeed);

View File

@@ -11,7 +11,7 @@ Module.register("updatenotification", {
start: function () {
var self = this;
Log.log("Start updatenotification");
setInterval( () => { self.moduleList = {};self.updateDom(2) } , self.config.refreshInterval)
setInterval( () => { self.moduleList = {};self.updateDom(2); } , self.config.refreshInterval);
},
notificationReceived: function (notification, payload, sender) {
@@ -43,7 +43,7 @@ Module.register("updatenotification", {
// if the module WAS in the list, but shouldn't be
if(this.moduleList[payload.module] != undefined){
// remove it
delete this.moduleList[payload.module]
delete this.moduleList[payload.module];
self.updateDom(2);
}
}
@@ -66,7 +66,7 @@ Module.register("updatenotification", {
if(this.suspended==false){
// process the hash of module info found
for(key of Object.keys(this.moduleList)){
let m= this.moduleList[key]
let m= this.moduleList[key];
var message = document.createElement("div");
message.className = "small bright";

View File

@@ -32,7 +32,8 @@ WeatherProvider.register("darksky", {
this.setCurrentWeather(currentWeather);
}).catch(function(request) {
Log.error("Could not load data ... ", request);
});
})
.finally(() => this.updateAvailable())
},
fetchWeatherForecast() {
@@ -47,7 +48,8 @@ WeatherProvider.register("darksky", {
this.setWeatherForecast(forecast);
}).catch(function(request) {
Log.error("Could not load data ... ", request);
});
})
.finally(() => this.updateAvailable())
},
// Create a URL from the config and base URL.

View File

@@ -34,6 +34,7 @@ WeatherProvider.register("openweathermap", {
.catch(function(request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable())
},
// Overwrite the fetchCurrentWeather method.
@@ -54,6 +55,7 @@ WeatherProvider.register("openweathermap", {
.catch(function(request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable())
},
/** OpenWeatherMap Specific Methods - These are not part of the default provider methods */

View File

@@ -41,6 +41,7 @@ WeatherProvider.register("ukmetoffice", {
.catch(function(request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable())
},
// Overwrite the fetchCurrentWeather method.
@@ -62,6 +63,7 @@ WeatherProvider.register("ukmetoffice", {
.catch(function(request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable())
},

View File

@@ -35,6 +35,7 @@ WeatherProvider.register("weathergov", {
.catch(function(request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable())
},
// Overwrite the fetchCurrentWeather method.
@@ -53,6 +54,7 @@ WeatherProvider.register("weathergov", {
.catch(function(request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable())
},
/** Weather.gov Specific Methods - These are not part of the default provider methods */

0
modules/default/weather/weather.js Executable file → Normal file
View File

View File

@@ -79,16 +79,12 @@ var WeatherProvider = Class.extend({
setCurrentWeather: function(currentWeatherObject) {
// We should check here if we are passing a WeatherDay
this.currentWeatherObject = currentWeatherObject;
this.updateAvailable();
},
// Set the weatherForecastArray and notify the delegate that new information is available.
setWeatherForecast: function(weatherForecastArray) {
// We should check here if we are passing a WeatherDay
this.weatherForecastArray = weatherForecastArray;
this.updateAvailable();
},
// Set the fetched location name.

View File

@@ -180,9 +180,9 @@ Module.register("weatherforecast",{
rainCell.innerHTML = "";
} else {
if(config.units !== "imperial") {
rainCell.innerHTML = parseFloat(forecast.rain).toFixed(1) + " mm";
rainCell.innerHTML = parseFloat(forecast.rain).toFixed(1).replace(".", this.config.decimalSymbol) + " mm";
} else {
rainCell.innerHTML = (parseFloat(forecast.rain) / 25.4).toFixed(2) + " in";
rainCell.innerHTML = (parseFloat(forecast.rain) / 25.4).toFixed(2).replace(".", this.config.decimalSymbol) + " in";
}
}
rainCell.className = "align-right bright rain";
@@ -353,7 +353,7 @@ Module.register("weatherforecast",{
icon: this.config.iconTable[forecast.weather[0].icon],
maxTemp: this.roundValue(forecast.temp.max),
minTemp: this.roundValue(forecast.temp.min),
rain: forecast.rain
rain: this.processRain(forecast, data.list)
};
this.forecast.push(forecastData);
@@ -434,5 +434,38 @@ Module.register("weatherforecast",{
roundValue: function(temperature) {
var decimals = this.config.roundTemp ? 0 : 1;
return parseFloat(temperature).toFixed(decimals);
},
/* processRain(forecast, allForecasts)
* Calculates the amount of rain for a whole day even if long term forecasts isn't available for the appid.
*
* When using the the fallback endpoint forecasts are provided in 3h intervals and the rain-property is an object instead of number.
* That object has a property "3h" which contains the amount of rain since the previous forecast in the list.
* This code finds all forecasts that is for the same day and sums the amount of rain and returns that.
*/
processRain: function(forecast, allForecasts) {
//If the amount of rain actually is a number, return it
if (!isNaN(forecast.rain)) {
return forecast.rain;
}
//Find all forecasts that is for the same day
var checkDateTime = (!!forecast.dt_txt) ? moment(forecast.dt_txt, "YYYY-MM-DD hh:mm:ss") : moment(forecast.dt, "X");
var daysForecasts = allForecasts.filter(function(item) {
var itemDateTime = (!!item.dt_txt) ? moment(item.dt_txt, "YYYY-MM-DD hh:mm:ss") : moment(item.dt, "X");
return itemDateTime.isSame(checkDateTime, "day") && item.rain instanceof Object;
});
//If no rain this day return undefined so it wont be displayed for this day
if (daysForecasts.length == 0) {
return undefined;
}
//Summarize all the rain from the matching days
return daysForecasts.map(function(item) {
return Object.values(item.rain)[0];
}).reduce(function(a, b) {
return a + b;
}, 0);
}
});

4131
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,13 @@
{
"name": "magicmirror",
"version": "2.9.0-develop",
"version": "2.10.0-develop",
"description": "The open source modular smart mirror platform.",
"main": "js/electron.js",
"scripts": {
"start": "sh run-start.sh",
"start": "./run-start.sh",
"install": "cd vendor && npm install",
"install-fonts": "cd fonts && npm install",
"postinstall": "sh installers/postinstall/postinstall.sh && npm run install-fonts",
"postinstall": "sh untrack-css.sh && sh installers/postinstall/postinstall.sh && npm run install-fonts",
"test": "NODE_ENV=test ./node_modules/mocha/bin/mocha tests --recursive",
"test:unit": "NODE_ENV=test ./node_modules/mocha/bin/mocha tests/unit --recursive",
"test:e2e": "NODE_ENV=test ./node_modules/mocha/bin/mocha tests/e2e --recursive",
@@ -55,14 +55,18 @@
"stylelint-config-standard": "latest",
"time-grunt": "latest"
},
"optionalDependencies": {
"electron": "^3.0.13"
},
"dependencies": {
"colors": "^1.1.2",
"electron": "^3.0.13",
"console-stamp": "^0.2.9",
"express": "^4.16.2",
"express-ipfilter": "^1.0.1",
"feedme": "latest",
"helmet": "^3.9.0",
"iconv-lite": "latest",
"lodash": "^4.17.11",
"moment": "latest",
"request": "^2.88.0",
"rrule": "^2.6.2",

62
run-start.sh Normal file → Executable file
View File

@@ -1,4 +1,64 @@
#!/bin/bash
# use bash instead of sh
./untrack-css.sh
if [ -z "$DISPLAY" ]; then #If not set DISPLAY is SSH remote or tty
export DISPLAY=:0 # Set by default display
fi
electron js/electron.js $1
# get the processor architecture
arch=$(uname -m)
# got the config option, if any
serveronly=$(grep -i serveronly: config/config.js | awk '{print tolower($2)}' | tr -d ,\"\')
# set default if not defined in config
serveronly="${serveronly:=false}"
# check for xwindows running
xorg=$(pgrep Xorg)
#check for macOS
mac=$(uname)
#
# if the user requested serveronly OR
# electron support for armv6l has been dropped OR
# system is in text mode
#
if [ "$serveronly." != "false." -o "$arch" == "armv6l" ] || [ "$xorg." == "." -a $mac != 'Darwin' ]; then
# if user explicitly configured to run server only (no ui local)
# OR there is no xwindows running, so no support for browser graphics
if [ "$serveronly." == "true." -o "$xorg." == "." ]; then
# start server mode,
node serveronly
else
# start the server in the background
# wait for server to be ready
# need bash for this
exec 3< <(node serveronly)
# Read the output of server line by line until one line 'point your browser'
while read line; do
case "$line" in
*point\ your\ browser*)
echo $line
break
;;
*)
echo $line
#sleep .25
;;
esac
done <&3
# Close the file descriptor
exec 3<&-
# lets use chrome to display here now
# get the server port address from the ready message
port=$(echo $line | awk -F\: '{print $4}')
# start chromium
echo "Starting chromium browser now, have patience, it takes a minute"
chromium-browser -noerrdialogs -kiosk -start_maximized --disable-infobars --app=http://localhost:$port --ignore-certificate-errors-spki-list --ignore-ssl-errors --ignore-certificate-errors 2>/dev/null
exit
fi
else
# we can use electron directly
`electron js/electron.js $1`;
fi

View File

@@ -0,0 +1,35 @@
/* Magic Mirror Test config default weather
*
* By fewieden https://github.com/fewieden
*
* MIT Licensed.
*/
let config = {
port: 8080,
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
language: "en",
timeFormat: 12,
units: "metric",
electronOptions: {
webPreferences: {
nodeIntegration: true,
},
},
modules: [
{
module: "weather",
position: "bottom_bar",
config: {
location: "Munich",
apiKey: "fake key",
initialLoadDelay: 3000
}
}
]
};
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = config;}

View File

@@ -0,0 +1,40 @@
/* Magic Mirror Test config default weather
*
* By fewieden https://github.com/fewieden
*
* MIT Licensed.
*/
let config = {
port: 8080,
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
language: "en",
timeFormat: 24,
units: "metric",
electronOptions: {
webPreferences: {
nodeIntegration: true,
},
},
modules: [
{
module: "weather",
position: "bottom_bar",
config: {
location: "Munich",
apiKey: "fake key",
initialLoadDelay: 3000,
useBeaufort: false,
showWindDirectionAsArrow: true,
showHumidity: true,
roundTemp: true,
degreeLabel: true
}
}
]
};
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = config;}

View File

@@ -0,0 +1,37 @@
/* Magic Mirror Test config default weather
*
* By fewieden https://github.com/fewieden
*
* MIT Licensed.
*/
let config = {
port: 8080,
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
language: "en",
timeFormat: 24,
units: "imperial",
electronOptions: {
webPreferences: {
nodeIntegration: true,
},
},
modules: [
{
module: "weather",
position: "bottom_bar",
config: {
location: "Munich",
apiKey: "fake key",
initialLoadDelay: 3000,
decimalSymbol: ",",
showHumidity: true
}
}
]
};
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = config;}

View File

@@ -0,0 +1,37 @@
/* Magic Mirror Test config default weather
*
* By fewieden https://github.com/fewieden
*
* MIT Licensed.
*/
let config = {
port: 8080,
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
language: "en",
timeFormat: 12,
units: "metric",
electronOptions: {
webPreferences: {
nodeIntegration: true,
},
},
modules: [
{
module: "weather",
position: "bottom_bar",
config: {
type: "forecast",
location: "Munich",
apiKey: "fake key",
weatherEndpoint: "/forecast/daily",
initialLoadDelay: 3000
}
}
]
};
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = config;}

View File

@@ -0,0 +1,40 @@
/* Magic Mirror Test config default weather
*
* By fewieden https://github.com/fewieden
*
* MIT Licensed.
*/
let config = {
port: 8080,
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
language: "en",
timeFormat: 12,
units: "metric",
electronOptions: {
webPreferences: {
nodeIntegration: true,
},
},
modules: [
{
module: "weather",
position: "bottom_bar",
config: {
type: "forecast",
location: "Munich",
apiKey: "fake key",
weatherEndpoint: "/forecast/daily",
initialLoadDelay: 3000,
showPrecipitationAmount: true,
colored: true,
tableClass: "myTableClass"
}
}
]
};
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = config;}

View File

@@ -0,0 +1,4 @@
const generateWeather = require("./weather_current");
const generateWeatherForecast = require("./weather_forecast");
module.exports = {generateWeather, generateWeatherForecast};

View File

@@ -0,0 +1,54 @@
const _ = require('lodash');
function generateWeather(extendedData = {}) {
return JSON.stringify(_.merge({}, {
coord:{
lon: 11.58,
lat: 48.14
},
weather:[
{
id: 615,
main: "Snow",
description: "light rain and snow",
icon: "13d"
},
{
id: 500,
main: "Rain",
description: "light rain",
icon: "10d"
}
],
base: "stations",
main:{
temp: 1.49,
pressure: 1005,
humidity: 93.7,
temp_min: 1,
temp_max: 2
},
visibility: 7000,
wind:{
speed: 11.8,
deg: 250
},
clouds:{
all: 75
},
dt: 1547387400,
sys:{
type: 1,
id: 1267,
message: 0.0031,
country: "DE",
sunrise: 1547362817,
sunset: 1547394301
},
id: 2867714,
name: "Munich",
cod: 200
}, extendedData));
}
module.exports = generateWeather;

View File

@@ -0,0 +1,97 @@
const _ = require('lodash');
function generateWeatherForecast(extendedData = {}) {
return JSON.stringify(_.merge({}, {
"city": {
"id": 2867714,
"name": "Munich",
"coord": {"lon": 11.5754, "lat": 48.1371},
"country": "DE",
"population": 1260391,
"timezone": 7200
},
"cod": "200",
"message": 0.9653487,
"cnt": 7,
"list": [{
"dt": 1568372400,
"sunrise": 1568350044,
"sunset": 1568395948,
"temp": {"day": 24.44, "min": 15.35, "max": 24.44, "night": 15.35, "eve": 18, "morn": 23.03},
"pressure": 1031.65,
"humidity": 70,
"weather": [{"id": 801, "main": "Clouds", "description": "few clouds", "icon": "02d"}],
"speed": 3.35,
"deg": 314,
"clouds": 21
}, {
"dt": 1568458800,
"sunrise": 1568436525,
"sunset": 1568482223,
"temp": {"day": 20.81, "min": 13.56, "max": 21.02, "night": 13.56, "eve": 16.6, "morn": 15.88},
"pressure": 1028.81,
"humidity": 72,
"weather": [{"id": 500, "main": "Rain", "description": "light rain", "icon": "10d"}],
"speed": 2.21,
"deg": 81,
"clouds": 100
}, {
"dt": 1568545200,
"sunrise": 1568523007,
"sunset": 1568568497,
"temp": {"day": 22.65, "min": 13.76, "max": 22.88, "night": 15.27, "eve": 17.45, "morn": 13.76},
"pressure": 1023.75,
"humidity": 64,
"weather": [{"id": 800, "main": "Clear", "description": "sky is clear", "icon": "01d"}],
"speed": 1.15,
"deg": 7,
"clouds": 0
}, {
"dt": 1568631600,
"sunrise": 1568609489,
"sunset": 1568654771,
"temp": {"day": 23.45, "min": 13.95, "max": 23.45, "night": 13.95, "eve": 17.75, "morn": 15.21},
"pressure": 1020.41,
"humidity": 64,
"weather": [{"id": 800, "main": "Clear", "description": "sky is clear", "icon": "01d"}],
"speed": 3.07,
"deg": 298,
"clouds": 7
}, {
"dt": 1568718000,
"sunrise": 1568695970,
"sunset": 1568741045,
"temp": {"day": 20.55, "min": 10.95, "max": 20.55, "night": 10.95, "eve": 14.82, "morn": 13.24},
"pressure": 1019.4,
"humidity": 66,
"weather": [{"id": 800, "main": "Clear", "description": "sky is clear", "icon": "01d"}],
"speed": 2.8,
"deg": 333,
"clouds": 2
}, {
"dt": 1568804400,
"sunrise": 1568782452,
"sunset": 1568827319,
"temp": {"day": 18.15, "min": 7.75, "max": 18.15, "night": 7.75, "eve": 12.45, "morn": 9.41},
"pressure": 1017.56,
"humidity": 52,
"weather": [{"id": 800, "main": "Clear", "description": "sky is clear", "icon": "01d"}],
"speed": 2.92,
"deg": 34,
"clouds": 0
}, {
"dt": 1568890800,
"sunrise": 1568868934,
"sunset": 1568913593,
"temp": {"day": 14.85, "min": 5.56, "max": 15.05, "night": 5.56, "eve": 9.56, "morn": 6.25},
"pressure": 1022.7,
"humidity": 59,
"weather": [{"id": 800, "main": "Clear", "description": "sky is clear", "icon": "01d"}],
"speed": 2.89,
"deg": 51,
"clouds": 1
}]
}, extendedData));
}
module.exports = generateWeatherForecast;

View File

@@ -0,0 +1,270 @@
const expect = require("chai").expect;
const fs = require("fs");
const moment = require("moment");
const path = require("path");
const wdajaxstub = require("webdriverajaxstub");
const helpers = require("../global-setup");
const {generateWeather, generateWeatherForecast} = require("./mocks");
const wait = () => new Promise(res => setTimeout(res, 3000));
describe("Weather module", function() {
let app;
helpers.setupTimeout(this);
async function setup(responses) {
app = await helpers.startApplication({
args: ["js/electron.js"]
});
wdajaxstub.init(app.client, responses);
app.client.setupStub();
}
afterEach(function() {
return helpers.stopApplication(app);
});
describe("Current weather", function() {
let template;
before(function() {
template = fs.readFileSync(path.join(__dirname, "..", "..", "..", "modules", "default", "weather", "current.njk"), "utf8");
});
describe("Default configuration", function() {
before(function() {
process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/currentweather_default.js";
});
it("should render wind speed and wind direction", async function() {
const weather = generateWeather();
await setup([weather, template]);
return app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(2)", "6 WSW", 10000);
});
it("should render sunrise", async function() {
const sunrise = moment().startOf("day").unix();
const sunset = moment().startOf("day").unix();
const weather = generateWeather({sys: {sunrise, sunset}});
await setup([weather, template]);
await app.client.waitForExist(".weather .normal.medium span.wi.dimmed.wi-sunrise", 10000);
return app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(4)", "12:00 am", 10000);
});
it("should render sunset", async function() {
const sunrise = moment().startOf("day").unix();
const sunset = moment().endOf("day").unix();
const weather = generateWeather({sys: {sunrise, sunset}});
await setup([weather, template]);
await app.client.waitForExist(".weather .normal.medium span.wi.dimmed.wi-sunset", 10000);
return app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(4)", "11:59 pm", 10000);
});
it("should render temperature with icon", async function() {
const weather = generateWeather();
await setup([weather, template]);
await app.client.waitForExist(".weather .large.light span.wi.weathericon.wi-snow", 10000);
return app.client.waitUntilTextExists(".weather .large.light span.bright", "1.5°", 10000);
});
it("should render feels like temperature", async function() {
const weather = generateWeather();
await setup([weather, template]);
return app.client.waitUntilTextExists(".weather .normal.medium span.dimmed", "Feels like -5.6°", 10000);
});
});
describe("Configuration Options", function() {
before(function() {
process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/currentweather_options.js";
});
it("should render useBeaufort = false", async function() {
const weather = generateWeather();
await setup([weather, template]);
return app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(2)", "12", 10000);
});
it("should render showWindDirectionAsArrow = true", async function() {
const weather = generateWeather();
await setup([weather, template]);
await app.client.waitForExist(".weather .normal.medium sup i.fa-long-arrow-up", 10000);
const element = await app.client.getHTML(".weather .normal.medium sup i.fa-long-arrow-up");
expect(element).to.include("transform:rotate(250deg);");
});
it("should render showHumidity = true", async function() {
const weather = generateWeather();
await setup([weather, template]);
await app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(3)", "93", 10000);
return app.client.waitForExist(".weather .normal.medium sup i.wi-humidity", 10000);
});
it("should render degreeLabel = true", async function() {
const weather = generateWeather();
await setup([weather, template]);
await app.client.waitUntilTextExists(".weather .large.light span.bright", "1°C", 10000);
return app.client.waitUntilTextExists(".weather .normal.medium span.dimmed", "Feels like -6°C", 10000);
});
});
describe("Current weather units", function() {
before(function() {
process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/currentweather_units.js";
});
it("should render imperial units", async function() {
const weather = generateWeather({
main:{
temp: 1.49 * 9 / 5 + 32,
temp_min: 1 * 9 / 5 + 32,
temp_max: 2 * 9 / 5 + 32
},
wind:{
speed: 11.8 * 2.23694
},
});
await setup([weather, template]);
await app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(2)", "6 WSW", 10000);
await app.client.waitUntilTextExists(".weather .large.light span.bright", "34,7°", 10000);
return app.client.waitUntilTextExists(".weather .normal.medium span.dimmed", "22,0°", 10000);
});
it("should render decimalSymbol = ','", async function() {
const weather = generateWeather({
main:{
temp: 1.49 * 9 / 5 + 32,
temp_min: 1 * 9 / 5 + 32,
temp_max: 2 * 9 / 5 + 32
},
wind:{
speed: 11.8 * 2.23694
},
});
await setup([weather, template]);
await app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(3)", "93,7", 10000);
await app.client.waitUntilTextExists(".weather .large.light span.bright", "34,7°", 10000);
return app.client.waitUntilTextExists(".weather .normal.medium span.dimmed", "22,0°", 10000);
});
});
});
describe("Weather Forecast", function() {
let template;
before(function() {
template = fs.readFileSync(path.join(__dirname, "..", "..", "..", "modules", "default", "weather", "forecast.njk"), "utf8");
});
describe("Default configuration", function() {
before(function() {
process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/forecastweather_default.js";
});
it("should render days", async function() {
const weather = generateWeatherForecast();
await setup([weather, template]);
const days = ["Fri", "Sat", "Sun", "Mon", "Tue"];
for (const [index, day] of days.entries()) {
await app.client.waitUntilTextExists(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(1)`, day, 10000);
}
});
it("should render icons", async function() {
const weather = generateWeatherForecast();
await setup([weather, template]);
const icons = ["day-cloudy", "rain", "day-sunny", "day-sunny", "day-sunny"];
for (const [index, icon] of icons.entries()) {
await app.client.waitForExist(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(2) span.wi-${icon}`, 10000);
}
});
it("should render max temperatures", async function() {
const weather = generateWeatherForecast();
await setup([weather, template]);
const temperatures = ["24.4°", "21.0°", "22.9°", "23.4°", "20.6°"];
for (const [index, temp] of temperatures.entries()) {
await app.client.waitUntilTextExists(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp, 10000);
}
});
it("should render min temperatures", async function() {
const weather = generateWeatherForecast();
await setup([weather, template]);
const temperatures = ["15.3°", "13.6°", "13.8°", "13.9°", "10.9°"];
for (const [index, temp] of temperatures.entries()) {
await app.client.waitUntilTextExists(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(4)`, temp, 10000);
}
});
it("should render fading of rows", async function() {
const weather = generateWeatherForecast();
await setup([weather, template]);
const opacities = [1, 1, 0.8, 0.5333333333333333, 0.2666666666666667];
await app.client.waitForExist('.weather table.small', 10000);
for (const [index, opacity] of opacities.entries()) {
const html = await app.client.getHTML(`.weather table.small tr:nth-child(${index + 1})`);
expect(html).to.includes(`<tr style="opacity: ${opacity};">`);
}
});
});
describe("Configuration Options", function() {
before(function() {
process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/forecastweather_options.js";
});
it("should render custom table class", async function() {
const weather = generateWeatherForecast();
await setup([weather, template]);
await app.client.waitForExist(`.weather table.myTableClass`, 10000);
});
it("should render colored rows", async function() {
const weather = generateWeatherForecast();
await setup([weather, template]);
await app.client.waitForExist(`.weather table.myTableClass`, 10000);
const rows = await app.client.$$('.weather table.myTableClass tr.colored');
expect(rows.length).to.be.equal(5);
});
});
});
});

View File

@@ -6,11 +6,10 @@ const describe = global.describe;
const it = global.it;
const before = global.before;
const after = global.after;
const mlog = require("mocha-logger");
describe("Vendors", function () {
return; // Test still getting failed in Travis
helpers.setupTimeout(this);
var app = null;
@@ -40,5 +39,17 @@ describe("Vendors", function () {
});
});
});
Object.keys(vendors).forEach(vendor => {
it(`should return 404 HTTP code for vendor https://localhost/"${vendor}"`, function() {
urlVendor = "http://localhost:8080/" + vendors[vendor];
request.get(urlVendor, function (err, res, body) {
if (!err)
expect(res.statusCode).to.equal(404);
else
mlog.pending(`There error vendor 404 test ${err}`);
});
});
});
});
});

33
tests/node_modules/webdriverajaxstub/index.js generated vendored Normal file
View File

@@ -0,0 +1,33 @@
function plugin (wdInstance, requests) {
if (typeof wdInstance.addCommand !== "function") {
throw new Error("You can't use WebdriverAjaxStub with this version of WebdriverIO");
}
function stub(requests, done) {
window.XMLHttpRequest = function () {
this.open = function (method, url) {
this.method = method;
this.url = url;
};
this.send = function () {
this.status = 200;
this.readyState = 4;
const response = requests.shift() || [];
this.response = response;
this.responseText = response;
this.onreadystatechange();
};
return this;
};
done();
}
wdInstance.addCommand("setupStub", function() {
return wdInstance.executeAsync(stub, requests);
});
}
module.exports.init = plugin;

0
translations/en.json Executable file → Normal file
View File

View File

@@ -31,5 +31,6 @@
"UPDATE_INFO_SINGLE": "Tu actual instalación está {COMMIT_COUNT} commit cambios detrás de la rama {BRANCH_NAME}.",
"UPDATE_INFO_MULTIPLE": "Tu actual instalación está {COMMIT_COUNT} commits cambios detrás de la rama {BRANCH_NAME}.",
"FEELS": "Sensación térmica de"
"FEELS": "Sensación térmica de",
"PRECIP": "Precipitación"
}

33
translations/ms-my.json Normal file
View File

@@ -0,0 +1,33 @@
{
"LOADING": "Tunggu Sebentar &hellip;",
"TODAY": "Hari ini",
"TOMORROW": "Esok",
"DAYAFTERTOMORROW": "Lusa",
"RUNNING": "Berakhir dalam",
"EMPTY": "Tidak ada agenda",
"WEEK": "Minggu ke-{weekNumber}",
"N": "U",
"NNE": "UUT",
"NE": "TL",
"ENE": "TTL",
"E": "T",
"ESE": "TT",
"SE": "T",
"SSE": "ST",
"S": "S",
"SSW": "SBD",
"SW": "BD",
"WSW": "BBD",
"W": "B",
"WNW": "BBL",
"NW": "BL",
"NNW": "UBL",
"UPDATE_NOTIFICATION": "MagicMirror² mempunyai update terkini.",
"UPDATE_NOTIFICATION_MODULE": "Modul {MODULE_NAME} mempunyai update terkini.",
"UPDATE_INFO_SINGLE": "Pemasangan MagicMirror² ini mempunyai {COMMIT_COUNT} commit terkebelakang dari branch {BRANCH_NAME}.",
"UPDATE_INFO_MULTIPLE": "Pemasangan MagicMirror² ini mempunyai {COMMIT_COUNT} commit terkebelakang dari branch {BRANCH_NAME}."
}

View File

@@ -40,7 +40,8 @@ var translations = {
"cs" : "translations/cs.json", // Czech
"hr" : "translations/hr.json", // Croatian
"sk" : "translations/sk.json", // Slovak
"tlh" : "translations/tlh.json" // Klingon
"tlh" : "translations/tlh.json", // Klingon
"ms-my" : "translations/ms-my.json" // Malay
};
if (typeof module !== "undefined") {module.exports = translations;}

11
untrack-css.sh Executable file
View File

@@ -0,0 +1,11 @@
# Long history here
# https://github.com/MichMich/MagicMirror/pull/1540
STATUS_CUSTOM_CSS=$(git ls-files -v css/custom.css| awk '{print $1}')
if [ "$STATUS_CUSTOM_CSS" = "H" ]; then
echo "We'll remove from the repository the css/custom.css"
echo "This script apply git update-index --skip-worktree css/custom.css"
git update-index --skip-worktree css/custom.css
git rm --cached css/custom.css
fi

2
vendor/package-lock.json generated vendored
View File

@@ -5,7 +5,7 @@
"dependencies": {
"@fortawesome/fontawesome-free": {
"version": "5.6.3",
"resolved": "https://npm.fontawesome.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.6.3.tgz",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.6.3.tgz",
"integrity": "sha512-s5PLdI9NYgjBvfrv6rhirPHlAHWx+Sfo/IjsAeiXYfmemC/GSjwsyz1wLnGPazbLPXWfk62ks980o9AmsxYUEQ=="
},
"a-sync-waterfall": {