├── .DS_Store ├── .gitignore ├── .previews ├── .DS_Store ├── almost.gif ├── full.gif ├── half.gif ├── none.png ├── preview.gif ├── preview_minimal.gif ├── preview_speed.png ├── preview_strength.png ├── preview_strength_fullscreen.png └── preview_verbose.png ├── LICENSE ├── README.md ├── eslint.config.js ├── images ├── strength_almost.png ├── strength_full.png ├── strength_half.png └── strength_none.png ├── internet-monitor.css ├── internet-monitor.js ├── node_helper.js └── package.json /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Node working file 15 | package-lock.json 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | 23 | # nyc test coverage 24 | .nyc_output 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # Bower dependency directory (https://bower.io/) 30 | bower_components 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (https://nodejs.org/api/addons.html) 36 | build/Release 37 | 38 | # Dependency directories 39 | node_modules/ 40 | jspm_packages/ 41 | 42 | # TypeScript v1 declaration files 43 | typings/ 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # Yarn Integrity file 58 | .yarn-integrity 59 | 60 | # dotenv environment variables file 61 | .env 62 | 63 | # next.js build output 64 | .next 65 | -------------------------------------------------------------------------------- /.previews/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.previews/.DS_Store -------------------------------------------------------------------------------- /.previews/almost.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.previews/almost.gif -------------------------------------------------------------------------------- /.previews/full.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.previews/full.gif -------------------------------------------------------------------------------- /.previews/half.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.previews/half.gif -------------------------------------------------------------------------------- /.previews/none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.previews/none.png -------------------------------------------------------------------------------- /.previews/preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.previews/preview.gif -------------------------------------------------------------------------------- /.previews/preview_minimal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.previews/preview_minimal.gif -------------------------------------------------------------------------------- /.previews/preview_speed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.previews/preview_speed.png -------------------------------------------------------------------------------- /.previews/preview_strength.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.previews/preview_strength.png -------------------------------------------------------------------------------- /.previews/preview_strength_fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.previews/preview_strength_fullscreen.png -------------------------------------------------------------------------------- /.previews/preview_verbose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/.previews/preview_verbose.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 ronny3050 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # internet-monitor 2 | 3 | A [MagicMirror²](https://github.com/MagicMirrorOrg/MagicMirror) module to monitor internet statistics such as strength and speed information. 4 | 5 | **This is a fork of ronny3050's module with some modifications to get it working again.** 6 | 7 | ![Monitor Visualization](.previews/preview.gif) 8 | ![Minimal Visualization](.previews/preview_minimal.gif) 9 | ![StrengthFullscreen Visualization](.previews/preview_strength_fullscreen.png) 10 | 11 | ## Installation 12 | 13 | To install the module, just clone this repository to your **modules** folder: 14 | 15 | `git clone https://github.com/BrianHepler/internet-monitor`. 16 | 17 | Then run `cd internet-monitor` and `npm install` which will install the dependencies. 18 | 19 | ## Using the module 20 | 21 | To use this module, add it to the modules array in the `config/config.js` file: 22 | 23 | ````javascript 24 | modules: [ 25 | { 26 | module: 'internet-monitor', 27 | position: 'top_center', 28 | header: 'Internet Monitor', 29 | config:{ 30 | type: '', 31 | maxTime: 20000, 32 | updateInterval: 0, 33 | verbose: false, 34 | serverId: 54504, 35 | displayStrength: true, 36 | displaySpeed: true, 37 | strengthIconSize: 80, 38 | maxGaugeScale: 100, 39 | }, 40 | } 41 | ] 42 | ```` 43 | 44 | You can also customize the wifi symbol. 45 | 46 | ````javascript 47 | modules: [ 48 | { 49 | module: 'internet-monitor', 50 | position: 'top_center', 51 | header: 'Internet Monitor', 52 | config:{ 53 | type: '', 54 | maxTime: 20000, 55 | updateInterval: 0, 56 | verbose: false, 57 | displayStrength: true, 58 | displaySpeed: true, 59 | strengthIconSize: 80, 60 | maxGaugeScale: 100, 61 | wifiSymbol:{ 62 | size: 50, 63 | fullColor: '#3afc25', 64 | almostColor: '#ffff0c', 65 | halfColor: '#ff8c00', 66 | noneColor: '#ff1111' 67 | }, 68 | }, 69 | } 70 | ] 71 | ```` 72 | 73 | ## Configuration options 74 | 75 | The following properties can be configured: 76 | 77 | | Option | Description | 78 | |--------|--------------| 79 | |type | Style of the speed gauges
Possible values: 'minimal' Minimalistic Style as shown in the second image above.
Default value: '' | 80 | | updateInterval | Time to rerun/update tests (Milliseconds)
Default value: 0
Please note that updateInterval has to be greater than maxTime | 81 | | displayStrength | Display Internet Strength
Possible values: true or false
Default value: true
| 82 | | displaySpeed | Display download and upload speed gauges
Possible values: true or false
Default value: true
| 83 | | strengthIconSize | Size of the strength icon
Default value: 80 | 84 | | maxGuageScale | Maximum gauge value (Mbps)
Default value: 100 | 85 | | serverId | Test against specific SpeedTest server (optional)
Default value: ''
List of servers can be found at SpeedTest. | 86 | | wifiSymbol | Customize WiFi Symbol (Optional)

| 87 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | const globals = require("globals"); 2 | const {configs: eslintConfigs} = require("@eslint/js"); 3 | const eslintPluginImport = require("eslint-plugin-import"); 4 | const eslintPluginStylistic = require("@stylistic/eslint-plugin"); 5 | 6 | const config = [ 7 | { 8 | files: ["**/*.js"], 9 | languageOptions: { 10 | globals: { 11 | ...globals.browser, 12 | ...globals.node 13 | } 14 | }, 15 | plugins: { 16 | ...eslintPluginStylistic.configs["all-flat"].plugins, 17 | import: eslintPluginImport 18 | }, 19 | rules: { 20 | ...eslintConfigs.all.rules, 21 | ...eslintPluginImport.configs.recommended.rules, 22 | ...eslintPluginStylistic.configs["all-flat"].rules, 23 | "capitalized-comments": "off", 24 | complexity: ["error", 25], 25 | "consistent-this": "off", 26 | "default-case": "off", 27 | "func-style": "off", 28 | "init-declarations": "off", 29 | "line-comment-position": "off", 30 | "max-lines": "off", 31 | "max-lines-per-function": ["error", 110], 32 | "max-params": "off", 33 | "max-statements": ["error", 50], 34 | "multiline-comment-style": "off", 35 | "no-await-in-loop": "off", 36 | "no-inline-comments": "off", 37 | "no-magic-numbers": "off", 38 | "no-undef": "warn", 39 | "no-ternary": "off", 40 | "one-var": "off", 41 | "sort-keys": "off", 42 | strict: "off", 43 | "@stylistic/array-element-newline": ["error", "consistent"], 44 | "@stylistic/dot-location": ["error", "property"], 45 | "@stylistic/function-call-argument-newline": ["error", "consistent"], 46 | "@stylistic/indent": ["error", 2], 47 | "@stylistic/lines-around-comment": "off", 48 | "@stylistic/object-property-newline": "off", 49 | "@stylistic/quote-props": ["error", "as-needed"], 50 | "@stylistic/padded-blocks": ["error", "never"] 51 | } 52 | }, 53 | { 54 | files: ["**/*.mjs"], 55 | languageOptions: { 56 | globals: { 57 | ...globals.node 58 | }, 59 | sourceType: "module" 60 | }, 61 | plugins: { 62 | ...eslintPluginStylistic.configs["all-flat"].plugins 63 | }, 64 | rules: { 65 | ...eslintConfigs.all.rules, 66 | ...eslintPluginStylistic.configs["all-flat"].rules, 67 | "func-style": "off", 68 | "max-lines-per-function": ["error", 100], 69 | "no-magic-numbers": "off", 70 | "one-var": "off", 71 | "prefer-destructuring": "off" 72 | } 73 | } 74 | ]; 75 | 76 | /* 77 | * Set debug to true for testing purposes. 78 | * Since some plugins have not yet been optimized for the flat config, 79 | * we will be able to optimize this file in the future. It can be helpful 80 | * to write the ESLint config to a file and compare it after changes. 81 | */ 82 | const debug = false; 83 | 84 | if (debug === true) { 85 | const FileSystem = require("fs"); 86 | FileSystem.writeFile("eslint-config-DEBUG.json", JSON.stringify(config, null, 2), (error) => { 87 | if (error) { 88 | throw error; 89 | } 90 | }); 91 | } 92 | 93 | module.exports = config; 94 | -------------------------------------------------------------------------------- /images/strength_almost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/images/strength_almost.png -------------------------------------------------------------------------------- /images/strength_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/images/strength_full.png -------------------------------------------------------------------------------- /images/strength_half.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/images/strength_half.png -------------------------------------------------------------------------------- /images/strength_none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHepler/internet-monitor/5fd5eb81d19ed1f9b049fb16a4383cb7dbbf2856/images/strength_none.png -------------------------------------------------------------------------------- /internet-monitor.css: -------------------------------------------------------------------------------- 1 | #downloadSpeedGauge, #uploadSpeedGauge{ 2 | width:200px; height:160px; 3 | display: inline-block; 4 | margin: 1em; 5 | } 6 | 7 | .wifi{ 8 | z-index : 1; 9 | } 10 | .wifi-symbol-1 { 11 | display: none; 12 | } 13 | .wifi-symbol-1 [foo], .wifi-symbol-1 { 14 | display: block; 15 | position: absolute; 16 | top: 65%; 17 | display: inline-block; 18 | width: 150px; 19 | height: 150px; 20 | margin-top: -187.5px; 21 | -ms-transform: rotate(-45deg) translate(-100px); 22 | -moz-transform: rotate(-45deg) translate(-100px); 23 | -o-transform: rotate(-45deg) translate(-100px); 24 | -webkit-transform: rotate(-45deg) translate(-100px); 25 | transform: rotate(-45deg) translate(-100px); 26 | } 27 | .wifi-symbol-1 .wifi-circle { 28 | box-sizing: border-box; 29 | -moz-box-sizing: border-box; 30 | display: block; 31 | width: 100%; 32 | height: 100%; 33 | font-size: 21.42857px; 34 | position: absolute; 35 | bottom: 0; 36 | left: 0; 37 | border-color: #FFFFCC; 38 | border-style: solid; 39 | border-width: 1em 1em 0 0; 40 | -webkit-border-radius: 0 100% 0 0; 41 | border-radius: 0 100% 0 0; 42 | opacity: 0; 43 | -o-animation: wifianimation-2 3s infinite; 44 | -moz-animation: wifianimation-2 3s infinite; 45 | -webkit-animation: wifianimation-2 3s infinite; 46 | animation: wifianimation-2 3s infinite; 47 | } 48 | .wifi-symbol-1 .wifi-circle.first { 49 | -o-animation-delay: 800ms; 50 | -moz-animation-delay: 800ms; 51 | -webkit-animation-delay: 800ms; 52 | animation-delay: 800ms; 53 | } 54 | .wifi-symbol-1 .wifi-circle.second { 55 | width: 5em; 56 | height: 5em; 57 | -o-animation-delay: 400ms; 58 | -moz-animation-delay: 400ms; 59 | -webkit-animation-delay: 400ms; 60 | animation-delay: 400ms; 61 | } 62 | .wifi-symbol-1 .wifi-circle.third { 63 | width: 3em; 64 | height: 3em; 65 | } 66 | .wifi-symbol-1 .wifi-circle.fourth { 67 | width: 1em; 68 | height: 1em; 69 | opacity: 1; 70 | background-color: #FFFFCC; 71 | -o-animation: none; 72 | -moz-animation: none; 73 | -webkit-animation: none; 74 | animation: none; 75 | } 76 | 77 | .wifi-symbol-2 { 78 | display: none; 79 | } 80 | .wifi-symbol-2 [foo], .wifi-symbol-2 { 81 | display: block; 82 | position: absolute; 83 | top: 65%; 84 | display: inline-block; 85 | width: 150px; 86 | height: 150px; 87 | margin-top: -187.5px; 88 | -ms-transform: rotate(-45deg) translate(-100px); 89 | -moz-transform: rotate(-45deg) translate(-100px); 90 | -o-transform: rotate(-45deg) translate(-100px); 91 | -webkit-transform: rotate(-45deg) translate(-100px); 92 | transform: rotate(-45deg) translate(-100px); 93 | } 94 | .wifi-symbol-2 .wifi-circle { 95 | box-sizing: border-box; 96 | -moz-box-sizing: border-box; 97 | display: block; 98 | width: 100%; 99 | height: 100%; 100 | font-size: 21.42857px; 101 | position: absolute; 102 | bottom: 0; 103 | left: 0; 104 | border-color: #FFFF0C; 105 | border-style: solid; 106 | border-width: 1em 1em 0 0; 107 | -webkit-border-radius: 0 100% 0 0; 108 | border-radius: 0 100% 0 0; 109 | opacity: 0; 110 | -o-animation: wifianimation-2 3s infinite; 111 | -moz-animation: wifianimation-2 3s infinite; 112 | -webkit-animation: wifianimation-2 3s infinite; 113 | animation: wifianimation-2 3s infinite; 114 | } 115 | .wifi-symbol-2 .wifi-circle.first { 116 | opacity: 0.3; 117 | -o-animation: none; 118 | -moz-animation: none; 119 | -webkit-animation: none; 120 | animation: none; 121 | } 122 | .wifi-symbol-2 .wifi-circle.second { 123 | width: 5em; 124 | height: 5em; 125 | -o-animation-delay: 400ms; 126 | -moz-animation-delay: 400ms; 127 | -webkit-animation-delay: 400ms; 128 | animation-delay: 400ms; 129 | } 130 | .wifi-symbol-2 .wifi-circle.third { 131 | width: 3em; 132 | height: 3em; 133 | } 134 | .wifi-symbol-2 .wifi-circle.fourth { 135 | width: 1em; 136 | height: 1em; 137 | opacity: 1; 138 | background-color: #FFFF0C; 139 | -o-animation: none; 140 | -moz-animation: none; 141 | -webkit-animation: none; 142 | animation: none; 143 | } 144 | 145 | .wifi-symbol-3 { 146 | display: none; 147 | } 148 | .wifi-symbol-3 [foo], .wifi-symbol-3 { 149 | display: block; 150 | position: absolute; 151 | top: 65%; 152 | display: inline-block; 153 | width: 150px; 154 | height: 150px; 155 | margin-top: -187.5px; 156 | -ms-transform: rotate(-45deg) translate(-100px); 157 | -moz-transform: rotate(-45deg) translate(-100px); 158 | -o-transform: rotate(-45deg) translate(-100px); 159 | -webkit-transform: rotate(-45deg) translate(-100px); 160 | transform: rotate(-45deg) translate(-100px); 161 | } 162 | .wifi-symbol-3 .wifi-circle { 163 | box-sizing: border-box; 164 | -moz-box-sizing: border-box; 165 | display: block; 166 | width: 100%; 167 | height: 100%; 168 | font-size: 21.42857px; 169 | position: absolute; 170 | bottom: 0; 171 | left: 0; 172 | border-color: #FFFF0C; 173 | border-style: solid; 174 | border-width: 1em 1em 0 0; 175 | -webkit-border-radius: 0 100% 0 0; 176 | border-radius: 0 100% 0 0; 177 | opacity: 0; 178 | -o-animation: wifianimation-2 3s infinite; 179 | -moz-animation: wifianimation-2 3s infinite; 180 | -webkit-animation: wifianimation-2 3s infinite; 181 | animation: wifianimation-2 3s infinite; 182 | } 183 | .wifi-symbol-3 .wifi-circle.first { 184 | opacity: 0.3; 185 | -o-animation: none; 186 | -moz-animation: none; 187 | -webkit-animation: none; 188 | animation: none; 189 | } 190 | .wifi-symbol-3 .wifi-circle.second { 191 | width: 5em; 192 | height: 5em; 193 | opacity: 0.3; 194 | -o-animation: none; 195 | -moz-animation: none; 196 | -webkit-animation: none; 197 | animation: none; 198 | } 199 | .wifi-symbol-3 .wifi-circle.third { 200 | width: 3em; 201 | height: 3em; 202 | } 203 | .wifi-symbol-3 .wifi-circle.fourth { 204 | width: 1em; 205 | height: 1em; 206 | opacity: 1; 207 | background-color: #FFFF0C; 208 | -o-animation: none; 209 | -moz-animation: none; 210 | -webkit-animation: none; 211 | animation: none; 212 | } 213 | 214 | .wifi-symbol-4 { 215 | display: none; 216 | } 217 | .wifi-symbol-4 [foo], .wifi-symbol-4 { 218 | display: block; 219 | position: absolute; 220 | top: 65%; 221 | display: inline-block; 222 | width: 150px; 223 | height: 150px; 224 | margin-top: -187.5px; 225 | -ms-transform: rotate(-45deg) translate(-100px); 226 | -moz-transform: rotate(-45deg) translate(-100px); 227 | -o-transform: rotate(-45deg) translate(-100px); 228 | -webkit-transform: rotate(-45deg) translate(-100px); 229 | transform: rotate(-45deg) translate(-100px); 230 | } 231 | .wifi-symbol-4 .wifi-circle { 232 | box-sizing: border-box; 233 | -moz-box-sizing: border-box; 234 | display: block; 235 | width: 100%; 236 | height: 100%; 237 | font-size: 21.42857px; 238 | position: absolute; 239 | bottom: 0; 240 | left: 0; 241 | border-color: #FFFF0C; 242 | border-style: solid; 243 | border-width: 1em 1em 0 0; 244 | -webkit-border-radius: 0 100% 0 0; 245 | border-radius: 0 100% 0 0; 246 | opacity: 0; 247 | -o-animation: wifianimation-2 3s infinite; 248 | -moz-animation: wifianimation-2 3s infinite; 249 | -webkit-animation: wifianimation-2 3s infinite; 250 | animation: wifianimation-2 3s infinite; 251 | } 252 | .wifi-symbol-4 .wifi-circle.first { 253 | opacity: 0.3; 254 | -o-animation: none; 255 | -moz-animation: none; 256 | -webkit-animation: none; 257 | animation: none; 258 | } 259 | .wifi-symbol-4 .wifi-circle.second { 260 | width: 5em; 261 | height: 5em; 262 | opacity: 0.3; 263 | -o-animation: none; 264 | -moz-animation: none; 265 | -webkit-animation: none; 266 | animation: none; 267 | } 268 | .wifi-symbol-4 .wifi-circle.third { 269 | width: 3em; 270 | height: 3em; 271 | opacity: 0.3; 272 | -o-animation: none; 273 | -moz-animation: none; 274 | -webkit-animation: none; 275 | animation: none; 276 | } 277 | .wifi-symbol-4 .wifi-circle.fourth { 278 | width: 1em; 279 | height: 1em; 280 | opacity: 1; 281 | background-color: #FFFF0C; 282 | -o-animation: none; 283 | -moz-animation: none; 284 | -webkit-animation: none; 285 | animation: none; 286 | } 287 | 288 | @-o-keyframes wifianimation-2 { 289 | 0% { 290 | opacity: 1; 291 | } 292 | 5% { 293 | opactiy: 0.8; 294 | } 295 | 6% { 296 | opactiy: 0.9; 297 | } 298 | 100% { 299 | opactiy: 0.1; 300 | } 301 | } 302 | @-moz-keyframes wifianimation-2 { 303 | 0% { 304 | opacity: 1; 305 | } 306 | 5% { 307 | opactiy: 0.8; 308 | } 309 | 6% { 310 | opactiy: 0.9; 311 | } 312 | 100% { 313 | opactiy: 0.1; 314 | } 315 | } 316 | @-webkit-keyframes wifianimation-2 { 317 | 0% { 318 | opacity: 1; 319 | } 320 | 5% { 321 | opactiy: 0.8; 322 | } 323 | 6% { 324 | opactiy: 0.9; 325 | } 326 | 100% { 327 | opactiy: 0.1; 328 | } 329 | } -------------------------------------------------------------------------------- /internet-monitor.js: -------------------------------------------------------------------------------- 1 | /* global JustGage Module Log $ */ 2 | /** 3 | * Created by debayan on 7/24/16. 4 | */ 5 | 6 | Module.register("internet-monitor", { 7 | 8 | defaults: { 9 | serverId: "", 10 | type: "", 11 | updateInterval: 60 * 1000 * 30, 12 | verbose: false, 13 | displayStrength: true, 14 | displaySpeed: true, 15 | strengthIconSize: 80, 16 | maxGaugeScale: 100 17 | }, 18 | payload: [], 19 | 20 | downloadBarState: "not_started", 21 | updating: false, 22 | 23 | start () { 24 | Log.log("Internet-monitor module started!"); 25 | this.sendSocketNotification("Start", this.config); 26 | }, 27 | 28 | getScripts () { 29 | return [ 30 | this.file("node_modules/justgage/raphael.min.js"), 31 | this.file("node_modules/justgage/dist/justgage.min.js"), 32 | this.file("node_modules/jquery/dist/jquery.min.js") 33 | ]; 34 | }, 35 | 36 | getStyles () { 37 | return ["internet-monitor.css"]; 38 | }, 39 | 40 | notificationReceived (notification, payload, sender) { 41 | // Module is ready. Start the initial check 42 | if (notification === "MODULE_DOM_CREATED") { 43 | this.sendSocketNotification("Check", this.config); 44 | } 45 | Log.debug(`notificationReceived - payload: ${payload}`); 46 | Log.debug(`notificationReceived - sender: ${sender}`); 47 | }, 48 | 49 | socketNotificationReceived (notification, payload) { 50 | if (notification === "downloadSpeedProgress") { 51 | if (this.config.displaySpeed) { 52 | if (this.downloadBarState === "not_started") { 53 | this.downloadBarState = "started"; 54 | } 55 | Log.log("updating DOWNLOAD"); 56 | this.download.refresh(payload, this.config.maxGaugeScale); 57 | } 58 | } 59 | if (notification === "uploadSpeedProgress") { 60 | if (this.config.displaySpeed) { 61 | Log.log("updating UPLOAD"); 62 | this.upload.refresh(payload, this.config.maxGaugeScale); 63 | } 64 | } 65 | let container; 66 | if (notification === "data") { 67 | if (this.config.verbose) { 68 | if (!this.updating) { 69 | container = document.createElement("div"); 70 | container.style = "text-align: left; display:inline-block;"; 71 | $(container).appendTo("#internetData"); 72 | } 73 | $("#internetData > div").html(` Server: ${payload.server.host}`) 74 | .append("
" + 75 | ` Location: ${payload.server.location} (${payload.server.country})`) 76 | .append("
"); 77 | } 78 | } 79 | 80 | if (notification === "ping") { 81 | // Log.log("ping [" + payload + "]"); 82 | // if (this.downloadBarState == "not_started") { 83 | // this.updateDom(); 84 | // } 85 | 86 | if (this.config.displayStrength) { 87 | if (Object.hasOwn(this.config, "wifiSymbol")) { 88 | if (payload < 70) { 89 | $(container).append("
"); 90 | } else if (payload >= 70 && payload < 100) { 91 | $(container).append("
"); 92 | } else if (payload >= 100 && payload < 150) { 93 | $(container).append("
"); 94 | } else if (payload >= 150) { 95 | $(container).append("
"); 96 | } 97 | 98 | $(".wifi-symbol-1 .wifi-circle").css({ 99 | "border-color": this.config.wifiSymbol.fullColor, 100 | "font-size": this.config.wifiSymbol.size / 7, 101 | "margin-top": 0 - this.config.wifiSymbol.size - this.config.wifiSymbol.size * 0.25, 102 | "margin-left": 0.5 * (150 - this.config.wifiSymbol.size) 103 | }); 104 | $(".wifi-symbol-1 [foo], .wifi-symbol-1").css({ 105 | width: this.config.wifiSymbol.size, 106 | height: this.config.wifiSymbol.size 107 | }); 108 | 109 | $(".wifi-symbol-2 .wifi-circle").css({ 110 | "border-color": this.config.wifiSymbol.almostColor, 111 | "font-size": this.config.wifiSymbol.size / 7, 112 | "margin-top": 0 - this.config.wifiSymbol.size - this.config.wifiSymbol.size * 0.25, 113 | "margin-left": 0.5 * (150 - this.config.wifiSymbol.size) 114 | }); 115 | $(".wifi-symbol-2 [foo], .wifi-symbol-2").css({ 116 | width: this.config.wifiSymbol.size, 117 | height: this.config.wifiSymbol.size 118 | }); 119 | 120 | $(".wifi-symbol-3 .wifi-circle").css({ 121 | "border-color": this.config.wifiSymbol.halfColor, 122 | "font-size": this.config.wifiSymbol.size / 7, 123 | "margin-top": 0 - this.config.wifiSymbol.size - this.config.wifiSymbol.size * 0.25, 124 | "margin-left": 0.5 * (150 - this.config.wifiSymbol.size) 125 | }); 126 | $(".wifi-symbol-3 [foo], .wifi-symbol-3").css({ 127 | width: this.config.wifiSymbol.size, 128 | height: this.config.wifiSymbol.size 129 | }); 130 | 131 | $(".wifi-symbol-4 .wifi-circle").css({ 132 | "border-color": this.config.wifiSymbol.noneColor, 133 | "font-size": this.config.wifiSymbol.size / 7, 134 | "margin-top": 0 - this.config.wifiSymbol.size - this.config.wifiSymbol.size * 0.25, 135 | "margin-left": 0.5 * (150 - this.config.wifiSymbol.size) 136 | }); 137 | $(".wifi-symbol-4 [foo], .wifi-symbol-4").css({ 138 | width: this.config.wifiSymbol.size, 139 | height: this.config.wifiSymbol.size 140 | }); 141 | } else if (payload < 70) { 142 | $("#pingStrength").attr("src", this.file("images/strength_full.png")); 143 | } else if (payload >= 70 && payload < 100) { 144 | $("#pingStrength").attr("src", this.file("images/strength_almost.png")); 145 | } else if (payload >= 100 && payload < 150) { 146 | $("#pingStrength").attr("src", this.file("images/strength_half.png")); 147 | } else if (payload >= 150) { 148 | $("#pingStrength").attr("src", this.file("images/strength_none.png")); 149 | } 150 | } 151 | } 152 | }, 153 | 154 | getDom () { 155 | const wrapper = document.createElement("div"); 156 | wrapper.className = "small"; 157 | // Log.log(this.config); 158 | 159 | if (this.config.displayStrength) { 160 | Log.log("creating pingDiv"); 161 | const pingDiv = document.createElement("div"); 162 | pingDiv.id = "pingDiv"; 163 | pingDiv.className = "strength"; 164 | 165 | const img = document.createElement("img"); 166 | img.src = this.file("images/strength_none.png"); 167 | img.height = this.config.strengthIconSize; 168 | img.id = "pingStrength"; 169 | img.className = "pingStrength"; 170 | pingDiv.appendChild(img); 171 | 172 | wrapper.appendChild(pingDiv); 173 | } 174 | 175 | if (this.config.displaySpeed) { 176 | Log.log("creating speed"); 177 | const minimal = this.config.type === "minimal"; 178 | 179 | const downloadSpeedGauge = document.createElement("div"); 180 | downloadSpeedGauge.id = "downloadSpeedGauge"; 181 | downloadSpeedGauge.className = "speedGauge"; 182 | 183 | const uploadSpeedGauge = document.createElement("div"); 184 | uploadSpeedGauge.id = "uploadSpeedGauge"; 185 | uploadSpeedGauge.className = "speedGauge"; 186 | 187 | this.download = new JustGage({ 188 | // id: "downloadSpeedGauge", 189 | parentNode: downloadSpeedGauge, 190 | value: 0, 191 | min: 0, 192 | max: this.config.maxGaugeScale, 193 | title: "Download Speed", 194 | refreshAnimationType: "linear", 195 | gaugeWidthScale: 0.8, 196 | valueFontColor: "#FFFFFF", 197 | valueFontFamily: "Roboto Condensed", 198 | titleFontFamily: "Roboto Condensed", 199 | titleFontColor: "#AAAAAA", 200 | hideMindMax: minimal, 201 | gaugeColor: "#000000", 202 | levelColors: ["#FF0000", "#FFFF00", "#00FF00"], 203 | hideInnerShadow: true, 204 | symbol: "Mbps" 205 | }); 206 | 207 | this.upload = new JustGage({ 208 | // id: "uploadSpeedGauge", 209 | parentNode: uploadSpeedGauge, 210 | value: 0, 211 | min: 0, 212 | max: this.config.maxGaugeScale, 213 | title: "Upload Speed", 214 | refreshAnimationType: "linear", 215 | gaugeWidthScale: 0.8, 216 | valueFontColor: "#FFFFFF", 217 | valueFontFamily: "Roboto Condensed", 218 | titleFontFamily: "Roboto Condensed", 219 | titleFontColor: "#AAAAAA", 220 | hideMindMax: minimal, 221 | gaugeColor: "#000000", 222 | levelColors: ["#FF0000", "#FFFF00", "#00FF00"], 223 | hideInnerShadow: true, 224 | symbol: "Mbps" 225 | }); 226 | 227 | if (minimal) { 228 | const downOpt = { 229 | gaugeColor: "#000", 230 | levelColors: "#fff", 231 | hideInnerShadow: true 232 | }; 233 | const upOpt = { 234 | gaugeColor: "#000", 235 | levelColors: "#fff", 236 | hideInnerShadow: true 237 | }; 238 | this.download.update(downOpt); 239 | this.upload.update(upOpt); 240 | } 241 | wrapper.appendChild(downloadSpeedGauge); 242 | wrapper.appendChild(uploadSpeedGauge); 243 | } 244 | 245 | if (this.config.verbose) { 246 | const data = document.createElement("div"); 247 | data.id = "internetData"; 248 | wrapper.appendChild(data); 249 | } 250 | 251 | return wrapper; 252 | } 253 | 254 | }); 255 | -------------------------------------------------------------------------------- /node_helper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by debayan on 7/23/16. 3 | */ 4 | const Log = require("logger"); 5 | const NodeHelper = require("node_helper"); 6 | const speedtest = require("speedtest-net"); 7 | 8 | module.exports = NodeHelper.create({ 9 | start () { 10 | Log.log(`${this.name} helper started ...`); 11 | this.config = null; 12 | this.interval = null; 13 | }, 14 | 15 | socketNotificationReceived (notification, payload) { 16 | if (notification === "Start") { 17 | this.config = payload; 18 | } 19 | if (notification === "Check") { 20 | this.checkSpeed(); 21 | } 22 | }, 23 | 24 | async checkSpeed () { 25 | Log.log("Checking speed..."); 26 | let Check; 27 | try { 28 | Check = await speedtest({serverId: this.config.serverId, 29 | acceptLicense: true, 30 | acceptGdpr: true, 31 | progress: (data) => this.handleProgressEvent(data)}); 32 | } catch (err) { 33 | Log.error("[internet-monitor]", err.message); 34 | } finally { 35 | if (Check) { 36 | Log.debug("Result: ", Check); 37 | this.sendSocketNotification("data", Check); 38 | Log.debug("Done"); 39 | } 40 | } // end try 41 | this.scheduleUpdate(); 42 | }, 43 | 44 | handleProgressEvent (data) { 45 | switch (data.type) { 46 | case "download": 47 | Log.debug(`Examining download statistic: ${data.download.bandwidth}`); 48 | this.sendSocketNotification("downloadSpeedProgress", this.oToMbps(data.download.bandwidth)); 49 | break; 50 | case "upload": 51 | Log.debug(`Examining upload statistic: ${data.upload.bandwidth}`); 52 | this.sendSocketNotification("uploadSpeedProgress", this.oToMbps(data.upload.bandwidth)); 53 | break; 54 | case "ping": 55 | Log.debug(`Examining ping statistic:${data.ping.latency}`); 56 | this.sendSocketNotification("ping", Math.round(data.ping.latency)); 57 | } 58 | }, 59 | 60 | // Convert octect to Mbps [Match with Speedtest web result] 61 | oToMbps (value) { 62 | if (!value) { 63 | return 0; 64 | } 65 | return (value * 0.000008).toFixed(2); 66 | }, 67 | 68 | /** update process **/ 69 | scheduleUpdate () { 70 | if (this.config.updateInterval < 60 * 1000) { 71 | this.config.updateInterval = 60 * 1000; 72 | } 73 | clearInterval(this.interval); 74 | this.interval = setInterval(() => this.checkSpeed(), this.config.updateInterval); 75 | } 76 | 77 | }); 78 | 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "internet-speed", 3 | "version": "2.0.0", 4 | "description": "Displays ping, download and upload speed on your smart mirror.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/BrianHepler/internet-monitor" 8 | }, 9 | "main": "index.js", 10 | "scripts": { 11 | "lint": "eslint .", 12 | "lint:fix": "eslint . --fix", 13 | "test": "npm run lint" 14 | }, 15 | "keywords": [ 16 | "internet", 17 | "speed" 18 | ], 19 | "author": "Debayan Deb", 20 | "license": "MIT", 21 | "dependencies": { 22 | "speedtest-net": "flying19880517/speedtest.net", 23 | "jquery": "^3.7.1", 24 | "justgage": "^1.6.1" 25 | }, 26 | "devDependencies": { 27 | "@eslint/js": "^8.56.0", 28 | "@stylistic/eslint-plugin": "^1.5.3", 29 | "eslint": "^8.56.0", 30 | "eslint-plugin-import": "^2.29.1", 31 | "globals": "^13.24.0" 32 | } 33 | } 34 | --------------------------------------------------------------------------------