Merge branch 'v2-back' of https://git.vfsh.dev/voidf1sh/hestia into v2-back
This commit is contained in:
commit
178bc1e115
12
TODO.md
12
TODO.md
@ -1,10 +1,14 @@
|
||||
# In Progress
|
||||
1. Strip to bones
|
||||
1. ~~Strip to bones~~
|
||||
2. Better commenting
|
||||
2. Add startup and shutdown logic (start half implemented, not tested)
|
||||
|
||||
# Immediate To-Do
|
||||
# Done
|
||||
1. GPIO Interface
|
||||
1. Duplicate and adapt `HestiaClasses` from branch `v2-front`
|
||||
|
||||
# Immediate To-Do
|
||||
1. Connect to MQTT
|
||||
|
||||
# Roadmap
|
||||
1. Add control logic for automatic start and stop
|
||||
2. Add wiring and sensors for safeties
|
||||
1. Add wiring and sensors for safeties
|
@ -1,29 +1,81 @@
|
||||
export class State {
|
||||
constructor(config) {
|
||||
config.mqtt.subscriptions.forEach(subscription => {
|
||||
this[subscription.name] = {
|
||||
on: false,
|
||||
topic: subscription.topic,
|
||||
publisher: 'back',
|
||||
power: (communicator) => {
|
||||
// This *should* toggle the state, asks if state is true, if it is set it false, otherwise set it true
|
||||
this[subscription.name].on ? this[subscription.name].on = false : this[subscription.name].on = true;
|
||||
communicator.send(subscription.name, JSON.stringify(this));
|
||||
}
|
||||
};
|
||||
});
|
||||
this.igniter = {
|
||||
on: false,
|
||||
name: "igniter",
|
||||
topic: config.mqtt.topics.igniter,
|
||||
publisher: 'front',
|
||||
power: (communicator) => {
|
||||
// This *should* toggle the state, asks if state is true, if it is set it false, otherwise set it true
|
||||
this.igniter.on ? this.igniter.on = false : this.igniter.on = true;
|
||||
communicator.send(config.mqtt.topics.igniter, JSON.stringify(this.igniter));
|
||||
}
|
||||
};
|
||||
|
||||
this.exhaust = {
|
||||
on: false,
|
||||
name: "exhaust",
|
||||
topic: config.mqtt.topics.exhaust,
|
||||
publisher: 'front',
|
||||
power: (communicator) => {
|
||||
// This *should* toggle the state, asks if state is true, if it is set it false, otherwise set it true
|
||||
this.exhaust.on ? this.exhaust.on = false : this.exhaust.on = true;
|
||||
communicator.send(config.mqtt.topics.exhaust, JSON.stringify(this.exhaust));
|
||||
}
|
||||
};
|
||||
|
||||
this.auger = {
|
||||
on: false,
|
||||
name: "auger",
|
||||
feedRate: 500,
|
||||
topic: config.mqtt.topics.auger,
|
||||
publisher: 'front',
|
||||
power: (communicator) => {
|
||||
// This *should* toggle the state, asks if state is true, if it is set it false, otherwise set it true
|
||||
this.auger.on ? this.auger.on = false : this.auger.on = true;
|
||||
communicator.send(config.mqtt.topics.auger, JSON.stringify(this.auger));
|
||||
}
|
||||
};
|
||||
console.log(`State initialized.`)
|
||||
};
|
||||
};
|
||||
|
||||
export class Communicator {
|
||||
constructor(state) {
|
||||
// Connect to the MQTT Broker
|
||||
this.client = mqtt.connect(config.mqtt.address);
|
||||
this.publisher = state.publisher;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Subscribe to status topics
|
||||
config.mqtt.subscriptions.forEach(subscription => {
|
||||
this.client.subscribe(subscription.topic);
|
||||
state[subscription.name].topic = subscription.topic;
|
||||
init(state, config) {
|
||||
// Connect to the MQTT Broker
|
||||
console.log(`Attempting MQTT connection to broker: ${config.mqtt.address}, with username: ${config.mqtt.username}`);
|
||||
this.client = mqtt.connect(config.mqtt.address, {
|
||||
username: config.mqtt.username,
|
||||
password: config.mqtt.password
|
||||
});
|
||||
const { client } = this;
|
||||
|
||||
client.on('connect', () => {
|
||||
console.log('Connected to MQTT broker');
|
||||
// Subscribe to status topics
|
||||
config.states.elements.forEach(element => {
|
||||
client.subscribe(state[element].topic, (err) => {
|
||||
if (!err) {
|
||||
console.log(`Subscribed to ${state[element].topic}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Handle when the Broker sends us a message
|
||||
client.on('message', (topic, message) => {
|
||||
const msgStr = message.toString();
|
||||
const msgJson = JSON.parse(msgStr);
|
||||
console.log(`Message received on topic ${topic}: ${msgStr}`);
|
||||
console.log(msgJson);
|
||||
state[msgJson.name].on = msgJson.on;
|
||||
window.refreshState(window.document, state);
|
||||
});
|
||||
}
|
||||
|
||||
@ -32,9 +84,9 @@ export class Communicator {
|
||||
// Publish with retain flag set to true
|
||||
this.client.publish(topic, message, { retain: true }, (err) => {
|
||||
if (err) {
|
||||
throw err;
|
||||
console.error('Failed to publish message:', err);
|
||||
} else {
|
||||
// TODO: Pass back a success message
|
||||
console.log('Message published and retained on topic:', topic);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -50,5 +50,15 @@
|
||||
"bcm": 25,
|
||||
"mode": "IN"
|
||||
}
|
||||
]
|
||||
],
|
||||
"power": {
|
||||
"start": {
|
||||
"exhaustDelay": 30000,
|
||||
"augerDelay": 60000,
|
||||
"fireCheckDelay": 420000
|
||||
},
|
||||
"stop": {
|
||||
"exhaustDelay": 600000
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,11 @@ const dotenv = require('dotenv').config();
|
||||
const debug = process.env.DEBUG === "TRUE";
|
||||
const { pins } = require('./config.json');
|
||||
const gpio = require('./VoidGPIO.js');
|
||||
const pinMap = new Map();
|
||||
|
||||
for (const pin of pins) {
|
||||
pinMap.set(pin.key, pin);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
log(message) {
|
||||
@ -13,14 +18,32 @@ module.exports = {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
},
|
||||
gpio: {
|
||||
setDefaults() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let stateChanges = [];
|
||||
for (const pin of pins) {
|
||||
if (pin.mode === 'OUT') {
|
||||
gpio.setPin(pin.board, pin.defaultState, (err) => {
|
||||
if (err) reject(err);
|
||||
stateChanges.push( `Set ${pin.key} pin to ${pin.defaultState}.`);
|
||||
})
|
||||
}
|
||||
}
|
||||
resolve(stateChanges.join('\n'));
|
||||
});
|
||||
},
|
||||
// Boot up sanity check during debug mode
|
||||
async debugInit() {
|
||||
debugInit() {
|
||||
module.exports.log('Resetting all output pins.');
|
||||
pins.forEach(async (pin) => {
|
||||
module.exports.gpio.setDefaults().then(changes => {
|
||||
module.exports.log(changes);
|
||||
}).catch(e => console.error(e));
|
||||
|
||||
pins.forEach(pin => {
|
||||
if (pin.mode === 'OUT') {
|
||||
gpio.setPin(pin.board, pin.defaultState, err => {
|
||||
if (err) throw err;
|
||||
module.exports.log(`Set ${pin.key} pin to ${pin.defaultState}.`);
|
||||
module.exports.log();
|
||||
});
|
||||
};
|
||||
});
|
||||
@ -48,5 +71,45 @@ module.exports = {
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
power: {
|
||||
start: {
|
||||
init() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Check pin states
|
||||
|
||||
// Set pins to default states
|
||||
module.exports.gpio.setDefaults().then(changes => {
|
||||
module.exports.log(changes);
|
||||
}).catch(e => console.error(e));
|
||||
// Power on igniter
|
||||
gpio.setPin(pinMap.igniter.board, 1, (err) => {
|
||||
if (err) reject(err);
|
||||
})
|
||||
// Wait for igniter preheat
|
||||
|
||||
// Start exhaust
|
||||
|
||||
// Finish igniter preheat
|
||||
|
||||
// Check for vacuum
|
||||
|
||||
// Start auger
|
||||
|
||||
// Wait for fire
|
||||
|
||||
// Check for fire
|
||||
|
||||
// Power off igniter
|
||||
|
||||
// Report successful ignition
|
||||
});
|
||||
}
|
||||
},
|
||||
stop: {
|
||||
init() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user