Skip to content

Commit 467372e

Browse files
feat: add QR code display and menu header icons
1 parent e672c11 commit 467372e

File tree

8 files changed

+383
-15
lines changed

8 files changed

+383
-15
lines changed

MMM-Remote-Control.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,23 @@
1313
.brightness-filtered {
1414
transition: filter 1.5s ease-in-out;
1515
}
16+
17+
/* QR Code Styling */
18+
.qrcode-container {
19+
display: flex;
20+
flex-direction: column;
21+
align-items: center;
22+
gap: 0.5em;
23+
}
24+
25+
.qrcode-image {
26+
border-radius: 0.5em;
27+
padding: 0.5em;
28+
background: rgba(255, 255, 255, 0.1);
29+
backdrop-filter: blur(10px);
30+
}
31+
32+
.url-text {
33+
text-align: center;
34+
margin: 0.3em 0;
35+
}

MMM-Remote-Control.js

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010

1111
Module.register("MMM-Remote-Control", {
1212

13-
requiresVersion: "2.12.0",
14-
1513
// Default module config.
1614
defaults: {
17-
customCommand: {}
15+
customCommand: {},
16+
showQRCode: true,
17+
qrCodeSize: 150,
18+
qrCodePosition: "above" // "below", "above", or "replace"
1819
},
1920

2021
// Define start sequence.
@@ -28,6 +29,8 @@ Module.register("MMM-Remote-Control", {
2829

2930
this.brightness = 100;
3031
this.temp = 327;
32+
33+
this.qrCodeDataUrl = null;
3134
},
3235

3336
getStyles () {
@@ -72,6 +75,17 @@ Module.register("MMM-Remote-Control", {
7275
}
7376
break;
7477

78+
case "QR_CODE_GENERATED":
79+
this.qrCodeDataUrl = payload;
80+
if (this.data.position) {
81+
this.updateDom();
82+
}
83+
break;
84+
85+
case "QR_CODE_ERROR":
86+
Log.error(`QR Code generation error: ${payload}`);
87+
break;
88+
7589
case "USER_PRESENCE":
7690
this.sendNotification(notification, payload);
7791
break;
@@ -247,8 +261,56 @@ Module.register("MMM-Remote-Control", {
247261
case "80": portToShow = ""; break;
248262
default: portToShow = `:${this.port}`; break;
249263
}
250-
wrapper.innerHTML = `http://${this.addresses[0]}${portToShow}/remote.html`;
251-
wrapper.className = "normal xsmall";
264+
265+
const url = `http://${this.addresses[0]}${portToShow}/remote.html`;
266+
267+
// Show QR code if enabled
268+
if (this.config.showQRCode) {
269+
const container = document.createElement("div");
270+
container.className = "qrcode-container";
271+
272+
// Add URL text above QR code (unless position is "replace")
273+
if (this.config.qrCodePosition !== "replace") {
274+
const urlText = document.createElement("div");
275+
urlText.innerHTML = url;
276+
urlText.className = "normal xsmall url-text";
277+
if (this.config.qrCodePosition === "below") {
278+
container.append(urlText);
279+
}
280+
}
281+
282+
// Request QR code generation if not already done
283+
if (!this.qrCodeDataUrl) {
284+
this.sendSocketNotification("GENERATE_QR_CODE", {
285+
url,
286+
size: this.config.qrCodeSize
287+
});
288+
}
289+
290+
// Display QR code if available
291+
if (this.qrCodeDataUrl) {
292+
const qrImage = document.createElement("img");
293+
qrImage.src = this.qrCodeDataUrl;
294+
qrImage.className = "qrcode-image";
295+
qrImage.alt = "QR Code for Remote Control";
296+
container.append(qrImage);
297+
}
298+
299+
// Add URL text below QR code
300+
if (this.config.qrCodePosition === "above") {
301+
const urlText = document.createElement("div");
302+
urlText.innerHTML = url;
303+
urlText.className = "normal xsmall url-text";
304+
container.append(urlText);
305+
}
306+
307+
wrapper.append(container);
308+
} else {
309+
// Just show URL text
310+
wrapper.innerHTML = url;
311+
wrapper.className = "normal xsmall";
312+
}
313+
252314
return wrapper;
253315
},
254316

README.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Since we all want our [SD cards to live a long and prosper life](http://raspberr
1010

1111
The module also includes a **RESTful API** for controlling all aspects of your mirror from other network-enabled devices and controllers--anything that can open a URL. See the [API README](API/README.md) for more info!
1212

13+
**New:** The module can now display a QR code on your mirror for easy mobile access - simply scan and connect!
14+
1315
## Screenshots
1416

1517
### Main menu
@@ -51,13 +53,12 @@ cd MMM-Remote-Control
5153
npm ci --omit=dev
5254
```
5355

54-
- (2) Add the module to your `config.js` file, if you add a `position`, it will display the URL to the remote on the mirror.
56+
- (2) Add the module to your `config.js` file. **Note:** You must set a `position` to display the URL/QR code on the mirror.
5557

5658
```js
5759
{
5860
module: 'MMM-Remote-Control',
59-
// uncomment the following line to show the URL of the remote control on the mirror
60-
// position: 'bottom_left',
61+
position: 'bottom_left', // Required to show URL/QR code on mirror
6162
// you can hide this module afterwards from the remote control itself
6263
config: {
6364
customCommand: {}, // Optional, See "Using Custom Commands" below
@@ -66,7 +67,15 @@ npm ci --omit=dev
6667
// uncomment any of the lines below if you're gonna use it
6768
// customMenu: "custom_menu.json", // Optional, See "Custom Menu Items" below
6869
// apiKey: "", // Optional, See API/README.md for details
69-
// classes: {} // Optional, See "Custom Classes" below
70+
// classes: {}, // Optional, See "Custom Classes" below
71+
72+
// QR Code options (new!)
73+
// showQRCode: true, // Optional, display QR code for easy mobile access (default: true)
74+
// qrCodeSize: 150, // Optional, size of QR code in pixels (default: 150)
75+
// qrCodePosition: "below" // Optional:
76+
// "below" - Show URL above, QR code below (default)
77+
// "above" - Show QR code above, URL below
78+
// "replace" - Show only QR code, no URL text
7079
}
7180
},
7281
```

cspell.config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"newsfeed",
5353
"newsitems",
5454
"Norsk",
55+
"openmeteo",
5556
"passwordless",
5657
"plusplus",
5758
"poweroff",

demo.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ let config = {
8989
},
9090
{
9191
module: "MMM-Remote-Control",
92+
position: "bottom_right",
9293
config: {
9394
secureEndpoints: false,
9495
classes: {

node_helper.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,9 @@ module.exports = NodeHelper.create({
13251325
// check if we have got saved default settings
13261326
this.loadDefaultSettings();
13271327
}
1328+
if (notification === "GENERATE_QR_CODE") {
1329+
this.generateQRCode(payload);
1330+
}
13281331
if (notification === "REMOTE_ACTION") {
13291332
if ("action" in payload) {
13301333
this.executeQuery(payload, {isSocket: true});
@@ -1386,5 +1389,27 @@ module.exports = NodeHelper.create({
13861389
this.updateModuleApiMenu();
13871390
}
13881391
},
1392+
1393+
/**
1394+
* Generate QR code as data URL
1395+
* @param {object} payload - Object with url and size properties
1396+
*/
1397+
async generateQRCode (payload) {
1398+
try {
1399+
const QRCode = require("qrcode");
1400+
const dataUrl = await QRCode.toDataURL(payload.url, {
1401+
width: payload.size,
1402+
margin: 1,
1403+
color: {
1404+
dark: "#FFFFFF",
1405+
light: "#00000000"
1406+
}
1407+
});
1408+
this.sendSocketNotification("QR_CODE_GENERATED", dataUrl);
1409+
} catch (error) {
1410+
Log.error(`QR Code generation failed: ${error}`);
1411+
this.sendSocketNotification("QR_CODE_ERROR", error.message);
1412+
}
1413+
},
13891414
...require("./API/api.js")
13901415
});

0 commit comments

Comments
 (0)