mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-08-21 12:55:22 +00:00
Merge branch 'develop' into features/weather_forecast_and_forecast_daily_support
This commit is contained in:
@@ -33,8 +33,8 @@ Therefore **we highly recommend you to include the following information in your
|
||||
|
||||
- A high quality screenshot of your working module
|
||||
- A short, one sentence, clear description what it does (duh!)
|
||||
- What external API's it depend on, including web links to those
|
||||
- Wheteher the API/request require a key and the user limitations of those. (Is it free?)
|
||||
- What external API's it depends upon, including web links to those
|
||||
- Whether the API/request require a key and the user limitations of those. (Is it free?)
|
||||
|
||||
Surely this also help you get better recognition and feedback for your work.
|
||||
|
||||
@@ -46,8 +46,8 @@ A module can be placed in one single folder. Or multiple modules can be grouped
|
||||
|
||||
### Files
|
||||
- **modulename/modulename.js** - This is your core module script.
|
||||
- **modulename/node_helper.js** - This is an optional helper that will be loaded by the node script. The node helper and module script can communicate with each other using an intergrated socket system.
|
||||
- **modulename/public** - Any files in this folder can be accesed via the browser on `/modulename/filename.ext`.
|
||||
- **modulename/node_helper.js** - This is an optional helper that will be loaded by the node script. The node helper and module script can communicate with each other using an integrated socket system.
|
||||
- **modulename/public** - Any files in this folder can be accessed via the browser on `/modulename/filename.ext`.
|
||||
- **modulename/anyfileorfolder** Any other file or folder in the module folder can be used by the core module script. For example: *modulename/css/modulename.css* would be a good path for your additional module styles.
|
||||
|
||||
## The Core module file: modulename.js
|
||||
@@ -89,7 +89,7 @@ After the module is initialized, the module instance has a few available module
|
||||
| `this.data` | Object | The data object contain additional metadata about the module instance. (See below) |
|
||||
|
||||
|
||||
The `this.data` data object contain the follwoing metadata:
|
||||
The `this.data` data object contain the following metadata:
|
||||
- `data.classes` - The classes which are added to the module dom wrapper.
|
||||
- `data.file` - The filename of the core module file.
|
||||
- `data.path` - The path of the module folder.
|
||||
@@ -98,7 +98,7 @@ The `this.data` data object contain the follwoing metadata:
|
||||
|
||||
|
||||
#### `defaults: {}`
|
||||
Any properties defined in the defaults object, will be merged with the module config as defined in the user's config.js file. This is the best place to set your modules's configuration defaults. Any of the module configuration properties can be accessed using `this.config.propertyName`, but more about that later.
|
||||
Any properties defined in the defaults object, will be merged with the module config as defined in the user's config.js file. This is the best place to set your modules' configuration defaults. Any of the module configuration properties can be accessed using `this.config.propertyName`, but more about that later.
|
||||
|
||||
#### `requiresVersion:`
|
||||
|
||||
@@ -134,7 +134,7 @@ loaded: function(callback) {
|
||||
````
|
||||
|
||||
#### `start()`
|
||||
This method is called when all modules are loaded an the system is ready to boot up. Keep in mind that the dom object for the module is not yet created. The start method is a perfect place to define any additional module properties:
|
||||
This method is called when all modules are loaded and the system is ready to boot up. Keep in mind that the dom object for the module is not yet created. The start method is a perfect place to define any additional module properties:
|
||||
|
||||
**Example:**
|
||||
````javascript
|
||||
@@ -161,7 +161,7 @@ getScripts: 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.
|
||||
**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.
|
||||
|
||||
|
||||
#### `getStyles()`
|
||||
@@ -174,14 +174,14 @@ The getStyles method is called to request any additional stylesheets that need t
|
||||
getStyles: function() {
|
||||
return [
|
||||
'script.css', // will try to load it from the vendor folder, otherwise it will load is from the module folder.
|
||||
'font-awesome.css', // this file is available in the vendor folder, so it doesn't need to be avialable in the module folder.
|
||||
'font-awesome.css', // this file is available in the vendor folder, so it doesn't need to be available in the module folder.
|
||||
this.file('anotherfile.css'), // this file will be loaded straight from the module folder.
|
||||
'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css', // this file will be loaded from the bootstrapcdn servers.
|
||||
]
|
||||
}
|
||||
|
||||
````
|
||||
**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.
|
||||
**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**
|
||||
@@ -239,7 +239,7 @@ That MagicMirror core has the ability to send notifications to modules. Or even
|
||||
|
||||
- `notification` - String - The notification identifier.
|
||||
- `payload` - AnyType - The payload of a notification.
|
||||
- `sender` - Module - The sender of the notification. If this argument is `undefined`, the sender of the notififiction is the core system.
|
||||
- `sender` - Module - The sender of the notification. If this argument is `undefined`, the sender of the notification is the core system.
|
||||
|
||||
**Example:**
|
||||
````javascript
|
||||
@@ -346,7 +346,7 @@ Possible configurable options:
|
||||
- `lockString` - String - When setting lock string, the module can not be shown without passing the correct lockstring. This way (multiple) modules can prevent a module from showing. It's considered best practice to use your modules identifier as the locksString: `this.identifier`. See *visibility locking* below.
|
||||
|
||||
|
||||
**Note 1:** If the hide animation is canceled, for instance because the show method is called before the hide animation was finished, the callback will not be called.<br>
|
||||
**Note 1:** If the hide animation is cancelled, for instance because the show method is called before the hide animation was finished, the callback will not be called.<br>
|
||||
**Note 2:** If the hide animation is hijacked (an other method calls hide on the same module), the callback will not be called.<br>
|
||||
**Note 3:** If the dom is not yet created, the hide method won't work. Wait for the `DOM_OBJECTS_CREATED` [notification](#notificationreceivednotification-payload-sender).
|
||||
|
||||
@@ -371,7 +371,7 @@ Possible configurable options:
|
||||
|
||||
(*Introduced in version: 2.1.0.*)
|
||||
|
||||
Visiblity locking helps the module system to prevent unwanted hide/show actions. The following scenario explains the concept:
|
||||
Visibility locking helps the module system to prevent unwanted hide/show actions. The following scenario explains the concept:
|
||||
|
||||
**Module B asks module A to hide:**
|
||||
````javascript
|
||||
@@ -436,7 +436,7 @@ If no translation is found, a fallback will be used. The fallback sequence is as
|
||||
- 4. Translation as defined in core translation file of the fallback language (the first defined core translation file).
|
||||
- 5. The key (identifier) of the translation.
|
||||
|
||||
When adding translations to your module, it's a good idea to see if an apropriate translation is already available in the [core translation files](https://github.com/MichMich/MagicMirror/tree/master/translations). This way, your module can benefit from the existing translations.
|
||||
When adding translations to your module, it's a good idea to see if an appropriate translation is already available in the [core translation files](https://github.com/MichMich/MagicMirror/tree/master/translations). This way, your module can benefit from the existing translations.
|
||||
|
||||
**Example:**
|
||||
````javascript
|
||||
@@ -490,7 +490,7 @@ this.translate("RUNNING", {
|
||||
)}); // Will return a translated string for the identifier RUNNING, replacing `{timeUntilEnd}` with the contents of the variable `timeUntilEnd` in the order that translator intended. (has a fallback)
|
||||
````
|
||||
|
||||
**Example swedish .json file that does not have the variable in it:**
|
||||
**Example Swedish .json file that does not have the variable in it:**
|
||||
````javascript
|
||||
{
|
||||
"RUNNING": "Slutar",
|
||||
|
@@ -32,6 +32,7 @@ The following properties can be configured:
|
||||
| `defaultSymbol` | The default symbol. <br><br> **Possible values:** See [Font Awsome](http://fontawesome.io/icons/) website. <br> **Default value:** `calendar`
|
||||
| `maxTitleLength` | The maximum title length. <br><br> **Possible values:** `10` - `50` <br> **Default value:** `25`
|
||||
| `wrapEvents` | Wrap event titles to multiple lines. Breaks lines at the length defined by `maxTitleLength`. <br><br> **Possible values:** `true` or `false` <br> **Default value:** `false`
|
||||
| `maxTitleLines` | The maximum number of lines a title will wrap vertically before being cut (Only enabled if `wrapEvents` is also enabled). <br><br> **Possible values:** `0` - `10` <br> **Default value:** `3`
|
||||
| `fetchInterval` | How often does the content needs to be fetched? (Milliseconds) <br><br> **Possible values:** `1000` - `86400000` <br> **Default value:** `300000` (5 minutes)
|
||||
| `animationSpeed` | Speed of the update animation. (Milliseconds) <br><br> **Possible values:** `0` - `5000` <br> **Default value:** `2000` (2 seconds)
|
||||
| `fade` | Fade the future events to black. (Gradient) <br><br> **Possible values:** `true` or `false` <br> **Default value:** `true`
|
||||
|
@@ -19,6 +19,7 @@ Module.register("calendar", {
|
||||
defaultRepeatingCountTitle: "",
|
||||
maxTitleLength: 25,
|
||||
wrapEvents: false, // wrap events to multiple lines breaking at maxTitleLength
|
||||
maxTitleLines: 3,
|
||||
fetchInterval: 5 * 60 * 1000, // Update every 5 minutes.
|
||||
animationSpeed: 2000,
|
||||
fade: true,
|
||||
@@ -51,7 +52,7 @@ Module.register("calendar", {
|
||||
|
||||
// Define required scripts.
|
||||
getStyles: function () {
|
||||
return ["calendar.css", "font-awesome5.css", "font-awesome5.v4shims.css"];
|
||||
return ["calendar.css", "font-awesome.css"];
|
||||
},
|
||||
|
||||
// Define required scripts.
|
||||
@@ -220,7 +221,7 @@ Module.register("calendar", {
|
||||
var titleWrapper = document.createElement("td"),
|
||||
repeatingCountTitle = "";
|
||||
|
||||
if (this.config.displayRepeatingCountTitle) {
|
||||
if (this.config.displayRepeatingCountTitle && event.firstYear !== undefined) {
|
||||
|
||||
repeatingCountTitle = this.countTitleForUrl(event.url);
|
||||
|
||||
@@ -584,9 +585,10 @@ Module.register("calendar", {
|
||||
* @param {string} string Text string to shorten
|
||||
* @param {number} maxLength The max length of the string
|
||||
* @param {boolean} wrapEvents Wrap the text after the line has reached maxLength
|
||||
* @param {number} maxTitleLines The max number of vertical lines before cutting event title
|
||||
* @returns {string} The shortened string
|
||||
*/
|
||||
shorten: function (string, maxLength, wrapEvents) {
|
||||
shorten: function (string, maxLength, wrapEvents, maxTitleLines) {
|
||||
if (typeof string !== "string") {
|
||||
return "";
|
||||
}
|
||||
@@ -595,12 +597,21 @@ Module.register("calendar", {
|
||||
var temp = "";
|
||||
var currentLine = "";
|
||||
var words = string.split(" ");
|
||||
var line = 0;
|
||||
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
var word = words[i];
|
||||
if (currentLine.length + word.length < (typeof maxLength === "number" ? maxLength : 25) - 1) { // max - 1 to account for a space
|
||||
currentLine += (word + " ");
|
||||
} else {
|
||||
line++;
|
||||
if (line > maxTitleLines - 1) {
|
||||
if (i < words.length) {
|
||||
currentLine += "…";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentLine.length > 0) {
|
||||
temp += (currentLine + "<br>" + word + " ");
|
||||
} else {
|
||||
@@ -651,7 +662,7 @@ Module.register("calendar", {
|
||||
title = title.replace(needle, replacement);
|
||||
}
|
||||
|
||||
title = this.shorten(title, this.config.maxTitleLength, this.config.wrapEvents);
|
||||
title = this.shorten(title, this.config.maxTitleLength, this.config.wrapEvents, this.config.maxTitleLines);
|
||||
return title;
|
||||
},
|
||||
|
||||
|
78
modules/default/calendar/vendor/ical.js/ical.js
vendored
78
modules/default/calendar/vendor/ical.js/ical.js
vendored
@@ -80,16 +80,45 @@
|
||||
}
|
||||
}
|
||||
|
||||
var addTZ = function(dt, name, params){
|
||||
var addTZ = function(dt, params){
|
||||
var p = parseParams(params);
|
||||
|
||||
if (params && p){
|
||||
dt[name].tz = p.TZID
|
||||
if (params && p && dt){
|
||||
dt.tz = p.TZID
|
||||
}
|
||||
|
||||
return dt
|
||||
}
|
||||
|
||||
var parseTimestamp = function(val){
|
||||
//typical RFC date-time format
|
||||
var comps = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(Z)?$/.exec(val);
|
||||
if (comps !== null) {
|
||||
if (comps[7] == 'Z'){ // GMT
|
||||
return new Date(Date.UTC(
|
||||
parseInt(comps[1], 10),
|
||||
parseInt(comps[2], 10)-1,
|
||||
parseInt(comps[3], 10),
|
||||
parseInt(comps[4], 10),
|
||||
parseInt(comps[5], 10),
|
||||
parseInt(comps[6], 10 )
|
||||
));
|
||||
// TODO add tz
|
||||
} else {
|
||||
return new Date(
|
||||
parseInt(comps[1], 10),
|
||||
parseInt(comps[2], 10)-1,
|
||||
parseInt(comps[3], 10),
|
||||
parseInt(comps[4], 10),
|
||||
parseInt(comps[5], 10),
|
||||
parseInt(comps[6], 10)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var dateParam = function(name){
|
||||
return function(val, params, curr){
|
||||
|
||||
@@ -108,37 +137,24 @@
|
||||
comps[3]
|
||||
);
|
||||
|
||||
return addTZ(curr, name, params);
|
||||
curr[name] = addTZ(curr[name], params);
|
||||
return curr;
|
||||
}
|
||||
}
|
||||
|
||||
curr[name] = []
|
||||
val.split(',').forEach(function(val){
|
||||
var newDate = parseTimestamp(val);
|
||||
curr[name].push(addTZ(newDate, params));
|
||||
});
|
||||
|
||||
//typical RFC date-time format
|
||||
var comps = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(Z)?$/.exec(val);
|
||||
if (comps !== null) {
|
||||
if (comps[7] == 'Z'){ // GMT
|
||||
curr[name] = new Date(Date.UTC(
|
||||
parseInt(comps[1], 10),
|
||||
parseInt(comps[2], 10)-1,
|
||||
parseInt(comps[3], 10),
|
||||
parseInt(comps[4], 10),
|
||||
parseInt(comps[5], 10),
|
||||
parseInt(comps[6], 10 )
|
||||
));
|
||||
// TODO add tz
|
||||
} else {
|
||||
curr[name] = new Date(
|
||||
parseInt(comps[1], 10),
|
||||
parseInt(comps[2], 10)-1,
|
||||
parseInt(comps[3], 10),
|
||||
parseInt(comps[4], 10),
|
||||
parseInt(comps[5], 10),
|
||||
parseInt(comps[6], 10)
|
||||
);
|
||||
}
|
||||
if (curr[name].length === 0){
|
||||
delete curr[name];
|
||||
} else if (curr[name].length === 1){
|
||||
curr[name] = curr[name][0];
|
||||
}
|
||||
|
||||
return addTZ(curr, name, params)
|
||||
return curr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +164,11 @@
|
||||
if (date.exdates === undefined) {
|
||||
date.exdates = [];
|
||||
}
|
||||
date.exdates.push(date.exdate);
|
||||
if (Array.isArray(date.exdate)){
|
||||
date.exdates = date.exdates.concat(date.exdate);
|
||||
} else {
|
||||
date.exdates.push(date.exdate);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ Module.register("clock",{
|
||||
analogShowDate: "top", // options: false, 'top', or 'bottom'
|
||||
secondsColor: "#888888",
|
||||
timezone: null,
|
||||
autoTimezone: false
|
||||
},
|
||||
// Define required scripts.
|
||||
getScripts: function() {
|
||||
@@ -39,16 +40,31 @@ Module.register("clock",{
|
||||
start: function() {
|
||||
Log.info("Starting module: " + this.name);
|
||||
|
||||
// Schedule update interval.
|
||||
var self = this;
|
||||
setInterval(function() {
|
||||
self.updateDom();
|
||||
}, 1000);
|
||||
if (this.config.autoTimezone) {
|
||||
this.sendSocketNotification("AUTO_TIMEZONE");
|
||||
} else {
|
||||
// Schedule update interval.
|
||||
var self = this;
|
||||
setInterval(function() {
|
||||
self.updateDom();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// Set locale.
|
||||
moment.locale(config.language);
|
||||
|
||||
},
|
||||
|
||||
socketNotificationReceived: function (notification, payload) {
|
||||
if (notification === "UPDATE_TIMEZONE") {
|
||||
var self = this;
|
||||
self.config.timezone = payload.timezone;
|
||||
setInterval(function() {
|
||||
self.updateDom();
|
||||
}, 1000);
|
||||
}
|
||||
},
|
||||
|
||||
// Override dom generator.
|
||||
getDom: function() {
|
||||
|
||||
@@ -137,7 +153,8 @@ Module.register("clock",{
|
||||
clockCircle.style.backgroundSize = "100%";
|
||||
|
||||
// The following line solves issue: https://github.com/MichMich/MagicMirror/issues/611
|
||||
clockCircle.style.border = "1px solid black";
|
||||
// clockCircle.style.border = "1px solid black";
|
||||
clockCircle.style.border = "rgba(0, 0, 0, 0.1)"; //Updated fix for Issue 611 where non-black backgrounds are used
|
||||
|
||||
} else if (this.config.analogFace != "none") {
|
||||
clockCircle.style.border = "2px solid white";
|
||||
|
29
modules/default/clock/node_helper.js
Normal file
29
modules/default/clock/node_helper.js
Normal file
@@ -0,0 +1,29 @@
|
||||
var http = require("http");
|
||||
var NodeHelper = require("node_helper");
|
||||
|
||||
module.exports = NodeHelper.create({
|
||||
start: function () {
|
||||
},
|
||||
|
||||
socketNotificationReceived: function (notification, payload) {
|
||||
var self = this;
|
||||
|
||||
if (notification === "AUTO_TIMEZONE") {
|
||||
console.log("Loading timezone...");
|
||||
http.get("http://ip-api.com/json", function (req) {
|
||||
var data = "";
|
||||
req.on("data", function (d) {
|
||||
data += d;
|
||||
});
|
||||
req.on("end", function () {
|
||||
var body = JSON.parse(data);
|
||||
payload.timezone = body.timezone;
|
||||
self.sendSocketNotification("UPDATE_TIMEZONE", payload);
|
||||
});
|
||||
}).on("error", function () {
|
||||
payload.error = "Could not figure out the timezone.";
|
||||
self.sendSocketNotification("UPDATE_TIMEZONE", payload);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@@ -11,6 +11,7 @@ Module.register("currentweather",{
|
||||
|
||||
// Default module config.
|
||||
defaults: {
|
||||
autoLocation: false,
|
||||
location: false,
|
||||
locationID: false,
|
||||
appid: "",
|
||||
@@ -109,8 +110,19 @@ Module.register("currentweather",{
|
||||
this.weatherType = null;
|
||||
this.feelsLike = null;
|
||||
this.loaded = false;
|
||||
this.scheduleUpdate(this.config.initialLoadDelay);
|
||||
|
||||
if (this.config.autoLocation) {
|
||||
this.sendSocketNotification("AUTO_LOCATION");
|
||||
} else {
|
||||
this.scheduleUpdate(this.config.initialLoadDelay);
|
||||
}
|
||||
},
|
||||
|
||||
socketNotificationReceived: function (notification, payload) {
|
||||
if (notification === "UPDATE_LOCATION") {
|
||||
this.config.location = payload.location;
|
||||
this.scheduleUpdate(this.config.initialLoadDelay);
|
||||
}
|
||||
},
|
||||
|
||||
// add extra information of current weather
|
||||
@@ -198,16 +210,19 @@ Module.register("currentweather",{
|
||||
large.appendChild(weatherIcon);
|
||||
|
||||
var degreeLabel = "";
|
||||
if (this.config.degreeLabel) {
|
||||
switch (this.config.units ) {
|
||||
if (this.config.units === "metric" || this.config.units === "imperial") {
|
||||
degreeLabel += "°";
|
||||
}
|
||||
if(this.config.degreeLabel) {
|
||||
switch(this.config.units) {
|
||||
case "metric":
|
||||
degreeLabel = " °C";
|
||||
degreeLabel += "C";
|
||||
break;
|
||||
case "imperial":
|
||||
degreeLabel = " °F";
|
||||
degreeLabel += "F";
|
||||
break;
|
||||
case "default":
|
||||
degreeLabel = " K";
|
||||
degreeLabel += "K";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
29
modules/default/currentweather/node_helper.js
Normal file
29
modules/default/currentweather/node_helper.js
Normal file
@@ -0,0 +1,29 @@
|
||||
var http = require("http");
|
||||
var NodeHelper = require("node_helper");
|
||||
|
||||
module.exports = NodeHelper.create({
|
||||
start: function () {
|
||||
},
|
||||
|
||||
socketNotificationReceived: function (notification, payload) {
|
||||
var self = this;
|
||||
|
||||
if (notification === "AUTO_LOCATION") {
|
||||
console.log("Loading timezone...");
|
||||
http.get("http://ip-api.com/json", function (req) {
|
||||
var data = "";
|
||||
req.on("data", function (d) {
|
||||
data += d;
|
||||
});
|
||||
req.on("end", function () {
|
||||
var body = JSON.parse(data);
|
||||
payload.location = body.city + ", " + body.regionName;
|
||||
self.sendSocketNotification("UPDATE_LOCATION", payload);
|
||||
});
|
||||
}).on("error", function () {
|
||||
payload.error = "Could not figure out the timezone.";
|
||||
self.sendSocketNotification("UPDATE_LOCATION", payload);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@@ -2,7 +2,7 @@
|
||||
|
||||
This module is aimed to be the replacement for the current `currentweather` and `weatherforcast` modules. The module will be configurable to be used as a current weather view, or to show the forecast. This way the module can be used twice to fullfil both purposes.
|
||||
|
||||
The biggest cange is the use of weather providers. This way we are not bound to one API source. And users can choose which API they want to use as their source.
|
||||
The biggest change is the use of weather providers. This way we are not bound to one API source. And users can choose which API they want to use as their source.
|
||||
|
||||
The module is in a very early stage, and needs a lot of work. It's API isn't set in stone, so keep that in mind when you want to contribute.
|
||||
|
||||
@@ -71,6 +71,9 @@ The following properties can be configured:
|
||||
| `tableClass` | The class for the forecast table. <br><br> **Default value:** `'small'`
|
||||
| `colored` | If set to `true`, the min and max temperature are color coded. <br><br> **Default value:** `false`
|
||||
| `showRainAmount` | Show the amount of rain in the forecast <br><br> **Possible values:** `true` or `false` <br> **Default value:** `true`
|
||||
| `fade` | Fade the future events to black. (Gradient) <br><br> **Possible values:** `true` or `false` <br> **Default value:** `true`
|
||||
| `fadePoint` | Where to start fade? <br><br> **Possible values:** `0` (top of the list) - `1` (bottom of list) <br> **Default value:** `0.25`
|
||||
| `maxNumberOfDays` | How many days of forecast to return. Specified by config.js <br><br> **Possible values:** `1` - `16` <br> **Default value:** `5` (5 days) <br> This value is optional. By default the weatherforecast module will return 5 days.
|
||||
|
||||
### Openweathermap options
|
||||
|
||||
|
@@ -65,9 +65,9 @@
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="dimmed light small">
|
||||
{{ "LOADING" | translate }}
|
||||
{{ "LOADING" | translate | safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Unclomment the line below to see the contents of the `current` object. -->
|
||||
<!-- Uncomment the line below to see the contents of the `current` object. -->
|
||||
<!-- <div style="word-wrap:break-word" class="xsmall dimmed">{{current | dump}}</div> -->
|
||||
|
@@ -1,7 +1,10 @@
|
||||
{% if forecast %}
|
||||
{% set numSteps = forecast | calcNumSteps %}
|
||||
{% set currentStep = 0 %}
|
||||
<table class="{{ config.tableClass }}">
|
||||
{% set forecast = forecast.slice(0, numSteps) %}
|
||||
{% for f in forecast %}
|
||||
<tr {% if config.colored %}class="colored"{% endif %}>
|
||||
<tr {% if config.colored %}class="colored"{% endif %} {% if config.fade %}style="opacity: {{ currentStep | opacity(numSteps) }};"{% endif %}>
|
||||
<td class="day">{{ f.date.format('ddd') }}</td>
|
||||
<td class="bright weather-icon"><span class="wi weathericon wi-{{ f.weatherType }}"></span></td>
|
||||
<td class="align-right bright max-temp">
|
||||
@@ -16,13 +19,14 @@
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% set currentStep = currentStep + 1 %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="dimmed light small">
|
||||
{{ "LOADING" | translate }}
|
||||
{{ "LOADING" | translate | safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Unclomment the line below to see the contents of the `current` object. -->
|
||||
<!-- Uncomment the line below to see the contents of the `current` object. -->
|
||||
<!-- <div style="word-wrap:break-word" class="xsmall dimmed">{{forecast | dump}}</div> -->
|
||||
|
@@ -33,6 +33,9 @@ Module.register("weather",{
|
||||
decimalSymbol: ".",
|
||||
showIndoorTemperature: false,
|
||||
showIndoorHumidity: false,
|
||||
maxNumberOfDays: 5,
|
||||
fade: true,
|
||||
fadePoint: 0.25, // Start on 1/4th of the list.
|
||||
|
||||
initialLoadDelay: 0, // 0 seconds delay
|
||||
retryDelay: 2500,
|
||||
@@ -59,7 +62,7 @@ Module.register("weather",{
|
||||
return ["font-awesome.css", "weather-icons.css", "weather.css"];
|
||||
},
|
||||
|
||||
// Return the scripts that are nessecery for the weather module.
|
||||
// Return the scripts that are necessary for the weather module.
|
||||
getScripts: function () {
|
||||
return [
|
||||
"moment.js",
|
||||
@@ -215,7 +218,28 @@ Module.register("weather",{
|
||||
}.bind(this));
|
||||
|
||||
this.nunjucksEnvironment().addFilter("decimalSymbol", function(value) {
|
||||
return value.replace(/\./g, this.config.decimalSymbol);
|
||||
return value.toString().replace(/\./g, this.config.decimalSymbol);
|
||||
}.bind(this));
|
||||
|
||||
this.nunjucksEnvironment().addFilter("calcNumSteps", function(forecast) {
|
||||
return Math.min(forecast.length, this.config.maxNumberOfDays);
|
||||
}.bind(this));
|
||||
|
||||
this.nunjucksEnvironment().addFilter("opacity", function(currentStep, numSteps) {
|
||||
if (this.config.fade && this.config.fadePoint < 1) {
|
||||
if (this.config.fadePoint < 0) {
|
||||
this.config.fadePoint = 0;
|
||||
}
|
||||
var startingPoint = numSteps * this.config.fadePoint;
|
||||
var numFadesteps = numSteps - startingPoint;
|
||||
if (currentStep >= startingPoint) {
|
||||
return 1 - (currentStep - startingPoint) / numFadesteps;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
});
|
||||
|
29
modules/default/weatherforecast/node_helper.js
Normal file
29
modules/default/weatherforecast/node_helper.js
Normal file
@@ -0,0 +1,29 @@
|
||||
var http = require("http");
|
||||
var NodeHelper = require("node_helper");
|
||||
|
||||
module.exports = NodeHelper.create({
|
||||
start: function () {
|
||||
},
|
||||
|
||||
socketNotificationReceived: function (notification, payload) {
|
||||
var self = this;
|
||||
|
||||
if (notification === "AUTO_LOCATION") {
|
||||
console.log("Loading timezone...");
|
||||
http.get("http://ip-api.com/json", function (req) {
|
||||
var data = "";
|
||||
req.on("data", function (d) {
|
||||
data += d;
|
||||
});
|
||||
req.on("end", function () {
|
||||
var body = JSON.parse(data);
|
||||
payload.location = body.city + ", " + body.regionName;
|
||||
self.sendSocketNotification("UPDATE_LOCATION", payload);
|
||||
});
|
||||
}).on("error", function () {
|
||||
payload.error = "Could not figure out the timezone.";
|
||||
self.sendSocketNotification("UPDATE_LOCATION", payload);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@@ -11,6 +11,7 @@ Module.register("weatherforecast",{
|
||||
|
||||
// Default module config.
|
||||
defaults: {
|
||||
autoLocation: false,
|
||||
location: false,
|
||||
locationID: false,
|
||||
appid: "",
|
||||
@@ -95,10 +96,20 @@ Module.register("weatherforecast",{
|
||||
|
||||
this.forecast = [];
|
||||
this.loaded = false;
|
||||
this.scheduleUpdate(this.config.initialLoadDelay);
|
||||
|
||||
this.updateTimer = null;
|
||||
|
||||
if (this.config.autoLocation) {
|
||||
this.sendSocketNotification("AUTO_LOCATION");
|
||||
} else {
|
||||
this.scheduleUpdate(this.config.initialLoadDelay);
|
||||
}
|
||||
},
|
||||
|
||||
socketNotificationReceived: function (notification, payload) {
|
||||
if (notification === "UPDATE_LOCATION") {
|
||||
this.config.location = payload.location;
|
||||
this.scheduleUpdate(this.config.initialLoadDelay);
|
||||
}
|
||||
},
|
||||
|
||||
// Override dom generator.
|
||||
@@ -143,16 +154,19 @@ Module.register("weatherforecast",{
|
||||
iconCell.appendChild(icon);
|
||||
|
||||
var degreeLabel = "";
|
||||
if (this.config.units === "metric" || this.config.units === "imperial") {
|
||||
degreeLabel += "°";
|
||||
}
|
||||
if(this.config.scale) {
|
||||
switch(this.config.units) {
|
||||
case "metric":
|
||||
degreeLabel = " °C";
|
||||
degreeLabel += "C";
|
||||
break;
|
||||
case "imperial":
|
||||
degreeLabel = " °F";
|
||||
degreeLabel += "F";
|
||||
break;
|
||||
case "default":
|
||||
degreeLabel = " K";
|
||||
degreeLabel = "K";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user