mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-28 12:12:20 +00:00
Update compliments with support for cron type date/time for selections, addition to just date. (#3481)
> - What does the pull request accomplish? Use a list if needed. this change allows uses to configure date/time events for compliments.. also linked site that will build the cron entry.. and example was Happy hour in a pub, on fri/sat between 5 and 7 pm. or just after midnight on Halloween (Boooooo!) I also added testcases for #3478 (and added support for this in MMM-Config), with a custom, drop down selection list of the types.. ) | if this is approved I will update the module doc
This commit is contained in:
parent
974a1da9f0
commit
d9665b35df
@ -32,6 +32,7 @@ Thanks to: @btoconnor, @bugsounet, @JasonStieber, @khassel, @kleinmantara and @W
|
||||
|
||||
### Added
|
||||
|
||||
- [compliments] Added support for cron type date/time format entries.. mm hh DD MM dow (minutes/hours/days/months and day of week) see https://crontab.cronhub.io for construction
|
||||
- [calendar] Added config option "showEndsOnlyWithDuration" for default calendar
|
||||
- [compliments] Added `specialDayUnique` config option, defaults to `false` (#3465)
|
||||
- [weather] Provider weathergov: Use `precipitationLast3Hours` if `precipitationLastHour` is `null` (#3124)
|
||||
|
@ -1,3 +1,5 @@
|
||||
/* global Cron */
|
||||
|
||||
Module.register("compliments", {
|
||||
// Module config defaults.
|
||||
defaults: {
|
||||
@ -21,10 +23,12 @@ Module.register("compliments", {
|
||||
lastIndexUsed: -1,
|
||||
// Set currentweather from module
|
||||
currentWeatherType: "",
|
||||
|
||||
cron_regex: /^(((\d+,)+\d+|((\d+|[*])[/]\d+|((JAN|FEB|APR|MA[RY]|JU[LN]|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|APR|MA[RY]|JU[LN]|AUG|SEP|OCT|NOV|DEC))?))|(\d+-\d+)|\d+(-\d+)?[/]\d+(-\d+)?|\d+|[*]|(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?) ?){5}$/i,
|
||||
date_regex: "[1-9.][0-9.][0-9.]{2}-([0][1-9]|[1][0-2])-([1-2][0-9]|[0][1-9]|[3][0-1])",
|
||||
pre_defined_types: ["anytime", "morning", "afternoon", "evening"],
|
||||
// Define required scripts.
|
||||
getScripts () {
|
||||
return ["moment.js"];
|
||||
return ["croner.js", "moment.js"];
|
||||
},
|
||||
|
||||
// Define start sequence.
|
||||
@ -38,12 +42,46 @@ Module.register("compliments", {
|
||||
this.config.compliments = JSON.parse(response);
|
||||
this.updateDom();
|
||||
}
|
||||
|
||||
// Schedule update timer.
|
||||
let minute_sync_delay = 1;
|
||||
// loop thru all the configured when events
|
||||
for (let m of Object.keys(this.config.compliments)) {
|
||||
// if it is a cron entry
|
||||
if (this.isCronEntry(m)) {
|
||||
// we need to synch our interval cycle to the minute
|
||||
minute_sync_delay = (60 - (moment().second())) * 1000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Schedule update timer. sync to the minute start (if needed), so minute based events happen on the minute start
|
||||
setTimeout(() => {
|
||||
setInterval(() => {
|
||||
this.updateDom(this.config.fadeSpeed);
|
||||
}, this.config.updateInterval);
|
||||
},
|
||||
minute_sync_delay);
|
||||
},
|
||||
|
||||
// check to see if this entry could be a cron entry wich contains spaces
|
||||
isCronEntry (entry) {
|
||||
return entry.includes(" ");
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} cronExpression The cron expression. See https://croner.56k.guru/usage/pattern/
|
||||
* @param {Date} [timestamp] The timestamp to check. Defaults to the current time.
|
||||
* @returns {number} The number of seconds until the next cron run.
|
||||
*/
|
||||
getSecondsUntilNextCronRun (cronExpression, timestamp = new Date()) {
|
||||
// Required for seconds precision
|
||||
const adjustedTimestamp = new Date(timestamp.getTime() - 1000);
|
||||
|
||||
// https://www.npmjs.com/package/croner
|
||||
const cronJob = new Cron(cronExpression);
|
||||
const nextRunTime = cronJob.nextRun(adjustedTimestamp);
|
||||
|
||||
const secondsDelta = (nextRunTime - adjustedTimestamp) / 1000;
|
||||
return secondsDelta;
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate a random index for a list of compliments.
|
||||
@ -75,8 +113,9 @@ Module.register("compliments", {
|
||||
* @returns {string[]} array with compliments for the time of the day.
|
||||
*/
|
||||
complimentArray () {
|
||||
const hour = moment().hour();
|
||||
const date = moment().format("YYYY-MM-DD");
|
||||
const now = moment();
|
||||
const hour = now.hour();
|
||||
const date = now.format("YYYY-MM-DD");
|
||||
let compliments = [];
|
||||
|
||||
// Add time of day compliments
|
||||
@ -91,20 +130,49 @@ Module.register("compliments", {
|
||||
// Add compliments based on weather
|
||||
if (this.currentWeatherType in this.config.compliments) {
|
||||
Array.prototype.push.apply(compliments, this.config.compliments[this.currentWeatherType]);
|
||||
// if the predefine list doesn't include it (yet)
|
||||
if (!this.pre_defined_types.includes(this.currentWeatherType)) {
|
||||
// add it
|
||||
this.pre_defined_types.push(this.currentWeatherType);
|
||||
}
|
||||
}
|
||||
|
||||
// Add compliments for anytime
|
||||
Array.prototype.push.apply(compliments, this.config.compliments.anytime);
|
||||
|
||||
// Add compliments for special days
|
||||
for (let entry in this.config.compliments) {
|
||||
if (new RegExp(entry).test(date)) {
|
||||
// Only display compliments configured for the day if specialDayUnique is set to true
|
||||
// get the list of just date entry keys
|
||||
let temp_list = Object.keys(this.config.compliments).filter((k) => {
|
||||
if (this.pre_defined_types.includes(k)) return false;
|
||||
else return true;
|
||||
});
|
||||
|
||||
let date_compliments = [];
|
||||
// Add compliments for special day/times
|
||||
for (let entry of temp_list) {
|
||||
// check if this could be a cron type entry
|
||||
if (this.isCronEntry(entry)) {
|
||||
// make sure the regex is valid
|
||||
if (new RegExp(this.cron_regex).test(entry)) {
|
||||
// check if we are in the time range for the cron entry
|
||||
if (this.getSecondsUntilNextCronRun(entry, now.set("seconds", 0).toDate()) <= 1) {
|
||||
// if so, use its notice entries
|
||||
Array.prototype.push.apply(date_compliments, this.config.compliments[entry]);
|
||||
}
|
||||
} else Log.error(`compliments cron syntax invalid=${JSON.stringify(entry)}`);
|
||||
} else if (new RegExp(entry).test(date)) {
|
||||
Array.prototype.push.apply(date_compliments, this.config.compliments[entry]);
|
||||
}
|
||||
}
|
||||
|
||||
// if we found any date compliments
|
||||
if (date_compliments.length) {
|
||||
// and the special flag is true
|
||||
if (this.config.specialDayUnique) {
|
||||
// clear the non-date compliments if any
|
||||
compliments.length = 0;
|
||||
}
|
||||
Array.prototype.push.apply(compliments, this.config.compliments[entry]);
|
||||
}
|
||||
// put the date based compliments on the list
|
||||
Array.prototype.push.apply(compliments, date_compliments);
|
||||
}
|
||||
|
||||
return compliments;
|
||||
|
18
tests/configs/modules/compliments/compliments_cron_entry.js
Normal file
18
tests/configs/modules/compliments/compliments_cron_entry.js
Normal file
@ -0,0 +1,18 @@
|
||||
let config = {
|
||||
modules: [
|
||||
{
|
||||
module: "compliments",
|
||||
position: "middle_center",
|
||||
config: {
|
||||
specialDayUnique: true,
|
||||
compliments: {
|
||||
anytime: ["just a test"],
|
||||
"00-10 16-19 * * fri": ["just pub time"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== "undefined") { module.exports = config; }
|
@ -0,0 +1,18 @@
|
||||
let config = {
|
||||
modules: [
|
||||
{
|
||||
module: "compliments",
|
||||
position: "middle_center",
|
||||
config: {
|
||||
specialDayUnique: true,
|
||||
compliments: {
|
||||
anytime: ["just a test"],
|
||||
"* * * * *": ["anytime cron"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== "undefined") { module.exports = config; }
|
@ -77,5 +77,16 @@ describe("Compliments module", () => {
|
||||
await expect(doTest(["Special day message"])).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("cron type key", () => {
|
||||
beforeAll(async () => {
|
||||
await helpers.startApplication("tests/configs/modules/compliments/compliments_e2e_cron_entry.js");
|
||||
await helpers.getDocument();
|
||||
});
|
||||
|
||||
it("compliments array contains only special value", async () => {
|
||||
await expect(doTest(["anytime cron"])).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -43,5 +43,41 @@ describe("Compliments module", () => {
|
||||
await expect(doTest(["Happy new year!"])).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test only custom date events shown with new property", () => {
|
||||
it("shows 'Special day message' on May 6", async () => {
|
||||
await helpers.startApplication("tests/configs/modules/compliments/compliments_specialDayUnique_true.js", "06 May 2022 10:00:00 GMT");
|
||||
await expect(doTest(["Special day message"])).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test all date events shown without neww property", () => {
|
||||
it("shows 'any message' on May 6", async () => {
|
||||
await helpers.startApplication("tests/configs/modules/compliments/compliments_specialDayUnique_false.js", "06 May 2022 10:00:00 GMT");
|
||||
await expect(doTest(["Special day message", "Typical message 1", "Typical message 2", "Typical message 3"])).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test only custom cron date event shown with new property", () => {
|
||||
it("shows 'any message' on May 6", async () => {
|
||||
await helpers.startApplication("tests/configs/modules/compliments/compliments_cron_entry.js", "06 May 2022 17:03:00 GMT");
|
||||
await expect(doTest(["just pub time"])).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test any event shows after time window", () => {
|
||||
it("shows 'any message' on May 6", async () => {
|
||||
await helpers.startApplication("tests/configs/modules/compliments/compliments_cron_entry.js", "06 May 2022 17:11:00 GMT");
|
||||
await expect(doTest(["just a test"])).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test any event shows different day", () => {
|
||||
it("shows 'any message' on May 5", async () => {
|
||||
await helpers.startApplication("tests/configs/modules/compliments/compliments_cron_entry.js", "05 May 2022 17:00:00 GMT");
|
||||
await expect(doTest(["just a test"])).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
9
vendor/package-lock.json
generated
vendored
9
vendor/package-lock.json
generated
vendored
@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.5.2",
|
||||
"animate.css": "^4.1.1",
|
||||
"croner": "^8.0.2",
|
||||
"moment": "^2.30.1",
|
||||
"moment-timezone": "^0.5.45",
|
||||
"nunjucks": "^3.2.4",
|
||||
@ -50,6 +51,14 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/croner": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/croner/-/croner-8.0.2.tgz",
|
||||
"integrity": "sha512-HgSdlSUX8mIgDTTiQpWUP4qY4IFRMsduPCYdca34Pelt8MVdxdaDOzreFtCscA6R+cRZd7UbD1CD3uyx6J3X1A==",
|
||||
"engines": {
|
||||
"node": ">=18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||
|
1
vendor/package.json
vendored
1
vendor/package.json
vendored
@ -13,6 +13,7 @@
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.5.2",
|
||||
"animate.css": "^4.1.1",
|
||||
"croner": "^8.0.2",
|
||||
"moment": "^2.30.1",
|
||||
"moment-timezone": "^0.5.45",
|
||||
"nunjucks": "^3.2.4",
|
||||
|
3
vendor/vendor.js
vendored
3
vendor/vendor.js
vendored
@ -5,7 +5,8 @@ const vendor = {
|
||||
"weather-icons-wind.css": "node_modules/weathericons/css/weather-icons-wind.css",
|
||||
"font-awesome.css": "css/font-awesome.css",
|
||||
"nunjucks.js": "node_modules/nunjucks/browser/nunjucks.min.js",
|
||||
"suncalc.js": "node_modules/suncalc/suncalc.js"
|
||||
"suncalc.js": "node_modules/suncalc/suncalc.js",
|
||||
"croner.js": "node_modules/croner/dist/croner.umd.min.js"
|
||||
};
|
||||
|
||||
if (typeof module !== "undefined") {
|
||||
|
Loading…
x
Reference in New Issue
Block a user