Read the statement by Michael Teeuw here.
Trying to write my own Module...
-
Thanks for the great support.
I currently have no errors with what you’ve helped provide me with. However, it displays the
else
condition, andNO DATA
.Right now, my
MMM-EMonitor.js
looks like the following:Module.register ("MMM-EMonitor", { //default module config. defaults: { // Insert defaults here interval: 900000 // Every 15 mins }, getStyles: function() { return ["MMM-EMonitor.css"]; }, // Define the start sequence start: function() { Log.log("Starting module: " + this.name); //this.securitykey = REDACTED; this.url = 'https://api.emonitor.us/location/getCurrentData?security_key=REDACTED'; this.getCurrentData(this); }, getCurrentData: function(that) { that.sendSocketNotification('GET-CURRENT-DATA', that.url); setTimeout(that.getCurrentData, that.config.interval, that); }, getDom: function(){ var wrapper = document.createElement("div"); if(this.xml){ var channels = this.xml.getElementsByTagName("channel"); for(var i = 0; i < channels.length; i++){ for(var n = 0; n < channels[i].children.length; n++){ if(channels[i].children[n].tagName === "name" || channels[i].children[n].tagName === "watts"){ var element = document.createElement("div"); element.classList.add(channels[i].children[n].tagName); element.innerHTML = channels[i].children[n].textContent; wrapper.appendChild(element); } } } } else { wrapper.innerHTML = "NO DATA"; } return wrapper; } });
and my
css
looks like the following:.MMM-EMonitor .centered { text-align: center; }
Like I mentioned, the
NO DATA
is showing up. The security key is working, and returns the XML which I have in my original post. -
You don’t have
this.xml
defined anywhere in your script. If you look at @strawberry-3-141’s post, it says:I’m assuming that you saved your server response into this.xml
You need to create a function that uses the URL and saves that data in a variable called
xml
. Since your program never does that,this.xml
isn’t defined so your if/else always goes to “NO DATA”.Why do you have
getCurrentData: function(that) { that.sendSocketNotification('GET-CURRENT-DATA', that.url); setTimeout(that.getCurrentData, that.config.interval, that); },
in your program? Did you just see it in another persons code? This code snippet sends your URL to node_helper.js. Are you using that node_helper to pull the XML data from the website? If so, you’re going to need a
socketNotificationReceived
function to get the data and put it into thexml
variable.The modules documentation shows you some examples of that.
-
Ahh, that makes sense. I do not have a
node_helper.js
, and I had thegetCurrentData
function because I tried to replicate a different module. I will remove these lines of code since they serve no purpose for me at the moment.I’ll try to take a look at examples to see how to save the data into the
xml
variable, so thatthis.xml
can be used. -
MMM-EMonitor.js
Module.register ("MMM-EMonitor", { //default module config. defaults: { // Insert defaults here interval: 900000, // Every 15 mins security_key: null, animationSpeed: 1000 }, getStyles: function() { return ["MMM-EMonitor.css"]; }, // Define the start sequence start: function() { Log.log("Starting module: " + this.name); this.loaded = false; this.xml = null; this.url = 'https://api.emonitor.us/location/getCurrentData?security_key='; setInterval(this.getCurrentData(), this.config_interval); }, getCurrentData: function() { var self = this; var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { self.xml = self.parseXML(this.responseText); self.loaded = true; self.updateDom(self.config.animationSpeed); } }; xhttp.open("GET", this.url+this.config.security_key, true); xhttp.send(); }, getDom: function(){ var wrapper = document.createElement("div"); if(!this.loaded) { wrapper.innerHTML = "Loading..."; return wrapper; } if(this.xml !== null){ var table = document.createElement("table"); table.classList.add("xsmall", "table"); var channels = this.xml.getElementsByTagName("channel"); for(var i = 0; i < channels.length; i++){ var row = document.createElement("tr"); for(var n = 0; n < channels[i].children.length; n++){ if(channels[i].children[n].tagName === "name" || channels[i].children[n].tagName === "watts"){ var element = document.createElement("td"); element.classList.add(channels[i].children[n].tagName); element.innerHTML = channels[i].children[n].textContent; row.appendChild(element); } table.appendChild(row); } } wrapper.appendChild(table); } else { console.log("Returned no Data"); wrapper.innerHTML = "NO DATA"; } return wrapper; }, parseXML: function(xmlStr){ return ( new window.DOMParser() ).parseFromString(xmlStr, "text/xml"); } });
Your config.js should have:
{ module: 'MMM-EMonitor', position: 'top_left', config: { security_key: 'XXXXXXXXXXXXXXX' //your security key } }
This just displays everything in a large table. You may want to modify the for loop to not display data when the wattage is 0, that should get rid of a bunch of rows.
-
This is awesome.
A few clarifying questions:
-
Is the purpose of the
xhttp.open("GET"...
line to make the API call to the website? Is this when the connection is made to the XML page? -
So, you’re going through each
"channel"
and creating a row in the table for each channel? And then for each channel’s name and wattage, a data object is created? -
If I didn’t have any
.css
file, would the data still show up?
Thanks for the clarifications, and again, thanks for the great support. This community is top-notch!
-
-
- yes the xmlhttprequest is also better known as ajax request
- for each channel a row will be created and for name and watts a column will be created with their specific values
- the data will still be displayed, but without any custom styling
-
I’m trying to display just the
names
where thewatts
that are != 0. I want both the values greater than 0 and the values less than 0 (in order to include the negative values from the solar generation).I attempted to modify the
getDom
. It is displaying everynames
in the .XML and shows thewatts
value only if it is != 0. But how do I also remove thenames
that are 0? The output currently looks like the following:Power Panel 66 Outlets 20 Heat Pump Oven East Solar Panel -70 West Solar Panel -50
getDom: function(){ var wrapper = document.createElement("div"); if(!this.loaded) { wrapper.innerHTML = "Loading..."; return wrapper; } if(this.xml !== null){ var table = document.createElement("table"); table.classList.add("xsmall", "table"); var channels = this.xml.getElementsByTagName("channel"); for(var i = 0; i < channels.length; i++){ var row = document.createElement("tr"); for(var n = 0; n < channels[i].children.length; n++){ if(channels[i].children[n].tagName === "name" || channels[i].children[n].tagName === "watts"){ var element = document.createElement("td"); element.classList.add(channels[i].children[n].tagName); if (channels[i].children[n].textContent != 0){ element.innerHTML = channels[i].children[n].textContent; row.appendChild(element); } } table.appendChild(row); } } wrapper.appendChild(table); } else { console.log("Returned no Data"); wrapper.innerHTML = "NO DATA"; } return wrapper; },
-
Looks like you need to modify your other if/then statement. The one you’ve modified checks both the name and watts to see if they are !=0. Since the name always !=0, it’s displayed.
-
It looks like the values are not updating. (The wattage values didn’t change at all overnight).
Should the line:
setInterval(this.getCurrentData(), this.config_interval);
be changed to:
setInterval(this.getCurrentData(), this.interval);
Are we calling the
interval
variable in the config incorrectly?Thanks!
-
@nbrenn
this.config.interval