compose.yml für dockge dazu

This commit is contained in:
rxf
2026-03-11 11:58:49 +01:00
parent 2739d478f6
commit e01ab276b6
10 changed files with 2078 additions and 1301 deletions

View File

@@ -1,118 +1,169 @@
var express = require('express');
let router = express.Router();
let mqtt = require('mqtt');
let moment = require('moment');
const fs = require('await-fs');
var router = express.Router();
var mqtt = require('mqtt');
var moment = require('moment');
var fs = require('fs/promises');
var crypto = require('crypto');
var DEFAULT_BRENNDAUER = 300;
var brenndauer = DEFAULT_BRENNDAUER;
const configName = "config.json"
var MQTTHOST = process.env.MQTTHOST || 'localhost';
var MQTTPORT = process.env.MQTTPORT || 1883;
var MQTTUSR = process.env.MQTTUSR || '';
var MQTTPWD = process.env.MQTTPWD || '';
var TOPIC = process.env.TOPIC || 'sonoff';
var SWITCH_API_TOKEN = process.env.SWITCH_API_TOKEN || '';
var switchOffTimer;
var state = {
connect: 'disconnected',
relais: 'UNKNOWN',
offtime: undefined,
lastError: undefined
};
let brenndauer = 300; // 20sec Relais ON
var client = mqtt.connect('mqtt://' + MQTTHOST + ':' + MQTTPORT, {
username: MQTTUSR,
password: MQTTPWD
});
// MQTT:
let MQTTHOST = process.env.MQTTHOST;
let MQTTPORT = process.env.MQTTPORT;
let MQTTUSR = process.env.MQTTUSR;
let MQTTPWD = process.env.MQTTPWD;
let TOPIC=process.env.TOPIC;
if (MQTTHOST === undefined) { MQTTHOST = 'localhost';}
if (MQTTPORT === undefined) { MQTTPORT = 1883;}
if (MQTTUSR === undefined) { MQTTUSR = "";}
if (MQTTPWD === undefined) { MQTTPWD = "";}
if (TOPIC === undefined) { TOPIC = "sonoff";}
/*
if (MQTTHOST === undefined) { MQTTHOST = 'laufschrift.rexfue.de';}
if (MQTTPORT === undefined) { MQTTPORT = 1883;}
if (MQTTUSR === undefined) { MQTTUSR = "stwLauf";}
if (MQTTPWD === undefined) { MQTTPWD = "37CrNcgP";}
*/
// console.log("H",MQTTHOST," P",MQTTPORT," U",MQTTUSR," p",MQTTPWD);
let tio;
let connected = false;
let relais = 'MIST';
let client = mqtt.connect("mqtt://" + MQTTHOST + ":" + MQTTPORT,{username: MQTTUSR, password: MQTTPWD});
let offtime = "";
let retur = {};
console.log("Start: ", moment().format("YYYY-MM-DD HH:mm"));
console.log('Start: ', moment().format('YYYY-MM-DD HH:mm'));
client.on('connect', function() {
connected = true;
retur.connect = 'connected';
client.subscribe('stat/'+TOPIC+'/POWER');
})
client.on('message',function(topix,message) {
relais = message.toString();
console.log("Status = ",relais);
if (relais == 'OFF') {
delete retur.offtime;
}
retur.relais = relais;
});
client.on('reconnect', function(){
retur.connect = 'reconnect';
});
// Konfig einlesen und entsprechende Variablen einstellen
(async () => {
try{
let json = await fs.readFile('config/config.json','utf8')
js = JSON.parse(json);
if(js.brenndauer != undefined) {
brenndauer = js.brenndauer;
state.connect = 'connected';
state.lastError = undefined;
client.subscribe('stat/' + TOPIC + '/POWER', function(err) {
if (err) {
state.lastError = 'subscribe failed: ' + err.message;
}
console.log(brenndauer);
}catch(err){
console.log(err)
});
});
client.on('reconnect', function() {
state.connect = 'reconnect';
});
client.on('offline', function() {
state.connect = 'offline';
});
client.on('error', function(err) {
state.lastError = err.message;
});
client.on('message', function(_topic, message) {
state.relais = message.toString();
if (state.relais === 'OFF') {
state.offtime = undefined;
}
})()
// beim start mal den Zustand abfragen
doPublish("");
});
function getResponse() {
return {
connect: state.connect,
relais: state.relais,
offtime: state.offtime,
lastError: state.lastError
};
}
function doPublish(payload) {
// retur.relais='pending';
client.publish('cmnd/'+TOPIC+'/Power',payload);
if (payload == 'On') {
offtime = moment().add(brenndauer, 's').format("HH.mm");
tio = setTimeout(doPublish, brenndauer * 1000, "Off");
retur.offtime = offtime;
} else if (payload == 'Off') {
clearTimeout(tio);
client.publish('cmnd/' + TOPIC + '/Power', payload, function(err) {
if (err) {
state.lastError = err.message;
}
});
if (payload === 'On') {
clearTimeout(switchOffTimer);
state.offtime = moment().add(brenndauer, 's').format('HH.mm');
switchOffTimer = setTimeout(doPublish, brenndauer * 1000, 'Off');
} else if (payload === 'Off') {
clearTimeout(switchOffTimer);
state.offtime = undefined;
}
}
// end MQTT
/* GET switch data */
router.get('/:cmd', function(req, res, next) {
let cmd = req.params.cmd;
let wert = req.query.wert;
if (cmd == 'get_status') {
doPublish("");
} else if (cmd == 'switch_on') {
doPublish("On");
} else if (cmd == 'switch_off') {
doPublish("Off");
} else if (cmd == 'check') {
} else {
retur = { error: "invalid command"};
res.json(retur);
// Read optional runtime config.
(async function loadConfig() {
try {
var json = await fs.readFile('config/config.json', 'utf8');
var cfg = JSON.parse(json);
if (cfg.brenndauer !== undefined) {
brenndauer = Number(cfg.brenndauer) || DEFAULT_BRENNDAUER;
}
} catch (err) {
state.lastError = 'config load failed: ' + err.message;
}
console.log("return: ",retur)
res.json(retur);
})();
// Query initial state once at startup.
doPublish('');
function timingSafeEqualString(a, b) {
var aBuf = Buffer.from(String(a));
var bBuf = Buffer.from(String(b));
if (aBuf.length !== bBuf.length) {
return false;
}
return crypto.timingSafeEqual(aBuf, bBuf);
}
function extractRequestToken(req) {
var authHeader = req.get('authorization') || '';
if (authHeader.startsWith('Bearer ')) {
return authHeader.slice(7).trim();
}
var apiKeyHeader = req.get('x-api-key');
if (apiKeyHeader) {
return apiKeyHeader;
}
if (typeof req.query.token === 'string') {
return req.query.token;
}
return '';
}
router.use(function(req, res, next) {
if (!SWITCH_API_TOKEN) {
return next();
}
var providedToken = extractRequestToken(req);
if (!providedToken || !timingSafeEqualString(providedToken, SWITCH_API_TOKEN)) {
return res.status(401).json({ error: 'unauthorized' });
}
return next();
});
router.get('/:cmd', function(req, res) {
var cmd = req.params.cmd;
if (cmd === 'get_status') {
doPublish('');
return res.json(getResponse());
}
if (cmd === 'switch_on') {
doPublish('On');
return res.json(getResponse());
}
if (cmd === 'switch_off') {
doPublish('Off');
return res.json(getResponse());
}
if (cmd === 'check') {
return res.json(getResponse());
}
return res.status(400).json({ error: 'invalid command' });
});
module.exports = router;