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