Compare commits

...

189 Commits

Author SHA1 Message Date
Michael Teeuw
30d5bfe59e Merge pull request #2873 from MichMich/develop
v2.20.0
2022-07-02 13:07:02 +02:00
Michael Teeuw
b716ec33d9 Release v2.20.0 2022-07-02 13:00:01 +02:00
Michael Teeuw
e25209d9f9 Merge pull request #2871 from sdetweil/fix_maxEntries
Fix maximumEntries regression
2022-06-28 15:26:31 +02:00
Sam Detweiler
1f4ac82495 add changelog for #2868 2022-06-28 08:05:13 -05:00
Sam Detweiler
0baf58f3fd fix regression calendar.maximumEntries not used 2022-06-28 08:01:28 -05:00
Michael Teeuw
9a769203e3 Merge pull request #2870 from khassel/update_deps 2022-06-25 10:33:18 +02:00
Karsten Hassel
1435efaea7 update depencies (before upcoming new release) 2022-06-24 23:44:17 +02:00
Michael Teeuw
c411ac821e Merge pull request #2864 from KristjanESPERANTO/develop
Use .yaml instead of .yml
2022-06-17 15:34:21 +02:00
Michael Teeuw
da0489fc0c Merge pull request #2866 from kolbyjack/broadcast-duplicate-events
Include duplicate events in broadcasts
2022-06-17 15:32:17 +02:00
Jonathan Kolb
c82de1e314 Group filters that only apply when limiting for display 2022-06-09 09:21:00 -04:00
Jonathan Kolb
604a555e14 Include duplicate events in broadcasts 2022-06-09 07:52:29 -04:00
Kristjan SCHMIDT
87e011ff96 Add entry for YAML file extention 2022-06-07 00:07:56 +02:00
Kristjan SCHMIDT
9b2051827c Use .yaml instead of .yml
This is the recommended file extension: https://yaml.org/faq.html
2022-06-06 23:57:52 +02:00
Michael Teeuw
47aefb0c82 Merge pull request #2858 from turrisxyz/Pinned-Dependencies-GitHub
chore: Set permissions for GitHub actions
2022-06-04 14:59:28 +02:00
Michael Teeuw
70da1d6f5c Merge pull request #2861 from turrisxyz/Dependabot-GitHub-Actions
chore: Included githubactions in the dependabot config
2022-06-04 14:59:14 +02:00
Michael Teeuw
c0743ce9de Merge pull request #2857 from khassel/fetch 2022-06-04 14:14:52 +02:00
naveen
fe7b4044e0 chore: Included githubactions in the dependabot config
This should help with keeping the GitHub actions updated on new releases. This will also help with keeping it secure.

Dependabot helps in keeping the supply chain secure https://docs.github.com/en/code-security/dependabot

GitHub actions up to date https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot

https://github.com/ossf/scorecard/blob/main/docs/checks.md#dependency-update-tool
Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com>
2022-06-02 01:29:42 +00:00
nathannaveen
701ce8ad47 chore: Set permissions for GitHub actions
Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much.

- Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions

https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs

[Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>
2022-05-30 00:58:20 +00:00
Karsten Hassel
591f907134 fix newsfeedfetcher using correct stream version (changed with node-18-fetch) 2022-05-28 22:28:37 +02:00
Michael Teeuw
4f1db749c0 Merge pull request #2855 from khassel/fetch 2022-05-28 06:38:52 +02:00
Karsten Hassel
ae72ed8c67 improve startApplication 2022-05-27 21:49:29 +02:00
Karsten Hassel
ab7934fa98 Merge branch 'develop' into fetch
# Conflicts:
#	CHANGELOG.md
2022-05-27 21:04:07 +02:00
Michael Teeuw
a4c77f0c9e Merge pull request #2853 from khassel/update_deps 2022-05-27 20:32:45 +02:00
Karsten Hassel
0023c64d59 use internal fetch function of node instead external node-fetch library if node version >= v18 2022-05-27 19:46:28 +02:00
Karsten Hassel
b55b3bd63b update dependencies including electron to v19 2022-05-24 23:50:33 +02:00
Michael Teeuw
cbda20f67e Merge pull request #2850 from khassel/iframe
added a new config option `httpHeaders` used by helmet
2022-05-18 09:15:32 +02:00
Michael Teeuw
e598dbb206 Merge branch 'develop' into iframe 2022-05-18 09:15:16 +02:00
Michael Teeuw
094881fc5c Merge pull request #2848 from rejas/issue_2192
Show endDate for calendar events when using dateHeaders
2022-05-18 09:14:36 +02:00
Michael Teeuw
b13414cab8 Merge branch 'develop' into issue_2192 2022-05-18 09:14:29 +02:00
Michael Teeuw
3e65ac653b Merge pull request #2844 from rejas/actions
Update github actions
2022-05-18 09:13:40 +02:00
Michael Teeuw
05621c9876 Merge branch 'develop' into actions 2022-05-18 09:13:31 +02:00
Michael Teeuw
938619ce0c Merge pull request #2843 from khassel/update-deps
update dependencies
2022-05-18 09:12:59 +02:00
Michael Teeuw
8e5267d44f Merge pull request #2842 from MMRIZE/weather
Added outgoing notification of the weather module
2022-05-18 09:12:48 +02:00
Karsten Hassel
3b55886c45 added a new config option httpHeaders used by helmet 2022-05-13 22:29:43 +02:00
rejas
ed3aceb427 Update CHANGELOG 2022-05-10 21:44:46 +02:00
rejas
c3b2aaec69 Show endDate for calendar events
when dateHeader is enabled and showEnd is set to true
2022-05-10 21:44:39 +02:00
veeck
bb1d3431cc Update node test matrix for real 2022-05-02 22:35:03 +02:00
veeck
fe83fe338a Update CHANGELOG 2022-05-02 22:02:20 +02:00
veeck
6504b5e818 Update github actions and tested node versions 2022-05-02 22:01:26 +02:00
Karsten Hassel
8578900bfb update deps 2022-05-02 21:50:16 +02:00
Michael Teeuw
d730dd04bf Merge pull request #2839 from rohitdharavath/patch-1 2022-04-26 20:46:38 +02:00
eouia
1d90c5e1fe Add JSDoc description 2022-04-26 17:37:23 +02:00
eouia
0f39b7733c fix typo jsdom tag returns 2022-04-26 14:57:47 +02:00
eouia
038b6765e7 Change property name clearly 2022-04-26 14:52:05 +02:00
eouia
58569a648c Added ECMA Version of lint to 2020 2022-04-26 14:51:12 +02:00
eouia
df0f048ecc Added outgoing notification 2022-04-26 13:55:39 +02:00
Rohith Dharavath
288a008e72 Update electron.js
corrected spelling mistake
2022-04-21 01:53:22 +05:30
Michael Teeuw
439690b981 Merge pull request #2836 from khassel/fix-non-latin 2022-04-09 19:18:17 +02:00
Karsten Hassel
b4e75f6844 fix problems with non latin fonds caused by updating to fontsource (fixes #2835). 2022-04-05 20:58:48 +02:00
Michael Teeuw
3f6a5a7772 Prepare 2.20.0-develop 2022-04-01 20:49:47 +02:00
Michael Teeuw
a2d7cdcfb4 Merge pull request #2834 from MichMich/develop
Release v2.19.0
2022-04-01 20:43:39 +02:00
Michael Teeuw
d995ce38ea Add missing contributor to list. 2022-04-01 20:39:22 +02:00
Michael Teeuw
0b21a22027 Prepare 2.19.0 2022-04-01 20:36:55 +02:00
Michael Teeuw
111d75b351 Merge pull request #2832 from khassel/disable-gpu
Add env var to disable gpu under electron when set
2022-04-01 20:34:15 +02:00
Michael Teeuw
b54cac72ec Merge branch 'develop' into disable-gpu 2022-04-01 20:30:01 +02:00
Michael Teeuw
69b2dd698c Merge pull request #2819 from krekos/patch-1
Add missing CS translations
2022-04-01 20:29:13 +02:00
Michael Teeuw
16bf19d115 Merge branch 'patch-1' of https://github.com/krekos/magicmirror into pr/krekos/2819 2022-04-01 20:24:04 +02:00
Michael Teeuw
c57c9c2a8f Run Prettier. 2022-04-01 20:21:46 +02:00
Michael Teeuw
9f750e5980 Add Changelog. 2022-04-01 20:20:43 +02:00
Krekos
8d296e563d Add missing CS translations 2022-04-01 20:18:54 +02:00
Karsten Hassel
88f7570caf add comments in electron.js 2022-03-29 21:24:17 +02:00
Karsten Hassel
00a7c6b5be added new env var ELECTRON_DISABLE_GPU which disable gpu under electron if set (fixes #2831). 2022-03-29 20:41:36 +02:00
Michael Teeuw
612b06346d Merge pull request #2829 from sdetweil/calfix 2022-03-29 19:55:20 +02:00
Michael Teeuw
9620566fbb Merge pull request #2830 from khassel/node-ical 2022-03-29 19:54:48 +02:00
Karsten Hassel
ed65c70a36 update node-ical to v0.15 and added luxon as dependency for not breaking the "no-optional" install (see #2718 and #2824). 2022-03-28 19:41:41 +02:00
Sam Detweiler
cdd87436be fix fullday/showend conflict #2629 2022-03-27 09:16:25 -05:00
Michael Teeuw
a143ebc8e0 Merge pull request #2827 from shin10/develop 2022-03-26 15:21:40 +01:00
Michael Trenkler
93581ca4d9 toggle pointer-events with suspension 2022-03-26 15:15:21 +01:00
Michael Teeuw
c5e9c9a683 Merge pull request #2825 from rejas/issue_2812 2022-03-22 21:41:55 +01:00
veeck
1bdab10872 Update dependencies 2022-03-22 21:29:49 +01:00
veeck
eca339ad60 Fix weird code in weathergov, still returns no data though 2022-03-22 21:11:44 +01:00
veeck
af5eb3447f Update CHANGELOG 2022-03-22 20:49:07 +01:00
rejas
b72cb52a71 Remove windspeed conversion from openweathermap 2022-03-22 20:46:15 +01:00
Michael Teeuw
d0565a15d3 Merge pull request #2820 from KristjanESPERANTO/german 2022-03-12 19:49:45 +01:00
Kristjan SCHMIDT
468bf1d6a0 Update German translation
- Remove unnecessary HTML Entities
- Completion of missing translations
- Rewordings
- Corrections of typography mistakes
2022-03-12 13:03:14 +01:00
Krekos
1d2637c980 Add missing CS translations 2022-03-12 12:21:20 +01:00
Michael Teeuw
a52c68d852 Merge pull request #2809 from Nerfzooka/patch-1
Revive contribution link
2022-03-11 15:46:16 +01:00
Michael Teeuw
e12f57d872 Merge pull request #2815 from 10bias/weather-provider-weatherflow
Weather provider weatherflow
2022-03-11 15:43:22 +01:00
Michael Teeuw
5def02ff7f Merge pull request #2810 from philnagel/weatherModule-weathergov-feelsLikeFix
fix parsing of feels like for weathergov
2022-03-11 15:39:11 +01:00
Michael Teeuw
7cab6eb680 Merge branch 'develop' into patch-1 2022-03-11 15:38:08 +01:00
Michael Teeuw
dcaa3526a4 Merge pull request #2817 from khassel/update_deps
Update dependencies
2022-03-11 15:36:43 +01:00
Michael Teeuw
2a989bc235 Merge pull request #2818 from kolbyjack/fix/changing-start-date
Don't adjust startDate for full day events if endDate is in the past
2022-03-11 15:36:25 +01:00
Jon Kolb
d588fab981 Don't adjust startDate for full day events if endDate is in the past 2022-03-02 22:09:15 -05:00
Karsten Hassel
9cb006b871 update dependencies 2022-02-28 23:08:56 +01:00
tobias
9056abaf4a add function to switch units 2022-02-26 11:09:41 +01:00
tobias
3c27fd10b6 fix a problem with sunrise 2022-02-25 18:30:01 +01:00
tobias
4048d79fc5 run lint:prettier 2022-02-22 11:14:28 +01:00
tobias
212e60c12d fix copy and paste mistake in comment 2022-02-22 11:12:17 +01:00
tobias
45142bc1bc updated the changelog 2022-02-21 14:58:48 +01:00
tobias
e791a663c8 add weatherprovider for weatherflow 2022-02-21 14:54:35 +01:00
Michael Teeuw
81ae95eba7 Merge pull request #2814 from KristjanESPERANTO/patch-2 2022-02-20 12:18:21 +01:00
Kristjan ESPERANTO
7ca5d81123 Update CHANGELOG.md 2022-02-20 02:30:47 +01:00
Kristjan ESPERANTO
e234d2379b Fix log output
Before:
```
MMM-OlympicGames - Load translationfalse: translations/de.json
translator.js:107 MMM-OlympicGames - Load translation  fallback: translations/en.json
```

After:
```
MMM-OlympicGames - Load translation: translations/de.json
translator.js:107 MMM-OlympicGames - Load translation fallback: translations/en.json
```
2022-02-20 02:24:22 +01:00
philna
d0838d53c2 fix parsing of feels like for weathergov 2022-02-08 21:07:08 -06:00
Michael Teeuw
880e2160a3 Merge pull request #2808 from KristjanESPERANTO/min-node-version-14 2022-02-07 09:41:36 +01:00
Nerfzooka
c214d776df Revive contribution link
Not sure if this is the contribution page that was intended, but the old link was pretty dead (https://docs.magicmirror.builders/getting-started/contributing.html).
2022-02-04 13:33:20 -05:00
Michael Teeuw
0a8220ca52 Merge pull request #2806 from khassel/update_deps
update to electron v17 and other deps
2022-02-02 09:08:59 +01:00
Michael Teeuw
b0c57272c2 Merge branch 'develop' into update_deps 2022-02-02 09:08:47 +01:00
Michael Teeuw
fbdebcae8a Merge pull request #2807 from KristjanESPERANTO/develop
Update Danish translation
2022-02-02 09:03:16 +01:00
Michael Teeuw
8e376deaaa Merge branch 'develop' into develop 2022-02-02 09:03:01 +01:00
Kristjan SCHMIDT
2d353ffa35 Minimal node version is 14
This was probably overseen in #2746
2022-02-02 01:47:04 +01:00
Kristjan SCHMIDT
b70a9c36fa Begin with capital letters 2022-02-02 00:48:50 +01:00
Kristjan SCHMIDT
c98967cb1e Update Danish translation 2022-02-02 00:46:05 +01:00
Kristjan SCHMIDT
05f0d1855c Update Danish translation
Translation from @The-Exterminator #2805
2022-02-01 23:51:01 +01:00
Karsten Hassel
cee5043625 update to electron v17 and other deps 2022-02-01 20:07:18 +01:00
Michael Teeuw
528358f3c3 Merge pull request #2795 from oscarb/patch-1 2022-01-28 11:23:15 +01:00
Michael Teeuw
da90412cea Merge pull request #2798 from khassel/cors 2022-01-28 11:22:43 +01:00
Michael Teeuw
e794aab012 Merge pull request #2799 from KristjanESPERANTO/develop 2022-01-28 11:21:50 +01:00
Michael Teeuw
69daf14ffd Merge pull request #2800 from khassel/update_deps 2022-01-28 11:21:14 +01:00
Karsten Hassel
afa6c4270d update dependencies including electron v17 beta 2022-01-27 22:05:33 +01:00
Kristjan SCHMIDT
be22309e45 Undo minor change: Version 1.0.0 wasn't MagicMirror² 2022-01-26 23:54:20 +01:00
Kristjan SCHMIDT
6f27e5ae07 MagicMirror -> MagicMirror² 2022-01-26 23:47:51 +01:00
Kristjan SCHMIDT
7e79547973 Add "Using a consistent spelling of MagicMirror²." 2022-01-26 23:16:22 +01:00
Kristjan SCHMIDT
a5668b1b99 Magic Mirror -> MagicMirror²
Consistent spelling
2022-01-26 23:09:26 +01:00
Karsten Hassel
f04dd6b6cd introduce useCorsProxy, per default only enabled for darksky and envcanada 2022-01-26 22:44:20 +01:00
Karsten Hassel
9f9c17ea8a increase test timeout to 20 sec. 2022-01-26 00:38:34 +01:00
Karsten Hassel
48845ab60e Merge branch 'develop' into cors
# Conflicts:
#	CHANGELOG.md
2022-01-26 00:31:02 +01:00
Karsten Hassel
59bc2318f8 fix weather tests and add CHANGELOG 2022-01-26 00:29:01 +01:00
Karsten Hassel
c622db918b working version, use corsUrl in weather providers 2022-01-25 23:42:42 +01:00
Michael Teeuw
4b381f33b5 Merge pull request #2794 from khassel/newsfeed-title-url
Newsfeed module: Add option to display title as url
2022-01-25 14:24:22 +01:00
Karsten Hassel
7cfc7b9d74 first cors approach 2022-01-25 00:43:57 +01:00
Oscar Björkman
7f52f9bcf2 Fix broken link to contribution guidelines 2022-01-23 01:55:56 +01:00
Karsten Hassel
c4e7e42cdd added new config option showTitleAsUrl to newsfeed module 2022-01-22 23:34:57 +01:00
Michael Teeuw
d181365620 Merge pull request #2788 from khassel/husky 2022-01-19 20:04:41 +01:00
Michael Teeuw
97b474665a Merge pull request #2787 from kolbyjack/broadcast_all_events 2022-01-19 20:03:49 +01:00
Karsten Hassel
284b01c524 husky changes 2022-01-17 21:39:21 +01:00
Jon Kolb
e3857ca0f4 Address review feedback 2022-01-17 10:48:16 -05:00
Jonathan Kolb
0aee42255f Return full list of events from createEventList for broadcasting 2022-01-17 10:07:12 -05:00
Michael Teeuw
fcb0d33e29 Merge pull request #2774 from khassel/remove-old-weather-modules 2022-01-14 23:11:12 +01:00
Karsten Hassel
3a761f2082 change link color to white 2022-01-14 22:54:42 +01:00
Karsten Hassel
ed0ad7b988 use fake modules instead 2022-01-14 22:16:07 +01:00
Karsten Hassel
c392b5a661 Merge branch 'develop' into remove-old-weather-modules
# Conflicts:
#	modules/default/currentweather/currentweather.js
2022-01-14 22:07:21 +01:00
Michael Teeuw
766848eea3 Merge pull request #2776 from SiderealArt/patch-1
Update zh-tw translation
2022-01-14 10:22:20 +01:00
Michael Teeuw
7ede537d1b Fix prettier issues. 2022-01-14 10:00:14 +01:00
Michael Teeuw
ec38f90662 Merge remote-tracking branch 'origin/develop' into pr/SiderealArt/2776 2022-01-14 09:58:05 +01:00
Michael Teeuw
d793b82d51 Merge pull request #2784 from khassel/e2e-tests 2022-01-14 07:10:26 +01:00
Michael Teeuw
aafeb1e875 Merge pull request #2785 from khassel/helmet-fix 2022-01-14 07:09:30 +01:00
Karsten Hassel
480c10b239 fix helmet, use defaults from v4 2022-01-14 00:05:08 +01:00
Karsten Hassel
82bb2544de add CHANGELOG and fix weather_spec 2022-01-13 22:46:10 +01:00
Karsten Hassel
b714abd9a0 Merge branch 'develop' into e2e-tests 2022-01-13 22:35:26 +01:00
Karsten Hassel
c1be0180f9 change weather_spec 2022-01-13 22:33:57 +01:00
Karsten Hassel
2cfafe7bfe improve waitForElement 2022-01-13 21:52:47 +01:00
Michael Teeuw
da8edbfdc1 Merge pull request #2783 from JHWelch/update-urls
Update urls
2022-01-13 09:44:07 +01:00
Jordan Welch
54bcbbc1de Update contribution link to active URL 2022-01-12 20:36:35 -06:00
Jordan Welch
5463183e01 Update config introduction to active URL. 2022-01-12 20:35:25 -06:00
Karsten Hassel
42b80b18f8 testing wait alternatives 2022-01-13 00:50:15 +01:00
Michael Teeuw
65fada7ef1 Merge pull request #2771 from CFenner/patch-1 2022-01-12 20:50:09 +01:00
Christopher Fenner
9e4997aa81 Merge branch 'develop' into patch-1 2022-01-12 20:39:09 +01:00
Michael Teeuw
e8c6ef945a Merge pull request #2782 from khassel/helmet 2022-01-12 20:18:01 +01:00
Karsten Hassel
14a22efae1 Merge branch 'develop' into helmet 2022-01-12 20:07:20 +01:00
Michael Teeuw
f7f0bc8681 Merge pull request #2780 from Tom-Hirschberger/develop 2022-01-12 19:52:07 +01:00
Michael Teeuw
9cb8a135e6 Merge pull request #2778 from khassel/roboto 2022-01-12 19:47:34 +01:00
Michael Teeuw
a02bce6517 Merge pull request #2766 from k1rd3rf/patch-1 2022-01-12 19:46:22 +01:00
Karsten Hassel
9604c3a187 helmet upgrade to v5 2022-01-11 21:51:09 +01:00
Tom Hirschberger
1ba4213910 set the hidden class by classList features instead of string manipulation now 2022-01-11 15:54:45 +01:00
Tom Hirschberger
6c63fac240 updated changelog 2022-01-11 15:52:56 +01:00
Tom Hirschberger
b3dd531abb removed adding of shown class 2022-01-11 15:52:00 +01:00
Tom Hirschberger
4ce42d4f70 added shown/hidden class feature to CHANGELOG 2022-01-11 15:25:37 +01:00
Tom Hirschberger
4325fcdca2 automatically add/remove a hidden/shown class to the module wrappers if they get hidden or shown 2022-01-11 15:20:33 +01:00
SiderealArt
8cf9d5f3ed Update CHANGELOG.md 2022-01-11 09:01:24 +08:00
Karsten Hassel
8cb6015930 refactor tests 2022-01-10 23:27:53 +01:00
Karsten Hassel
f3cefde7cb update deps and add CHANGELOG 2022-01-10 22:42:07 +01:00
SiderealArt
92fcdde60d Update zh-tw translation 2022-01-10 17:33:12 +08:00
Karsten Hassel
2dcf55ea89 change from deprecated roboto-fontface to @fontsource 2022-01-09 16:17:38 +01:00
Christopher Fenner
8537f40f1d Update calendar.js 2022-01-09 11:25:03 +01:00
Christopher Fenner
8417590893 update test case 2022-01-09 11:10:00 +01:00
Christopher Fenner
4c43f5db15 use alternative calendar icon 2022-01-09 08:38:48 +01:00
Karsten Hassel
eb32ec89b4 remove old weather modules 2022-01-08 23:08:41 +01:00
Michael Teeuw
ad66c02735 Merge pull request #2773 from khassel/weather-test-absolute 2022-01-08 07:12:35 +01:00
Karsten Hassel
e8c0611db4 increase test timeout 2022-01-07 22:00:31 +01:00
Karsten Hassel
7fa54642e1 Merge branch 'develop' into weather-test-absolute
# Conflicts:
#	CHANGELOG.md
2022-01-07 21:52:37 +01:00
Michael Teeuw
0e6d40f96c Merge pull request #2764 from oraclesean/patch-1 2022-01-07 21:44:46 +01:00
Karsten Hassel
cd1fe4e182 weather test for new absolute property 2022-01-07 21:38:56 +01:00
CFenner
c56b601ab8 adjust test case 2022-01-06 21:49:21 +01:00
Christopher Fenner
e78fa11fd4 Update CHANGELOG.md 2022-01-06 21:40:19 +01:00
Christopher Fenner
1619dd29e9 Apply suggestions from code review 2022-01-06 21:28:25 +01:00
CFenner
793f3dd75c Merge remote-tracking branch 'upstream/develop' into patch-1 2022-01-06 21:24:24 +01:00
Christopher Fenner
ce05f8e958 use solid type for font awesome icons 2022-01-05 13:28:07 +01:00
Christopher Fenner
c8c4585946 use solid type for font awesome icons 2022-01-05 13:27:20 +01:00
Christopher Fenner
990d1adfb2 use solid type for font awesome icons 2022-01-05 13:26:50 +01:00
Christopher Fenner
404343de1d use solid type for font awesome icons 2022-01-05 13:19:55 +01:00
Christopher Fenner
24bfaaca7e use solid type for font awesome icons 2022-01-05 13:18:08 +01:00
Christopher Fenner
060ca43fc8 use solid type for font awesome icons
related to #2768
2022-01-05 13:13:40 +01:00
Fredrik Oterholt
b87e802c8d Broken link for contribution guidelines
Replace with correct URL for the contribution guidelines
2022-01-04 09:18:29 +01:00
Sean Scott
0f596d5620 Update weather.js
Set absoluteDates default to false
2022-01-02 14:45:24 -07:00
Sean Scott
3ebdb67bc0 Update CHANGELOG.md
Update CHANCEGLOG
2022-01-02 11:44:01 -07:00
Sean Scott
a5668ef729 Update forecast.njk
Add an absolute date option to the weather module's forecast.
2022-01-02 11:35:29 -07:00
Michael Teeuw
24fccf6c44 Merge pull request #2762 from MichMich/prepare-2.19.0-develop
Prepare v2.19.0-develop.
2022-01-01 19:47:26 +01:00
Michael Teeuw
e12692252e Prepare v2.19.0-develop. 2022-01-01 19:37:55 +01:00
170 changed files with 3997 additions and 7291 deletions

View File

@@ -16,7 +16,7 @@
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2018,
"ecmaVersion": 2020,
"ecmaFeatures": {
"globalReturn": true
}

View File

@@ -44,7 +44,7 @@ When submitting a new issue, please supply the following information:
**Node Version**: Make sure it's version 14 or later (recommended is 16).
**MagicMirror Version**: Please let us know which version of MagicMirror you are running. It can be found in the `package.json` file.
**MagicMirror² Version**: Please let us know which version of MagicMirror² you are running. It can be found in the `package.json` file.
**Description**: Provide a detailed description about the issue and include specific details to help us understand the problem. Adding screenshots will help describing the problem.

View File

@@ -10,16 +10,16 @@ If you're not sure if it's a real bug or if it's just you, please open a topic o
Problems installing or configuring your MagicMirror? Check out: [https://forum.magicmirror.builders/category/10/troubleshooting](https://forum.magicmirror.builders/category/10/troubleshooting)
A common problem is that your config file could be invalid. Please run in your MagicMirror directory: `npm run config:check` and see if it reports an error.
A common problem is that your config file could be invalid. Please run in your MagicMirror² directory: `npm run config:check` and see if it reports an error.
## I found a bug in the MagicMirror installer
## I found a bug in the MagicMirror² installer
If you are facing an issue or found a bug while trying to install MagicMirror via the installer please report it in the respective GitHub repository:
If you are facing an issue or found a bug while trying to install MagicMirror² via the installer please report it in the respective GitHub repository:
[https://github.com/sdetweil/MagicMirror_scripts](https://github.com/sdetweil/MagicMirror_scripts)
## I found a bug in the MagicMirror Docker image
## I found a bug in the MagicMirror² Docker image
If you are facing an issue or found a bug while running MagicMirror inside a Docker container please create an issue in the corresponding repository:
If you are facing an issue or found a bug while running MagicMirror² inside a Docker container please create an issue in the corresponding repository:
- karsten13/magicmirror: [https://gitlab.com/khassel/magicmirror](https://gitlab.com/khassel/magicmirror)
- (deprecated) bastilimbach/docker-magicmirror: [https://github.com/bastilimbach/docker-MagicMirror](https://github.com/bastilimbach/docker-MagicMirror)
@@ -35,7 +35,7 @@ When submitting a new issue, please supply the following information:
**Node Version**: Make sure it's version 14 or later (recommended is 16).
**MagicMirror Version**: Please let us know which version of MagicMirror you are running. It can be found in the `package.json` file.
**MagicMirror² Version**: Please let us know which version of MagicMirror² you are running. It can be found in the `package.json` file.
**Description**: Provide a detailed description about the issue and include specific details to help us understand the problem. Adding screenshots will help describing the problem.

View File

@@ -1,4 +1,4 @@
Hello and thank you for wanting to contribute to the MagicMirror project
Hello and thank you for wanting to contribute to the MagicMirror² project
**Please make sure that you have followed these 4 rules before submitting your Pull Request:**

6
.github/dependabot.yaml vendored Normal file
View File

@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@@ -9,16 +9,19 @@ on:
pull_request:
branches: [master, develop]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix:
node-version: [14.x, 16.x, 17.x]
node-version: [14.x, 16.x, 18.x]
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
@@ -33,6 +36,4 @@ jobs:
npm run test:prettier
npm run test:js
npm run test:css
npm run test:unit
npm run test:e2e
npm run test:electron
npm run test

View File

@@ -1,4 +1,5 @@
# This workflow runs the automated test and uploads the coverage results to codecov.io
# For more information see: https://github.com/codecov/codecov-action
name: "Run Codecov Tests"
@@ -8,13 +9,16 @@ on:
pull_request:
branches: [master, develop]
permissions:
contents: read
jobs:
run-and-upload-coverage-report:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Install dependencies and run coverage
run: |
Xvfb :99 -screen 0 1024x768x16 &

View File

@@ -1,4 +1,5 @@
# This workflow enforces the update of a changelog file on every pull request
# For more information see: https://github.com/dangoslen/changelog-enforcer
name: "Enforce Changelog"
@@ -11,10 +12,8 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Enforce changelog
uses: dangoslen/changelog-enforcer@v2
uses: dangoslen/changelog-enforcer@v3
with:
changeLogPath: "CHANGELOG.md"
skipLabels: "Skip Changelog"

View File

@@ -1,4 +1,7 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint:staged
[ -f "$(dirname "$0")/_/husky.sh" ] && . "$(dirname "$0")/_/husky.sh"
if command -v npm &> /dev/null; then
npm run lint:staged
fi

View File

@@ -5,6 +5,64 @@ This project adheres to [Semantic Versioning](https://semver.org/).
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror².
## [2.20.0] - 2022-07-02
Special thanks to the following contributors: @eouia, @khassel, @kolbyjack, @KristjanESPERANTO, @nathannaveen, @naveensrinivasan, @rejas, @rohitdharavath and @sdetweil.
### Added
- Added a new config option `httpHeaders` used by helmet (see https://helmetjs.github.io/). You can now set own httpHeaders which will override the defaults in `js/defauls.js` which is useful e.g. if you want to embed MagicMirror into annother website (solves #2847).
- Show endDate for calendar events when dateHeader is enabled and showEnd is set to true (#2192).
- Added the notification emitting from the weather module on infromation updated.
- Use recommended file extention for YAML files (#2864).
### Updated
- Use latest node 18 when running tests on github actions.
- Update `electron` to v19 and other dependencies.
- Use internal fetch function of node instead external `node-fetch` library if used node version >= `v18`.
- Include duplicate events in broadcasts.
### Fixed
- Fix problems with non latin fonds caused by updating to fontsource (fixes #2835).
## [2.19.0] - 2022-04-01
Special thanks to the following contributors: @10bias, @CFenner, @JHWelch, @k1rd3rf, @khassel, @kolbyjack, @krekos, @KristjanESPERANTO, @Nerfzooka, @oraclesean, @oscarb, @philnagel, @rejas, @sdetweil, @shin10, @SiderealArt and @Tom-Hirschberger.
### Added
- Added a config option under the weather module, `absoluteDates`, providing an option to format weather forecast date output with either absolute or relative dates.
- Added test for new weather forecast `absoluteDates` property.
- The modules get a class hidden added/removed if they get hidden/shown which will also toggle pointer-events.
- Added new config option `showTitleAsUrl` to newsfeed module. If set, the displayed title is a link to the article which is useful when running in a browser and you want to read this article.
- Added internal cors proxy to get weather providers working without public proxies (fixes #2714). The new url `http(s)://address:port/cors?url=https://whatever-to-proxy` can be used in other modules too.
- Added a WeatherProvider for Weatherflow.
- Added new env var `ELECTRON_DISABLE_GPU` which disable gpu under electron if set (fixes #2831).
- Added missing Czech translations.
### Updated
- Deprecated roboto fonts package `roboto-fontface-bower` replaced with `fontsource`.
- Update `electron` to v17, `helmet` to v5 (use defaults of v4) and other dependencies
- Updates Font Awesome css class to new default style (fixes #2768)
- Replaced deprecated modules `currentweather` and `weatherforecast` with dummy modules only displaying that they have to be replaced.
- Include all calendar events from the configured date range when broadcasting.
- Update Danish and German translation.
- Update `node-ical` to v0.15 and added `luxon` as dependency for not breaking the "no-optional" install (see #2718 and #2824).
### Fixed
- Improved and speedup e2e tests, artificial wait after mm start removed.
- Improved husky setup not blocking `git commit` if `husky` or `npm` is not installed.
- Using a consistent spelling of MagicMirror².
- Fix minor console output issue for loading translations (#2814).
- Don't adjust startDate for full day events if endDate is in the past.
- Fix windspeed conversion error in openweathermap provider. (#2812)
- Fix conflicting parms turning off showEnd for full day events. (#2629)
- Fix regression, calendar.maximumEntries not used to filter calendar level entries (#2868)
## [2.18.0] - 2022-01-01
Special thanks to the following contributors: @AmpioRosso, @eouia, @fewieden, @jupadin, @khassel, @kolbyjack, @KristjanESPERANTO, @MariusVaice, @rejas, @rico24 and @sdetweil.
@@ -29,6 +87,7 @@ Special thanks to the following contributors: @AmpioRosso, @eouia, @fewieden, @j
- Added dangerouslyDisableAutoEscaping config option for newsfeed templates (fixes #2712).
- Added missing shebang to `installers/mm.sh`.
- Node versions in templates and github workflows.
- Updated translations for Traditional Chinese (Taiwan) (zh-tw.json).
### Fixed
@@ -252,7 +311,7 @@ Special thanks to the following contributors: @Alvinger, @AndyPoms, @ashishtank,
- Rename Greek translation to correct ISO 639-1 alpha-2 code (gr > el). (#2155)
- Add a space after icons of sunrise and sunset. (#2169)
- Fix calendar when no DTEND record found in event, startDate overlay when endDate set. (#2177)
- Fix windspeed convertion error in ukmetoffice weather provider. (#2189)
- Fix windspeed conversion error in ukmetoffice weather provider. (#2189)
- Fix console.debug not having timestamps. (#2199)
- Fix calendar full day event east of UTC start time. (#2200)
- Fix non-fullday recurring rule processing. (#2216)
@@ -275,8 +334,8 @@ Special thanks to the following contributors: @bryanzzhu, @bugsounet, @chamakura
### Added
- `--dry-run` Added option in fetch call within updatenotification node_helper. This is to prevent
MagicMirror from consuming any fetch result. Causes conflict with MMPM when attempting to check
for updates to MagicMirror and/or MagicMirror modules.
MagicMirror² from consuming any fetch result. Causes conflict with MMPM when attempting to check
for updates to MagicMirror² and/or MagicMirror² modules.
- Test coverage with Istanbul, run it with `npm run test:coverage`.
- Added lithuanian language.
- Added support in weatherforecast for OpenWeather onecall API.
@@ -349,7 +408,7 @@ Special thanks to the following contributors: @AndreKoepke, @andrezibaia, @bryan
🚨 READ THIS BEFORE UPDATING 🚨
In the past years the project has grown a lot. This came with a huge downside: poor maintainability. If I let the project continue the way it was, it would eventually crash and burn. More important: I would completely lose the drive and interest to continue the project. Because of this the decision was made to simplify the core by removing all side features like automatic installers and support for exotic platforms. This release (2.11.0) is the first real release that will reflect (parts) of these changes. As a result of this, some things might break. So before you continue make sure to backup your installation. Your config, your modules or better yet: your full MagicMirror folder. In other words: update at your own risk.
In the past years the project has grown a lot. This came with a huge downside: poor maintainability. If I let the project continue the way it was, it would eventually crash and burn. More important: I would completely lose the drive and interest to continue the project. Because of this the decision was made to simplify the core by removing all side features like automatic installers and support for exotic platforms. This release (2.11.0) is the first real release that will reflect (parts) of these changes. As a result of this, some things might break. So before you continue make sure to backup your installation. Your config, your modules or better yet: your full MagicMirror² folder. In other words: update at your own risk.
For more information regarding this major change, please check issue [#1860](https://github.com/MichMich/MagicMirror/issues/1860).
@@ -550,7 +609,7 @@ Fixed `package.json` version number.
- Fixed unhandled error on bad git data in updatenotification module [#1285](https://github.com/MichMich/MagicMirror/issues/1285).
- Weather forecast now works with openweathermap in new weather module. Daily data are displayed, see issue [#1504](https://github.com/MichMich/MagicMirror/issues/1504).
- Fixed analogue clock border display issue where non-black backgrounds used (previous fix for issue 611)
- Fixed compatibility issues caused when modules request different versions of Font Awesome, see issue [#1522](https://github.com/MichMich/MagicMirror/issues/1522). MagicMirror now uses [Font Awesome 5 with v4 shims included for backwards compatibility](https://fontawesome.com/how-to-use/on-the-web/setup/upgrading-from-version-4#shims).
- Fixed compatibility issues caused when modules request different versions of Font Awesome, see issue [#1522](https://github.com/MichMich/MagicMirror/issues/1522). MagicMirror² now uses [Font Awesome 5 with v4 shims included for backwards compatibility](https://fontawesome.com/how-to-use/on-the-web/setup/upgrading-from-version-4#shims).
- Installation script problems with raspbian
- Calendar: only show repeating count if the event is actually repeating [#1534](https://github.com/MichMich/MagicMirror/pull/1534)
- Calendar: Fix exdate handling when multiple values are specified (comma separated)
@@ -662,7 +721,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
## [2.4.0] - 2018-07-01
**Warning:** This release includes an updated version of Electron. This requires a Raspberry Pi configuration change to allow the best performance and prevent the CPU from overheating. Please read the information on the [MagicMirror Wiki](https://github.com/michmich/magicmirror/wiki/configuring-the-raspberry-pi#enable-the-open-gl-driver-to-decrease-electrons-cpu-usage).
**Warning:** This release includes an updated version of Electron. This requires a Raspberry Pi configuration change to allow the best performance and prevent the CPU from overheating. Please read the information on the [MagicMirror² Wiki](https://github.com/michmich/magicmirror/wiki/configuring-the-raspberry-pi#enable-the-open-gl-driver-to-decrease-electrons-cpu-usage).
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
@@ -903,7 +962,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
- Add use pm2 for manager process into Installer RaspberryPi script.
- Russian Translation.
- Afrikaans Translation.
- Add postinstall script to notify user that MagicMirror installed successfully despite warnings from NPM.
- Add postinstall script to notify user that MagicMirror² installed successfully despite warnings from NPM.
- Init tests using mocha.
- Option to use RegExp in Calendar's titleReplace.
- Hungarian Translation.
@@ -966,7 +1025,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
- Add VSCode IntelliSense support.
- Module API: Add Visibility locking to module system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#visibility-locking) for more information.
- Module API: Method to overwrite the module's header. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) for more information.
- Module API: Option to define the minimum MagicMirror version to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresversion) for more information.
- Module API: Option to define the minimum MagicMirror² version to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresversion) for more information.
- Calendar module now broadcasts the event list to all other modules using the notification system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/calendar) for more information.
- Possibility to use the calendar feed as the source for the weather (currentweather & weatherforecast) location data. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/weatherforecast) for more information.
- Added option to show rain amount in the weatherforecast default module
@@ -1113,6 +1172,6 @@ It includes (but is not limited to) the following features:
## [1.0.0] - 2014-02-16
### Initial release of MagicMirror.
### Initial release of MagicMirror
This was part of the blogpost: [https://michaelteeuw.nl/post/83916869600/magic-mirror-part-vi-production-of-the](https://michaelteeuw.nl/post/83916869600/magic-mirror-part-vi-production-of-the)

View File

@@ -40,7 +40,7 @@ Contributions of all kinds are welcome, not only in the form of code but also wi
- documentation
- translations
For the full contribution guidelines, check out: [https://docs.magicmirror.builders/getting-started/contributing.html](https://docs.magicmirror.builders/getting-started/contributing.html)
For the full contribution guidelines, check out: [https://docs.magicmirror.builders/about/contributing.html](https://docs.magicmirror.builders/about/contributing.html)
## Enjoying MagicMirror? Consider a donation!

View File

@@ -1,10 +1,10 @@
/* Magic Mirror Config Sample
/* MagicMirror² Config Sample
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*
* For more information on how you can configure this file
* see https://docs.magicmirror.builders/getting-started/configuration.html#general
* see https://docs.magicmirror.builders/configuration/introduction.html
* and https://docs.magicmirror.builders/modules/configuration.html
*/
let config = {
@@ -14,7 +14,7 @@ let config = {
// - "0.0.0.0", "::" to listen on any interface
// Default, when address config is left out or empty, is "localhost"
port: 8080,
basePath: "/", // The URL path where MagicMirror is hosted. If you are using a Reverse proxy
basePath: "/", // The URL path where MagicMirror² is hosted. If you are using a Reverse proxy
// you must set the sub path here. basePath must end with a /
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], // Set [] to allow all IP addresses
// or add a specific IPv4 of 192.168.1.5 :

View File

@@ -1,4 +1,4 @@
/* Magic Mirror Custom CSS Sample
/* MagicMirror² Custom CSS Sample
*
* Change color and fonts here.
*

View File

@@ -138,6 +138,14 @@ sup {
margin-bottom: var(--gap-modules);
}
.module.hidden {
pointer-events: none;
}
.module:not(.hidden) {
pointer-events: auto;
}
.region.bottom .module {
margin-top: var(--gap-modules);
margin-bottom: 0;
@@ -170,10 +178,6 @@ sup {
pointer-events: none;
}
.region.fullscreen * {
pointer-events: auto;
}
.region.right {
right: 0;
text-align: right;

View File

@@ -7,20 +7,31 @@
"name": "magicmirror-fonts",
"license": "MIT",
"dependencies": {
"roboto-fontface": "^0.10.0"
"@fontsource/roboto": "^4.5.7",
"@fontsource/roboto-condensed": "^4.5.8"
}
},
"node_modules/roboto-fontface": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz",
"integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g=="
"node_modules/@fontsource/roboto": {
"version": "4.5.7",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.7.tgz",
"integrity": "sha512-m57UMER23Mk6Drg9OjtHW1Y+0KPGyZfE5XJoPTOsLARLar6013kJj4X2HICt+iFLJqIgTahA/QAvSn9lwF1EEw=="
},
"node_modules/@fontsource/roboto-condensed": {
"version": "4.5.8",
"resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-4.5.8.tgz",
"integrity": "sha512-HCuf1rVSOsXnl/KgHNRLCr8XS/Dunzn10BjhliJiEZ5qPynXCWH4RRBFupIODHamhj2Uyp/iZkSQp574luKp6A=="
}
},
"dependencies": {
"roboto-fontface": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz",
"integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g=="
"@fontsource/roboto": {
"version": "4.5.7",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.7.tgz",
"integrity": "sha512-m57UMER23Mk6Drg9OjtHW1Y+0KPGyZfE5XJoPTOsLARLar6013kJj4X2HICt+iFLJqIgTahA/QAvSn9lwF1EEw=="
},
"@fontsource/roboto-condensed": {
"version": "4.5.8",
"resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-4.5.8.tgz",
"integrity": "sha512-HCuf1rVSOsXnl/KgHNRLCr8XS/Dunzn10BjhliJiEZ5qPynXCWH4RRBFupIODHamhj2Uyp/iZkSQp574luKp6A=="
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "magicmirror-fonts",
"description": "Package for fonts use by MagicMirror Core.",
"description": "Package for fonts use by MagicMirror² Core.",
"repository": {
"type": "git",
"url": "git+https://github.com/MichMich/MagicMirror.git"
@@ -10,6 +10,7 @@
"url": "https://github.com/MichMich/MagicMirror/issues"
},
"dependencies": {
"roboto-fontface": "^0.10.0"
"@fontsource/roboto": "^4.5.7",
"@fontsource/roboto-condensed": "^4.5.8"
}
}

View File

@@ -2,57 +2,54 @@
font-family: Roboto;
font-style: normal;
font-weight: 100;
src: local("Roboto Thin"), local("Roboto-Thin"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.woff2") format("woff2"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.woff") format("woff");
src: local("Roboto Thin"), local("Roboto-Thin"), url("node_modules/@fontsource/roboto/files/roboto-all-100-normal.woff") format("woff");
}
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-weight: 300;
src: local("Roboto Condensed Light"), local("RobotoCondensed-Light"), url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Light.woff2") format("woff2"),
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Light.woff") format("woff");
src: local("Roboto Condensed Light"), local("RobotoCondensed-Light"), url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-all-300-normal.woff") format("woff");
}
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-weight: 400;
src: local("Roboto Condensed"), local("RobotoCondensed-Regular"), url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Regular.woff2") format("woff2"),
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Regular.woff") format("woff");
src: local("Roboto Condensed"), local("RobotoCondensed-Regular"), url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-all-400-normal.woff") format("woff");
}
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-weight: 700;
src: local("Roboto Condensed Bold"), local("RobotoCondensed-Bold"), url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Bold.woff2") format("woff2"),
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Bold.woff") format("woff");
src: local("Roboto Condensed Bold"), local("RobotoCondensed-Bold"), url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-all-700-normal.woff") format("woff");
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 400;
src: local("Roboto"), local("Roboto-Regular"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.woff2") format("woff2"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.woff") format("woff");
src: local("Roboto"), local("Roboto-Regular"), url("node_modules/@fontsource/roboto/files/roboto-all-400-normal.woff") format("woff");
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 500;
src: local("Roboto Medium"), local("Roboto-Medium"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.woff2") format("woff2"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.woff") format("woff");
src: local("Roboto Medium"), local("Roboto-Medium"), url("node_modules/@fontsource/roboto/files/roboto-all-500-normal.woff") format("woff");
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 700;
src: local("Roboto Bold"), local("Roboto-Bold"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.woff2") format("woff2"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.woff") format("woff");
src: local("Roboto Bold"), local("Roboto-Bold"), url("node_modules/@fontsource/roboto/files/roboto-all-700-normal.woff") format("woff");
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 300;
src: local("Roboto Light"), local("Roboto-Light"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Light.woff2") format("woff2"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Light.woff") format("woff");
src: local("Roboto Light"), local("Roboto-Light"), url("node_modules/@fontsource/roboto/files/roboto-all-300-normal.woff") format("woff");
}

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* The Core App (Server)
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -37,7 +37,7 @@ if (process.env.MM_PORT) {
process.on("uncaughtException", function (err) {
Log.error("Whoops! There was an uncaught exception...");
Log.error(err);
Log.error("MagicMirror will not quit, but it might be a good idea to check why this happened. Maybe no internet connection?");
Log.error("MagicMirror² will not quit, but it might be a good idea to check why this happened. Maybe no internet connection?");
Log.error("If you think this really is an issue, please open an issue on GitHub: https://github.com/MichMich/MagicMirror/issues");
});
@@ -128,7 +128,7 @@ function App() {
let m = new Module();
if (m.requiresVersion) {
Log.log(`Check MagicMirror version for node helper '${moduleName}' - Minimum version: ${m.requiresVersion} - Current version: ${global.version}`);
Log.log(`Check MagicMirror² version for node helper '${moduleName}' - Minimum version: ${m.requiresVersion} - Current version: ${global.version}`);
if (cmpVersions(global.version, m.requiresVersion) >= 0) {
Log.log("Version is ok!");
} else {

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
*
* Check the configuration file for errors
*

View File

@@ -1,6 +1,6 @@
/* global mmPort */
/* Magic Mirror
/* MagicMirror²
* Config Defaults
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -25,6 +25,9 @@ const defaults = {
units: "metric",
zoom: 1,
customCss: "css/custom.css",
// httpHeaders used by helmet, see https://helmetjs.github.io/. You can add other/more object values by overriding this in config.js,
// e.g. you need to add `frameguard: false` for embedding MagicMirror in another website, see https://github.com/MichMich/MagicMirror/issues/2847
httpHeaders: { contentSecurityPolicy: false, crossOriginOpenerPolicy: false, crossOriginEmbedderPolicy: false, crossOriginResourcePolicy: false, originAgentCluster: false },
modules: [
{
@@ -36,7 +39,7 @@ const defaults = {
position: "upper_third",
classes: "large thin",
config: {
text: "Magic Mirror<sup>2</sup>"
text: "MagicMirror²"
}
},
{
@@ -59,7 +62,7 @@ const defaults = {
position: "middle_center",
classes: "xsmall",
config: {
text: "If you get this message while your config file is already created,<br>" + "it probably contains an error. To validate your config file run in your MagicMirror directory<br>" + "<pre>npm run config:check</pre>"
text: "If you get this message while your config file is already created,<br>" + "it probably contains an error. To validate your config file run in your MagicMirror² directory<br>" + "<pre>npm run config:check</pre>"
}
},
{

View File

@@ -1,4 +1,4 @@
/* Magic Mirror Deprecated Config Options List
/* MagicMirror² Deprecated Config Options List
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.

View File

@@ -8,6 +8,12 @@ const Log = require("logger");
let config = process.env.config ? JSON.parse(process.env.config) : {};
// Module to control application life.
const app = electron.app;
// If ELECTRON_DISABLE_GPU is set electron is started with --disable-gpu flag.
// See https://www.electronjs.org/docs/latest/tutorial/offscreen-rendering for more info.
if (process.env.ELECTRON_DISABLE_GPU !== undefined) {
app.disableHardwareAcceleration();
}
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

20
js/fetch.js Normal file
View File

@@ -0,0 +1,20 @@
/**
* fetch
*
* @param {string} url to be fetched
* @param {object} options object e.g. for headers
* @class
*/
async function fetch(url, options) {
const nodeVersion = process.version.match(/^v(\d+)\.*/)[1];
if (nodeVersion >= 18) {
// node version >= 18
return global.fetch(url, options);
} else {
// node version < 18
const nodefetch = require("node-fetch");
return nodefetch(url, options);
}
}
module.exports = fetch;

View File

@@ -1,6 +1,6 @@
/* global defaultModules, vendor */
/* Magic Mirror
/* MagicMirror²
* Module and File loaders.
*
* By Michael Teeuw https://michaelteeuw.nl

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Log
*
* This logger is very simple, but needs to be extended.

View File

@@ -1,6 +1,6 @@
/* global Loader, defaults, Translator */
/* Magic Mirror
/* MagicMirror²
* Main System
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -245,6 +245,7 @@ const MM = (function () {
if (moduleWrapper !== null) {
moduleWrapper.style.transition = "opacity " + speed / 1000 + "s";
moduleWrapper.style.opacity = 0;
moduleWrapper.classList.add("hidden");
clearTimeout(module.showHideTimer);
module.showHideTimer = setTimeout(function () {
@@ -310,6 +311,7 @@ const MM = (function () {
moduleWrapper.style.transition = "opacity " + speed / 1000 + "s";
// Restore the position. See hideModule() for more info.
moduleWrapper.style.position = "static";
moduleWrapper.classList.remove("hidden");
updateWrapperStates();
@@ -478,7 +480,7 @@ const MM = (function () {
* Main init method.
*/
init: function () {
Log.info("Initializing MagicMirror.");
Log.info("Initializing MagicMirror².");
loadConfig();
Log.setLogLevel(config.logLevel);

View File

@@ -1,6 +1,6 @@
/* global Class, cloneObject, Loader, MMSocket, nunjucks, Translator */
/* Magic Mirror
/* MagicMirror²
* Module Blueprint.
* @typedef {Object} Module
*
@@ -12,7 +12,7 @@ const Module = Class.extend({
* All methods (and properties) below can be subclassed. *
*********************************************************/
// Set the minimum MagicMirror module version for this module.
// Set the minimum MagicMirror² module version for this module.
requiresVersion: "2.0.0",
// Module config defaults.
@@ -74,7 +74,7 @@ const Module = Class.extend({
},
/**
* Generates the dom which needs to be displayed. This method is called by the Magic Mirror core.
* Generates the dom which needs to be displayed. This method is called by the MagicMirror² core.
* This method can to be subclassed if the module wants to display info on the mirror.
* Alternatively, the getTemplate method could be subclassed.
*
@@ -109,7 +109,7 @@ const Module = Class.extend({
/**
* Generates the header string which needs to be displayed if a user has a header configured for this module.
* This method is called by the Magic Mirror core, but only if the user has configured a default header for the module.
* This method is called by the MagicMirror² core, but only if the user has configured a default header for the module.
* This method needs to be subclassed if the module wants to display modified headers on the mirror.
*
* @returns {string} The header to display above the header.
@@ -141,7 +141,7 @@ const Module = Class.extend({
},
/**
* Called by the Magic Mirror core when a notification arrives.
* Called by the MagicMirror² core when a notification arrives.
*
* @param {string} notification The identifier of the notification.
* @param {*} payload The payload of the notification.
@@ -434,7 +434,7 @@ const Module = Class.extend({
});
/**
* Merging MagicMirror (or other) default/config script by @bugsounet
* Merging MagicMirror² (or other) default/config script by @bugsounet
* Merge 2 objects or/with array
*
* Usage:
@@ -498,7 +498,7 @@ Module.create = function (name) {
Module.register = function (name, moduleDefinition) {
if (moduleDefinition.requiresVersion) {
Log.log("Check MagicMirror version for module '" + name + "' - Minimum version: " + moduleDefinition.requiresVersion + " - Current version: " + window.mmVersion);
Log.log("Check MagicMirror² version for module '" + name + "' - Minimum version: " + moduleDefinition.requiresVersion + " - Current version: " + window.mmVersion);
if (cmpVersions(window.mmVersion, moduleDefinition.requiresVersion) >= 0) {
Log.log("Version is ok!");
} else {

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Node Helper Superclass
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -23,7 +23,7 @@ const NodeHelper = Class.extend({
},
/* stop()
* Called when the MagicMirror server receives a `SIGINT`
* Called when the MagicMirror² server receives a `SIGINT`
* Close any open connections, stop any sub-processes and
* gracefully exit the module.
*

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Server
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -10,6 +10,7 @@ const path = require("path");
const ipfilter = require("express-ipfilter").IpFilter;
const fs = require("fs");
const helmet = require("helmet");
const fetch = require("fetch");
const Log = require("logger");
const Utils = require("./utils.js");
@@ -61,13 +62,14 @@ function Server(config, callback) {
app.use(function (req, res, next) {
ipfilter(config.ipWhitelist, { mode: config.ipWhitelist.length === 0 ? "deny" : "allow", log: false })(req, res, function (err) {
if (err === undefined) {
res.header("Access-Control-Allow-Origin", "*");
return next();
}
Log.log(err.message);
res.status(403).send("This device is not allowed to access your mirror. <br> Please check your config.js or config.js.sample to change this.");
});
});
app.use(helmet({ contentSecurityPolicy: false }));
app.use(helmet(config.httpHeaders));
app.use("/js", express.static(__dirname));
@@ -76,6 +78,33 @@ function Server(config, callback) {
app.use(directory, express.static(path.resolve(global.root_path + directory)));
}
app.get("/cors", async function (req, res) {
// example: http://localhost:8080/cors?url=https://google.de
try {
const reg = "^/cors.+url=(.*)";
let url = "";
let match = new RegExp(reg, "g").exec(req.url);
if (!match) {
url = "invalid url: " + req.url;
Log.error(url);
res.send(url);
} else {
url = match[1];
Log.log("cors url: " + url);
const response = await fetch(url, { headers: { "User-Agent": "Mozilla/5.0 MagicMirror/" + global.version } });
const header = response.headers.get("Content-Type");
const data = await response.text();
if (header) res.set("Content-Type", header);
res.send(data);
}
} catch (error) {
Log.error(error);
res.send(error);
}
});
app.get("/version", function (req, res) {
res.send(global.version);
});

View File

@@ -1,6 +1,6 @@
/* global io */
/* Magic Mirror
/* MagicMirror²
* TODO add description
*
* By Michael Teeuw https://michaelteeuw.nl

View File

@@ -1,6 +1,6 @@
/* global translations */
/* Magic Mirror
/* MagicMirror²
* Translator (l10n)
*
* By Christopher Fenner https://github.com/CFenner
@@ -104,7 +104,7 @@ const Translator = (function () {
* @param {Function} callback Function called when done.
*/
load(module, file, isFallback, callback) {
Log.log(`${module.name} - Load translation${isFallback && " fallback"}: ${file}`);
Log.log(`${module.name} - Load translation${isFallback ? " fallback" : ""}: ${file}`);
if (this.translationsFallback[module.name]) {
callback();

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Utils
*
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com

View File

@@ -1,5 +1,5 @@
# Module: Alert
The alert module is one of the default modules of the MagicMirror. This module displays notifications from other modules.
The alert module is one of the default modules of the MagicMirror². This module displays notifications from other modules.
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/alert.html).

View File

@@ -1,6 +1,6 @@
/* global NotificationFx */
/* Magic Mirror
/* MagicMirror²
* Module: alert
*
* By Paul-Vincent Roll https://paulvincentroll.com/

View File

@@ -9,6 +9,8 @@
*
* Copyright 2014, Codrops
* https://tympanus.net/codrops/
*
* @param {object} window The window object
*/
(function (window) {
/**

View File

@@ -3,7 +3,7 @@
{% if imageUrl %}
<img src="{{ imageUrl }}" height="{{ imageHeight }}" style="margin-bottom: 10px;"/>
{% else %}
<span class="bright fa fa-{{ imageFA }}" style='margin-bottom: 10px; font-size: {{ imageHeight }};'/></span>
<span class="bright fas fa-{{ imageFA }}" style='margin-bottom: 10px; font-size: {{ imageHeight }};'/></span>
{% endif %}
<br/>
{% endif %}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror нотификация",
"sysTitle": "MagicMirror² нотификация",
"welcome": "Добре дошли, стартирането беше успешно"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Notifikation",
"sysTitle": "MagicMirror² Notifikation",
"welcome": "Velkommen, modulet er succesfuldt startet!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Benachrichtigung",
"sysTitle": "MagicMirror² Benachrichtigung",
"welcome": "Willkommen, Start war erfolgreich!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Notification",
"sysTitle": "MagicMirror² Notification",
"welcome": "Welcome, start was successful!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Notificaciones",
"sysTitle": "MagicMirror² Notificaciones",
"welcome": "Bienvenido, ¡se iniciado correctamente!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Notification",
"sysTitle": "MagicMirror² Notification",
"welcome": "Bienvenue, le démarrage a été un succès!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror értesítés",
"sysTitle": "MagicMirror² értesítés",
"welcome": "Üdvözöljük, indulás sikeres!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Notificatie",
"sysTitle": "MagicMirror² Notificatie",
"welcome": "Welkom, Succesvol gestart!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Уведомление",
"sysTitle": "MagicMirror² Уведомление",
"welcome": "Добро пожаловать, старт был успешным!"
}

View File

@@ -1,6 +1,6 @@
# Module: Calendar
The `calendar` module is one of the default modules of the MagicMirror.
The `calendar` module is one of the default modules of the MagicMirror².
This module displays events from a public .ical calendar. It can combine multiple calendars.
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/calendar.html).

View File

@@ -1,6 +1,6 @@
/* global cloneObject */
/* Magic Mirror
/* MagicMirror²
* Module: Calendar
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -13,7 +13,7 @@ Module.register("calendar", {
maximumNumberOfDays: 365,
limitDays: 0, // Limit the number of days shown, 0 = no limit
displaySymbol: true,
defaultSymbol: "calendar", // Fontawesome Symbol see https://fontawesome.com/cheatsheet?from=io
defaultSymbol: "calendar-alt", // Fontawesome Symbol see https://fontawesome.com/cheatsheet?from=io
showLocation: false,
displayRepeatingCountTitle: false,
defaultRepeatingCountTitle: "",
@@ -43,7 +43,7 @@ Module.register("calendar", {
tableClass: "small",
calendars: [
{
symbol: "calendar",
symbol: "calendar-alt",
url: "https://www.calendarlabs.com/templates/ical/US-Holidays.ics"
}
],
@@ -164,7 +164,7 @@ Module.register("calendar", {
const oneHour = oneMinute * 60;
const oneDay = oneHour * 24;
const events = this.createEventList();
const events = this.createEventList(true);
const wrapper = document.createElement("table");
wrapper.className = this.config.tableClass;
@@ -239,7 +239,7 @@ Module.register("calendar", {
const symbols = this.symbolsForEvent(event);
symbols.forEach((s, index) => {
const symbol = document.createElement("span");
symbol.className = "fa fa-fw fa-" + s;
symbol.className = "fas fa-fw fa-" + s;
if (index > 0) {
symbol.style.paddingLeft = "5px";
}
@@ -305,6 +305,12 @@ Module.register("calendar", {
timeWrapper.className = "time light align-left " + this.timeClassForUrl(event.url);
timeWrapper.style.paddingLeft = "2px";
timeWrapper.innerHTML = moment(event.startDate, "x").format("LT");
// Add endDate to dataheaders if showEnd is enabled
if (this.config.showEnd) {
timeWrapper.innerHTML += " - " + moment(event.endDate, "x").format("LT");
}
eventWrapper.appendChild(timeWrapper);
titleWrapper.classList.add("align-right");
}
@@ -329,8 +335,7 @@ Module.register("calendar", {
//subtract one second so that fullDayEvents end at 23:59:59, and not at 0:00:00 one the next day
event.endDate -= oneSecond;
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.fullDayEventDateFormat));
}
if (this.config.getRelative > 0 && event.startDate < now) {
} else if (this.config.getRelative > 0 && event.startDate < now) {
// Ongoing and getRelative is set
timeWrapper.innerHTML = this.capFirst(
this.translate("RUNNING", {
@@ -382,7 +387,7 @@ Module.register("calendar", {
}
}
} else if (event.startDate - now < this.config.getRelative * oneHour) {
// If event is within getRelative hours, display 'in xxx' time format or moment.fromNow()
// If event is within getRelative hours, display 'in xxx' time format or moment.fromNow()
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
}
} else {
@@ -477,9 +482,10 @@ Module.register("calendar", {
/**
* Creates the sorted list of all events.
*
* @param {boolean} limitNumberOfEntries Whether to filter returned events for display.
* @returns {object[]} Array with events.
*/
createEventList: function () {
createEventList: function (limitNumberOfEntries) {
const now = new Date();
const today = moment().startOf("day");
const future = moment().startOf("day").add(this.config.maximumNumberOfDays, "days").toDate();
@@ -490,22 +496,20 @@ Module.register("calendar", {
for (const e in calendar) {
const event = JSON.parse(JSON.stringify(calendar[e])); // clone object
if (event.endDate < now) {
if (this.config.hidePrivate && event.class === "PRIVATE") {
// do not add the current event, skip it
continue;
}
if (this.config.hidePrivate) {
if (event.class === "PRIVATE") {
// do not add the current event, skip it
if (limitNumberOfEntries) {
if (event.endDate < now) {
continue;
}
}
if (this.config.hideOngoing) {
if (event.startDate < now) {
if (this.config.hideOngoing && event.startDate < now) {
continue;
}
if (this.listContainsEvent(events, event)) {
continue;
}
}
if (this.listContainsEvent(events, event)) {
continue;
}
event.url = calendarUrl;
event.today = event.startDate >= today && event.startDate < today + 24 * 60 * 60 * 1000;
@@ -548,6 +552,10 @@ Module.register("calendar", {
return a.startDate - b.startDate;
});
if (!limitNumberOfEntries) {
return events;
}
// Limit the number of days displayed
// If limitDays is set > 0, limit display to that number of days
if (this.config.limitDays > 0) {
@@ -835,22 +843,14 @@ Module.register("calendar", {
* The all events available in one array, sorted on startdate.
*/
broadcastEvents: function () {
const eventList = [];
for (const url in this.calendarData) {
for (const ev of this.calendarData[url]) {
const event = cloneObject(ev);
event.symbol = this.symbolsForEvent(event);
event.calendarName = this.calendarNameForUrl(url);
event.color = this.colorForUrl(url);
delete event.url;
eventList.push(event);
}
const eventList = this.createEventList(false);
for (const event of eventList) {
event.symbol = this.symbolsForEvent(event);
event.calendarName = this.calendarNameForUrl(event.url);
event.color = this.colorForUrl(event.url);
delete event.url;
}
eventList.sort(function (a, b) {
return a.startDate - b.startDate;
});
this.sendNotification("CALENDAR_EVENTS", eventList);
}
});

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Node Helper: Calendar - CalendarFetcher
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -8,7 +8,7 @@ const CalendarUtils = require("./calendarutils");
const Log = require("logger");
const NodeHelper = require("node_helper");
const ical = require("node-ical");
const fetch = require("node-fetch");
const fetch = require("fetch");
const digest = require("digest-fetch");
const https = require("https");

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Calendar Util Methods
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -470,7 +470,7 @@ const CalendarUtils = {
}
// Adjust start date so multiple day events will be displayed as happening today even though they started some days ago already
if (fullDayEvent && startDate <= today) {
if (fullDayEvent && startDate <= today && endDate > today) {
startDate = moment(today);
}
// if the start and end are the same, then make end the 'end of day' value (start is at 00:00:00)
@@ -498,23 +498,8 @@ const CalendarUtils = {
return a.startDate - b.startDate;
});
// include up to maximumEntries current or upcoming events
// If past events should be included, include all past events
const now = moment();
let entries = 0;
let events = [];
for (let ne of newEvents) {
if (moment(ne.endDate, "x").isBefore(now)) {
if (config.includePastEvents) events.push(ne);
continue;
}
entries++;
// If max events has been saved, skip the rest
if (entries > config.maximumEntries) break;
events.push(ne);
}
return events;
let maxEvents = newEvents.slice(0, config.maximumEntries);
return maxEvents;
},
/**

View File

@@ -1,6 +1,6 @@
/* CalendarFetcher Tester
* use this script with `node debug.js` to test the fetcher without the need
* of starting the MagicMirror core. Adjust the values below to your desire.
* of starting the MagicMirror² core. Adjust the values below to your desire.
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Node Helper: Calendar
*
* By Michael Teeuw https://michaelteeuw.nl

View File

@@ -1,6 +1,6 @@
# Module: Clock
The `clock` module is one of the default modules of the MagicMirror.
The `clock` module is one of the default modules of the MagicMirror².
This module displays the current date and time. The information will be updated realtime.
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/clock.html).

View File

@@ -1,6 +1,6 @@
/* global SunCalc */
/* Magic Mirror
/* MagicMirror²
* Module: Clock
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -199,13 +199,13 @@ Module.register("clock", {
sunWrapper.innerHTML =
'<span class="' +
(isVisible ? "bright" : "") +
'"><i class="fa fa-sun-o" aria-hidden="true"></i> ' +
'"><i class="fas fa-sun" aria-hidden="true"></i> ' +
untilNextEventString +
"</span>" +
'<span><i class="fa fa-arrow-up" aria-hidden="true"></i> ' +
'<span><i class="fas fa-arrow-up" aria-hidden="true"></i> ' +
formatTime(this.config, sunTimes.sunrise) +
"</span>" +
'<span><i class="fa fa-arrow-down" aria-hidden="true"></i> ' +
'<span><i class="fas fa-arrow-down" aria-hidden="true"></i> ' +
formatTime(this.config, sunTimes.sunset) +
"</span>";
digitalWrapper.appendChild(sunWrapper);
@@ -230,13 +230,13 @@ Module.register("clock", {
moonWrapper.innerHTML =
'<span class="' +
(isVisible ? "bright" : "") +
'"><i class="fa fa-moon-o" aria-hidden="true"></i> ' +
'"><i class="fas fa-moon" aria-hidden="true"></i> ' +
illuminatedFractionString +
"</span>" +
'<span><i class="fa fa-arrow-up" aria-hidden="true"></i> ' +
'<span><i class="fas fa-arrow-up" aria-hidden="true"></i> ' +
(moonRise ? formatTime(this.config, moonRise) : "...") +
"</span>" +
'<span><i class="fa fa-arrow-down" aria-hidden="true"></i> ' +
'<span><i class="fas fa-arrow-down" aria-hidden="true"></i> ' +
(moonSet ? formatTime(this.config, moonSet) : "...") +
"</span>";
digitalWrapper.appendChild(moonWrapper);

View File

@@ -1,6 +1,6 @@
# Module: Compliments
The `compliments` module is one of the default modules of the MagicMirror.
The `compliments` module is one of the default modules of the MagicMirror².
This module displays a random compliment.
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/compliments.html).

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Module: Compliments
*
* By Michael Teeuw https://michaelteeuw.nl

View File

@@ -1,8 +0,0 @@
# Module: Current Weather
> :warning: **This module is deprecated in favor of the [weather](https://docs.magicmirror.builders/modules/weather.html) module.**
The `currentweather` module is one of the default modules of the MagicMirror.
This module displays the current weather, including the windspeed, the sunset or sunrise time, the temperature and an icon to display the current conditions.
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/currentweather.html).

View File

@@ -1,15 +0,0 @@
.currentweather .weathericon,
.currentweather .fa-home {
font-size: 75%;
line-height: 65px;
display: inline-block;
transform: translate(0, -3px);
}
.currentweather .humidityIcon {
padding-right: 4px;
}
.currentweather .humidity-padding {
padding-bottom: 6px;
}

View File

@@ -1,6 +1,6 @@
/* eslint-disable */
/* Magic Mirror
/* MagicMirror²
* Module: CurrentWeather
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -9,592 +9,25 @@
* This module is deprecated. Any additional feature will no longer be merged.
*/
Module.register("currentweather", {
// Default module config.
defaults: {
location: false,
locationID: false,
appid: "",
units: config.units,
updateInterval: 10 * 60 * 1000, // every 10 minutes
animationSpeed: 1000,
timeFormat: config.timeFormat,
showPeriod: true,
showPeriodUpper: false,
showWindDirection: true,
showWindDirectionAsArrow: false,
useBeaufort: true,
useKMPHwind: false,
lang: config.language,
decimalSymbol: ".",
showHumidity: false,
showSun: true,
degreeLabel: false,
showIndoorTemperature: false,
showIndoorHumidity: false,
showFeelsLike: true,
initialLoadDelay: 0, // 0 seconds delay
retryDelay: 2500,
apiVersion: "2.5",
apiBase: "https://api.openweathermap.org/data/",
weatherEndpoint: "weather",
appendLocationNameToHeader: true,
useLocationAsHeader: false,
calendarClass: "calendar",
tableClass: "large",
onlyTemp: false,
hideTemp: false,
roundTemp: false,
iconTable: {
"01d": "day-sunny",
"02d": "day-cloudy",
"03d": "cloudy",
"04d": "cloudy-windy",
"09d": "showers",
"10d": "rain",
"11d": "thunderstorm",
"13d": "snow",
"50d": "fog",
"01n": "night-clear",
"02n": "night-cloudy",
"03n": "night-cloudy",
"04n": "night-cloudy",
"09n": "night-showers",
"10n": "night-rain",
"11n": "night-thunderstorm",
"13n": "night-snow",
"50n": "night-alt-cloudy-windy"
}
},
// create a variable for the first upcoming calendar event. Used if no location is specified.
firstEvent: false,
// create a variable to hold the location name based on the API result.
fetchedLocationName: "",
// Define required scripts.
getScripts: function () {
return ["moment.js"];
},
// Define required scripts.
getStyles: function () {
return ["weather-icons.css", "currentweather.css"];
},
// Define required translations.
getTranslations: function () {
// The translations for the default modules are defined in the core translation files.
// Therefor we can just return false. Otherwise we should have returned a dictionary.
// If you're trying to build your own module including translations, check out the documentation.
return false;
},
// Define start sequence.
start: function () {
Log.info("Starting module: " + this.name);
// Set locale.
moment.locale(config.language);
this.windSpeed = null;
this.windDirection = null;
this.windDeg = null;
this.sunriseSunsetTime = null;
this.sunriseSunsetIcon = null;
this.temperature = null;
this.indoorTemperature = null;
this.indoorHumidity = null;
this.weatherType = null;
this.feelsLike = null;
this.loaded = false;
this.scheduleUpdate(this.config.initialLoadDelay);
},
// add extra information of current weather
// windDirection, humidity, sunrise and sunset
addExtraInfoWeather: function (wrapper) {
var small = document.createElement("div");
small.className = "normal medium";
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("sup");
if (this.config.showWindDirectionAsArrow) {
if (this.windDeg !== null) {
windDirection.innerHTML = ' &nbsp;<i class="fa fa-long-arrow-down" style="transform:rotate(' + this.windDeg + 'deg);"></i>&nbsp;';
}
} else {
windDirection.innerHTML = " " + this.translate(this.windDirection);
}
small.appendChild(windDirection);
}
var spacer = document.createElement("span");
spacer.innerHTML = "&nbsp;";
small.appendChild(spacer);
if (this.config.showHumidity) {
var humidity = document.createElement("span");
humidity.innerHTML = this.humidity;
var supspacer = document.createElement("sup");
supspacer.innerHTML = "&nbsp;";
var humidityIcon = document.createElement("sup");
humidityIcon.className = "wi wi-humidity humidityIcon";
humidityIcon.innerHTML = "&nbsp;";
small.appendChild(humidity);
small.appendChild(supspacer);
small.appendChild(humidityIcon);
}
if (this.config.showSun) {
var sunriseSunsetIcon = document.createElement("span");
sunriseSunsetIcon.className = "wi dimmed " + this.sunriseSunsetIcon;
small.appendChild(sunriseSunsetIcon);
var sunriseSunsetTime = document.createElement("span");
sunriseSunsetTime.innerHTML = " " + this.sunriseSunsetTime;
small.appendChild(sunriseSunsetTime);
}
wrapper.appendChild(small);
},
// Override dom generator.
getDom: function () {
var wrapper = document.createElement("div");
wrapper.className = this.config.tableClass;
if (this.config.appid === "") {
wrapper.innerHTML = "Please set the correct openweather <i>appid</i> in the config for module: " + this.name + ".";
wrapper.className = "dimmed light small";
return wrapper;
}
if (!this.loaded) {
wrapper.innerHTML = this.translate("LOADING");
wrapper.className = "dimmed light small";
return wrapper;
}
if (this.config.onlyTemp === false) {
this.addExtraInfoWeather(wrapper);
}
var large = document.createElement("div");
large.className = "light";
var degreeLabel = "";
if (this.config.units === "metric" || this.config.units === "imperial") {
degreeLabel += "°";
}
if (this.config.degreeLabel) {
switch (this.config.units) {
case "metric":
degreeLabel += "C";
break;
case "imperial":
degreeLabel += "F";
break;
case "default":
degreeLabel += "K";
break;
}
}
if (this.config.decimalSymbol === "") {
this.config.decimalSymbol = ".";
}
if (this.config.hideTemp === false) {
var weatherIcon = document.createElement("span");
weatherIcon.className = "wi weathericon wi-" + this.weatherType;
large.appendChild(weatherIcon);
var temperature = document.createElement("span");
temperature.className = "bright";
temperature.innerHTML = " " + this.temperature.replace(".", this.config.decimalSymbol) + degreeLabel;
large.appendChild(temperature);
}
if (this.config.showIndoorTemperature && this.indoorTemperature) {
var indoorIcon = document.createElement("span");
indoorIcon.className = "fa fa-home";
large.appendChild(indoorIcon);
var indoorTemperatureElem = document.createElement("span");
indoorTemperatureElem.className = "bright";
indoorTemperatureElem.innerHTML = " " + this.indoorTemperature.replace(".", this.config.decimalSymbol) + degreeLabel;
large.appendChild(indoorTemperatureElem);
}
if (this.config.showIndoorHumidity && this.indoorHumidity) {
var indoorHumidityIcon = document.createElement("span");
indoorHumidityIcon.className = "fa fa-tint";
large.appendChild(indoorHumidityIcon);
var indoorHumidityElem = document.createElement("span");
indoorHumidityElem.className = "bright";
indoorHumidityElem.innerHTML = " " + this.indoorHumidity + "%";
large.appendChild(indoorHumidityElem);
}
wrapper.appendChild(large);
if (this.config.showFeelsLike && this.config.onlyTemp === false) {
var small = document.createElement("div");
small.className = "normal medium";
var feelsLike = document.createElement("span");
feelsLike.className = "dimmed";
feelsLike.innerHTML = this.translate("FEELS", {
DEGREE: this.feelsLike + degreeLabel
});
small.appendChild(feelsLike);
wrapper.appendChild(small);
}
wrapper.innerHTML =
"<style>text-decoration: none</style>" +
"This module is deprecated since release v2.15 and removed with v2.19." +
'<br>Please use the `weather` module as replacement, more info in the <a href="https://docs.magicmirror.builders/modules/weather.html" style="color: #ffffff">documentation</a>.';
wrapper.className = "dimmed light small";
return wrapper;
},
// Override getHeader method.
getHeader: function () {
if (this.config.useLocationAsHeader && this.config.location !== false) {
return this.config.location;
}
if (this.config.appendLocationNameToHeader) {
if (this.data.header) return this.data.header + " " + this.fetchedLocationName;
else return this.fetchedLocationName;
}
return this.data.header ? this.data.header : "";
},
// Override notification handler.
notificationReceived: function (notification, payload, sender) {
if (notification === "DOM_OBJECTS_CREATED") {
if (this.config.appendLocationNameToHeader) {
this.hide(0, { lockString: this.identifier });
}
}
if (notification === "CALENDAR_EVENTS") {
var senderClasses = sender.data.classes.toLowerCase().split(" ");
if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) {
this.firstEvent = false;
for (var e in payload) {
var event = payload[e];
if (event.location || event.geo) {
this.firstEvent = event;
//Log.log("First upcoming event with location: ", event);
break;
}
}
}
}
if (notification === "INDOOR_TEMPERATURE") {
this.indoorTemperature = this.roundValue(payload);
this.updateDom(this.config.animationSpeed);
}
if (notification === "INDOOR_HUMIDITY") {
this.indoorHumidity = this.roundValue(payload);
this.updateDom(this.config.animationSpeed);
}
},
/* updateWeather(compliments)
* Requests new data from openweather.org.
* Calls processWeather on succesfull response.
*/
updateWeather: function () {
if (this.config.appid === "") {
Log.error("CurrentWeather: APPID not set!");
return;
}
var url = this.config.apiBase + this.config.apiVersion + "/" + this.config.weatherEndpoint + this.getParams();
var self = this;
var retry = true;
var weatherRequest = new XMLHttpRequest();
weatherRequest.open("GET", url, true);
weatherRequest.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200) {
self.processWeather(JSON.parse(this.response));
} else if (this.status === 401) {
self.updateDom(self.config.animationSpeed);
Log.error(self.name + ": Incorrect APPID.");
retry = true;
} else {
Log.error(self.name + ": Could not load weather.");
}
if (retry) {
self.scheduleUpdate(self.loaded ? -1 : self.config.retryDelay);
}
}
};
weatherRequest.send();
},
/* getParams(compliments)
* Generates an url with api parameters based on the config.
*
* return String - URL params.
*/
getParams: function () {
var params = "?";
if (this.config.locationID) {
params += "id=" + this.config.locationID;
} else if (this.config.location) {
params += "q=" + this.config.location;
} else if (this.firstEvent && this.firstEvent.geo) {
params += "lat=" + this.firstEvent.geo.lat + "&lon=" + this.firstEvent.geo.lon;
} else if (this.firstEvent && this.firstEvent.location) {
params += "q=" + this.firstEvent.location;
} else {
this.hide(this.config.animationSpeed, { lockString: this.identifier });
return;
}
params += "&units=" + this.config.units;
params += "&lang=" + this.config.lang;
params += "&APPID=" + this.config.appid;
return params;
},
/* processWeather(data)
* Uses the received data to set the various values.
*
* argument data object - Weather information received form openweather.org.
*/
processWeather: function (data) {
if (!data || !data.main || typeof data.main.temp === "undefined") {
// Did not receive usable new data.
// Maybe this needs a better check?
return;
}
this.humidity = parseFloat(data.main.humidity);
this.temperature = this.roundValue(data.main.temp);
this.fetchedLocationName = data.name;
this.feelsLike = 0;
if (this.config.useBeaufort) {
this.windSpeed = this.ms2Beaufort(this.roundValue(data.wind.speed));
} else if (this.config.useKMPHwind) {
this.windSpeed = parseFloat((data.wind.speed * 60 * 60) / 1000).toFixed(0);
} else {
this.windSpeed = parseFloat(data.wind.speed).toFixed(0);
}
// ONLY WORKS IF TEMP IN C //
var windInMph = parseFloat(data.wind.speed * 2.23694);
var tempInF = 0;
switch (this.config.units) {
case "metric":
tempInF = 1.8 * this.temperature + 32;
break;
case "imperial":
tempInF = this.temperature;
break;
case "default":
tempInF = 1.8 * (this.temperature - 273.15) + 32;
break;
}
if (windInMph > 3 && tempInF < 50) {
// windchill
var windChillInF = Math.round(35.74 + 0.6215 * tempInF - 35.75 * Math.pow(windInMph, 0.16) + 0.4275 * tempInF * Math.pow(windInMph, 0.16));
var windChillInC = (windChillInF - 32) * (5 / 9);
// this.feelsLike = windChillInC.toFixed(0);
switch (this.config.units) {
case "metric":
this.feelsLike = windChillInC.toFixed(0);
break;
case "imperial":
this.feelsLike = windChillInF.toFixed(0);
break;
case "default":
this.feelsLike = (windChillInC + 273.15).toFixed(0);
break;
}
} else if (tempInF > 80 && this.humidity > 40) {
// heat index
var Hindex =
-42.379 +
2.04901523 * tempInF +
10.14333127 * this.humidity -
0.22475541 * tempInF * this.humidity -
6.83783 * Math.pow(10, -3) * tempInF * tempInF -
5.481717 * Math.pow(10, -2) * this.humidity * this.humidity +
1.22874 * Math.pow(10, -3) * tempInF * tempInF * this.humidity +
8.5282 * Math.pow(10, -4) * tempInF * this.humidity * this.humidity -
1.99 * Math.pow(10, -6) * tempInF * tempInF * this.humidity * this.humidity;
switch (this.config.units) {
case "metric":
this.feelsLike = parseFloat((Hindex - 32) / 1.8).toFixed(0);
break;
case "imperial":
this.feelsLike = Hindex.toFixed(0);
break;
case "default":
var tc = parseFloat((Hindex - 32) / 1.8) + 273.15;
this.feelsLike = tc.toFixed(0);
break;
}
} else {
this.feelsLike = parseFloat(this.temperature).toFixed(0);
}
this.windDirection = this.deg2Cardinal(data.wind.deg);
this.windDeg = data.wind.deg;
this.weatherType = this.config.iconTable[data.weather[0].icon];
var now = new Date();
var sunrise = new Date(data.sys.sunrise * 1000);
var sunset = new Date(data.sys.sunset * 1000);
// 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 sunriseSunsetDateObject = sunrise < now && sunset > now ? sunset : sunrise;
var timeString = moment(sunriseSunsetDateObject).format("HH:mm");
if (this.config.timeFormat !== 24) {
//var hours = sunriseSunsetDateObject.getHours() % 12 || 12;
if (this.config.showPeriod) {
if (this.config.showPeriodUpper) {
//timeString = hours + moment(sunriseSunsetDateObject).format(':mm A');
timeString = moment(sunriseSunsetDateObject).format("h:mm A");
} else {
//timeString = hours + moment(sunriseSunsetDateObject).format(':mm a');
timeString = moment(sunriseSunsetDateObject).format("h:mm a");
}
} else {
//timeString = hours + moment(sunriseSunsetDateObject).format(':mm');
timeString = moment(sunriseSunsetDateObject).format("h:mm");
}
}
this.sunriseSunsetTime = timeString;
this.sunriseSunsetIcon = sunrise < now && sunset > now ? "wi-sunset" : "wi-sunrise";
this.show(this.config.animationSpeed, { lockString: this.identifier });
this.loaded = true;
this.updateDom(this.config.animationSpeed);
this.sendNotification("CURRENTWEATHER_DATA", { data: data });
this.sendNotification("CURRENTWEATHER_TYPE", { type: this.config.iconTable[data.weather[0].icon].replace("-", "_") });
},
/* scheduleUpdate()
* Schedule next update.
*
* argument delay number - Milliseconds before next update. If empty, this.config.updateInterval is used.
*/
scheduleUpdate: function (delay) {
var nextLoad = this.config.updateInterval;
if (typeof delay !== "undefined" && delay >= 0) {
nextLoad = delay;
}
var self = this;
setTimeout(function () {
self.updateWeather();
}, nextLoad);
},
/* ms2Beaufort(ms)
* Converts m2 to beaufort (windspeed).
*
* see:
* https://www.spc.noaa.gov/faq/tornado/beaufort.html
* https://en.wikipedia.org/wiki/Beaufort_scale#Modern_scale
*
* argument ms number - Windspeed in m/s.
*
* return number - Windspeed in beaufort.
*/
ms2Beaufort: function (ms) {
var kmh = (ms * 60 * 60) / 1000;
var speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000];
for (var beaufort in speeds) {
var speed = speeds[beaufort];
if (speed > kmh) {
return beaufort;
}
}
return 12;
},
deg2Cardinal: function (deg) {
if (deg > 11.25 && deg <= 33.75) {
return "NNE";
} else if (deg > 33.75 && deg <= 56.25) {
return "NE";
} else if (deg > 56.25 && deg <= 78.75) {
return "ENE";
} else if (deg > 78.75 && deg <= 101.25) {
return "E";
} 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";
}
},
/* function(temperature)
* Rounds a temperature to 1 decimal or integer (depending on config.roundTemp).
*
* argument temperature number - Temperature.
*
* return string - Rounded Temperature.
*/
roundValue: function (temperature) {
var decimals = this.config.roundTemp ? 0 : 1;
var roundValue = parseFloat(temperature).toFixed(decimals);
return roundValue === "-0" ? 0 : roundValue;
return "deprecated currentweather";
}
});

View File

@@ -1,9 +0,0 @@
const NodeHelper = require("node_helper");
const Log = require("logger");
module.exports = NodeHelper.create({
// Override start method.
start: function () {
Log.warn(`The module '${this.name}' is deprecated in favor of the 'weather'-module, please refer to the documentation for a migration path`);
}
});

View File

@@ -1,4 +1,4 @@
/* Magic Mirror Default Modules List
/* MagicMirror² Default Modules List
* Modules listed below can be loaded without the 'default/' prefix. Omitting the default folder name.
*
* By Michael Teeuw https://michaelteeuw.nl

View File

@@ -1,5 +1,5 @@
# Module: Hello World
The `helloworld` module is one of the default modules of the MagicMirror. It is a simple way to display a static text on the mirror.
The `helloworld` module is one of the default modules of the MagicMirror². It is a simple way to display a static text on the mirror.
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/helloworld.html).

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Module: HelloWorld
*
* By Michael Teeuw https://michaelteeuw.nl

View File

@@ -1,6 +1,6 @@
# Module: News Feed
The `newsfeed` module is one of the default modules of the MagicMirror.
The `newsfeed` module is one of the default modules of the MagicMirror².
This module displays news headlines based on an RSS feed. Scrolling through news headlines happens time-based (`updateInterval`), but can also be controlled by sending news feed specific notifications to the module.
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/newsfeed.html).

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Module: NewsFeed
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -20,6 +20,7 @@ Module.register("newsfeed", {
broadcastNewsFeeds: true,
broadcastNewsUpdates: true,
showDescription: false,
showTitleAsUrl: false,
wrapTitle: true,
wrapDescription: true,
truncDescription: true,
@@ -141,6 +142,7 @@ Module.register("newsfeed", {
sourceTitle: item.sourceTitle,
publishDate: moment(new Date(item.pubdate)).fromNow(),
title: item.title,
url: item.url,
description: item.description,
items: items
};

View File

@@ -6,6 +6,22 @@
{% endif %}
{% endmacro %}
{% macro escapeTitle(title, url, dangerouslyDisableAutoEscaping=false, showTitleAsUrl=false) %}
{% if dangerouslyDisableAutoEscaping %}
{% if showTitleAsUrl %}
<a href="{{ url }}" style="text-decoration:none;color:#ffffff" target="_blank">{{ title | safe }}</a>
{% else %}
{{ title | safe}}
{% endif %}
{% else %}
{% if showTitleAsUrl %}
<a href="{{ url }}" style="text-decoration:none;color:#ffffff" target="_blank">{{ title }}</a>
{% else %}
{{ title }}
{% endif %}
{% endif %}
{% endmacro %}
{% if loaded %}
{% if config.showAsList %}
<ul class="newsfeed-list">
@@ -22,7 +38,7 @@
</div>
{% endif %}
<div class="newsfeed-title bright medium light{{ ' no-wrap' if not config.wrapTitle }}">
{{ escapeText(item.title, config.dangerouslyDisableAutoEscaping) }}
{{ escapeTitle(item.title, item.url, config.dangerouslyDisableAutoEscaping, config.showTitleAsUrl) }}
</div>
{% if config.showDescription %}
<div class="newsfeed-desc small light{{ ' no-wrap' if not config.wrapDescription }}">
@@ -49,7 +65,7 @@
</div>
{% endif %}
<div class="newsfeed-title bright medium light{{ ' no-wrap' if not config.wrapTitle }}">
{{ escapeText(title, config.dangerouslyDisableAutoEscaping) }}
{{ escapeTitle(title, url, config.dangerouslyDisableAutoEscaping, config.showTitleAsUrl) }}
</div>
{% if config.showDescription %}
<div class="newsfeed-desc small light{{ ' no-wrap' if not config.wrapDescription }}">

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Node Helper: Newsfeed - NewsfeedFetcher
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -7,8 +7,9 @@
const Log = require("logger");
const FeedMe = require("feedme");
const NodeHelper = require("node_helper");
const fetch = require("node-fetch");
const fetch = require("fetch");
const iconv = require("iconv-lite");
const stream = require("stream");
/**
* Responsible for requesting an update on the set interval and broadcasting the data.
@@ -87,7 +88,13 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
fetch(url, { headers: headers })
.then(NodeHelper.checkFetchStatus)
.then((response) => {
response.body.pipe(iconv.decodeStream(encoding)).pipe(parser);
let nodeStream;
if (response.body instanceof stream.Readable) {
nodeStream = response.body;
} else {
nodeStream = stream.Readable.fromWeb(response.body);
}
nodeStream.pipe(iconv.decodeStream(encoding)).pipe(parser);
})
.catch((error) => {
fetchFailedCallback(this, error);

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Node Helper: Newsfeed
*
* By Michael Teeuw https://michaelteeuw.nl

View File

@@ -1,6 +1,6 @@
# Module: Update Notification
The `updatenotification` module is one of the default modules of the MagicMirror.
This will display a message whenever a new version of the MagicMirror application is available.
The `updatenotification` module is one of the default modules of the MagicMirror².
This will display a message whenever a new version of the MagicMirror² application is available.
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/updatenotification.html).

View File

@@ -1,4 +1,4 @@
/* Magic Mirror
/* MagicMirror²
* Module: UpdateNotification
*
* By Michael Teeuw https://michaelteeuw.nl

View File

@@ -1,7 +1,7 @@
{% if not suspended %}
{% for name, status in moduleList %}
<div class="small bright">
<i class="fa fa-exclamation-circle"></i>
<i class="fas fa-exclamation-circle"></i>
<span>
{% set mainTextLabel = "UPDATE_NOTIFICATION" if name === "default" else "UPDATE_NOTIFICATION_MODULE" %}
{{ mainTextLabel | translate({MODULE_NAME: name}) }}

View File

@@ -15,7 +15,7 @@
{% if config.showWindDirection %}
<sup>
{% if config.showWindDirectionAsArrow %}
<i class="fa fa-long-arrow-up" style="transform:rotate({{ current.windDirection }}deg);"></i>
<i class="fas fa-long-arrow-alt-up" style="transform:rotate({{ current.windDirection }}deg);"></i>
{% else %}
{{ current.cardinalWindDirection() | translate }}
{% endif %}
@@ -47,7 +47,7 @@
<div class="normal light indoor">
{% if config.showIndoorTemperature and indoor.temperature %}
<div>
<span class="fa fa-home"></span>
<span class="fas fa-home"></span>
<span class="bright">
{{ indoor.temperature | roundValue | unit("temperature") | decimalSymbol }}
</span>
@@ -55,7 +55,7 @@
{% endif %}
{% if config.showIndoorHumidity and indoor.humidity %}
<div>
<span class="fa fa-tint"></span>
<span class="fas fa-tint"></span>
<span class="bright">
{{ indoor.humidity | roundValue | unit("humidity") | decimalSymbol }}
</span>

View File

@@ -8,9 +8,9 @@
{% set forecast = forecast.slice(0, numSteps) %}
{% for f in forecast %}
<tr {% if config.colored %}class="colored"{% endif %} {% if config.fade %}style="opacity: {{ currentStep | opacity(numSteps) }};"{% endif %}>
{% if (currentStep == 0) and config.ignoreToday == false %}
{% if (currentStep == 0) and config.ignoreToday == false and config.absoluteDates == false %}
<td class="day">{{ "TODAY" | translate }}</td>
{% elif (currentStep == 1) and config.ignoreToday == false %}
{% elif (currentStep == 1) and config.ignoreToday == false and config.absoluteDates == false %}
<td class="day">{{ "TOMORROW" | translate }}</td>
{% else %}
<td class="day">{{ f.date.format('ddd') }}</td>

View File

@@ -1,6 +1,6 @@
/* global WeatherProvider, WeatherObject */
/* Magic Mirror
/* MagicMirror²
* Module: Weather
* Provider: Dark Sky
*
@@ -18,7 +18,8 @@ WeatherProvider.register("darksky", {
// Set the default config properties that is specific to this provider
defaults: {
apiBase: "https://cors-anywhere.herokuapp.com/https://api.darksky.net",
useCorsProxy: true,
apiBase: "https://api.darksky.net",
weatherEndpoint: "/forecast",
apiKey: "",
lat: 0,

View File

@@ -1,6 +1,6 @@
/* global WeatherProvider, WeatherObject */
/* Magic Mirror
/* MagicMirror²
* Module: Weather
* Provider: Environment Canada (EC)
*
@@ -40,6 +40,7 @@ WeatherProvider.register("envcanada", {
// Set the default config properties that is specific to this provider
defaults: {
useCorsProxy: true,
siteCode: "s1234567",
provCode: "ON"
},
@@ -73,7 +74,7 @@ WeatherProvider.register("envcanada", {
// Override the fetchCurrentWeather method to query EC and construct a Current weather object
//
fetchCurrentWeather() {
this.fetchData(this.getUrl(), "GET")
this.fetchData(this.getUrl(), "GET", "xml")
.then((data) => {
if (!data) {
// Did not receive usable new data.
@@ -93,7 +94,7 @@ WeatherProvider.register("envcanada", {
// Override the fetchWeatherForecast method to query EC and construct Forecast weather objects
//
fetchWeatherForecast() {
this.fetchData(this.getUrl(), "GET")
this.fetchData(this.getUrl(), "GET", "xml")
.then((data) => {
if (!data) {
// Did not receive usable new data.
@@ -113,7 +114,7 @@ WeatherProvider.register("envcanada", {
// Override the fetchWeatherHourly method to query EC and construct Forecast weather objects
//
fetchWeatherHourly() {
this.fetchData(this.getUrl(), "GET")
this.fetchData(this.getUrl(), "GET", "xml")
.then((data) => {
if (!data) {
// Did not receive usable new data.
@@ -129,26 +130,6 @@ WeatherProvider.register("envcanada", {
.finally(() => this.updateAvailable());
},
//
// Override fetchData function to handle XML document (base function assumes JSON)
//
fetchData: function (url, method = "GET", data = null) {
return new Promise(function (resolve, reject) {
const request = new XMLHttpRequest();
request.open(method, url, true);
request.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200) {
resolve(this.responseXML);
} else {
reject(request);
}
}
};
request.send();
});
},
//////////////////////////////////////////////////////////////////////////////////
//
// Environment Canada methods - not part of the standard Provider methods
@@ -160,11 +141,8 @@ WeatherProvider.register("envcanada", {
// URL defaults to the Englsih version simply because there is no language dependancy in the data
// being accessed. This is only pertinent when using the EC data elements that contain a textual forecast.
//
// Also note that access is supported through a proxy service (thingproxy.freeboard.io) to mitigate
// CORS errors when accessing EC
//
getUrl() {
return "https://thingproxy.freeboard.io/fetch/https://dd.weather.gc.ca/citypage_weather/xml/" + this.config.provCode + "/" + this.config.siteCode + "_e.xml";
return "https://dd.weather.gc.ca/citypage_weather/xml/" + this.config.provCode + "/" + this.config.siteCode + "_e.xml";
},
//

View File

@@ -1,6 +1,6 @@
/* global WeatherProvider, WeatherObject */
/* Magic Mirror
/* MagicMirror²
* Module: Weather
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -128,12 +128,7 @@ WeatherProvider.register("openweathermap", {
currentWeather.humidity = currentWeatherData.main.humidity;
currentWeather.temperature = currentWeatherData.main.temp;
currentWeather.feelsLikeTemp = currentWeatherData.main.feels_like;
if (this.config.windUnits === "metric") {
currentWeather.windSpeed = this.config.useKmh ? currentWeatherData.wind.speed * 3.6 : currentWeatherData.wind.speed;
} else {
currentWeather.windSpeed = currentWeatherData.wind.speed;
}
currentWeather.windSpeed = currentWeatherData.wind.speed;
currentWeather.windDirection = currentWeatherData.wind.deg;
currentWeather.weatherType = this.convertWeatherType(currentWeatherData.weather[0].icon);
currentWeather.sunrise = moment(currentWeatherData.sys.sunrise, "X");

View File

@@ -1,6 +1,6 @@
/* global WeatherProvider, WeatherObject */
/* Magic Mirror
/* MagicMirror²
* Module: Weather
* Provider: SMHI
*
@@ -237,7 +237,7 @@ WeatherProvider.register("smhi", {
},
/**
* Map the icon value from SMHI to an icon that MagicMirror understands.
* Map the icon value from SMHI to an icon that MagicMirror² understands.
* Uses different icons depending if its daytime or nighttime.
* SMHI's description of what the numeric value means is the comment after the case.
*

View File

@@ -1,6 +1,6 @@
/* global WeatherProvider, WeatherObject */
/* Magic Mirror
/* MagicMirror²
* Module: Weather
*
* By Malcolm Oakes https://github.com/maloakes

View File

@@ -1,6 +1,6 @@
/* global WeatherProvider, WeatherObject */
/* Magic Mirror
/* MagicMirror²
* Module: Weather
*
* By Malcolm Oakes https://github.com/maloakes

View File

@@ -1,6 +1,6 @@
/* global WeatherProvider, WeatherObject */
/* Magic Mirror
/* MagicMirror²
* Module: Weather
* Provider: Weatherbit
*

View File

@@ -0,0 +1,109 @@
/* global WeatherProvider, WeatherObject */
/* MagicMirror²
* Module: Weather
* Provider: Weatherflow
*
* By Tobias Dreyem https://github.com/10bias
* MIT Licensed
*
* This class is a provider for Weatherflow.
* Note that the Weatherflow API does not provide snowfall.
*/
WeatherProvider.register("weatherflow", {
// Set the name of the provider.
// Not strictly required, but helps for debugging
providerName: "WeatherFlow",
// Set the default config properties that is specific to this provider
defaults: {
apiBase: "https://swd.weatherflow.com/swd/rest/",
token: "",
stationid: ""
},
units: {
imperial: {
temp: "f",
wind: "mph",
pressure: "hpa",
precip: "in",
distance: "mi"
},
metric: {
temp: "c",
wind: "kph",
pressure: "mb",
precip: "mm",
distance: "km"
}
},
fetchCurrentWeather() {
this.fetchData(this.getUrl())
.then((data) => {
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
currentWeather.date = moment();
currentWeather.humidity = data.current_conditions.relative_humidity;
currentWeather.temperature = data.current_conditions.air_temperature;
currentWeather.windSpeed = data.current_conditions.wind_avg;
currentWeather.windDirection = data.current_conditions.wind_direction;
currentWeather.weatherType = data.forecast.daily[0].icon;
currentWeather.sunrise = moment(data.forecast.daily[0].sunrise, "X");
currentWeather.sunset = moment(data.forecast.daily[0].sunset, "X");
this.setCurrentWeather(currentWeather);
})
.catch(function (request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable());
},
fetchWeatherForecast() {
this.fetchData(this.getUrl())
.then((data) => {
const days = [];
for (const forecast of data.forecast.daily) {
const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
weather.date = moment(forecast.day_start_local, "X");
weather.minTemperature = forecast.air_temp_low;
weather.maxTemperature = forecast.air_temp_high;
weather.weatherType = forecast.icon;
weather.snow = 0;
days.push(weather);
}
this.setWeatherForecast(days);
})
.catch(function (request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable());
},
// Create a URL from the config and base URL.
getUrl() {
return (
this.config.apiBase +
"better_forecast?station_id=" +
this.config.stationid +
"&units_temp=" +
this.units[this.config.units].temp +
"&units_wind=" +
this.units[this.config.units].wind +
"&units_pressure=" +
this.units[this.config.units].pressure +
"&units_precip=" +
this.units[this.config.units].precip +
"&units_distance=" +
this.units[this.config.units].distance +
"&token=" +
this.config.token
);
}
});

View File

@@ -1,6 +1,6 @@
/* global WeatherProvider, WeatherObject */
/* Magic Mirror
/* MagicMirror²
* Module: Weather
* Provider: weather.gov
* https://weather-gov.github.io/api/general-faqs
@@ -40,7 +40,8 @@ WeatherProvider.register("weathergov", {
// Called to set the config, this config is the same as the weather module's config.
setConfig: function (config) {
this.config = config;
(this.config.apiBase = "https://api.weather.gov"), this.fetchWxGovURLs(this.config);
this.config.apiBase = "https://api.weather.gov";
this.fetchWxGovURLs(this.config);
},
// Called when the weather provider is about to start.
@@ -156,8 +157,13 @@ WeatherProvider.register("weathergov", {
currentWeather.rain = null;
currentWeather.snow = null;
currentWeather.precipitation = this.convertLength(currentWeatherData.precipitationLastHour.value);
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.heatIndex.value);
if (currentWeatherData.heatIndex.value !== null) {
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.heatIndex.value);
} else if (currentWeatherData.windChill.value !== null) {
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.windChill.value);
} else {
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.temperature.value);
}
// determine the sunrise/sunset times - not supplied in weather.gov data
currentWeather.updateSunTime(this.config.lat, this.config.lon);

View File

@@ -1,6 +1,6 @@
/* global WeatherProvider */
/* Magic Mirror
/* MagicMirror²
* Module: Weather
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -43,7 +43,8 @@ Module.register("weather", {
onlyTemp: false,
showPrecipitationAmount: false,
colored: false,
showFeelsLike: true
showFeelsLike: true,
absoluteDates: false
},
// Module properties.
@@ -153,6 +154,15 @@ Module.register("weather", {
if (this.weatherProvider.currentWeather()) {
this.sendNotification("CURRENTWEATHER_TYPE", { type: this.weatherProvider.currentWeather().weatherType.replace("-", "_") });
}
const notificationPayload = {
currentWeather: this.weatherProvider?.currentWeatherObject?.simpleClone() ?? null,
forecastArray: this.weatherProvider?.weatherForecastArray?.map((ar) => ar.simpleClone()) ?? [],
hourlyArray: this.weatherProvider?.weatherHourlyArray?.map((ar) => ar.simpleClone()) ?? [],
locationName: this.weatherProvider?.fetchedLocationName,
providerName: this.weatherProvider.providerName
};
this.sendNotification("WEATHER_UPDATED", notificationPayload);
},
scheduleUpdate: function (delay = null) {

View File

@@ -1,6 +1,6 @@
/* global SunCalc */
/* Magic Mirror
/* MagicMirror²
* Module: Weather
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -146,6 +146,23 @@ class WeatherObject {
this.sunrise = moment(times.sunrise, "X");
this.sunset = moment(times.sunset, "X");
}
/**
* Clone to simple object to prevent mutating and deprecation of legacy library.
*
* Before being handed to other modules, mutable values must be cloned safely.
* Especially 'moment' object is not immutable, so original 'date', 'sunrise', 'sunset' could be corrupted or changed by other modules.
*
* @returns {object} plained object clone of original weatherObject
*/
simpleClone() {
const toFlat = ["date", "sunrise", "sunset"];
let clone = { ...this };
for (const prop of toFlat) {
clone[prop] = clone?.[prop]?.valueOf() ?? clone?.[prop];
}
return clone;
}
}
/*************** DO NOT EDIT THE LINE BELOW ***************/

View File

@@ -1,6 +1,6 @@
/* global Class */
/* Magic Mirror
/* MagicMirror²
* Module: Weather
*
* By Michael Teeuw https://michaelteeuw.nl
@@ -111,8 +111,17 @@ const WeatherProvider = Class.extend({
this.delegate.updateAvailable(this);
},
getCorsUrl: function () {
if (this.config.mockData || typeof this.config.useCorsProxy === "undefined" || !this.config.useCorsProxy) {
return "";
} else {
return location.protocol + "//" + location.host + "/cors?url=";
}
},
// A convenience function to make requests. It returns a promise.
fetchData: function (url, method = "GET", data = null) {
fetchData: function (url, method = "GET", type = "json") {
url = this.getCorsUrl() + url;
const getData = function (mockData) {
return new Promise(function (resolve, reject) {
if (mockData) {
@@ -125,7 +134,11 @@ const WeatherProvider = Class.extend({
request.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200) {
resolve(JSON.parse(this.response));
if (type === "xml") {
resolve(this.responseXML);
} else {
resolve(JSON.parse(this.response));
}
} else {
reject(request);
}

View File

@@ -1,8 +0,0 @@
# Module: Weather Forecast
> :warning: **This module is deprecated in favor of the [weather](https://docs.magicmirror.builders/modules/weather.html) module.**
The `weatherforecast` module is one of the default modules of the MagicMirror.
This module displays the weather forecast for the coming week, including an an icon to display the current conditions, the minimum temperature and the maximum temperature.
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/weatherforecast.html).

View File

@@ -1,9 +0,0 @@
const NodeHelper = require("node_helper");
const Log = require("logger");
module.exports = NodeHelper.create({
// Override start method.
start: function () {
Log.warn(`The module '${this.name}' is deprecated in favor of the 'weather'-module, please refer to the documentation for a migration path`);
}
});

View File

@@ -1,27 +0,0 @@
.weatherforecast .day {
padding-left: 0;
padding-right: 25px;
}
.weatherforecast .weather-icon {
padding-right: 30px;
text-align: center;
}
.weatherforecast .min-temp {
padding-left: 20px;
padding-right: 0;
}
.weatherforecast .rain {
padding-left: 20px;
padding-right: 0;
}
.weatherforecast tr.colored .min-temp {
color: #bcddff;
}
.weatherforecast tr.colored .max-temp {
color: #ff8e99;
}

View File

@@ -1,7 +1,7 @@
/* eslint-disable */
/* Magic Mirror
* Module: WeatherForecast
/* MagicMirror²
* Module: CurrentWeather
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
@@ -9,510 +9,25 @@
* This module is deprecated. Any additional feature will no longer be merged.
*/
Module.register("weatherforecast", {
// Default module config.
defaults: {
location: false,
locationID: false,
lat: false,
lon: false,
appid: "",
units: config.units,
maxNumberOfDays: 7,
showRainAmount: false,
updateInterval: 10 * 60 * 1000, // every 10 minutes
animationSpeed: 1000,
timeFormat: config.timeFormat,
lang: config.language,
decimalSymbol: ".",
fade: true,
fadePoint: 0.25, // Start on 1/4th of the list.
colored: false,
scale: false,
initialLoadDelay: 2500, // 2.5 seconds delay. This delay is used to keep the OpenWeather API happy.
retryDelay: 2500,
apiVersion: "2.5",
apiBase: "https://api.openweathermap.org/data/",
forecastEndpoint: "forecast/daily",
excludes: false,
appendLocationNameToHeader: true,
calendarClass: "calendar",
tableClass: "small",
roundTemp: false,
iconTable: {
"01d": "wi-day-sunny",
"02d": "wi-day-cloudy",
"03d": "wi-cloudy",
"04d": "wi-cloudy-windy",
"09d": "wi-showers",
"10d": "wi-rain",
"11d": "wi-thunderstorm",
"13d": "wi-snow",
"50d": "wi-fog",
"01n": "wi-night-clear",
"02n": "wi-night-cloudy",
"03n": "wi-night-cloudy",
"04n": "wi-night-cloudy",
"09n": "wi-night-showers",
"10n": "wi-night-rain",
"11n": "wi-night-thunderstorm",
"13n": "wi-night-snow",
"50n": "wi-night-alt-cloudy-windy"
}
},
// create a variable for the first upcoming calendar event. Used if no location is specified.
firstEvent: false,
// create a variable to hold the location name based on the API result.
fetchedLocationName: "",
// Define required scripts.
getScripts: function () {
return ["moment.js"];
},
// Define required scripts.
getStyles: function () {
return ["weather-icons.css", "weatherforecast.css"];
},
// Define required translations.
getTranslations: function () {
// The translations for the default modules are defined in the core translation files.
// Therefor we can just return false. Otherwise we should have returned a dictionary.
// If you're trying to build your own module including translations, check out the documentation.
return false;
},
// Define start sequence.
start: function () {
Log.info("Starting module: " + this.name);
// Set locale.
moment.locale(config.language);
this.forecast = [];
this.loaded = false;
this.scheduleUpdate(this.config.initialLoadDelay);
this.updateTimer = null;
},
// Override dom generator.
getDom: function () {
var wrapper = document.createElement("div");
if (this.config.appid === "" || this.config.appid === "YOUR_OPENWEATHER_API_KEY") {
wrapper.innerHTML = "Please set the correct openweather <i>appid</i> in the config for module: " + this.name + ".";
wrapper.className = "dimmed light small";
return wrapper;
}
if (!this.loaded) {
wrapper.innerHTML = this.translate("LOADING");
wrapper.className = "dimmed light small";
return wrapper;
}
var table = document.createElement("table");
table.className = this.config.tableClass;
for (var f in this.forecast) {
var forecast = this.forecast[f];
var row = document.createElement("tr");
if (this.config.colored) {
row.className = "colored";
}
table.appendChild(row);
var dayCell = document.createElement("td");
dayCell.className = "day";
dayCell.innerHTML = forecast.day;
row.appendChild(dayCell);
var iconCell = document.createElement("td");
iconCell.className = "bright weather-icon";
row.appendChild(iconCell);
var icon = document.createElement("span");
icon.className = "wi weathericon " + forecast.icon;
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";
break;
case "imperial":
degreeLabel += "F";
break;
case "default":
degreeLabel = "K";
break;
}
}
if (this.config.decimalSymbol === "" || this.config.decimalSymbol === " ") {
this.config.decimalSymbol = ".";
}
var maxTempCell = document.createElement("td");
maxTempCell.innerHTML = forecast.maxTemp.replace(".", this.config.decimalSymbol) + degreeLabel;
maxTempCell.className = "align-right bright max-temp";
row.appendChild(maxTempCell);
var minTempCell = document.createElement("td");
minTempCell.innerHTML = forecast.minTemp.replace(".", this.config.decimalSymbol) + degreeLabel;
minTempCell.className = "align-right min-temp";
row.appendChild(minTempCell);
if (this.config.showRainAmount) {
var rainCell = document.createElement("td");
if (isNaN(forecast.rain)) {
rainCell.innerHTML = "";
} else {
if (config.units !== "imperial") {
rainCell.innerHTML = parseFloat(forecast.rain).toFixed(1).replace(".", this.config.decimalSymbol) + " mm";
} else {
rainCell.innerHTML = (parseFloat(forecast.rain) / 25.4).toFixed(2).replace(".", this.config.decimalSymbol) + " in";
}
}
rainCell.className = "align-right bright rain";
row.appendChild(rainCell);
}
if (this.config.fade && this.config.fadePoint < 1) {
if (this.config.fadePoint < 0) {
this.config.fadePoint = 0;
}
var startingPoint = this.forecast.length * this.config.fadePoint;
var steps = this.forecast.length - startingPoint;
if (f >= startingPoint) {
var currentStep = f - startingPoint;
row.style.opacity = 1 - (1 / steps) * currentStep;
}
}
}
return table;
wrapper.className = this.config.tableClass;
wrapper.innerHTML =
"<style>text-decoration: none</style>" +
"This module is deprecated since release v2.15 and removed with v2.19." +
'<br>Please use the `weather` module as replacement, more info in the <a href="https://docs.magicmirror.builders/modules/weather.html" style="color: #ffffff">documentation</a>.';
wrapper.className = "dimmed light small";
return wrapper;
},
// Override getHeader method.
getHeader: function () {
if (this.config.appendLocationNameToHeader) {
if (this.data.header) return this.data.header + " " + this.fetchedLocationName;
else return this.fetchedLocationName;
}
return this.data.header ? this.data.header : "";
},
// Override notification handler.
notificationReceived: function (notification, payload, sender) {
if (notification === "DOM_OBJECTS_CREATED") {
if (this.config.appendLocationNameToHeader) {
this.hide(0, { lockString: this.identifier });
}
}
if (notification === "CALENDAR_EVENTS") {
var senderClasses = sender.data.classes.toLowerCase().split(" ");
if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) {
this.firstEvent = false;
for (var e in payload) {
var event = payload[e];
if (event.location || event.geo) {
this.firstEvent = event;
//Log.log("First upcoming event with location: ", event);
break;
}
}
}
}
},
/* updateWeather(compliments)
* Requests new data from openweather.org.
* Calls processWeather on successful response.
*/
updateWeather: function () {
if (this.config.appid === "") {
Log.error("WeatherForecast: APPID not set!");
return;
}
var url = this.config.apiBase + this.config.apiVersion + "/" + this.config.forecastEndpoint + this.getParams();
var self = this;
var retry = true;
var weatherRequest = new XMLHttpRequest();
weatherRequest.open("GET", url, true);
weatherRequest.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200) {
self.processWeather(JSON.parse(this.response));
} else if (this.status === 401) {
self.updateDom(self.config.animationSpeed);
if (self.config.forecastEndpoint === "forecast/daily") {
self.config.forecastEndpoint = "forecast";
Log.warn(self.name + ": Your AppID does not support long term forecasts. Switching to fallback endpoint.");
}
retry = true;
} else {
Log.error(self.name + ": Could not load weather.");
}
if (retry) {
self.scheduleUpdate(self.loaded ? -1 : self.config.retryDelay);
}
}
};
weatherRequest.send();
},
/* getParams(compliments)
* Generates an url with api parameters based on the config.
*
* return String - URL params.
*/
getParams: function () {
var params = "?";
if (this.config.locationID) {
params += "id=" + this.config.locationID;
} else if (this.config.lat && this.config.lon) {
params += "lat=" + this.config.lat + "&lon=" + this.config.lon;
} else if (this.config.location) {
params += "q=" + this.config.location;
} else if (this.firstEvent && this.firstEvent.geo) {
params += "lat=" + this.firstEvent.geo.lat + "&lon=" + this.firstEvent.geo.lon;
} else if (this.firstEvent && this.firstEvent.location) {
params += "q=" + this.firstEvent.location;
} else {
this.hide(this.config.animationSpeed, { lockString: this.identifier });
return;
}
let numberOfDays;
if (this.config.forecastEndpoint === "forecast") {
numberOfDays = this.config.maxNumberOfDays < 1 || this.config.maxNumberOfDays > 5 ? 5 : this.config.maxNumberOfDays;
// don't get forecasts for the next day, as it would not represent the whole day
numberOfDays = numberOfDays * 8 - (Math.round(new Date().getHours() / 3) % 8);
} else {
numberOfDays = this.config.maxNumberOfDays < 1 || this.config.maxNumberOfDays > 17 ? 7 : this.config.maxNumberOfDays;
}
params += "&cnt=" + numberOfDays;
params += "&exclude=" + this.config.excludes;
params += "&units=" + this.config.units;
params += "&lang=" + this.config.lang;
params += "&APPID=" + this.config.appid;
return params;
},
/*
* parserDataWeather(data)
*
* Use the parse to keep the same struct between daily and forecast Endpoint
* from openweather.org
*
*/
parserDataWeather: function (data) {
if (data.hasOwnProperty("main")) {
data["temp"] = { min: data.main.temp_min, max: data.main.temp_max };
}
return data;
},
/* processWeather(data)
* Uses the received data to set the various values.
*
* argument data object - Weather information received form openweather.org.
*/
processWeather: function (data, momenttz) {
let mom = momenttz ? momenttz : moment; // Exception last.
// Forcast16 (paid) API endpoint provides this data. Onecall endpoint
// does not.
if (data.city) {
this.fetchedLocationName = data.city.name + ", " + data.city.country;
} else if (this.config.location) {
this.fetchedLocationName = this.config.location;
} else {
this.fetchedLocationName = "Unknown";
}
this.forecast = [];
var lastDay = null;
var forecastData = {};
var dayStarts = 8;
var dayEnds = 17;
if (data.city && data.city.sunrise && data.city.sunset) {
dayStarts = new Date(mom.unix(data.city.sunrise).locale("en").format("YYYY/MM/DD HH:mm:ss")).getHours();
dayEnds = new Date(mom.unix(data.city.sunset).locale("en").format("YYYY/MM/DD HH:mm:ss")).getHours();
}
// Handle different structs between forecast16 and onecall endpoints
var forecastList = null;
if (data.list) {
forecastList = data.list;
} else if (data.daily) {
forecastList = data.daily;
} else {
Log.error("Unexpected forecast data");
return undefined;
}
for (var i = 0, count = forecastList.length; i < count; i++) {
var forecast = forecastList[i];
forecast = this.parserDataWeather(forecast); // hack issue #1017
var day;
var hour;
if (forecast.dt_txt) {
day = mom(forecast.dt_txt, "YYYY-MM-DD hh:mm:ss").format("ddd");
hour = new Date(mom(forecast.dt_txt).locale("en").format("YYYY-MM-DD HH:mm:ss")).getHours();
} else {
day = mom(forecast.dt, "X").format("ddd");
hour = new Date(mom(forecast.dt, "X")).getHours();
}
if (day !== lastDay) {
forecastData = {
day: day,
icon: this.config.iconTable[forecast.weather[0].icon],
maxTemp: this.roundValue(forecast.temp.max),
minTemp: this.roundValue(forecast.temp.min),
rain: this.processRain(forecast, forecastList, mom)
};
this.forecast.push(forecastData);
lastDay = day;
// Stop processing when maxNumberOfDays is reached
if (this.forecast.length === this.config.maxNumberOfDays) {
break;
}
} else {
//Log.log("Compare max: ", forecast.temp.max, parseFloat(forecastData.maxTemp));
forecastData.maxTemp = forecast.temp.max > parseFloat(forecastData.maxTemp) ? this.roundValue(forecast.temp.max) : forecastData.maxTemp;
//Log.log("Compare min: ", forecast.temp.min, parseFloat(forecastData.minTemp));
forecastData.minTemp = forecast.temp.min < parseFloat(forecastData.minTemp) ? this.roundValue(forecast.temp.min) : forecastData.minTemp;
// Since we don't want an icon from the start of the day (in the middle of the night)
// we update the icon as long as it's somewhere during the day.
if (hour > dayStarts && hour < dayEnds) {
forecastData.icon = this.config.iconTable[forecast.weather[0].icon];
}
}
}
//Log.log(this.forecast);
this.show(this.config.animationSpeed, { lockString: this.identifier });
this.loaded = true;
this.updateDom(this.config.animationSpeed);
},
/* scheduleUpdate()
* Schedule next update.
*
* argument delay number - Milliseconds before next update. If empty, this.config.updateInterval is used.
*/
scheduleUpdate: function (delay) {
var nextLoad = this.config.updateInterval;
if (typeof delay !== "undefined" && delay >= 0) {
nextLoad = delay;
}
var self = this;
clearTimeout(this.updateTimer);
this.updateTimer = setTimeout(function () {
self.updateWeather();
}, nextLoad);
},
/* ms2Beaufort(ms)
* Converts m2 to beaufort (windspeed).
*
* see:
* https://www.spc.noaa.gov/faq/tornado/beaufort.html
* https://en.wikipedia.org/wiki/Beaufort_scale#Modern_scale
*
* argument ms number - Windspeed in m/s.
*
* return number - Windspeed in beaufort.
*/
ms2Beaufort: function (ms) {
var kmh = (ms * 60 * 60) / 1000;
var speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000];
for (var beaufort in speeds) {
var speed = speeds[beaufort];
if (speed > kmh) {
return beaufort;
}
}
return 12;
},
/* function(temperature)
* Rounds a temperature to 1 decimal or integer (depending on config.roundTemp).
*
* argument temperature number - Temperature.
*
* return string - Rounded Temperature.
*/
roundValue: function (temperature) {
var decimals = this.config.roundTemp ? 0 : 1;
var roundValue = parseFloat(temperature).toFixed(decimals);
return roundValue === "-0" ? 0 : roundValue;
},
/* 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, momenttz) {
let mom = momenttz ? momenttz : moment; // Exception last.
//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 ? mom(forecast.dt_txt, "YYYY-MM-DD hh:mm:ss") : mom(forecast.dt, "X");
var daysForecasts = allForecasts.filter(function (item) {
var itemDateTime = item.dt_txt ? mom(item.dt_txt, "YYYY-MM-DD hh:mm:ss") : mom(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);
return "deprecated weatherforecast";
}
});

6569
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "magicmirror",
"version": "2.18.0",
"version": "2.20.0",
"description": "The open source modular smart mirror platform.",
"main": "js/electron.js",
"scripts": {
@@ -9,7 +9,7 @@
"server": "node ./serveronly",
"install": "echo \"Installing vendor files ...\n\" && cd vendor && npm install --loglevel=error",
"install-fonts": "echo \"Installing fonts ...\n\" && cd fonts && npm install --loglevel=error",
"postinstall": "npm run install-fonts && echo \"MagicMirror installation finished successfully! \n\"",
"postinstall": "npm run install-fonts && echo \"MagicMirror² installation finished successfully! \n\"",
"test": "NODE_ENV=test jest -i --forceExit",
"test:coverage": "NODE_ENV=test nyc --reporter=lcov --reporter=text jest -i --forceExit",
"test:electron": "NODE_ENV=test jest --selectProjects electron -i --forceExit",
@@ -32,6 +32,7 @@
},
"keywords": [
"magic mirror",
"magicmirror",
"smart mirror",
"mirror UI",
"modular"
@@ -46,55 +47,58 @@
},
"homepage": "https://magicmirror.builders",
"devDependencies": {
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-jest": "^25.3.0",
"eslint-plugin-jsdoc": "^37.4.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jest": "^26.5.3",
"eslint-plugin-jsdoc": "^39.3.3",
"eslint-plugin-prettier": "^4.0.0",
"express-basic-auth": "^1.2.1",
"husky": "^7.0.4",
"jest": "^27.4.5",
"jsdom": "^19.0.0",
"husky": "^8.0.1",
"jest": "^28.1.1",
"jsdom": "^20.0.0",
"lodash": "^4.17.21",
"nyc": "^15.1.0",
"playwright": "^1.17.1",
"prettier": "^2.5.1",
"playwright": "^1.22.2",
"prettier": "^2.7.1",
"pretty-quick": "^3.1.3",
"sinon": "^12.0.1",
"stylelint": "^14.2.0",
"sinon": "^14.0.0",
"stylelint": "^14.9.1",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^24.0.0",
"stylelint-config-standard": "^26.0.0",
"stylelint-prettier": "^2.0.0",
"suncalc": "^1.8.0"
"suncalc": "^1.9.0"
},
"optionalDependencies": {
"electron": "^16.0.5"
"electron": "^19.0.6"
},
"dependencies": {
"colors": "^1.4.0",
"console-stamp": "^3.0.3",
"console-stamp": "^3.0.6",
"digest-fetch": "^1.2.1",
"eslint": "^8.5.0",
"express": "^4.17.2",
"eslint": "^8.18.0",
"express": "^4.18.1",
"express-ipfilter": "^1.2.0",
"feedme": "^2.0.2",
"helmet": "^4.6.0",
"helmet": "^5.1.0",
"iconv-lite": "^0.6.3",
"luxon": "^1.28.0",
"module-alias": "^2.2.2",
"moment": "^2.29.1",
"node-fetch": "^2.6.6",
"node-ical": "^0.13.0",
"socket.io": "^4.4.0"
"moment": "^2.29.3",
"node-fetch": "^2.6.7",
"node-ical": "^0.15.1",
"socket.io": "^4.5.1"
},
"_moduleAliases": {
"node_helper": "js/node_helper.js",
"logger": "js/logger.js"
"logger": "js/logger.js",
"fetch": "js/fetch.js"
},
"engines": {
"node": ">=12"
"node": ">=14"
},
"jest": {
"verbose": true,
"testTimeout": 10000,
"testTimeout": 20000,
"testSequencer": "<rootDir>/tests/configs/test_sequencer.js",
"projects": [
{
"displayName": "unit",

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* Magic Mirror Test default config for modules
/* MagicMirror² Test default config for modules
*
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
* MIT Licensed.

View File

@@ -1,4 +1,4 @@
/* Magic Mirror Test config sample ipWhitelist
/* MagicMirror² Test config sample ipWhitelist
*
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
* MIT Licensed.

View File

@@ -1,4 +1,4 @@
/* Magic Mirror Test config sample module alert
/* MagicMirror² Test config sample module alert
*
* By rejas
* MIT Licensed.

View File

@@ -1,4 +1,4 @@
/* Magic Mirror Test config default calendar with auth by default
/* MagicMirror² Test config default calendar with auth by default
*
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
* MIT Licensed.

View File

@@ -1,4 +1,4 @@
/* Magic Mirror Test config default calendar
/* MagicMirror² Test config default calendar
*
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
* MIT Licensed.

View File

@@ -1,4 +1,4 @@
/* Magic Mirror Test config default calendar with auth by default
/* MagicMirror² Test config default calendar with auth by default
*
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
* MIT Licensed.

Some files were not shown because too many files have changed in this diff Show More