Merge pull request #21 from MichMich/v2-beta

Update from Master
This commit is contained in:
Paul-Vincent Roll 2016-05-02 16:50:05 +02:00
commit e5f4446c82
19 changed files with 184 additions and 77 deletions

View File

@ -4,5 +4,6 @@
"validateQuoteMarks": "\"",
"maximumLineLength": 250,
"requireCurlyBraces": [],
"requireCamelCaseOrUpperCaseIdentifiers": false
"requireCamelCaseOrUpperCaseIdentifiers": false,
"excludeFiles": [".jscsrc"],
}

View File

@ -25,7 +25,7 @@ MagicMirror² focuses on a modular plugin system and uses [Electron](http://elec
## Usage
#### Raspberry Pi Support
Electron, the app wrapper around MagicMirror², only supports the Raspberry Pi 2 & 3. The Raspberry Pi 1 is currently **not** supported. If you want to run this on a Raspberry Pi 1, use the [server only](#server-only) feature and setup a fullscreen browser yourself. Note the only Jessie is currently supported. If you want to use Wheezy, check out [this issue](https://github.com/MichMich/MagicMirror/issues/188).
Electron, the app wrapper around MagicMirror², only supports the Raspberry Pi 2 & 3. The Raspberry Pi 1 is currently **not** supported. If you want to run this on a Raspberry Pi 1, use the [server only](#server-only) feature and setup a fullscreen browser yourself.
#### Automatic Installer (Raspberry Pi Only!)
@ -39,7 +39,7 @@ curl -sL https://raw.githubusercontent.com/MichMich/MagicMirror/v2-beta/installe
1. Download and install the latest Node.js version.
2. Clone the repository and check out the beta branch: `git clone -b v2-beta https://github.com/MichMich/MagicMirror`
3. Enter the repository: `cd ~/MagicMirror`
4. Install and run the app: `npm install && npm start` (You may have to restart your terminal before this works!)
4. Install and run the app: `npm install && npm start`
**Important:** `npm start` does **not** work via SSH, use `DISPLAY=:0 nohup npm start &` instead. This starts the mirror on the remote display.
@ -77,6 +77,7 @@ The following properties can be configured:
| `port` | The port on which the MagicMirror² server will run on. The default value is `8080`. |
| `language` | The language of the interface. (Note: Not all elements will be localized.) Possible values are `en`, `nl`, `ru`, `fr`, etc., but the default value is `en`. |
| `timeFormat` | The form of time notation that will be used. Possible values are `12` or `24`. The default is `24`. |
| `units` | The units that will be used in the default weather modules. Possible values are `metric` or `imperial`. The default is `metric`. |
| `modules` | An array of active modules. **The array must contain objects. See the next table below for more information.** |
Module configuration:

View File

@ -9,6 +9,7 @@ var config = {
language: 'en',
timeFormat: 24,
units: 'metric',
modules: [
{

View File

@ -6,9 +6,9 @@
* MIT Licensed. *
* *
* Add any custom CSS below. *
* Changes to this files will not be ignored by GIT. *
* Changes to this files will be ignored by GIT. *
*****************************************************/
body {
}
}

View File

@ -18,7 +18,7 @@
echo "Installing helper tools ..."
sudo apt-get install curl wget build-essential unzip || exit
ARM=$(uname -m) # Determine which Pi is running.
NODE_LATEST="v5.11.0" # Set the latest version here.
NODE_LATEST="v6.0.0" # Set the latest version here.
DOWNLOAD_URL="https://nodejs.org/dist/latest/node-$NODE_LATEST-linux-$ARM.tar.gz" # Construct the download URL.
echo "Installing Latest Node.js ..."

View File

@ -12,7 +12,8 @@ var defaults = {
language: "en",
timeFormat: 24,
units: "metric",
modules: [
{
module: "helloworld",

View File

@ -21,6 +21,27 @@ var Log = (function() {
},
error: function(message) {
console.error(message);
},
warn: function(message) {
console.warn(message);
},
group: function(message) {
console.group(message);
},
groupCollapsed: function(message) {
console.groupCollapsed(message);
},
groupEnd: function() {
console.groupEnd();
},
time: function(message) {
console.time(message);
},
timeEnd: function(message) {
console.timeEnd(message);
},
timeStamp: function(message) {
console.timeStamp(message);
}
};
})();

View File

@ -97,7 +97,7 @@ start: function() {
####`getScripts()`
**Should return: Array**
The getScripts method is called to request any additional scripts that need to be loaded. This method should therefor return an array with strings. If you want to return a full path to a file in the module folder, use the `this.file('filename.js')` method. In all cases the loader will only load a file once. It even checks if the file is available in the default vendor folder.
The getScripts method is called to request any additional scripts that need to be loaded. This method should therefore return an array with strings. If you want to return a full path to a file in the module folder, use the `this.file('filename.js')` method. In all cases the loader will only load a file once. It even checks if the file is available in the default vendor folder.
**Example:**
````javascript
@ -117,7 +117,7 @@ getScripts: function() {
####`getStyles()`
**Should return: Array**
The getStyles method is called to request any additional scripts that need to be loaded. This method should therefor return an array with strings. If you want to return a full path to a file in the module folder, use the `this.file('filename.css')` method. In all cases the loader will only load a file once. It even checks if the file is available in the default vendor folder.
The getStyles method is called to request any additional stylesheets that need to be loaded. This method should therefore return an array with strings. If you want to return a full path to a file in the module folder, use the `this.file('filename.css')` method. In all cases the loader will only load a file once. It even checks if the file is available in the default vendor folder.
**Example:**
````javascript
@ -133,6 +133,22 @@ getStyles: function() {
````
**Note:** If a file can not be loaded, the boot up of the mirror will stall. Therefore it's advised not to use any external urls.
####`getTranslations()`
**Should return: Dictionary**
The getTranslations method is called to request translation files that need to be loaded. This method should therefore return a dictionary with the files to load, identified by the country's short name.
**Example:**
````javascript
getTranslations: function() {
return {
en: "translations/en.json",
de: "translations/de.json"
}
}
````
####`getDom()`
**Should return:** Dom Object
@ -261,6 +277,25 @@ To show a module, you can call the `show(speed, callback)` method. You can call
**Note 2:** If the show animation is hijacked (an other method calls show on the same module), the callback will not be called.<br>
**Note 3:** If the dom is not yet created, the show method won't work. Wait for the `DOM_OBJECTS_CREATED` [notification](#notificationreceivednotification-payload-sender).
####`this.translate(identifier)`
***identifier* String** - Identifier of the string that should be translated.
The Magic Mirror contains a convenience wrapper for `l18n`. You can use this to automatically serve different translations for your modules based on the user's `language` configuration.
**Example:**
````javascript
this.translate("INFO") //Will return a translated string for the identifier INFO
````
**Example json file:**
````javascript
{
"INFO": "Really important information!"
}
````
**Note:** Currently there is no fallback if a translation identifier does not exist in one language. Right now you always have to add all identifier to all your translations even if they are not translated yet (see [#191](https://github.com/MichMich/MagicMirror/issues/191)).
## The Node Helper: node_helper.js
@ -458,4 +493,4 @@ The Magic Mirror contains a convenience wrapper for logging. Currently, this log
Log.info('error');
Log.log('log');
Log.error('info');
```
````

View File

@ -112,36 +112,6 @@ The following properties can be configured:
</code>
</td>
</tr>
<tr>
<td><code>loadingText</code></td>
<td>Text to display while loading item.<br>
<br><b>Default value:</b> <code>'Loading events &hellip;'</code>
</td>
</tr>
<tr>
<td><code>emptyCalendarText</code></td>
<td>Text to display when there are no upcoming events.<br>
<br><b>Default value:</b> <code>'No upcoming events.'</code>
</td>
</tr>
<tr>
<td><code>todayText</code></td>
<td>Text to display when a fullday event is planned for today.<br>
<br><b>Default value:</b> <code>'Today'</code>
</td>
</tr>
<tr>
<td><code>tomorrowText</code></td>
<td>Text to display when a fullday event is planned for tomorrow.<br>
<br><b>Default value:</b> <code>'Tomorrow'</code>
</td>
</tr>
<tr>
<td><code>runningText</code></td>
<td>Text to display when an event is still running.<br>
<br><b>Default value:</b> <code>'Ends in'</code>
</td>
</tr>
</tbody>
</table>

View File

@ -124,7 +124,7 @@ Module.register("calendar",{
if (event.fullDayEvent) {
if (event.today) {
timeWrapper.innerHTML = this.translate("TODAY");
} else if (event.startDate - now < 24 * 60 * 60 * 1000) {
} else if (event.startDate - now < 24 * 60 * 60 * 1000 && event.startDate - now > 0) {
timeWrapper.innerHTML = this.translate("TOMORROW");
} else {
timeWrapper.innerHTML = moment(event.startDate,"x").fromNow();
@ -141,7 +141,8 @@ Module.register("calendar",{
timeWrapper.innerHTML = this.translate("RUNNING") + ' ' + moment(event.endDate,"x").fromNow(true);
}
}
// timeWrapper.innerHTML = moment(event.startDate,'x').format('lll');
//timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll');
//console.log(event);
timeWrapper.className = "time light";
eventWrapper.appendChild(timeWrapper);

View File

@ -99,7 +99,7 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe
continue;
}
if (fullDayEvent && endDate < today) {
if (fullDayEvent && endDate <= today) {
//console.log("It's a fullday event, and it is before today. So skip: " + title);
continue;
}

View File

@ -1,7 +1,7 @@
{
"TODAY": "Heute"
, "TOMORROW": "Morgen"
, "RUNNING": "Endet in"
, "RUNNING": "noch"
, "LOADING": "Lade Termine &hellip;"
, "EMPTY": "Keine Termine."
}

View File

@ -28,6 +28,14 @@ ical.objectHandlers['END'] = function(val, params, curr, stack){
if (curr.rrule) {
var rule = curr.rrule.replace('RRULE:', '');
if (rule.indexOf('DTSTART') === -1) {
if (curr.start.length === 8) {
var comps = /^(\d{4})(\d{2})(\d{2})$/.exec(curr.start);
if (comps) {
curr.start = new Date (comps[1], comps[2], comps[3]);
}
}
rule += ';DTSTART=' + curr.start.toISOString().replace(/[-:]/g, '');
rule = rule.replace(/\.[0-9]{3}/, '');
}

View File

@ -47,14 +47,21 @@ The following properties can be configured:
</tr>
<tr>
<td><code>showPeriod</code></td>
<td>Show the period (am/pm) with 12 hour format<br>
<td>Show the period (am/pm) with 12 hour format.<br>
<br><b>Possible values:</b> <code>true</code> or <code>false</code>
<br><b>Default value:</b> <code>true</code>
</td>
</tr>
<tr>
<td><code>showPeriodUpper</code></td>
<td>Show the period (AM/PM) with 12 hour format as uppercase<br>
<td>Show the period (AM/PM) with 12 hour format as uppercase.<br>
<br><b>Possible values:</b> <code>true</code> or <code>false</code>
<br><b>Default value:</b> <code>false</code>
</td>
</tr>
<tr>
<td><code>clockBold</code></td>
<td>Remove the colon and bold the minutes to make a more modern look.<br>
<br><b>Possible values:</b> <code>true</code> or <code>false</code>
<br><b>Default value:</b> <code>false</code>
</td>

View File

@ -1,41 +1,34 @@
/* global Log, Module, moment, config */
/* Magic Mirror
* Module: Clock
*
* By Michael Teeuw http://michaelteeuw.nl
* MIT Licensed.
*/
Module.register("clock",{
// Module config defaults.
defaults: {
timeFormat: config.timeFormat,
displaySeconds: true,
showPeriod: true,
showPeriodUpper: false,
clockBold: false
},
// Define required scripts.
getScripts: function() {
return ["moment.js"];
},
// Define start sequence.
start: function() {
Log.info("Starting module: " + this.name);
// Schedule update interval.
var self = this;
setInterval(function() {
self.updateDom();
}, 1000);
// Set locale.
moment.locale(config.language);
},
// Override dom generator.
getDom: function() {
// Create wrappers.
@ -44,35 +37,36 @@ Module.register("clock",{
var timeWrapper = document.createElement("div");
var secondsWrapper = document.createElement("sup");
var periodWrapper = document.createElement("span");
// Style Wrappers
dateWrapper.className = "date normal medium";
timeWrapper.className = "time bright large light";
secondsWrapper.className = "dimmed";
// Set content of wrappers.
// The moment().format('h') method has a bug on the Raspberry Pi.
// The moment().format("h") method has a bug on the Raspberry Pi.
// So we need to generate the timestring manually.
// See issue: https://github.com/MichMich/MagicMirror/issues/181
var timeString = moment().format('HH:mm');
if (this.config.clockBold === true) {
var timeString = moment().format("HH[<span class=\"bold\">]mm[</span>]");
} else {
var timeString = moment().format("HH:mm");
}
if (this.config.timeFormat !== 24) {
var now = new Date();
var hours = now.getHours() % 12 || 12;
timeString = hours + moment().format(':mm');
if (this.config.clockBold === true) {
timeString = hours + moment().format("[<span class=\"bold\">]mm[</span>]");
} else {
timeString = hours + moment().format(":mm");
}
}
dateWrapper.innerHTML = moment().format("dddd, LL");
timeWrapper.innerHTML = timeString;
secondsWrapper.innerHTML = moment().format("ss");
if (this.config.showPeriodUpper) {
periodWrapper.innerHTML = moment().format('A');
periodWrapper.innerHTML = moment().format("A");
} else {
periodWrapper.innerHTML = moment().format('a');
periodWrapper.innerHTML = moment().format("a");
}
// Combine wrappers.
wrapper.appendChild(dateWrapper);
wrapper.appendChild(timeWrapper);
@ -82,7 +76,6 @@ Module.register("clock",{
if (this.config.showPeriod && this.config.timeFormat !== 24) {
timeWrapper.appendChild(periodWrapper);
}
// Return the wrapper to the dom.
return wrapper;
}

View File

@ -50,9 +50,9 @@ The following properties can be configured:
</tr>
<tr>
<td><code>units</code></td>
<td>What units to use?<br>
<br><b>Possible values:</b> <code>default</code> = Kelvin, <code>metric</code> = Celsius, <code>imperial</code> =Fahrenheit
<br><b>Default value:</b> <code>metric</code>
<td>What units to use. Specified by config.js<br>
<br><b>Possible values:</b> <code>config.units</code> = Specified by config.js, <code>default</code> = Kelvin, <code>metric</code> = Celsius, <code>imperial</code> =Fahrenheit
<br><b>Default value:</b> <code>config.units</code>
</td>
</tr>
<tr>
@ -90,6 +90,13 @@ The following properties can be configured:
<br><b>Default value:</b> <code>false</code>
</td>
</tr>
<tr>
<td><code>showWindDirection</code></td>
<td>Show the wind direction next to the wind speed.<br>
<br><b>Possible values:</b> <code>true</code> or <code>false</code>
<br><b>Default value:</b> <code>false</code>
</td>
</tr>
<tr>
<td><code>lang</code></td>
<td>The language of the days.<br>

View File

@ -13,12 +13,13 @@ Module.register("currentweather",{
defaults: {
location: "",
appid: "",
units: "metric",
units: config.units,
updateInterval: 10 * 60 * 1000, // every 10 minutes
animationSpeed: 1000,
timeFormat: config.timeFormat,
showPeriod: true,
showPeriodUpper: false,
showWindDirection: false,
lang: config.language,
initialLoadDelay: 0, // 0 seconds delay
@ -68,6 +69,7 @@ Module.register("currentweather",{
moment.locale(config.language);
this.windSpeed = null;
this.windDirection = null;
this.sunriseSunsetTime = null;
this.sunriseSunsetIcon = null;
this.temperature = null;
@ -108,11 +110,16 @@ Module.register("currentweather",{
var windIcon = document.createElement("span");
windIcon.className = "wi wi-strong-wind dimmed";
small.appendChild(windIcon);
var windSpeed = document.createElement("span");
windSpeed.innerHTML = " " + this.windSpeed;
small.appendChild(windSpeed);
if (this.config.showWindDirection) {
var windDirection = document.createElement("span");
windDirection.innerHTML = " " + this.windDirection;
small.appendChild(windDirection);
}
var spacer = document.createElement("span");
spacer.innerHTML = "&nbsp;";
small.appendChild(spacer);
@ -198,6 +205,7 @@ Module.register("currentweather",{
processWeather: function(data) {
this.temperature = this.roundValue(data.main.temp);
this.windSpeed = this.ms2Beaufort(this.roundValue(data.wind.speed));
this.windDirection = this.deg2Cardinal(data.wind.deg);
this.weatherType = this.config.iconTable[data.weather[0].icon];
var now = new Date();
@ -274,6 +282,44 @@ Module.register("currentweather",{
*
* return number - Rounded Temperature.
*/
deg2Cardinal: function(deg) {
if (deg>11.25 && deg<33.75){
return "NNE";
}else if (deg>33.75 && deg<56.25){
return "ENE";
}else if (deg>56.25 && deg<78.75){
return "E";
}else if (deg>78.75 && deg<101.25){
return "ESE";
}else if (deg>101.25 && deg<123.75){
return "ESE";
}else if (deg>123.75 && deg<146.25){
return "SE";
}else if (deg>146.25 && deg<168.75){
return "SSE";
}else if (deg>168.75 && deg<191.25){
return "S";
}else if (deg>191.25 && deg<213.75){
return "SSW";
}else if (deg>213.75 && deg<236.25){
return "SW";
}else if (deg>236.25 && deg<258.75){
return "WSW";
}else if (deg>258.75 && deg<281.25){
return "W";
}else if (deg>281.25 && deg<303.75){
return "WNW";
}else if (deg>303.75 && deg<326.25){
return "NW";
}else if (deg>326.25 && deg<348.75){
return "NNW";
}else{
return "N";
}
},
roundValue: function(temperature) {
return parseFloat(temperature).toFixed(1);
}

View File

@ -50,9 +50,17 @@ The following properties can be configured:
</tr>
<tr>
<td><code>units</code></td>
<td>What units to use?<br>
<br><b>Possible values:</b> <code>default</code> = Kelvin, <code>metric</code> = Celsius, <code>imperial</code> =Fahrenheit
<br><b>Default value:</b> <code>metric</code>
<td>What units to use. Specified by config.js<br>
<br><b>Possible values:</b> <code>config.units</code> = Specified by config.js, <code>default</code> = Kelvin, <code>metric</code> = Celsius, <code>imperial</code> =Fahrenheit
<br><b>Default value:</b> <code>config.units</code>
</td>
</tr>
<tr>
<td><code>maxNumberOfDays</code></td>
<td>How many days of forecast to return. Specified by config.js<br>
<br><b>Possible values:</b> <code>1</code> - <code>16</code>
<br><b>Default value:</b> <code>7</code> (7 days)
<br>This value is optional. By default the weatherforecast module will return 7 days.
</td>
</tr>
<tr>

View File

@ -13,7 +13,8 @@ Module.register("weatherforecast",{
defaults: {
location: "",
appid: "",
units: "metric",
units: config.units,
maxNumberOfDays: 7,
updateInterval: 10 * 60 * 1000, // every 10 minutes
animationSpeed: 1000,
timeFormat: config.timeFormat,
@ -189,6 +190,12 @@ Module.register("weatherforecast",{
params += "q=" + this.config.location;
params += "&units=" + this.config.units;
params += "&lang=" + this.config.lang;
/*
* Submit a specific number of days to forecast, between 1 to 16 days.
* The OpenWeatherMap API properly handles values outside of the 1 - 16 range and returns 7 days by default.
* This is simply being pedantic and doing it ourselves.
*/
params += "&cnt=" + (((this.config.maxNumberOfDays < 1) || (this.config.maxNumberOfDays > 16)) ? 7 : this.config.maxNumberOfDays);
params += "&APPID=" + this.config.appid;
return params;