Read the statement by Michael Teeuw here.
triggering a module
-
hello all im still new to all this and trying to work my way through all this, I created a chores module that when all chores were marked done it would trigger the MMM-Fireworks module. but since the fireworks module updated it no longer triggers the fireworks and now im at a loss on how to get it to work. any help is greatly appreciated.
here is my chores module:
Module.register("MMM-DailyChoreGridColor", { defaults: { updateInterval: 60000, // 1 minute }, start: function() { this.choreList = { MONDAY: [ { chore: "Wash dishes", done: false }, { chore: "Take Out Trash", done: false }, { chore: "Wipe Down Counters", done: false }, { chore: "Pick Up Poop", done: false }, { chore: "Feed Pets", done: false }, { chore: "Play With Petey", done: false }, { chore: "Read", done: false }], TUESDAY: [ { chore: "Wash dishes", done: false }, { chore: "Take Out Trash", done: false }, { chore: "Wipe Down Counters", done: false }, { chore: "Pick Up Poop", done: false }, { chore: "Feed Pets", done: false }, { chore: "Play With Petey", done: false }, { chore: "Read", done: false }], WEDNESDAY: [ { chore: "Wash dishes", done: false }, { chore: "Take Out Trash", done: false }, { chore: "Wipe Down Counters", done: false }, { chore: "Pick Up Poop", done: false }, { chore: "Feed Pets", done: false }, { chore: "Play With Petey", done: false }, { chore: "Read", done: false }], THURSDAY: [ { chore: "Wash dishes", done: false }, { chore: "Take Out Trash", done: false }, { chore: "Wipe Down Counters", done: false }, { chore: "Pick Up Poop", done: false }, { chore: "Feed Pets", done: false }, { chore: "Play With Petey", done: false }, { chore: "Read", done: false }], FRIDAY: [ { chore: "Wash dishes", done: false }, { chore: "Take Out Trash", done: false }, { chore: "Wipe Down Counters", done: false }, { chore: "Pick Up Poop", done: false }, { chore: "Feed Pets", done: false }, { chore: "Play With Petey", done: false }, { chore: "Read", done: false }], SATURDAY: [ { chore: "Wash dishes", done: false }, { chore: "Take Out Trash", done: false }, { chore: "Wipe Down Counters", done: false }, { chore: "Pick Up Poop", done: false }, { chore: "Feed Pets", done: false }, { chore: "Play With Petey", done: false }], SUNDAY: [ { chore: "Wash dishes", done: false }, { chore: "Take Out Trash", done: false }, { chore: "Wipe Down Counters", done: false }, { chore: "Pick Up Poop", done: false }, { chore: "Feed Pets", done: false }, { chore: "Play With Petey", done: false }, { chore: "Clean Room", done: false }, { chore: "Clean Bathroom", done: false }, { chore: "Laundry", done: false }], }; }, getDom: function() { const wrapper = document.createElement("div"); wrapper.innerHTML = "<h2>Daily Chore List</h2>"; const table = document.createElement("table"); table.style.width = "100%"; table.style.margin = "auto"; table.style.borderCollapse = "collapse"; const headerRow = document.createElement("tr"); const daysOfWeek = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"]; daysOfWeek.forEach(day => { const dayHeader = document.createElement("th"); dayHeader.innerHTML = day; dayHeader.style.border = "1px solid black"; dayHeader.style.padding = "10px"; dayHeader.style.backgroundColor = "#f2f2f2"; dayHeader.style.textAlign = "center"; headerRow.appendChild(dayHeader); }); table.appendChild(headerRow); const maxChores = Math.max(...Object.values(this.choreList).map(day => day.length)); for (let i = 0; i < maxChores; i++) { const choreRow = document.createElement("tr"); daysOfWeek.forEach(day => { const choreCell = document.createElement("td"); const taskDiv = document.createElement("div"); const task = this.choreList[day][i]; if (task) { const taskText = document.createElement("span"); taskText.innerHTML = task.chore; const dropdown = document.createElement("select"); dropdown.options.add(new Option("X", "false")); dropdown.options.add(new Option("\u2713", "true")); dropdown.value = task.done ? "true" : "false"; this.updateDropdownColor(dropdown, task.done); dropdown.style.float = "right"; // Align dropdown to the right dropdown.onchange = () => { task.done = dropdown.value === "true"; this.updateDropdownColor(dropdown, task.done); console.log(`Task updated: ${task.chore}, Done: ${task.done}`); if (this.allChoresDone()) { console.log("All chores done, sending notification"); this.sendNotification("ALL_CHORES_DONE"); } else { console.log("Not all chores are done yet."); } }; taskDiv.appendChild(taskText); taskDiv.appendChild(dropdown); } choreCell.appendChild(taskDiv); choreCell.style.border = "1px solid black"; choreCell.style.padding = "10px"; choreCell.style.textAlign = "center"; choreRow.appendChild(choreCell); }); table.appendChild(choreRow); } const clearButton = document.createElement("button"); clearButton.innerHTML = "Clear All"; clearButton.style.marginTop = "20px"; clearButton.onclick = () => { Object.keys(this.choreList).forEach(day => { this.choreList[day].forEach(task => { task.done = false; }); }); this.updateDom(); console.log("All chores have been cleared."); }; wrapper.appendChild(clearButton); wrapper.appendChild(table); return wrapper; }, updateDropdownColor: function(dropdown, done) { if (done) { dropdown.style.backgroundColor = "green"; dropdown.style.color = "white"; } else { dropdown.style.backgroundColor = "red"; dropdown.style.color = "white"; } }, allChoresDone: function() { for (const day in this.choreList) { for (const task of this.choreList[day]) { if (!task.done) { console.log(`Task not done: ${task.chore}`); return false; } } } console.log("All chores done: true"); this.sendNotification("ALL_CHORES_DONE"); return true; } });
and here is the Fireworks module:
Module.register("MMM-Fireworks", { defaults: { startDateTime: "", // ISO format start time duration: 36000, // Duration in milliseconds (6 hours) // p5 Fireworks settings: fireworkSpawnChance: 0.5, // Chance each frame to spawn a new firework explosionParticleCount: 40, // Number of particles per explosion // Display settings: fullscreen: true, // If false, use the defined width/height. width: "400px", height: "500px", // Velocity settings for rocket particles: magnitude_high: -19, magnitude_low: -8, // Trailing effect transparency (alpha value for background): transparency: 10, // New canvas opacity (0.0 = fully transparent, 1.0 = fully opaque) canvasOpacity: 0.5, // Module management settings: disableAllModules: true, // Set to false so other modules remain visible. keepModules: [], // Array of module names to keep active. // Text overlay: text: "Good Job Buddy" }, start: function () { this.fireworksActive = false; this.disabledModules = []; this._p5Instance = null; }, // Create the module's container. // If fullscreen is true, force full screen; otherwise use the defined width/height. getDom: function () { const wrapper = document.createElement("div"); wrapper.id = "fireworksContainer"; if (this.config.fullscreen) { wrapper.style.position = "fixed"; wrapper.style.top = "0"; wrapper.style.left = "0"; wrapper.style.width = "100vw"; wrapper.style.height = "100vh"; wrapper.style.zIndex = "9999"; wrapper.style.background = "transparent"; } else { wrapper.style.position = "relative"; wrapper.style.width = this.config.width; wrapper.style.height = this.config.height; } // Create and append the text overlay element (initially hidden). if (this.config.text) { const textDiv = document.createElement("div"); textDiv.id = "fireworksText"; textDiv.className = "fireworks-text"; textDiv.innerHTML = this.config.text; textDiv.style.display = "none"; // Hidden by default; shown during fireworks. wrapper.appendChild(textDiv); } return wrapper; }, notificationReceived: function (notification, payload, sender) { console.log("Notification received: " + notification); if (notification === "ALL_CHORES_DONE") { this.startFireworks(); } else if (notification === "DOM_OBJECTS_CREATED") { this.scheduleFireworks(); } }, scheduleFireworks: function () { const MAX_DELAY = 2147483647; // Maximum delay in ms (~24.8 days) const startTime = new Date(this.config.startDateTime).getTime(); const currentTime = Date.now(); const duration = this.config.duration; if (currentTime < startTime) { let delay = startTime - currentTime; if (delay > MAX_DELAY) { setTimeout(() => this.scheduleFireworks(), MAX_DELAY); } else { setTimeout(() => this.startFireworks(), delay); } } else if (currentTime < startTime + duration) { this.startFireworks(); } else { console.warn("Fireworks time window has already passed."); } }, startFireworks: function () { this.fireworksActive = true; const container = document.getElementById("fireworksContainer"); container.classList.add("fullscreen"); // Show the text overlay during the fireworks period. const textDiv = document.getElementById("fireworksText"); if (textDiv) { textDiv.style.display = "block"; } // Do not hide other modules if disableAllModules is false. if (this.config.disableAllModules) { this.deactivateAndHideModules(); } this.initializeP5(); // Play fireworks sound const audio = new Audio("MagicMirror/Modules/MMM-Fireworks/fireworks-sound.mp3"); audio.play(); setTimeout(() => { this.stopFireworks(); }, this.config.duration); }, stopFireworks: function () { if (this._p5Instance) { this._p5Instance.remove(); this._p5Instance = null; } const container = document.getElementById("fireworksContainer"); container.innerHTML = ""; this.fireworksActive = false; if (this.config.disableAllModules) { this.reactivateAndShowModules(); } }, deactivateAndHideModules: function () { const self = this; MM.getModules().enumerate(function (module) { if ( module.name !== "MMM-Fireworks" && self.config.keepModules.indexOf(module.name) === -1 ) { console.log("Hiding module: " + module.name); module.hide(500, () => {}); if (module.suspend) { module.suspend(); } self.disabledModules.push(module); } }); }, reactivateAndShowModules: function () { const self = this; this.disabledModules.forEach(function (module) { console.log("Showing module: " + module.name); module.show(500, () => {}); if (module.resume) { module.resume(); } }); this.disabledModules = []; }, // Integrated p5.js fireworks sketch. initializeP5: function () { if (this._p5Instance) return; const self = this; const config = this.config; this._p5Instance = new p5(function (p) { let fireworks = []; let gravity; // Optional: clear the canvas fully every 2 minutes to remove ghost trails. setInterval(function () { console.log("Performing full redraw (clear) every 2 minutes."); p.clear(); }, 2 * 60 * 1000); p.setup = function () { const container = document.getElementById("fireworksContainer"); p.createCanvas(container.offsetWidth, container.offsetHeight); // Set the canvas opacity to the configured value. p.canvas.style.opacity = config.canvasOpacity; p.colorMode(p.HSB, 255); gravity = p.createVector(0, 0.2); p.background(0); }; p.draw = function () { // Use a semi-transparent background for the trailing effect. p.background(0, 0, 0, config.transparency); // Spawn a new firework with the specified probability. if (p.random(1) < config.fireworkSpawnChance) { fireworks.push(new Firework(p, gravity, config.explosionParticleCount)); } // Update and render fireworks. for (let i = fireworks.length - 1; i >= 0; i--) { fireworks[i].update(); fireworks[i].show(); if (fireworks[i].done()) { fireworks.splice(i, 1); } } }; // --- Particle Class --- class Particle { constructor(p, x, y, hu, isFirework) { this.p = p; this.pos = p.createVector(x, y); this.isFirework = isFirework; if (this.isFirework) { // Rocket's upward velocity based on config values. this.vel = p.createVector(0, p.random(config.magnitude_high, config.magnitude_low)); } else { this.vel = p5.Vector.random2D(); this.vel.mult(p.random(2, 10)); } this.acc = p.createVector(0, 0); this.lifespan = 255; this.hu = hu; } applyForce(force) { this.acc.add(force); } update() { if (!this.isFirework) { this.vel.mult(0.9); this.lifespan -= 4; } this.vel.add(this.acc); this.pos.add(this.vel); this.acc.mult(0); } done() { return this.lifespan < 0; } show() { this.p.strokeWeight(this.isFirework ? 4 : 2); this.p.stroke(this.hu, 255, 255, this.lifespan); this.p.point(this.pos.x, this.pos.y); } } // --- Firework Class --- class Firework { constructor(p, gravity, explosionCount) { this.p = p; this.hu = p.random(255); this.firework = new Particle(p, p.random(p.width), p.height, this.hu, true); this.exploded = false; this.particles = []; this.gravity = gravity; this.explosionCount = explosionCount; }
-
@chrisfr1976 yes! it definitely helps! my kid is going to love it. i linked it to a chore list so when he successfully completes all his chores through out the week the fireworks will set off and give him a little party.
-
@lucifer6669 i would use the developers window sources tab
to put stop on send and receive code
-
@sdetweil i apologize but i have no idea what that means
-
@lucifer6669 ctrl-shift-i
select the sources tabfind your source in the left nav
-
@sdetweil gotcha thank you, i dont know all the terminology. but upon completing all tasks i does send the notification but nothing happens after that
-
@lucifer6669 ok, you can step into his code too
-
@lucifer6669 Hi,
See my latest update:https://forum.magicmirror.builders/post/123879
You can use a notification now to start a fireworks. You can also send a specific text message to display. I think this solves your issue :)
-
@chrisfr1976 yes! it definitely helps! my kid is going to love it. i linked it to a chore list so when he successfully completes all his chores through out the week the fireworks will set off and give him a little party.
-