Skip to content
Snippets Groups Projects
Commit d4c8a3a0 authored by bird's avatar bird
Browse files

add door history recording and an endpoint to expose it (only toggled on for...

add door history recording and an endpoint to expose it (only toggled on for UCC right now) also handle a lot of the /state endpoints in one reused function.
parent 90d0c254
Branches
1 merge request!2add door history recording and an endpoint to expose it
......@@ -10,6 +10,8 @@ class DoorInfo {
state = null;
opener = null;
lastChange = null;
history = [];
historyEnabled = false;
}
const web_host = process.env.HTTP_BIND;
......@@ -44,6 +46,36 @@ let doors = {
'uwaes-door': new DoorInfo(),
};
doors['ucc-door'].historyEnabled = true;
doors['uwaes-door'].historyEnabled = false;
doors['unisfa-door'].historyEnabled = false;
// Load history from file if it exists
const loadHistory = () => {
try {
const history = JSON.parse(fs.readFileSync(`${__dirname}/door_history.json`, 'utf8'));
for (const [door, info] of Object.entries(history)) {
if (!doors[door]) continue;
doors[door].history = info.history || [];
}
console.log('Loaded door history from file');
} catch (err) {
console.log('No history file found, starting fresh');
}
};
// Save history to file
const saveHistory = () => {
const history = {};
for (const [door, info] of Object.entries(doors)) {
history[door] = {
history: info.history
};
}
fs.writeFileSync(`${__dirname}/door_history.json`, JSON.stringify(history, null, 2));
console.log('Saved door history to file');
};
const update_door_state = (door, state) => {
if (doors[door] === undefined) {
console.log(`Tried to update state for unknown door ${door}`);
......@@ -70,7 +102,23 @@ const update_door_state = (door, state) => {
// Only update lastChange if the state actually changed
if (oldState !== doors[door].state) {
doors[door].lastChange = new Date().toISOString();
const timestamp = new Date().toISOString();
doors[door].lastChange = timestamp;
// Add to history
doors[door].history.unshift({
timestamp,
state: doors[door].state,
opener: doors[door].opener
});
// Keep only last 1000 changes
if (doors[door].history.length > 1000) {
doors[door].history = doors[door].history.slice(0, 1000);
}
// Save history to file
saveHistory();
}
};
......@@ -83,6 +131,12 @@ const update_door_opener = (door, opener) => {
if (opener) {
console.log(`Marked door ${door} as opened by ${opener}`);
doors[door].opener = opener;
if (doors[door].state && doors[door].history.length > 0) {
doors[door].history[0].timestamp = new Date().toISOString();
doors[door].history[0].opener = opener;
saveHistory();
}
}
};
......@@ -130,6 +184,61 @@ const send_file = (res, code, fname, ctype) => {
res.end(data);
};
const handleHistoryRequest = (req, res, door) => {
const n = parseInt(req.url.split('/').pop());
if (isNaN(n) || n <= 0) {
return send_json(res, 400, { error: 'Invalid number of changes requested' });
}
const history = doors[door].history.slice(0, n);
return send_json(res, 200, history);
};
const handleLastChangeRequest = (res, door) => {
if (doors[door].lastChange === null) {
return send_json(res, 500, null);
}
return send_json(res, 200, {
lastChange: doors[door].lastChange,
state: doors[door].state
});
};
const handleStateRequest = (req, res) => {
const parts = req.url.split('/').filter(Boolean);
if (parts.length < 2) return send_error(res, 404);
const door = parts[1];
const doorId = `${door}-door`;
if (!doors[doorId]) {
return send_error(res, 404);
}
if (parts.length === 2) {
// handle /state/{door}
if (doors[doorId].state === null) {
return send_json(res, 500, null);
}
return send_json(res, 200, doors[doorId].state);
}
if (parts[2] === 'lastchange') {
return handleLastChangeRequest(res, doorId);
}
if (parts[2] === 'history') {
if (!doors[doorId].historyEnabled) {
return send_error(res, 404);
}
if (parts.length !== 4) return send_error(res, 404);
return handleHistoryRequest(req, res, doorId);
}
return send_error(res, 404);
};
// Serve state on http
const server = http.createServer((req, res) => {
console.log(`Serving request for ${req.url}`);
......@@ -169,28 +278,8 @@ const server = http.createServer((req, res) => {
return send_file(res, 200, fname, 'text/html');
}
if (req.url === '/state/ucc') {
if (doors['ucc-door'].state === null) {
return send_json(res, 500, null);
}
return send_json(res, 200, doors['ucc-door'].state);
}
if (req.url === '/state/unisfa') {
if (doors['unisfa-door'].state === null) {
return send_json(res, 500, null);
}
return send_json(res, 200, doors['unisfa-door'].state);
}
if (req.url === '/state/uwaes') {
if (doors['uwaes-door'].state === null) {
return send_json(res, 500, null);
}
return send_json(res, 200, doors['uwaes-door'].state);
if (req.url.startsWith('/state/')) {
return handleStateRequest(req, res);
}
if (req.url === '/opener/ucc') {
......@@ -233,42 +322,12 @@ const server = http.createServer((req, res) => {
return send_file(res, 200, './static/darkmode.js', 'text/javascript');
}
if (req.url === '/state/ucc/lastchange') {
if (doors['ucc-door'].lastChange === null) {
return send_json(res, 500, null);
}
return send_json(res, 200, {
lastChange: doors['ucc-door'].lastChange,
state: doors['ucc-door'].state
});
}
if (req.url === '/state/unisfa/lastchange') {
if (doors['unisfa-door'].lastChange === null) {
return send_json(res, 500, null);
}
return send_json(res, 200, {
lastChange: doors['unisfa-door'].lastChange,
state: doors['unisfa-door'].state
});
}
if (req.url === '/state/uwaes/lastchange') {
if (doors['uwaes-door'].lastChange === null) {
return send_json(res, 500, null);
}
return send_json(res, 200, {
lastChange: doors['uwaes-door'].lastChange,
state: doors['uwaes-door'].state
});
}
return send_error(res, 404);
});
// Load history when server starts
loadHistory();
// Run the server
server.listen(web_port, web_host, () => {
console.log(`HTTP server started on http://${web_host}:${web_port}`);
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment