Read the statement by Michael Teeuw here.
Problem Adding Buttons & required Remote-Control Modules
-
@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 19I think you meant pinctrl get 19, after sometime prior doing pinctrl set
pinctrl help
shows all it can do -
@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); } }); } });
-
@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
-
@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.
-
@ChrisLeduex buttons is interrupt driven, but can be changed to polling like you are doing
-
@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 } } });
-