• Recent
  • Tags
  • Unsolved
  • Solved
  • MagicMirror² Repository
  • Documentation
  • 3rd-Party-Modules
  • Donate
  • Discord
  • Register
  • Login
MagicMirror Forum
  • Recent
  • Tags
  • Unsolved
  • Solved
  • MagicMirror² Repository
  • Documentation
  • 3rd-Party-Modules
  • Donate
  • Discord
  • Register
  • Login
A New Chapter for MagicMirror: The Community Takes the Lead
Read the statement by Michael Teeuw here.

Peek-a-boo...

Scheduled Pinned Locked Moved Troubleshooting
18 Posts 5 Posters 9.6k Views 5 Watching
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    carteblanche @darrene
    last edited by Oct 21, 2016, 12:03 AM

    @darrene I went through all the steps and I can see in the console that the modules are receiving the notification broadcast as expected but for whatever reason the Calendar isn’t actually responding (i.e. HIDE_CALENDAR doesn’t make the calendar go away).

    Any ideas? I’m wondering if it has to do with where I put the code into calendar.js?

    D 1 Reply Last reply Oct 21, 2016, 7:50 AM Reply Quote 0
    • D Offline
      darrene @carteblanche
      last edited by Oct 21, 2016, 7:50 AM

      It sounds as though you’re almost there @carteblanche. That’s great!

      It’s either a case then of a mismatch between what you’re expecting to be broadcast and what is being, or as you say, the calendar not reacting to the notification it receives.

      So to be clear, in the console you see HIDE_CALENDAR as the notification that’s broadcast? if so, that rules out the first issue.

      I’m using the default calendar module rather than a 3rd-party one. I’m going to assume you are too but if not, you’ll just need to ensure it’s the right module you’re working on. (I don’t mean it to sound condescending and sorry if it’s obvious but personally speaking, I’m so busy looking closely at the issue that I usually find out afterwards it was something like that! :) )

      It could be the location in the calendar.js but it’s just as likely there’s a small typo which means the calendar is ignoring it.

      If we assume the notification is making it as far as the calendar module, I’ll post my entire calendar.js so you can compare the syntax and see where I’ve put it (in all of my modules I’ve tried to put it in the same place relatively - just before the Override Dom Generator section)

      Good luck!

      /* global Module */
      
      /* Magic Mirror
      * Module: Calendar
      *
      * By Michael Teeuw http://michaelteeuw.nl
      * MIT Licensed.
      */
      
      Module.register("calendar",{
      
      // Define module defaults
      defaults: {
      	maximumEntries: 10, // Total Maximum Entries
      	maximumNumberOfDays: 365,
      	displaySymbol: true,
      	defaultSymbol: "calendar", // Fontawesome Symbol see http://fontawesome.io/cheatsheet/
      	displayRepeatingCountTitle: false,
      	defaultRepeatingCountTitle: '',
      	maxTitleLength: 25,
      	fetchInterval: 5 * 60 * 1000, // Update every 5 minutes.
      	animationSpeed: 2000,
      	fade: true,
      	urgency: 7,
      	timeFormat: "relative",
      	fadePoint: 0.25, // Start on 1/4th of the list.
      	calendars: [
      		{
      			symbol: "calendar",
      			url: "http://www.calendarlabs.com/templates/ical/US-Holidays.ics",
      		},
      	],
      	titleReplace: {
      		"De verjaardag van ": "",
      		"'s birthday": ""
      	},
      },
      
      // Define required scripts.
      getStyles: function() {
      	return ["calendar.css", "font-awesome.css"];
      },
      
      // Define required scripts.
      getScripts: function() {
      	return ["moment.js"];
      },
      
      // Define required translations.
      getTranslations: function() {
      	// The translations for the defaut modules are defined in the core translation files.
      	// Therefor we can just return false. Otherwise we should have returned a dictionairy.
      	// If you're trying to build your own module including translations, check out the documentation.
      	return false;
      },
      
      // Override start method.
      start: function() {
      	Log.log("Starting module: " + this.name);
      
      	// Set locale.
      	moment.locale(config.language);
      
      	for (var c in this.config.calendars) {
      		var calendar = this.config.calendars[c];
      		calendar.url = calendar.url.replace("webcal://", "http://");
      		this.addCalendar(calendar.url, calendar.user, calendar.pass);
      	}
      
      	this.calendarData = {};
      	this.loaded = false;
      },
      
      // Override socket notification handler.
      socketNotificationReceived: function(notification, payload) {
      	if (notification === "CALENDAR_EVENTS") {
      		if (this.hasCalendarURL(payload.url)) {
      			this.calendarData[payload.url] = payload.events;
      			this.loaded = true;
      		}
      	} else if (notification === "FETCH_ERROR") {
      		Log.error("Calendar Error. Could not fetch calendar: " + payload.url);
      	} else if (notification === "INCORRECT_URL") {
      		Log.error("Calendar Error. Incorrect url: " + payload.url);
      	} else {
      		Log.log("Calendar received an unknown socket notification: " + notification);
      	}
      
      	this.updateDom(this.config.animationSpeed);
      },
      
          // added by DGE to respond to voice notifications
          notificationReceived: function(notification, payload, sender) {
                  if (notification === "HIDE_CALENDAR") {
                          this.hide();
                  } else if (notification === "SHOW_CALENDAR") {
                          this.show();
                  } else if (notification === "HIDE_ALL") {
                          this.hide();
                  } else if (notification === "SHOW_ALL") {
                          this.show();
                  }
          },
      
      
      
      // Override dom generator.
      getDom: function() {
      
      	var events = this.createEventList();
      	var wrapper = document.createElement("table");
      	wrapper.className = "small";
      
      	if (events.length === 0) {
      		wrapper.innerHTML = (this.loaded) ? this.translate("EMPTY") : this.translate("LOADING");
      		wrapper.className = "small dimmed";
      		return wrapper;
      	}
      
      	for (var e in events) {
      		var event = events[e];
      
      		var eventWrapper = document.createElement("tr");
      		eventWrapper.className = "normal";
      
      		if (this.config.displaySymbol) {
      			var symbolWrapper =  document.createElement("td");
      			symbolWrapper.className = "symbol";
      			var symbol =  document.createElement("span");
      			symbol.className = "fa fa-" + this.symbolForUrl(event.url);
      			symbolWrapper.appendChild(symbol);
      			eventWrapper.appendChild(symbolWrapper);
      		}
      
      		var titleWrapper = document.createElement("td"),
      			repeatingCountTitle = '';
      
      
      		if (this.config.displayRepeatingCountTitle) {
      
      			repeatingCountTitle = this.countTitleForUrl(event.url);
      
      			if(repeatingCountTitle !== '') {
      				var thisYear = new Date().getFullYear(),
      					yearDiff = thisYear - event.firstYear;
      
      				repeatingCountTitle = ', '+ yearDiff + '. ' + repeatingCountTitle;
      			}
      		}
      
      		titleWrapper.innerHTML = this.titleTransform(event.title) + repeatingCountTitle;
      		titleWrapper.className = "title bright";
      		eventWrapper.appendChild(titleWrapper);
      
      		var timeWrapper =  document.createElement("td");
      		//console.log(event.today);
      		var now = new Date();
      		// Define second, minute, hour, and day variables
      		var one_second = 1000; // 1,000 milliseconds
      		var one_minute = one_second * 60;
      		var one_hour = one_minute * 60;
      		var one_day = one_hour * 24;
      		if (event.fullDayEvent) {
      			if (event.today) {
      				timeWrapper.innerHTML = this.translate("TODAY");
      			} else if (event.startDate - now < one_day && event.startDate - now > 0) {
      				timeWrapper.innerHTML = this.translate("TOMORROW");
      			} else if (event.startDate - now < 2*one_day && event.startDate - now > 0) {
      			/*Provide ability to show "the day after tomorrow" instead of "in a day" 
      			 *if "DAYAFTERTOMORROW" is configured in a language's translation .json file, 
      			 *,which can be found in MagicMirror/translations/
      			 */
      				if (this.translate('DAYAFTERTOMORROW') !== 'DAYAFTERTOMORROW') {
      						timeWrapper.innerHTML = this.translate("DAYAFTERTOMORROW");
      				} else {
      						timeWrapper.innerHTML = moment(event.startDate, "x").fromNow();
      				}
      			} else {
      				/* Check to see if the user displays absolute or relative dates with their events
      				 * Also check to see if an event is happening within an 'urgency' time frameElement
      				 * For example, if the user set an .urgency of 7 days, those events that fall within that
      				 * time frame will be displayed with 'in xxx' time format or moment.fromNow()
      				 *
      				 * Note: this needs to be put in its own function, as the whole thing repeats again verbatim
      				 */
      				if (this.config.timeFormat === "absolute") {
      					if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * one_day))) {
      						// This event falls within the config.urgency period that the user has set
      						timeWrapper.innerHTML = moment(event.startDate, "x").fromNow();
      					} else {
      						timeWrapper.innerHTML = moment(event.startDate, "x").format("MMM Do");
      					}
      				} else {
      					timeWrapper.innerHTML =  moment(event.startDate, "x").fromNow();
      				}
      			}
      		} else {
      			if (event.startDate >= new Date()) {
      				if (event.startDate - now < 2 * one_day) {
      					// This event is within the next 48 hours (2 days)
      					if (event.startDate - now < 6 * one_hour) {
      						// If event is within 6 hour, display 'in xxx' time format or moment.fromNow()
      						timeWrapper.innerHTML = moment(event.startDate, "x").fromNow();
      					} else {
      						// Otherwise just say 'Today/Tomorrow at such-n-such time'
      						timeWrapper.innerHTML = moment(event.startDate, "x").calendar();
      					}
      				} else {
      					/* Check to see if the user displays absolute or relative dates with their events
      					 * Also check to see if an event is happening within an 'urgency' time frameElement
      					 * For example, if the user set an .urgency of 7 days, those events that fall within that
      					 * time frame will be displayed with 'in xxx' time format or moment.fromNow()
      					 *
      					 * Note: this needs to be put in its own function, as the whole thing repeats again verbatim
      					 */
      					if (this.config.timeFormat === "absolute") {
      						if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * one_day))) {
      							// This event falls within the config.urgency period that the user has set
      							timeWrapper.innerHTML = moment(event.startDate, "x").fromNow();
      						} else {
      							timeWrapper.innerHTML = moment(event.startDate, "x").format("MMM Do");
      						}
      					} else {
      						timeWrapper.innerHTML = moment(event.startDate, "x").fromNow();
      					}
      				}
      			} else {
      				timeWrapper.innerHTML =  this.translate("RUNNING") + ' ' + moment(event.endDate,"x").fromNow(true);
      			}
      		}
      		//timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll');
      		//console.log(event);
      		timeWrapper.className = "time light";
      		eventWrapper.appendChild(timeWrapper);
      
      		wrapper.appendChild(eventWrapper);
      
      		// Create fade effect.
      		if (this.config.fade && this.config.fadePoint < 1) {
      			if (this.config.fadePoint < 0) {
      				this.config.fadePoint = 0;
      			}
      			var startingPoint = events.length * this.config.fadePoint;
      			var steps = events.length - startingPoint;
      			if (e >= startingPoint) {
      				var currentStep = e - startingPoint;
      				eventWrapper.style.opacity = 1 - (1 / steps * currentStep);
      			}
      		}
      	}
      
      	return wrapper;
      },
      
      /* hasCalendarURL(url)
       * Check if this config contains the calendar url.
       *
       * argument url sting - Url to look for.
       *
       * return bool - Has calendar url
       */
      hasCalendarURL: function(url) {
      	for (var c in this.config.calendars) {
      		var calendar = this.config.calendars[c];
      		if (calendar.url === url) {
      			return true;
      		}
      	}
      
      	return false;
      },
      
      /* createEventList()
       * Creates the sorted list of all events.
       *
       * return array - Array with events.
       */
      createEventList: function() {
      	var events = [];
      	var today = moment().startOf("day");
      	for (var c in this.calendarData) {
      		var calendar = this.calendarData[c];
      		for (var e in calendar) {
      			var event = calendar[e];
      			event.url = c;
      			event.today = event.startDate >= today && event.startDate < (today + 24 * 60 * 60 * 1000);
      			events.push(event);
      		}
      	}
      
      	events.sort(function(a, b) {
      		return a.startDate - b.startDate;
      	});
      
      	return events.slice(0, this.config.maximumEntries);
      },
      
      /* createEventList(url)
       * Requests node helper to add calendar url.
       *
       * argument url sting - Url to add.
       */
      addCalendar: function(url, user, pass) {
      	this.sendSocketNotification("ADD_CALENDAR", {
      		url: url,
      		maximumEntries: this.config.maximumEntries,
      		maximumNumberOfDays: this.config.maximumNumberOfDays,
      		fetchInterval: this.config.fetchInterval,
      		user: user,
      		pass: pass
      	});
      },
      
      /* symbolForUrl(url)
       * Retrieves the symbol for a specific url.
       *
       * argument url sting - Url to look for.
       *
       * return string - The Symbol
       */
      symbolForUrl: function(url) {
      	for (var c in this.config.calendars) {
      		var calendar = this.config.calendars[c];
      		if (calendar.url === url && typeof calendar.symbol === "string")  {
      			return calendar.symbol;
      		}
      	}
      
      	return this.config.defaultSymbol;
      },
      /* countTitleForUrl(url)
       * Retrieves the name for a specific url.
       *
       * argument url sting - Url to look for.
       *
       * return string - The Symbol
       */
      countTitleForUrl: function(url) {
      	for (var c in this.config.calendars) {
      		var calendar = this.config.calendars[c];
      		if (calendar.url === url && typeof calendar.repeatingCountTitle === "string")  {
      			return calendar.repeatingCountTitle;
      		}
      	}
      
      	return this.config.defaultRepeatingCountTitle;
      },
      
      /* shorten(string, maxLength)
       * Shortens a sting if it's longer than maxLenthg.
       * Adds an ellipsis to the end.
       *
       * argument string string - The string to shorten.
       * argument maxLength number - The max lenth of the string.
       *
       * return string - The shortened string.
       */
      shorten: function(string, maxLength) {
      	if (string.length > maxLength) {
      		return string.slice(0,maxLength) + "&hellip;";
      	}
      
      	return string;
      },
      
      /* titleTransform(title)
       * Transforms the title of an event for usage.
       * Replaces parts of the text as defined in config.titleReplace.
       * Shortens title based on config.maxTitleLength
       *
       * argument title string - The title to transform.
       *
       * return string - The transformed title.
       */
      titleTransform: function(title) {
      	for (var needle in this.config.titleReplace) {
      		var replacement = this.config.titleReplace[needle];
      		title = title.replace(needle, replacement);
      	}
      
      	title = this.shorten(title, this.config.maxTitleLength);
      	return title;
      }
      

      });

      C 1 Reply Last reply Oct 21, 2016, 4:28 PM Reply Quote 0
      • D Offline
        darrene
        last edited by Oct 21, 2016, 8:00 AM

        As I mentioned earlier, the approach I’ve taken isn’t exactly elegant. It’s the way to go for a HIDE_ALL or SHOW_ALL because obviously all the modules would need to know then, but a more efficient approach would really be to target modules as you need them - that involved reworking the voicecontrol.js or node-helper though and passing two variables - the notification and the target module. I just wasn’t confident enough to do this yet.

        1 Reply Last reply Reply Quote 0
        • C Offline
          carteblanche @darrene
          last edited by carteblanche Oct 21, 2016, 6:20 PM Oct 21, 2016, 4:28 PM

          @darrene thank you for sharing your calendar.js file because that is where I found where the issue was…it was the name for the function notificationReceived: – needed to have a lower case “n”.

          Now it works perfectly!! And as you predicted I experienced a massive grin.

          update:
          I’ve been testing this out with other modules and it works like a charm. I also discovered (after trial and error) that its possible to combine the hide/show with the hide all/show all command simply by revising the if statement on the notificationReceived function with an “or” condition specifying both commands . See below is an example of the revised code:

          notificationReceived: function(notification, payload, sender) {
          if (notification === “HIDE_CALENDAR” || “HIDE_ALL”) {
          this.hide();
          } else if (notification === “SHOW_CALENDAR” || “SHOW_ALL”) {
          this.show();
          }
          },

          C D 2 Replies Last reply Oct 21, 2016, 7:19 PM Reply Quote 0
          • C Offline
            carteblanche @carteblanche
            last edited by carteblanche Oct 21, 2016, 7:27 PM Oct 21, 2016, 7:19 PM

            @carteblanche said in Peek-a-boo...:

            @darrene thank you for sharing your calendar.js file because that is where I found where the issue was…it was the name for the function notificationReceived: – needed to have a lower case “n”.

            Now it works perfectly!! And as you predicted I experienced a massive grin.

            update:
            I’ve been testing this out with other modules and it works like a charm. I also discovered (after trial and error) that its possible to combine the hide/show with the hide all/show all command simply by revising the if statement on the notificationReceived function with an “or” condition specifying both commands . See below is an example of the revised code:

            notificationReceived: function(notification, payload, sender) {
            if (notification === “HIDE_CALENDAR” || “HIDE_ALL”) {
            this.hide();
            } else if (notification === “SHOW_CALENDAR” || “SHOW_ALL”) {
            this.show();
            }
            },

            update: while this worked for a short period, upon further testing this code seems to cause some issues with HIDE_ALL auto suspending all modules on launch. So the or condition if statement doesn’t appear to be a viable solution, the only way to include hide/show all is the way you have the code now @darrene with the multiple else if statements.

            S 1 Reply Last reply Oct 21, 2016, 8:14 PM Reply Quote 0
            • S Offline
              strawberry 3.141 Project Sponsor Module Developer @carteblanche
              last edited by Oct 21, 2016, 8:14 PM

              @carteblanche

              if (notification === "HIDE_CALENDAR" || "HIDE_ALL")
              
              this will be always true: notification === "HIDE_CALENDAR" can be true or false, but "HIDE_ALL" will be always true
              

              that’s why it always hide the module

              it must be like that

              if (notification === "HIDE_CALENDAR" || notification === "HIDE_ALL") {
                  this.hide();
              } else if (notification === "SHOW_CALENDAR" || notification === "SHOW_ALL") {
                  this.show();
              }
              },
              

              Please create a github issue if you need help, so I can keep track

              C 1 Reply Last reply Oct 21, 2016, 8:17 PM Reply Quote 0
              • C Offline
                carteblanche @strawberry 3.141
                last edited by Oct 21, 2016, 8:17 PM

                @strawberry-3.141 Thank you for the tip! Now it makes perfect sense.

                It does still work with the multiple else if statements but for the sake of cleaner code I like the idea of using the or condition.

                1 Reply Last reply Reply Quote 0
                • D Offline
                  darrene @carteblanche
                  last edited by Oct 22, 2016, 12:30 PM

                  Apologies for the typo in notification @carteblanche - I should have copied and pasted the code originally, rather than typing it off the the top of my head!

                  Glad to read that you managed to sort it though. Nice work :)

                  C B 2 Replies Last reply Oct 23, 2016, 5:11 AM Reply Quote 0
                  • C Offline
                    carteblanche @darrene
                    last edited by Oct 23, 2016, 5:11 AM

                    @darrene hey no worries at all on the typo. I can’t thank you enough for helping out and providing the comprehensive step-by-step guide in plain english to noobs like me. I don’t know how I would have got the voice module working without your help so thanks again!

                    1 Reply Last reply Reply Quote 0
                    • B Offline
                      Baltibu @darrene
                      last edited by Oct 23, 2016, 10:33 AM

                      @darrene I think you a lot for your help.
                      i get it work with all module that I have :-)
                      Your descpition was very helpfull. thanks again .

                      1 Reply Last reply Reply Quote 0
                      • 1
                      • 2
                      • 2 / 2
                      2 / 2
                      • First post
                        12/18
                        Last post
                      Enjoying MagicMirror? Please consider a donation!
                      MagicMirror created by Michael Teeuw.
                      Forum managed by Sam, technical setup by Karsten.
                      This forum is using NodeBB as its core | Contributors
                      Contact | Privacy Policy