Hi Sam,
My replies are getting flagged as spam apologies for the delay. But I think I found where the Selfie script sends out the notification. Do you think the other scripts I sent earlier are configured correctly?
Hi Sam,
My replies are getting flagged as spam apologies for the delay. But I think I found where the Selfie script sends out the notification. Do you think the other scripts I sent earlier are configured correctly?
So I’ve been playing around with this or a while now but cant seem to get it. I essentially want to send a notification to a modules using another. Sounds simple but I cant find any examples on how to do this. If anyone can help that would be great I’m sure its something simple in the end but please have a look at the below files and let me know what I’m missing and where, many thanks in advance!
Node_Helper.js for MMM-ALEXACONTROL
/**
* Magic Mirror
* Node Helper: MMM-AlexaControl
*
* By JoChef2
* MIT Licensed.
*/
var NodeHelper = require("node_helper");
var FauxMo = require('node-fauxmo');
var pm2 = require('pm2');
const exec = require("child_process").exec;
module.exports = NodeHelper.create({
start: function () {
console.log('MMM-AlexaControl helper, started...');
this.config = null;
this.setDevicesCounter = 0; // Counter for only one node_helper start look line 225
},
formattedName: function(devname,actionString){
var result=actionString
if(devname != undefined){
var s = actionString.split(' ')
if(s.length>1)
s.splice(1,0,devname)
else
s.unshift(devname)
result = s.join(' ')
}
return result;
},
setDevices: function(){
_this = this;
cD = this.customDevices(this.config.devices);
nD = this.notificationDevices(cD, this.config.notifications);
coD = this.commandDevices(nD, this.config.commands)
pD = this.pageDevices(coD);
mD = this.menuDevices(pD);
//console.log(pD);
//console.log(mD);
fauxMoPages = new FauxMo(mD); // creates fauxmo devices
},
customDevices : function(customD){ // creates your custom devices from config
_this = this
for(i = 0; i < Object.keys(customD.devices).length; i++){
if(customD.devices[i].port === undefined){
customD.devices[i].port = _this.config.startPort + 30 + i;
}
customD.devices[i].handler = new Function('action', customD.devices[i].handler)
}
return customD;
},
notificationDevices: function(notificationD, notifications){ // creates your notification devices
_this = this
counter = 0 + Object.keys(notificationD.devices).length
_this.n = []
for(i = 0; i < Object.keys(notifications).length; i++){
device = {}
device.name = _this.formattedName(_this.translations["deviceName"],notifications[i].name)
if(notifications[i].port === undefined){
device.port = _this.config.startPort + 50 + i
}else{
device.port = notifications[i].port
}
if(notifications[i].OnOff){
_this.n[i] = notifications[i].notification
device.handler = new Function('action', 'if(action === 1){_this.sendSocketNotification("CUSTOM",' + JSON.stringify(_this.n[i][0]) + ')}else{_this.sendSocketNotification("CUSTOM",' + JSON.stringify(_this.n[i][1]) + ')}')
}else{
_this.n[i] = notifications[i].notification
device.handler = new Function('action', '_this.sendSocketNotification("CUSTOM",' + JSON.stringify(_this.n[i]) + ')')
}
notificationD.devices[i + counter] = device
}
return notificationD;
},
commandDevices: function(commandD, commands){
_this = this
counter = 0 + Object.keys(commandD.devices).length
_this.n = []
_this.opts = { timeout: 8000 };
_this.exec = exec
for(i = 0; i < Object.keys(commands).length; i++){
device = {}
device.name = _this.formattedName(_this.translations["deviceName"],commands[i].name)
if(commands[i].port === undefined){
device.port = _this.config.startPort + 75 + i
}else{
device.port = commands[i].port
}
_this.n[i] = commands[i].command
if(commands[i].OnOff){
device.handler = new Function('action', 'if(action === 1){_this.exec(' + JSON.stringify(_this.n[i][0]) + '), _this.opts, (error, stdout, stderr) => {_this.checkForExecError(error, stdout, stderr); }}else{_this.exec(' + JSON.stringify(_this.n[i][1]) + '), _this.opts, (error, stdout, stderr) => {_this.checkForExecError(error, stdout, stderr); }}')
}
else{
device.handler = new Function('action', 'if(action === 1){_this.exec(' + JSON.stringify(_this.n[i]) + '), _this.opts, (error, stdout, stderr) => {_this.checkForExecError(error, stdout, stderr); }}')
}
commandD.devices[i + counter] = device
}
return commandD;
},
pageDevices: function(pageD){ // creates your page devices
_this = this;
counter = 0 + Object.keys(pageD.devices).length
this.pPort = _this.config.startPort
if(_this.config.pages > 0){
for(i = 0; i < _this.config.pages; i++){
device = {}
device.name = _this.formattedName(_this.translations["deviceName"],_this.translations["page"] + (i + 1))
device.port = _this.pPort - 100
device.handler = new Function('action', `_this.sendSocketNotification("PAGE_CHANGED", ` + i +`)`)
pageD.devices[i + counter] = device
this.pPort++
}
}
return pageD
},
menuDevices: function(menuD){ // create your devices to control the Mirror and pi
_this = this;
var opts = { timeout: 8000 };
//console.log("menu device ")
counter = 0 + Object.keys(menuD.devices).length
if(this.config.refresh){
device = {}
device.name = _this.formattedName(_this.translations["deviceName"],_this.translations["refresh"])
device.port = _this.config.startPort
device.handler = function(action) {_this.sendSocketNotification("ACTION", "refresh")}
menuD.devices[counter] = device;
counter++;
}
_this.config.startPort++
if(this.config.restart){ // only with PM2
device = {}
device.name = _this.formattedName(_this.translations["deviceName"],_this.translations["restart"])
device.port = _this.config.startPort
device.handler = function(action) {
pm2.connect((err) => {
if (err) {
console.error(err);
}
console.log("Restarting PM2 process: " + _this.config.pm2ProcessName);
pm2.restart(_this.config.pm2ProcessName, function(err, apps) {
pm2.disconnect();
if (err) { console.log(err); }
});
});
}
menuD.devices[counter] = device;
counter++;
}
_this.config.startPort++
if(this.config.stop){ // only with PM2
device = {}
device.name = _this.formattedName(_this.translations["deviceName"],_this.translations["stop"])
device.port = _this.config.startPort
device.handler = function(action) {
pm2.connect((err) => {
if (err) {
console.error(err);
}
console.log("Stopping PM2 process: " + _this.config.pm2ProcessName);
pm2.stop(_this.config.pm2ProcessName, function(err, apps) {
pm2.disconnect();
if (err) { console.log(err); }
});
});
}
menuD.devices[counter] = device;
counter++;
}
_this.config.startPort++
if(this.config.reboot){ //reboot the pi
device = {}
device.name = _this.formattedName(_this.translations["deviceName"],_this.translations["reboot"])
device.port = _this.config.startPort
device.handler = function(action) {
exec("sudo shutdown -r now", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}
menuD.devices[counter] = device;
counter++;
}
_this.config.startPort++
if(this.config.shutdown){ // shutdwon the pi
device = {}
device.name = _this.formattedName(_this.translations["deviceName"],_this.translations["shutdown"])
device.port = _this.config.startPort
device.handler = function(action) {
exec("sudo shutdown -h now", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}
menuD.devices[counter] = device;
counter++;
}
_this.config.startPort++
/**
* for me worked only vcgencmd display_power 0 and vcgencmd display_power 1
* probably for you work tvservice --off and tvservice --preferred
* test it in terminal if you aren't sure
*/
if(this.config.monitorToggle){
console.log("monitorToggle requested")
device = {}
device.name = _this.formattedName(_this.translations["deviceName"],_this.translations["monitor"])
device.port = _this.config.startPort
if(this.config.vcgencmd =='vcgencmd'){
device.handler = function(action) {
if(action === 1){
exec("vcgencmd display_power 1", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}if(action === 0){
exec("vcgencmd display_power 0", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}
}
}
else if(this.config.vcgencmd =='tvservice'){
device.handler = function(action) {
if(action === 1){
exec("tvservice --preferred", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}if(action === 0){
exec("tvservice --off", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}
}
}
else if(this.config.vcgencmd =='cec-client'){
device.handler = function(action) {
if(action === 1){
exec("echo \'on "+ _this.config.cecAddress +"\' | cec-client -s -d 1", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}if(action === 0){
exec("echo \'standby "+ _this.config.cecAddress +"\' | cec-client -s -d 1", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}
}
}
else if(this.config.vcgencmd =='hide'){
console.log("configuring toggle with hide")
device.handler = function(action) {
console.log("received monitor toggle with hide action="+action)
_this.sendSocketNotification('MONITOR_ACTION', action?"SLEEP_WAKE":"SLEEP_HIDE")
}
}
else{
device.handler = function(action){
console.log("Please configure the option vcgencmd")
}
}
menuD.devices[counter] = device;
counter++;
}
_this.config.startPort++
if(this.config.usb){ // toggle usb power of your pi
device = {}
device.name = _this.formattedName(_this.translations["deviceName"],_this.translations["usb"])
device.port = _this.config.startPort
device.handler = function(action) {
if(action === 0){
exec("echo '1-1' |sudo tee /sys/bus/usb/drivers/usb/unbind", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}
else{
exec("echo '1-1' |sudo tee /sys/bus/usb/drivers/usb/bind", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}
}
menuD.devices[counter] = device;
counter++;
}
_this.config.startPort++
return menuD;
},
/* monitorOff: function(){
var opts = { timeout: 8000 };
if(this.config.vcgencmd){
exec("vcgencmd display_power 0", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}else{
exec("tvservice --off", opts, (error, stdout, stderr) => {
_this.checkForExecError(error, stdout, stderr);
});
}
}, */
checkForExecError: function(error, stdout, stderr) {
if (stderr) {
console.log('stderr: "' + stderr + '"');
return 1;
}
if (error !== null) {
console.log('exec error: ' + error);
return 1;
}
return 0;
},
socketNotificationReceived: function(notification, payload) {
if(notification === "SET_DEVICE"){ // set all your devices
this.config = payload;
if(this.setDevicesCounter === 0){ // set your devices only the first time a
this.setDevices(); // notification is received
this.setDevicesCounter++;
}
}
if(notification === "TRANSLATIONS"){ // get translations and put them in an array
this.translations = [];
this.translations = payload;
}
}
});
MMM- AlexaControl config.js
/**
* Magic Mirror
* Module: MMM-AlexaControl
*
* By JoChef2
* MIT Licensed.
*/
Module.register("MMM-AlexaControl",{
defaults:{
image: true, // shows the image
height: 265, // heigth of the image
width: 265, // width of the image
pages: 0, // number off pages in MMM-Pages module. 0 means you doesn't use it
devices: { // empty object for your custom devices
devices: []
},
notifications: [], // empty array for your notification devices
commands: [], // empty array for your command devices
startPort: 11000, // the lowest used port
refresh: true, // refresh your Mirror
restart: true, // restart your Mirror with pm2
stop: true, // stops your Mirror with pm2
reboot: false, // reboot your pi
shutdown: false, // shutdown your pi
pm2ProcessName: "mm", // name of your pm2 process
monitorToggle: true, // switch your monitor on and off
vcgencmd: 'vcgencmd', // command you use for monitor toggle
cecAddress: "0.0.0.0", // Address for the cec-client
usb: false // toggle usb power of your pi
},
getTranslations: function(){ // add more translations
return {
en: "translations/en.json",
de: "translations/de.json"
}
},
start: function(){
Log.log('Starting module: ' + this.name);
// send all translations to node_helper
this.sendSocketNotification('TRANSLATIONS', {"monitor": this.translate("MONITOR"), "shutdown": this.translate("SHUTDOWN"), "reboot": this.translate("REBOOT"), "page": this.translate("PAGE"), "refresh": this.translate("REFRESH"), "restart": this.translate("RESTART"), "stop": this.translate("STOP"), "usb": this.translate("USB"), "deviceName":this.translate(this.config.deviceName)});
this.sendSocketNotification('SET_DEVICE', this.config); // send the config to node_helper
},
getDom: function(){ // returns only an image or an empty div (necessary for MMM-Pages)
if(this.config.image){
let img = document.createElement("img");
img.classList = "img";
img.src = "MMM-AlexaControl/AlexaLogoGrey.png";
img.height = this.config.height;
img.width = this.config.width;
return img;
}else{
return document.createElement("div");
}
},
socketNotificationReceived: function(notification, payload) {
if(notification === "PAGE_CHANGED"){ // change pages of MMM-Pages
this.sendNotification("PAGE_CHANGED", payload);
}
if(notification === "ACTION"){ // refresh the Mirror
if(payload === "refresh"){
window.location.reload(true);
}
}
if(notification === "SELFIE_SHOOT"){
this.sendNotification("SELFIE_SHOOT"); // send any notification to any module
}
if(notification =='MONITOR_ACTION'){
Log.log('RECEIVE monitor NOTIFICATION='+payload)
this.sendNotification(notification,payload)
}
}
});
Config.js
/* Magic Mirror Config Sample
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*
* For more information on how you can configure this file
* see https://docs.magicmirror.builders/getting-started/configuration.html#general
* and https://docs.magicmirror.builders/modules/configuration.html
*/
let config = {
address: "localhost", // Address to listen on, can be:
// - "localhost", "127.0.0.1", "::1" to listen on loopback interface
// - another specific IPv4/6 to listen on a specific interface
// - "0.0.0.0", "::" to listen on any interface
// Default, when address config is left out or empty, is "localhost"
port: 8080,
basePath: "/", // The URL path where MagicMirror is hosted. If you are using a Reverse proxy
// you must set the sub path here. basePath must end with a /
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], // Set [] to allow all IP addresses
// or add a specific IPv4 of 192.168.1.5 :
// ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.1.5"],
// or IPv4 range of 192.168.3.0 --> 192.168.3.15 use CIDR format :
// ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.3.0/28"],
useHttps: false, // Support HTTPS or not, default "false" will use HTTP
httpsPrivateKey: "", // HTTPS private key path, only require when useHttps is true
httpsCertificate: "", // HTTPS Certificate path, only require when useHttps is true
language: "en",
locale: "en-UK",
logLevel: ["INFO", "LOG", "WARN", "ERROR"], // Add "DEBUG" for even more logging
timeFormat: 12,
units: "metric",
serverOnly: true,
// local for armv6l processors, default
// starts serveronly and then starts chrome browser
// false, default for all NON-armv6l devices
// true, force serveronly mode, because you want to.. no UI on this device
modules: [
{
disabled: false,
module:"MMM-Config",
position:"top_right", // the QR code (if requested) will appear here
config:{
showQR: false,
//restart: "pm2",
//force_update: true,
//debug: true
}
},
{
module: 'MMM-AlexaControl',
position: 'middle_center',
notifications:[
{
name: 'Next page',
port: 11102,
OnOff: false,
notification: ["PAGE_INCREMENT", 'payload']
},
{
name: 'Previous page',
port: 11103,
OnOff: false,
notification: ["PAGE_DECREMENT", 'payload']
},
{
name: 'Selfie',
port: 11104,
OnOff: false,
notification: ["SELFIE_SHOOT"]
}
],
config:{
image: true,
deviceName: "mirror",
pm2ProcessName: "mm",
vcgencmd: "hide",
startPort: 11001,
refresh: true,
restart: true,
//stop: true,
reboot: true,
shutdown: true,
monitorToggle: true,
//cecAddress: "0.0.0.0",
//usb: false
pages: 2,
}
},
{
module: 'MMM-SleepWake',
config:{
//delay: 15, // default
mode: 'pi'
}
},
{
module: 'MMM-pages',
config: {
pages: 2,
modules:
[[ "MMM-Astro" ],
[ "MMM-OpenWeatherMapForecast", "compliments" ]],
fixed: [ "clock", "MMM-page-indicator" ],
hiddenPages: {
"screenSaver": [ "clock", "MMM-SomeBackgroundImageModule" ],
"admin": [ "MMM-ShowMeSystemStatsModule", "MMM-AnOnScreenMenuModule" ],
},
}
},
{
module: 'MMM-page-indicator',
position: 'bottom_bar',
config: {
pages: 2,
}
},
{
disabled: false,
module: "MMM-Selfieshot",
position: "bottom_center",
config: {
displayButton: "portrait",
storePath: "/media/smartmirror/Storage/Photos",
width:1280,
height:720,
quality: 100,
device: null,
shootMessage: "Smile!",
shootCountdown: 3,
displayCountdown: true,
displayResult: true,
playShutter: true,
shutterSound: "shutter.mp3",
}
},
{
disabled: false,
module: 'MMM-Astro',
position: 'top_left',
config: {
sign: "leo",
iconset: "4",
extend: false,
}
},
{
module: "MMM-OpenWeatherMapForecast",
header: "Weather",
position: "top_right",
classes: "default everyone",
disabled: true,
config: {
iconset: "4c",
units: "metric",
useAnimatedIcons: true,
concise: false,
forecastLayout: "table",
showWind: true
}
},
{
module: "alert",
},
{
module: "updatenotification",
position: "top_bar"
},
{
module: "clock",
position: "top_center"
},
{
module: "compliments",
position: "lower_third"
},
]
};
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = config;}
@alyx ok I found the issue, I commented out all the options in alexa and then ran them individually and etc.
Turns out the notification/ command and devices options werent configured correctly by the conf generator. after commenting those out I can now find them on alexa
@sdetweil Ive rebooted the machine 3 times at this point ahah, I have an echo3 would that be considered new? I know the 4th gen is the latest
@sdetweil I did delete and rediscover but the thing is they arent showing up in the discovery now lol
@sdetweil
Yes thats what I mean I haven’t changed anything like that although. I just used the script and the generated config file. It seems alexa can no longer find the devices and is displaying them as offline
@alyx ok screw that its working now all of a sudden ahaha
The alexa thing still isnt working tho
@sdetweil Before I was able to connect my alexa as a smart device with pm2 but now its not showing at all on alexa is what i mean.
Yep that the link I use but I get the the home page and its the same blank interface as before with no modules tab or anything? Like I just used it to make the latest conf file so I know it works some how haha
@sdetweil OK back working now with that thanks! Although the conf for my pm2 seems to be not working anymore, I think I saw a similar issue somewhere in the comments here?
Also I cant get the conf page anymore cause it can no longer get /modules/MMM-Config/review
?
@sdetweil Ah no worries was out for some materials to build the mirror frame myself haha
@sdetweil
Did the debug what folder does it go to? I have the somefile ready also
As for the messages I get the first part but not the second saying its created
So I’m experiencing a new issue where when I use the editor and trhen press save its not actually saving the new co’ve reinstallked the module and even chmod the folder to 777
Is this an issue others are experiencing?
I have the config for it on the defualt settings and the somefile.txt reports that everything is find and it opened successfully on port 8301 ( this seems to change actually) I’m thinking that the port is changing while I’m editing?
@sdetweil ok I flash reinstalled MM (worryingly good at it now…) and it seems to be working :)
The config pops up on the webpage correctly and all.
Thanks Sam!
@sdetweil I used sudo because some package files reported back errors and that I dont have the required permissions?
@sdetweil So I did as you said and the npm run is stuck loading for a while and the text file is empty.
Now I’m running in server mode if that matters? I used npm run server >somefile.txt
@alyx actually i had a harder look, does this seem important?
smartmirror@smartmirror-ThinkCentre-M72e:~/MagicMirror/modules/MMM-Config$ sudo npm install
npm WARN lifecycle mmm-config@1.0.0~postinstall: cannot run in wd mmm-config@1.0.0 node exec_script.js ./postinstall:postinstall.cmd (wd=/home/smartmirror/MagicMirror/modules/MMM-Config)
npm WARN mmm-config@1.0.0 No repository field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.3.2 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {“os”:“darwin”,“arch”:“any”} (current: {“os”:“linux”,“arch”:“x64”})
audited 136 packages in 1.22s
7 packages are looking for funding
run npm fund for details
found 3 moderate severity vulnerabilities
run npm audit fix to fix them, or npm audit for details
smartmirror@smartmirror-ThinkCentre-M72e:~/MagicMirror/modules/MMM-Config$
@sdetweil Yep I did it within the MMM-Config directory, did it again there with no luck. Got some audit issues for npm but nothing big
@sdetweil no worries cheers buddy lemme know if you need anything