MQTT Visualisierte Steuerung Aktor: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
| (7 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
=== Voraussetzungen === | === Voraussetzungen === | ||
*[[Voraussetzungen für Node.js-Projekt]] | *[[Voraussetzungen für Node.js-Projekt]] | ||
| + | *apt install mosquitto-clients | ||
==== Neues Verzeichnis für das Projekt erstellen ==== | ==== Neues Verzeichnis für das Projekt erstellen ==== | ||
| Zeile 15: | Zeile 16: | ||
Erstelle die Datei server.js im Verzeichnis /usr/local/control mit folgendem Inhalt: | Erstelle die Datei server.js im Verzeichnis /usr/local/control mit folgendem Inhalt: | ||
<pre> | <pre> | ||
| + | |||
const mqtt = require('mqtt'); | const mqtt = require('mqtt'); | ||
const express = require('express'); | const express = require('express'); | ||
| Zeile 20: | Zeile 22: | ||
const app = express(); | const app = express(); | ||
const port = 3000; | const port = 3000; | ||
| + | const fs = require('fs'); | ||
let status = { | let status = { | ||
| Zeile 28: | Zeile 31: | ||
}; | }; | ||
| − | // MQTT | + | // MQTT connection options (without TLS for unencrypted communication) |
| − | const | + | const options = { |
| − | + | // username: 'xinux', | |
| − | + | // password: '123Start$', | |
| − | }); | + | // port: 8883, |
| + | // protocol: 'mqtts', | ||
| + | // ca: fs.readFileSync('./ca.crt') | ||
| + | port: 1883, | ||
| + | host: 'mqtt.dkbi.int' | ||
| + | }; | ||
| + | |||
| + | const client = mqtt.connect(options); | ||
client.on('connect', () => { | client.on('connect', () => { | ||
| − | console.log('Connected to the broker'); | + | console.log('Connected to the MQTT broker'); |
client.subscribe('home/+/status', (err) => { | client.subscribe('home/+/status', (err) => { | ||
if (!err) { | if (!err) { | ||
| Zeile 49: | Zeile 59: | ||
}); | }); | ||
| − | // | + | // Route to get the status of the lights and front door |
app.get('/status', (req, res) => { | app.get('/status', (req, res) => { | ||
res.send(status); | res.send(status); | ||
}); | }); | ||
| − | // Serve static directory for the web interface | + | // Route to toggle a device |
| + | app.post('/toggle/:device', (req, res) => { | ||
| + | const device = req.params.device; | ||
| + | const currentStatus = status[device]; | ||
| + | |||
| + | if (!currentStatus) { | ||
| + | res.status(400).send({ error: 'Invalid device' }); | ||
| + | return; | ||
| + | } | ||
| + | |||
| + | // Toggle the status (for front door: closed/open) | ||
| + | let newStatus; | ||
| + | if (device === 'frontDoor') { | ||
| + | newStatus = currentStatus === 'closed' ? 'open' : 'closed'; | ||
| + | } else { | ||
| + | newStatus = currentStatus === 'on' ? 'off' : 'on'; | ||
| + | } | ||
| + | status[device] = newStatus; | ||
| + | |||
| + | // Send MQTT message | ||
| + | const topic = `home/${device}/status`; | ||
| + | client.publish(topic, newStatus, (err) => { | ||
| + | if (err) { | ||
| + | console.log(`Error sending message to ${device}: ${err.message}`); | ||
| + | res.status(500).send({ success: false, message: 'Error sending message' }); | ||
| + | } else { | ||
| + | console.log(`Message sent: ${device} is now ${newStatus}`); | ||
| + | res.send({ success: true, message: `Device ${device} successfully toggled` }); | ||
| + | } | ||
| + | }); | ||
| + | }); | ||
| + | |||
| + | // Serve the static directory for the web interface | ||
app.use(express.static(path.join(__dirname))); | app.use(express.static(path.join(__dirname))); | ||
// Start the web server | // Start the web server | ||
app.listen(port, () => { | app.listen(port, () => { | ||
| − | console.log(`Control Center is running at http:// | + | console.log(`Control Center is running at http://localhost:${port}`); |
}); | }); | ||
</pre> | </pre> | ||
| Zeile 73: | Zeile 115: | ||
<meta charset="UTF-8"> | <meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| − | <title> | + | <title>Devices</title> |
<style> | <style> | ||
.device { | .device { | ||
| Zeile 82: | Zeile 124: | ||
font-size: 1.5em; | font-size: 1.5em; | ||
} | } | ||
| − | .on { | + | .lamp-on { |
| − | background-color: | + | background-color: yellow; |
| + | color: black; | ||
| + | } | ||
| + | .lamp-off { | ||
| + | background-color: gray; | ||
color: white; | color: white; | ||
} | } | ||
| − | . | + | .door-open { |
background-color: red; | background-color: red; | ||
color: white; | color: white; | ||
} | } | ||
| − | . | + | .door-closed { |
| − | |||
| − | |||
| − | |||
| − | |||
background-color: gray; | background-color: gray; | ||
color: white; | color: white; | ||
| Zeile 104: | Zeile 146: | ||
.then(response => response.json()) | .then(response => response.json()) | ||
.then(data => { | .then(data => { | ||
| − | document.getElementById('livingRoom').className = 'device ' + (data.livingRoom === 'on' ? 'on' : 'off'); | + | document.getElementById('livingRoom').className = 'device ' + (data.livingRoom === 'on' ? 'lamp-on' : 'lamp-off'); |
| − | document.getElementById('bedroom').className = 'device ' + (data.bedroom === 'on' ? 'on' : 'off'); | + | document.getElementById('bedroom').className = 'device ' + (data.bedroom === 'on' ? 'lamp-on' : 'lamp-off'); |
| − | document.getElementById('kitchen').className = 'device ' + (data.kitchen === 'on' ? 'on' : 'off'); | + | document.getElementById('kitchen').className = 'device ' + (data.kitchen === 'on' ? 'lamp-on' : 'lamp-off'); |
| − | document.getElementById('frontDoor').className = 'device ' + (data.frontDoor === 'open' ? 'open' : 'closed'); | + | document.getElementById('frontDoor').className = 'device ' + (data.frontDoor === 'open' ? 'door-open' : 'door-closed'); |
}); | }); | ||
} | } | ||
| Zeile 115: | Zeile 157: | ||
</head> | </head> | ||
<body> | <body> | ||
| − | <h1> | + | <h1>Devices</h1> |
| − | <div id="livingRoom" class="device off">Living Room Light | + | <div id="livingRoom" class="device lamp-off">Living Room Light</div> |
| − | <div id="bedroom" class="device off">Bedroom Light | + | <div id="bedroom" class="device lamp-off">Bedroom Light</div> |
| − | <div id="kitchen" class="device off">Kitchen Light | + | <div id="kitchen" class="device lamp-off">Kitchen Light</div> |
| − | <div id="frontDoor" class="device closed">Front Door | + | <div id="frontDoor" class="device door-closed">Front Door</div> |
</body> | </body> | ||
</html> | </html> | ||
| Zeile 153: | Zeile 195: | ||
* http://aktor.dkbi.com:3000 | * http://aktor.dkbi.com:3000 | ||
| − | |||
| − | |||
| − | |||
| − | === | + | === MQTT-Nachrichten senden === |
| − | |||
==== Licht im Wohnzimmer einschalten ==== | ==== Licht im Wohnzimmer einschalten ==== | ||
| − | * mosquitto_pub -h | + | * mosquitto_pub -h mqtt.dkbi.int -t home/livingRoom/status -m "on" |
==== Licht im Wohnzimmer ausschalten ==== | ==== Licht im Wohnzimmer ausschalten ==== | ||
| − | * mosquitto_pub -h | + | * mosquitto_pub -h mqtt.dkbi.int -t home/livingRoom/status -m "off" |
==== Haustür öffnen ==== | ==== Haustür öffnen ==== | ||
| − | * mosquitto_pub -h | + | * mosquitto_pub -h mqtt.dkbi.int -t home/frontDoor/status -m "open" |
==== Haustür schließen ==== | ==== Haustür schließen ==== | ||
| − | * mosquitto_pub -h | + | * mosquitto_pub -h mqtt.dkbi.int -t home/frontDoor/status -m "closed" |
| − | |||
| − | |||
| − | |||
Aktuelle Version vom 4. November 2024, 14:20 Uhr
Voraussetzungen
- Voraussetzungen für Node.js-Projekt
- apt install mosquitto-clients
Neues Verzeichnis für das Projekt erstellen
- mkdir /usr/local/control
- cd /usr/local/control
Initialisiere das Node.js-Projekt
- npm init -y
Installiere die benötigten Pakete
- npm install mqtt express
Konfiguration des Node.js-Servers
Erstelle die Datei server.js im Verzeichnis /usr/local/control mit folgendem Inhalt:
const mqtt = require('mqtt');
const express = require('express');
const path = require('path');
const app = express();
const port = 3000;
const fs = require('fs');
let status = {
livingRoom: 'off',
bedroom: 'off',
kitchen: 'off',
frontDoor: 'closed'
};
// MQTT connection options (without TLS for unencrypted communication)
const options = {
// username: 'xinux',
// password: '123Start$',
// port: 8883,
// protocol: 'mqtts',
// ca: fs.readFileSync('./ca.crt')
port: 1883,
host: 'mqtt.dkbi.int'
};
const client = mqtt.connect(options);
client.on('connect', () => {
console.log('Connected to the MQTT broker');
client.subscribe('home/+/status', (err) => {
if (!err) {
console.log('Subscribed to all topics');
}
});
});
client.on('message', (topic, message) => {
const room = topic.split('/')[1];
status[room] = message.toString();
console.log(`Status of ${room}: ${status[room]}`);
});
// Route to get the status of the lights and front door
app.get('/status', (req, res) => {
res.send(status);
});
// Route to toggle a device
app.post('/toggle/:device', (req, res) => {
const device = req.params.device;
const currentStatus = status[device];
if (!currentStatus) {
res.status(400).send({ error: 'Invalid device' });
return;
}
// Toggle the status (for front door: closed/open)
let newStatus;
if (device === 'frontDoor') {
newStatus = currentStatus === 'closed' ? 'open' : 'closed';
} else {
newStatus = currentStatus === 'on' ? 'off' : 'on';
}
status[device] = newStatus;
// Send MQTT message
const topic = `home/${device}/status`;
client.publish(topic, newStatus, (err) => {
if (err) {
console.log(`Error sending message to ${device}: ${err.message}`);
res.status(500).send({ success: false, message: 'Error sending message' });
} else {
console.log(`Message sent: ${device} is now ${newStatus}`);
res.send({ success: true, message: `Device ${device} successfully toggled` });
}
});
});
// Serve the static directory for the web interface
app.use(express.static(path.join(__dirname)));
// Start the web server
app.listen(port, () => {
console.log(`Control Center is running at http://localhost:${port}`);
});
HTML-Datei erstellen
Erstelle eine Datei index.html im selben Verzeichnis, die den Status der Lichter und des Haustüröffners anzeigt und eine visuelle Darstellung mit Farben bietet:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Devices</title>
<style>
.device {
margin: 20px;
padding: 10px;
border-radius: 10px;
text-align: center;
font-size: 1.5em;
}
.lamp-on {
background-color: yellow;
color: black;
}
.lamp-off {
background-color: gray;
color: white;
}
.door-open {
background-color: red;
color: white;
}
.door-closed {
background-color: gray;
color: white;
}
</style>
<script>
function fetchStatus() {
fetch('/status')
.then(response => response.json())
.then(data => {
document.getElementById('livingRoom').className = 'device ' + (data.livingRoom === 'on' ? 'lamp-on' : 'lamp-off');
document.getElementById('bedroom').className = 'device ' + (data.bedroom === 'on' ? 'lamp-on' : 'lamp-off');
document.getElementById('kitchen').className = 'device ' + (data.kitchen === 'on' ? 'lamp-on' : 'lamp-off');
document.getElementById('frontDoor').className = 'device ' + (data.frontDoor === 'open' ? 'door-open' : 'door-closed');
});
}
setInterval(fetchStatus, 1000); // Fetch status every second
</script>
</head>
<body>
<h1>Devices</h1>
<div id="livingRoom" class="device lamp-off">Living Room Light</div>
<div id="bedroom" class="device lamp-off">Bedroom Light</div>
<div id="kitchen" class="device lamp-off">Kitchen Light</div>
<div id="frontDoor" class="device door-closed">Front Door</div>
</body>
</html>
systemd-Unit erstellen
Erstelle eine Datei /etc/systemd/system/control.service mit folgendem Inhalt:
[Unit] Description=Home Control Center [Service] Type=simple WorkingDirectory=/usr/local/control ExecStart=/usr/bin/node server.js ExecStartPost=/bin/echo "Home Control Center Start" [Install] WantedBy=multi-user.target
Server starten
systemd-Service starten
- systemctl start control.service
systemd-Service beim Booten starten lassen
- systemctl enable control.service
Öffne deinen Browser und gehe zu
MQTT-Nachrichten senden
Licht im Wohnzimmer einschalten
- mosquitto_pub -h mqtt.dkbi.int -t home/livingRoom/status -m "on"
Licht im Wohnzimmer ausschalten
- mosquitto_pub -h mqtt.dkbi.int -t home/livingRoom/status -m "off"
Haustür öffnen
- mosquitto_pub -h mqtt.dkbi.int -t home/frontDoor/status -m "open"
Haustür schließen
- mosquitto_pub -h mqtt.dkbi.int -t home/frontDoor/status -m "closed"