Read the statement by Michael Teeuw here.
How to send notification to module via external REST API call?
-
Re: [Building my first module](using MMM-API) I tried following the module which @PTcrusher has created, i.e. MMM-Piggybank, but still could not understand how the main module.js socketNotificationReceived() method gets called when a notification is sent from the node_helper.js. In my case, I tried sending a socket notification in node_helper.js right from the POST block:
this.expressApp.post("/date_sent", (req, res) => { //console.log("datePost?", req.body); this.sendSocketNotification("date_sent", req.body); res.status(200).send({status: 200}) });
and trying to receive it in module.js:
socketNotificationReceived: function (notification, payload) { console.log("Receiving notification from MMM-Test"); if(notification === "date_sent") { console.log("Received"); // set dataNotification date_sent(payload); //this.dataNotification = payload; //this.updateDom(); } }
but to no avail. Nothing ever gets printed. If I uncomment the console.log() in the node_helper.js POST method, I can see that the POST request is received fine and well, but the socket notification is lost. Please help me.
-
@aderoks you have now experienced the shifting value of the ‘this.’ pointer.
it is sensitive to the context at the time.
inside the callback of the request, ‘this’ points to the request. NOT the module context.that is the reason you will see many times BEFORE the request
let self = this
and then in the callback, use self.
instead of this. -
@sdetweil Thank you for the response. I tried your suggested approach. My code looks like the following now:
node_helper.js
const NodeHelper = require("node_helper") const bodyParser = require("body-parser") const exec = require('child_process').exec module.exports = NodeHelper.create({ start: function() { var self = this; this.expressApp.use(bodyParser.json()) this.expressApp.use(bodyParser.urlencoded({extended: true})) this.expressApp.post("/date_sent", (req, res) => { console.log("datePost?", req.body); self.sendSocketNotification("date_sent", req.body); res.status(200).send({status: 200}) }); console.log("Starting node helper for: " + this.name); }, socketNotificationReceived: function(noti, payload) { var self = this; if (noti == "date_sent") { console.log("Received date_sent: " + payload); self.sendSocketNotification("date_sent", payload); } } })
module.js
socketNotificationReceived: function (notification, payload) { console.log("Receiving notification from MMM-Test"); if(notification === "date_sent") { console.log("Received"); // set dataNotification date_sent(payload); //this.dataNotification = payload; //this.updateDom(); } }, date_sent: function(payload) { console.log("Date received: " + payload); }
Now, I am seeing that whenever I restart magic mirror, I am having a constant stream of logs with the following line:
Received date_sent: [object Object]
This is coming from the socketNotificationReceived method of the node_helper.js itself. I am trying to send the notification again from there, but the socketNotificationReceived method in the module.js still doesn’t print anything.
-
@aderoks said in How to send notification to module via external REST API call?:
socketNotificationReceived method in the module.js still doesn’t print anything.
you have to open the developers window in the browser, ctrl-shift-i, and select the console tab
node_helper console output comes out on the terminal, browser side in the browser console
you can also step thru the modulename.js (browser side) code in the dev window sources tab
but start: time is pretty early…
typically the connection isn’t setup until after the module side receives start and sends the config to the helper
(as the helper can’t see the config directly) -
@aderoks if you add this to the session/script where u start MM then all the messages will be printed in the terminal window
export ELECTRON_ENABLE_LOGGING=true
-
@aderoks said in How to send notification to module via external REST API call?:
socketNotificationReceived: function (notification, payload) {
console.log(“Receiving notification from MMM-Test”);
if(notification === “date_sent”) {
console.log(“Received”);Generally, in the module.js you would use
Log.log
and it would print to the developer window Console. Or you could just do as Sam suggested and it would print to the terminal window. -
@sdetweil @mumblebaj Thanks so much for your responses. I have been trying to implement them. However, I am facing some obstacles, and at every step, I am feeling that a deeper understanding of the Magic Mirror framework itself is required which I am not being able to find anywhere. Let me start with my problems:
-
I am using a headless setup with my Raspberry Pi 4B, so my magic mirror is being displayed onto the monitor with which it’s directly connected, but I am doing all the development by opening a remote connection to it from another PC. So I am not understanding which browser window console would give me the output, since the Chromium window which I have open in this remote desktop is perhaps, surely not the one in which the Magic Mirror is running, isn’t it?
-
I tried giving the export ELECTRON_ENABLE_LOGGING=true code in the module.js, outside of the Module.register statement, since I felt that inside it, there are only functions and not variable declarations. The module refused to even load.
-
I considered that as you have said, let me consider that the notification is actually being sent to my main module.js file, even though I am not being able to see any output. Now what I actually want to do is refresh the calendar monthly view (I have taken this implementation: https://github.com/KirAsh4/calendar_monthly) with a month that the user will pass in from the REST API call. Here, I am facing the challenge that I don’t really know how the getDom() and refreshDom() functions work and if I can parameterize them, or they are overriden methods with a fixed signature. So, understandably, when I tried to just lamely copy the getDom method into a new one and parameterized it with the passed input and tried to call it from the socketNotificationReceived() method in module.js file to refresh the output to the desired month, nothing happened. Now of course, I don’t even know whether the notification even reached the module.js, but I am assuming it did, based on what all you have said.
This all is leading me to understand that I need to know more about what underlying JS framework Magic Mirror uses for its development. For instance, when I do Module.register(), what am I actualy doing? Are the functions inside it being made visible for external access? If so, how can I access them? I tried to use MMM-NotificationTrigger’s webhook functionality to achieve my end (https://github.com/MMRIZE/MMM-NotificationTrigger#usewebhook), however, after using MMM-Api (https://github.com/juzim/MMM-Api), I found that whatever custom function I am writing within the Module.register() code block is not being exposed as actions, so that if I try to fire a notification to it using MMM-NotificationTrigger, it probably isn’t collecting it. Which is why I moved to the current approach of exposing my own REST endpoints in node_helper.js and trying to collect data from there. However, now also, I am not being able to achieve my expectation. On the other hand, I now have a stream of “Received date_sent: [object Object]” messages being printed to the console from the socketNotificationReceived function of node_helper.js from the very startup of the application. What mechanism is responsible for sending these notifications? All these are questions which I haven’t found satisfactory answers in the forum, maybe because people already know how this framework works. If so, please point me to the framework I should learn, and I would get to learning it. But please also suggest ways for me to fix these problems in the meantime so that I can get my functionality up and running.
Sorry for the long response.
Thank you.
-
-
@aderoks let’s start somewhere
mm is a normal web page, with little applets (modules). the mm code calls each applet to get their content at getDom() and insert the content on the web page in the configured position:, using normal dynamic html apis. this allows the applets to present info anytime, not just page load time. if they want to change/update their displayed data, they call updateDom(), which informs mm to call their getDom() function to get the latest applet content
the code running in the browser (modulename.js) cannot directly read files or touch hardware ( raspi gpio pins for example), so there is an optional ‘server’ side component for each applet, the node_helper.js.
the two parts communicate with private socket.io functions.-
that ELECTRON_ENABLE_LOGGING=true is issued in the terminal window where u do npm start. (set an environment variable) or in the bash script used by pm2, installers/mm.sh
-
you can use the browser side of mm on any system. you just have to enable it, by setting the allowed connection on config.js
address:“0.0.0.0”, and ipWhitelist:[]
which means listen for connections from anywhere, and do not restrict source IP addresses. in a home environment, that means any system on your wifi or Ethernet network
http://mm_ip-address:mm-config.js-port
the env setting in 2 only echos the browser logging on the machine that launched mm…
register is the mm function to connect your applet to the mm runtime.
you need to read the specifications
https://docs.magicmirror.builders/development/introduction.html#general-advicemmm-api proposes to create a distinct API from outside mm, but again address/ipWhitelist control where it can be accessed from.
the only mechanism inside mm to communicate between modules is the send/receiveNotification functions. send is a broadcast to all modules. all the built-in modules do this.
clock send second/minute/hour/day ticks, calendar sends current entries, weather’s sends etc.MMM-API turns the API requests into send/receiveNotification operations
the send/socketNotification functions take a string as the identifier of the event, and an arbitrary untyped value .
if a receiving module wants to accept and process the event message,it must understand the format of the data ( aka payload) -
-
@mumblebaj Log.log is just a wrapper for console.log, which lets mm do the loglevel settings in config.js