• 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.

Problem Adding Buttons & required Remote-Control Modules

Scheduled Pinned Locked Moved Solved Troubleshooting
26 Posts 4 Posters 1.8k Views 4 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.
  • A Offline
    awwbaker @sdetweil
    last edited by Oct 29, 2024, 12:50 AM

    @sdetweil ,
    Hmmm…thanks Sam!!!

    1 Reply Last reply Reply Quote 0
    • C Offline
      ChrisLeduex
      last edited by Nov 4, 2024, 6:54 PM

      Hi guys, I’ve been trying to figure this out too. I think I’m close with these two files using ‘pinctrl’ instead of ‘/sys/class/gpio/’ but I can’t figure out what I’m missing.

      Based on the console log it looks like there’s an issue in my node_helper file, possible with the socketNotification functions because I’m not seeing any of my test messages.

      And based on the log files there may be something missing from the package.json file because sometimes I get this error “Error: Cannot find module ‘node helper’ MODULE_NOT_FOUND” but other times I don’t. And I tried running this fix but couldn’t get it to work.
      [https://forum.magicmirror.builders/user/jorickjuh](link url)

      Other than that I’m not seeing any other errors and module does appear to be working but it’s just not processing any button presses. I’ll keep trying but I’ll post my progress so far on here in case someone can see what I’m missing.

      test file:

      Module.register("MMM-PinToggleTest", {
        defaults: {
          pin: 19,
          modulesToToggle: ["clock", "calendar"],
          interval: 1000
        },
      
      //consol.log("MMM-PinToggleTest is starting...");
      
        start: function() {
          Log.info("MMM-PinToggleTest is starting, sending CONFIG...");
          consol.log("MMM-PinToggleTest is starting, sending CONFIG...");
          
          this.sendSocketNotification("CONFIG", {
            interval: this.config.interval,
            pin: this.config.pin
            });
          },
      
        start: function() {
          console.log("MMM-PinToggleTest started");
          this.previousPinState = null;
      
          // Request initial pin check from the helper
          this.sendSocketNotification("CONFIG", this.config);
        },
      
        socketNotificationReceived: function(notification, payload) {
          if (notification === "PIN_STATE") {
            const pinState = payload;
            console.log(`Received pin state: ${pinState}`);  // Log received state
      
            // Toggle modules based on pin state
            if (pinState !== this.previousPinState) {
              this.previousPinState = pinState;
              this.toggleModules(pinState === 1);
            }
          }
        },
      
        toggleModules: function(show) {
          console.log(`Toggling modules to ${show ? "show" : "hide"}`);
          this.config.modulesToToggle.forEach(moduleName => {
            const modules = MM.getModules().withClass(moduleName);
            modules.forEach(module => {
              if (show) {
                module.show(1000);  // Show module with fade-in effect
              } else {
                module.hide(1000);  // Hide module with fade-out effect
              }
            });
          });
        },
        
      
        getDom: function() {
          const wrapper = document.createElement("div");
          wrapper.innerHTML = "<small>MMM-PinToggleTest</small>";
          return wrapper;
        }
      });
      

      node_helper:

      const NodeHelper = require("node_helper");
      const exec = require("child_process").exec;
      //const rpio = require("rpio");
      //const Gpio = require("onoff").Gpio;
      
      module.exports = NodeHelper.create({
        start: function() {
          console.log("node_helper for MMM-PinToggleTest has started.");  // Confirm helper initialization
          this.previousPinState = null;
          this.lastChangeTime = 0;
          this.debounceDelay = 200;
        },
      
        socketNotificationReceived: function(notification, payload) {
          if (notification === "CONFIG") {
            console.log("Received CONFIG in node_helper:", payload);  // Log receipt of configuration
            this.config = payload;
            this.schedulePinCheck();
          }
        },
      
        schedulePinCheck: function() {
          console.log(`Setting up pin check every ${this.config.interval} ms`); // Confirmation log
          setInterval(() => {
            this.checkPinState();
          }, this.config.interval);
        },
      
        checkPinState: function() {
          const pinNumber = this.config.pin;
      
          exec(`pinctrl ${pinNumber}`, (error, stdout, stderr) => {
            if (error) {
              console.error(`Error reading GPIO pin ${pinNumber}: ${stderr}`);
              return;
            }
      
            const pinState = parseInt(stdout.trim(), 10);
            const now = Date.now();
      
            console.log(`Current pin state for GPIO ${pinNumber}: ${pinState}`);
      
            if (pinState !== this.previousPinState && (now - this.lastChangeTime > this.debounceDelay)) {
              this.previousPinState = pinState;
              this.lastChangeTime = now;
      
              console.log(`Pin state changed to ${pinState} at ${new Date(now).toISOString()}`);
              this.sendSocketNotification("PIN_STATE", pinState);
              
              // Small delay to avoid multiple triggers
              //setTimeout(() => {}, 100);
            }
          });
        }
      });
      
      S 1 Reply Last reply Nov 4, 2024, 7:56 PM Reply Quote 0
      • S Away
        sdetweil @ChrisLeduex
        last edited by sdetweil Nov 4, 2024, 8:50 PM Nov 4, 2024, 7:56 PM

        @ChrisLeduex well, you don’t have any source errors. altho you have 2 start: functions in the modulename.js

        I see this as output of the pinctrl command on my pi 4

         pinctrl
         0: ip    pu | hi // ID_SDA/GPIO0 = input
         1: ip    pu | hi // ID_SCL/GPIO1 = input
         2: ip    pu | hi // GPIO2 = input
         3: ip    pu | hi // GPIO3 = input
         4: ip    pu | hi // GPIO4 = input
         5: ip    pu | hi // GPIO5 = input
         6: ip    pu | hi // GPIO6 = input
         7: ip    pu | hi // GPIO7 = input
         8: ip    pu | hi // GPIO8 = input
         9: ip    pd | lo // GPIO9 = input
        10: ip    pd | lo // GPIO10 = input
        11: ip    pd | lo // GPIO11 = input
        12: ip    pd | lo // GPIO12 = input
        13: ip    pd | lo // GPIO13 = input
        14: ip    pn | hi // GPIO14 = input
        15: ip    pu | hi // GPIO15 = input
        16: ip    pd | lo // GPIO16 = input
        17: ip    pd | lo // GPIO17 = input
        18: ip    pd | lo // GPIO18 = input
        19: ip    pd | lo // GPIO19 = input
        20: ip    pd | lo // GPIO20 = input
        21: ip    pd | lo // GPIO21 = input
        22: ip    pd | lo // GPIO22 = input
        23: ip    pd | lo // GPIO23 = input
        24: ip    pd | lo // GPIO24 = input
        25: ip    pd | lo // GPIO25 = input
        26: ip    pd | lo // GPIO26 = input
        27: ip    pd | lo // GPIO27 = input
        28: a5    pu | hi // RGMII_MDIO/GPIO28 = RGMII_MDIO
        29: a5    pd | lo // RGMIO_MDC/GPIO29 = RGMII_MDC
        30: a3    pu | lo // CTS0/GPIO30 = CTS0
        31: a3    pn | lo // RTS0/GPIO31 = RTS0
        32: a3    pn | hi // TXD0/GPIO32 = TXD0
        33: a3    pu | hi // RXD0/GPIO33 = RXD0
        34: a3    pn | hi // SD1_CLK/GPIO34 = SD1_CLK
        35: a3    pu | hi // SD1_CMD/GPIO35 = SD1_CMD
        36: a3    pu | hi // SD1_DATA0/GPIO36 = SD1_DAT0
        37: a3    pu | hi // SD1_DATA1/GPIO37 = SD1_DAT1
        38: a3    pu | hi // SD1_DATA2/GPIO38 = SD1_DAT2
        39: a3    pu | hi // SD1_DATA3/GPIO39 = SD1_DAT3
        40: a0    pn | lo // PWM0_MISO/GPIO40 = PWM1_0
        41: a0    pn | lo // PWM1_MOSI/GPIO41 = PWM1_1
        42: op -- pu | lo // STATUS_LED_G_CLK/GPIO42 = output
        43: ip    pu | hi // SPIFLASH_CE_N/GPIO43 = input
        44: ip    pu | hi // SDA0/GPIO44 = input
        45: ip    pu | hi // SCL0/GPIO45 = input
        46: ip    pu | lo // RGMII_RXCLK/GPIO46 = input
        47: ip    pu | lo // RGMII_RXCTL/GPIO47 = input
        48: ip    pd | lo // RGMII_RXD0/GPIO48 = input
        49: ip    pd | lo // RGMII_RXD1/GPIO49 = input
        50: ip    pd | lo // RGMII_RXD2/GPIO50 = input
        51: ip    pd | lo // RGMII_RXD3/GPIO51 = input
        52: ip    pd | lo // RGMII_TXCLK/GPIO52 = input
        53and : ip    pd | lo // RGMII_TXCTL/GPIO53 = input
        

        and this for output of pinctrl 19

        19: ip    pd | lo // GPIO19 = input
        

        so the “pinctrl 19” command and parseInt(“19: ip pd | lo // GPIO19 = input”, 10);
        will return 19

        I think you meant pinctrl get 19, after sometime prior doing pinctrl set

        pinctrl help
        shows all it can do

        Sam

        How to add modules

        learning how to use browser developers window for css changes

        C 1 Reply Last reply Nov 5, 2024, 6:28 PM Reply Quote 0
        • C Offline
          ChrisLeduex @sdetweil
          last edited by Nov 5, 2024, 6:28 PM

          @sdetweil Thank you for catching those, too much copying and pasting.

          Removed one of the start functions from the module.js file and also updated this line in the node_helper.js file so now it is returning the pin state instead of the pin number.
          //const pinState = parseInt(stdout.trim(), 10);
          const pinState = stdout.includes(“hi”) ? 1 : 0;

          There still seems to be an issue somewhere in my node_helper.js file though because I’m still not seeing anything from that file in the console. Looking through the forum it seems node_helper file issues are common and I’ve tried implementing a few of the solutions I found there but still haven’t found the problem but I will keep trying. I suspect maybe I’m not nesting my socket notifications correctly.

          PinToggleTest.js

          Module.register("MMM-PinToggleTest", {
            defaults: {
              pin: 19,
              modulesToToggle: ["clock", "calendar"],
              interval: 1000
            },
          
            start: function() {
              console.log("MMM-PinToggleTest started");
              Log.info("MMM-PinToggleTest is starting, sending CONFIG...");
              this.previousPinState = null;
          
              // Request initial pin check from the helper
              this.sendSocketNotification("CONFIG", this.config);
            },
            
            socketNotificationReceived: function(notification, payload) {
          		if (notification === 'STARTED') {
              console.log("STARTED notification received from node_helper");
              this.config.text = 'Started';
              this.updateDom();
          		}
          	},
          
            socketNotificationReceived: function(notification, payload) {
              if (notification === "PIN_STATE") {
                const pinState = payload;
                console.log(`Received pin state: ${pinState}`);  // Log received state
          
                // Toggle modules based on pin state
                if (pinState !== this.previousPinState) {
                  this.previousPinState = pinState;
                  this.toggleModules(pinState === 1);
                }
              }
            },
          
            toggleModules: function(show) {
              console.log(`Toggling modules to ${show ? "show" : "hide"}`);
              this.config.modulesToToggle.forEach(moduleName => {
                const modules = MM.getModules().withClass(moduleName);
                modules.forEach(module => {
                  if (show) {
                    module.show(1000);  // Show module with fade-in effect
                  } else {
                    module.hide(1000);  // Hide module with fade-out effect
                  }
                });
              });
            },
          
            getDom: function() {
              const wrapper = document.createElement("div");
              wrapper.innerHTML = "<small>MMM-PinToggleTest</small>";
              return wrapper;
            }
          });
          

          node_helper.js

          const NodeHelper = require("node_helper");
          const exec = require("child_process").exec;
          //const rpio = require("rpio");
          //const Gpio = require("onoff").Gpio;
          
          //module.exports = NodeHelper.create({
          //  start: function() {
          //    console.log("Starting node_helper for MMM-PinToggleTest");
          //    this.previousPinState = null;
          //    this.config = null;
          //  },
          
          module.exports = NodeHelper.create({
            start() {
              this.started = false;
            },
          
            socketNotificationReceived: function(notification, payload) {
              if (notification === "CONFIG" && !this.started) {
                const self = this;
                console.log("CONFIG notification received");
                this.config = payload;
                this.schedulePinCheck();
                this.sendSocketNotification('STARTED', {message: 'test'});
                console.log("STARTED notification sent back to front end");
              }
            },
          
            schedulePinCheck: function() {
              console.log(`Setting up pin check every ${this.config.interval} ms`);
              setInterval(() => {
                this.checkPinState();
              }, this.config.interval);
            },
          
            checkPinState: function() {
              const pinNumber = this.config.pin;
          
              // Execute pinctrl command
              exec(`pinctrl get ${pinNumber}`, (error, stdout, stderr) => {
                if (error) {
                  console.error(`Error reading GPIO pin ${pinNumber}: ${stderr}`);
                  return;
                }
          
                //const pinState = parseInt(stdout.trim(), 10);
                const pinState = stdout.includes("hi") ? 1 : 0;
                console.log(`Detected pin state for pin ${pinNumber}: ${pinState}`);  // Log the detected state
          
                // Only send if state has changed
                  if (pinState !== this.previousPinState) {
                  this.previousPinState = pinState;
                  console.log(`Pin state changed to ${pinState}`);
                  this.sendSocketNotification("PIN_STATE", pinState);
                  
                  // Small delay to avoid multiple triggers
                  setTimeout(() => {}, 100);
                }
              });
            }
          });
          
          S 1 Reply Last reply Nov 5, 2024, 6:35 PM Reply Quote 0
          • S Away
            sdetweil @ChrisLeduex
            last edited by Nov 5, 2024, 6:35 PM

            @ChrisLeduex I see this from the output of npm start

            [2024-11-05 12:32:28.225] [LOG]   Current pin state for GPIO 19: 1 
            [2024-11-05 12:32:28.225] [LOG]   Pin state changed to 1 at 2024-11-05T18:32:28.224Z 
            [2024-11-05 12:32:28.244] [INFO]  [MMM-MealieMenu] Week starts: 2024-11-04, next week starts: 2024-11-11 
            [2024-11-05 12:32:28.375] [INFO]  Mealie error={} 
            [2024-11-05 12:32:28.400] [INFO]  Newsfeed-Fetcher: Broadcasting 15 items. 
            [2024-11-05 12:32:28.413] [INFO]  Newsfeed-Fetcher: Broadcasting 22 items. 
            [2024-11-05 12:32:28.819] [INFO]  Newsfeed-Fetcher: reloadInterval set to ttl=5400000 for url http://www.tagesschau.de/xml/rss2 
            [2024-11-05 12:32:28.847] [INFO]  Newsfeed-Fetcher: Broadcasting 40 items. 
            [2024-11-05 12:32:29.225] [LOG]   Current pin state for GPIO 19: 1 
            [2024-11-05 12:32:30.225] [LOG]   Current pin state for GPIO 19: 1 
            [2024-11-05 12:32:31.225] [LOG]   Current pin state for GPIO 19: 1 
            [2024-11-05 12:32:32.225] [LOG]   Current pin state for GPIO 19: 1 
            [2024-11-05 12:32:33.224] [LOG]   Current pin state for GPIO 19: 1 
            [2024-11-05 12:32:34.225] [LOG]   Current pin state for GPIO 19: 1 
            [2024-11-05 12:32:35.226] [LOG]   Current pin state for GPIO 19: 1 
            [2024-11-05 12:32:36.227] [LOG]   Current pin state for GPIO 19: 1 
            [2024-11-05 12:32:37.229] [LOG]   Current pin state for GPIO 19: 1 
            [2024-11-05 12:32:38.227] [LOG]   Current pin state for GPIO 19: 1 
            

            I wrote a little pinctrl script that just outputs 1

            #!/bin/bash
            echo 1
            

            as pinctrl is not on my linux desktop

            Sam

            How to add modules

            learning how to use browser developers window for css changes

            C 1 Reply Last reply Nov 5, 2024, 8:11 PM Reply Quote 0
            • C Offline
              ChrisLeduex @sdetweil
              last edited by Nov 5, 2024, 8:11 PM

              @sdetweil Ah yes, I forgot I have a python script I was kicking off manually that I forgot to run before testing those fixes. It is working now and both files are communicating with each other, thank you.

              My next step is to see if I can get this working with the MMM-Buttons/MMM-ModuleToggleButton modules.

              S 1 Reply Last reply Nov 5, 2024, 9:44 PM Reply Quote 0
              • S Away
                sdetweil @ChrisLeduex
                last edited by Nov 5, 2024, 9:44 PM

                @ChrisLeduex buttons is interrupt driven, but can be changed to polling like you are doing

                Sam

                How to add modules

                learning how to use browser developers window for css changes

                C 1 Reply Last reply Nov 6, 2024, 1:56 AM Reply Quote 0
                • C Offline
                  ChrisLeduex @sdetweil
                  last edited by Nov 6, 2024, 1:56 AM

                  @sdetweil Yeah you’re right, that one might be more difficult. But I do have MMM-ModuleToggleButton working with pinctrl. Here’s the updated node_helper.js file just in case anyone’s interested.

                  node_helper.js

                  const NodeHelper = require('node_helper'); // eslint-disable-line import/no-extraneous-dependencies
                  //const Gpio = require('onoff').Gpio;
                  const { exec } = require("child_process");
                  
                  module.exports = NodeHelper.create({
                    start() {
                      this.started = false;
                    },
                  
                    socketNotificationReceived(notification, payload) {
                      if (notification === 'TOGGLE_BUTTON_CONFIG' && !this.started) {
                        const self = this;
                        this.config = payload;
                  
                        //const button = new Gpio(this.config.buttonGpioPin, 'in', 'both', { persistentWatch: true, debounceTimeout: this.config.debounceTimeoutInMilliseconds });
                        //button.watch((err, state) => {
                        //  if (state === 1) {
                        //    self.sendSocketNotification(self.config.notificationName, true);
                        //  }
                        //});
                  
                        //this.started = true;
                        
                        // Set up GPIO as input using pinctrl command
                        const pin = this.config.buttonGpioPin;
                        const debounceTimeout = this.config.debounceTimeoutInMilliseconds;
                        const notificationName = this.config.notificationName;
                        let lastState = null;
                  
                        // Function to read the pin state using pinctrl
                        const checkPinState = () => {
                        exec(`pinctrl get ${pin}`, (err, stdout, stderr) => {
                          if (err) {
                            console.error(`Error reading GPIO state: ${err.message}`);
                            return;
                          }
                         
                          // Parse the pin state from stdout
                          const state = stdout.includes("hi") ? 1 : 0;
                  
                          // Handle state change with debounce
                          if (state !== lastState && state === 1) {
                            this.sendSocketNotification(notificationName, true);
                          }
                         
                          // Update last state
                          lastState = state;
                        });
                        };
                  
                      // Set up an interval to check the pin state with debounce
                      setInterval(checkPinState, debounceTimeout || 100); // Defaults to 100ms if debounce is not defined
                        
                      }
                    }
                  });
                  
                  1 Reply Last reply Reply Quote 0
                  • S sdetweil has marked this topic as solved on Nov 20, 2024, 3:13 AM
                  • 1
                  • 2
                  • 3
                  • 3 / 3
                  3 / 3
                  • First post
                    23/26
                    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