From 236faaefbe65df7ffbc216e31280d9dce9b1bd62 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 22 Aug 2024 20:07:05 -0400 Subject: [PATCH] Logic and comms ready for testing --- .vscode/launch.json | 2 +- src/custom_modules/HestiaClasses.js | 41 +++++++++++++--- src/custom_modules/VoidGPIO.js | 23 ++++----- src/custom_modules/config.json | 3 +- src/custom_modules/functions.js | 30 +++--------- src/main.js | 9 +++- src/python/fake_gpio.py | 75 +++++++++++++++++++++++++++++ 7 files changed, 137 insertions(+), 46 deletions(-) create mode 100644 src/python/fake_gpio.py diff --git a/.vscode/launch.json b/.vscode/launch.json index c52eeff..c9e16ec 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,7 @@ "skipFiles": [ "/**" ], - "program": "${workspaceFolder}/main.js" + "program": "${workspaceFolder}/src/main.js" } ] } \ No newline at end of file diff --git a/src/custom_modules/HestiaClasses.js b/src/custom_modules/HestiaClasses.js index b08b227..7db0d3a 100644 --- a/src/custom_modules/HestiaClasses.js +++ b/src/custom_modules/HestiaClasses.js @@ -5,11 +5,13 @@ module.exports = { // State class State: class State { constructor(config) { + this.publisher = 'backend'; + this.igniter = { on: false, name: "igniter", topic: config.mqtt.topics.igniter, - publisher: 'backend', + publisher: this.publisher, power: (communicator, pinState) => { // Set the power based on the desired pinState this.igniter.on = pinState === 1 ? true : false; @@ -21,7 +23,7 @@ module.exports = { on: false, name: "exhaust", topic: config.mqtt.topics.exhaust, - publisher: 'backend', + publisher: this.publisher, power: (communicator, pinState) => { // Set the power based on the desired pinState this.exhaust.on = pinState === 1 ? true : false; @@ -34,13 +36,37 @@ module.exports = { name: "auger", feedRate: 500, topic: config.mqtt.topics.auger, - publisher: 'backend', + publisher: this.publisher, power: (communicator, pinState) => { // Set the power based on the desired pinState this.auger.on = pinState === 1 ? true : false; communicator.send(config.mqtt.topics.auger, JSON.stringify(this.auger)); } }; + + this.pof = { + on: false, + name: "pof", + topic: config.mqtt.topics.pof, + publisher: this.publisher, + power: (communicator, pinState) => { + // Set the power based on the desired pinState + this.pof.on = pinState === 1 ? true : false; + communicator.send(config.mqtt.topics.pof, JSON.stringify(this.pof)); + } + }; + + this.vacuum = { + on: false, + name: "vacuum", + topic: config.mqtt.topics.vacuum, + publisher: this.publisher, + power: (communicator, pinState) => { + // Set the power based on the desired pinState + this.vacuum.on = pinState === 1 ? true : false; + communicator.send(config.mqtt.topics.vacuum, JSON.stringify(this.vacuum)); + } + }; console.log(`State initialized.`) }; }, @@ -76,19 +102,20 @@ module.exports = { // Handle when the Broker sends us a message client.on('message', (topic, message) => { // Save the existing state - const oldState = { ...state }; + const oldState = JSON.parse(JSON.stringify(state)); // The message is a buffer which will need to be converted to string const msgStr = message.toString(); // Since the message is a JSON object, we can parse it const msgJson = JSON.parse(msgStr); // Log the message - console.log(`Message received on topic ${topic}:`); - console.log(msgJson); + // console.log(`Message received on topic ${topic}:`); + // console.log(msgJson); // Check if the message is from the backend if (msgJson.publisher === this.publisher) { - console.log('Message is from the backend, ignoring'); + // console.log('Message is from the backend, ignoring'); return; } + // console.log('Message is from the frontend, updating state'); // Update the state state[msgJson.name].on = msgJson.on; // Emit the state change diff --git a/src/custom_modules/VoidGPIO.js b/src/custom_modules/VoidGPIO.js index b52909c..f83f272 100644 --- a/src/custom_modules/VoidGPIO.js +++ b/src/custom_modules/VoidGPIO.js @@ -1,20 +1,21 @@ const { exec } = require('child_process'); +const config = require('./config.json'); module.exports = { // Calls the GPIO Interface script to toggle a pin's state opposite of its current state - togglePin(pin) { - return new Promise((resolve, reject) => { - exec(`python3 src/python/gpio_interface.py toggle ${pin}`, (error, stdout, stderr) => { - if (error) reject(error); - if (stderr) reject(new Error(stderr)); - resolve(); - }); - }); - }, + // togglePin(pin) { + // return new Promise((resolve, reject) => { + // exec(`python3 ${config.gpioScript} toggle ${pin}`, (error, stdout, stderr) => { + // if (error) reject(error); + // if (stderr) reject(new Error(stderr)); + // resolve(); + // }); + // }); + // }, // Calls the GPIO Interface script to read a pin's state readPin(pin) { return new Promise((resolve, reject) => { - exec(`python3 src/python/gpio_interface.py read ${pin}`, (error, stdout, stderr) => { + exec(`python3 ${config.gpioScript} read ${pin}`, (error, stdout, stderr) => { if (error) reject(error); if (stderr) reject(new Error(stderr)); resolve(stdout.trim()); @@ -24,7 +25,7 @@ module.exports = { // Calls the GPIO Interface script to set a pin's state regardless of its current state setPin(pin, state) { return new Promise((resolve, reject) => { - exec(`python3 src/python/gpio_interface.py set ${pin} ${state}`, (error, stdout, stderr) => { + exec(`python3 ${config.gpioScript} set ${pin} ${state}`, (error, stdout, stderr) => { if (error) { reject(error); } diff --git a/src/custom_modules/config.json b/src/custom_modules/config.json index e7a7233..cc6aa1b 100644 --- a/src/custom_modules/config.json +++ b/src/custom_modules/config.json @@ -60,5 +60,6 @@ "stop": { "exhaustDelay": 600000 } - } + }, + "gpioScript": "src/python/gpio_interface.py" } \ No newline at end of file diff --git a/src/custom_modules/functions.js b/src/custom_modules/functions.js index c9e9c6b..0ed8fb8 100644 --- a/src/custom_modules/functions.js +++ b/src/custom_modules/functions.js @@ -38,33 +38,11 @@ module.exports = { }).catch(reject); }); }, - // Boot up sanity check during debug mode - async debugInit() { + async init(communicator, state) { module.exports.log('Resetting all output pins.'); - module.exports.gpio.setDefaults().then((changes) => { + module.exports.gpio.setDefaults(communicator, state).then((changes) => { module.exports.log(changes); }).catch(e => console.error(e)); - - for (const pin of pins) { - switch (pin.mode) { - case 'OUT': - gpio.togglePin(pin.board).then(() => { - module.exports.log(`Toggled ${pin.key}`); - }).catch(e => console.error(e)); - // Wait 1000ms before toggling again. - await module.exports.sleep(1000); - gpio.togglePin(pin.board).then(() => { - module.exports.log(`Toggled ${pin.key}`); - }).catch(e => console.error(e)); - break; - case 'IN': - gpio.readPin(pin.board).then(state => { - module.exports.log(`${pin.key} state: ${state}`); - }).catch(e => console.error(e)); - default: - break; - } - }; } }, power: { @@ -155,6 +133,10 @@ module.exports = { return gpio.setPin(pin.board, 1).then(() => { console.log(`${pin.key} powered on.`); }).catch(e => console.error(e)); + } else { + return gpio.setPin(pin.board, 0).then(() => { + console.log(`${pin.key} powered off.`); + }).catch(e => console.error(e)); } } }); diff --git a/src/main.js b/src/main.js index 5bf67fe..62f29ea 100644 --- a/src/main.js +++ b/src/main.js @@ -9,14 +9,19 @@ const comms = new Communicator(psState); comms.init(psState, config); -fn.gpio.debugInit(); +fn.gpio.init(comms, psState); // Sensor detection loop setInterval(() => { for (const pin of config.pins) { if (pin.mode === 'IN') { gpio.readPin(pin.board).then(state => { - fn.log(`${pin.key}: ${state}`); + const boolState = state === '1' ? true : false; + if (boolState !== psState[pin.key].on) { + psState[pin.key].on = boolState; + comms.send(config.mqtt.topics[pin.key], JSON.stringify(psState[pin.key])); + fn.log(`${pin.key}: ${state}`); + } }).catch(e => console.error(e)); } } diff --git a/src/python/fake_gpio.py b/src/python/fake_gpio.py new file mode 100644 index 0000000..5d5658c --- /dev/null +++ b/src/python/fake_gpio.py @@ -0,0 +1,75 @@ +import sys + +# Define the state of the pins +PIN_STATES = { + 7: 0, + 13: 0, + 15: 0, + 16: 0, + 22: 0 +} + +# Define a function to get the pin state from the array +def get_pin_state(pin): + if pin in PIN_STATES: + return PIN_STATES[pin] + else: + print(f"Invalid pin: {pin}") + return -1 + +# Modify the read_pin function to use the get_pin_state function +def read_pin(pin): + try: + # Read pin state + state = get_pin_state(pin) + # Return 1 if pin is HIGH, 0 if LOW + return 1 if state == 1 else 0 + except Exception as e: + # Handle errors + print(f"Error reading pin {pin}: {e}") + # Return -1 on error + return -1 + +# Modify the set_pin_state function to return success always +def set_pin_state(pin, state): + try: + # Set the pin state to either HIGH (1) or LOW (0) + # Exit with 0 for success + return 0 + except Exception as e: + # Handle errors + print(f"Error setting pin {pin} to state {state}: {e}") + # Exit with 1 for failure + return 1 + +def main(): + if len(sys.argv) < 3: + print("Usage: python3 gpio_interface.py []") + sys.exit(1) + + command = sys.argv[1].lower() + pin = int(sys.argv[2]) + + if command == "toggle": + result = toggle_pin(pin) + sys.exit(result) + elif command == "read": + result = read_pin(pin) + print(result) + sys.exit(0 if result >= 0 else 1) + elif command == "set": + if len(sys.argv) < 4: + print("Usage: python3 gpio_interface.py set ") + sys.exit(1) + state = int(sys.argv[3]) + if state not in [0, 1]: + print("Invalid state. Use 0 for LOW or 1 for HIGH.") + sys.exit(1) + result = set_pin_state(pin, state) + sys.exit(result) + else: + print("Invalid command. Use 'toggle', 'read', or 'set'.") + sys.exit(1) + +if __name__ == "__main__": + main()