Compare commits

...

22 Commits
main ... other

Author SHA1 Message Date
Filip Borum Poulsen be8a514bad Only turn off relay during overlay video 1 year ago
Filip Borum Poulsen dadd0440ed Fix copy paste mistake 1 year ago
Filip Borum Poulsen 74c4ddde51 Removed ClientAliveInterval 1 year ago
Filip Borum Poulsen 3360ed2527 Made it more pretty 1 year ago
Filip Borum Poulsen 18e0f8e157 Added ssh keep alive 1 year ago
Filip Borum Poulsen 18a7fe282b res.text -> res.send 1 year ago
Filip Borum Poulsen 971fb1bdac Added delete video and view selected 1 year ago
Filip Borum Poulsen 5219f3faba Added external webpage 1 year ago
Filip Borum Poulsen f30877ac6d Switched from ngrok to autossh 1 year ago
Filip Borum Poulsen 4cc805e565 Added ngrok 1 year ago
Filip Borum Poulsen 2aa2512763 Added audio device to service file 1 year ago
Filip Borum Poulsen c6318fd63a Changed crontab and only play audio on overlay video 1 year ago
Filip Borum Poulsen db75cec203 Fix wrong relay ip 1 year ago
Filip Borum Poulsen a1b999240a Added http to fetch calls 1 year ago
Filip Borum Poulsen 554fb7c60e Made scripts executable 1 year ago
Filip Borum Poulsen 2a1376c1c4 Added relay functionality 1 year ago
Filip Borum Poulsen 5538f75472 Added projector start stop and status 1 year ago
Filip Borum Poulsen 31bb849cd6 Made some changes 1 year ago
Filip Borum Poulsen 74af99cd53 Added crontab 1 year ago
Filip Borum Poulsen 461d0acb71 Added overlay video 1 year ago
Filip Borum Poulsen f111f3b3fc Move play to separate file 1 year ago
Filip Borum Poulsen dcdf469996 Changes 1 year ago

@ -0,0 +1,12 @@
Host bpfilip.dk
HostName bpfilip.dk
IdentityFile /home/pi/.ssh/id_rsa
User root
Port 2223
LocalForward 22 127.0.0.1:2222
RemoteForward 2222 127.0.0.1:22
RemoteForward 10.0.1.25:8080 127.0.0.1:8080
GatewayPorts yes
Compression yes
ServerAliveInterval 10
ServerAliveCountMax 3

@ -0,0 +1,14 @@
[Unit]
Description=Keeps an SSH tunnel to 'bpfilip.dk' open
After=network-online.target
[Service]
ExecStart=/usr/bin/autossh -M 0 -N -q -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" bpfilip.dk
ExecStop=/usr/bin/killall -s KILL autossh
User=1000
Group=1000
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target

@ -0,0 +1,8 @@
30 16 * * 5,6,0 /home/pi/video-player/start-projector.sh
0 17 * * 5,6,0 /home/pi/video-player/play-overlay.sh
0 18 * * 5,6,0 /home/pi/video-player/play-overlay.sh
0 19 * * 5,6,0 /home/pi/video-player/play-overlay.sh
30 19 * * 5,6,0 /home/pi/video-player/stop-projector.sh
0 7 * * * /home/pi/video-player/relay-on.sh
0 23 * * * /home/pi/video-player/relay-off.sh

@ -4,6 +4,8 @@ const express = require('express');
const app = express();
const fileUpload = require('express-fileupload');
const fetch = require('node-fetch');
app.use(express.json());
app.use(fileUpload());
@ -68,27 +70,40 @@ app.get('/videos', (req, res) => {
let process = null;
let mayRestart = false;
// if (fs.existsSync('/tmp/video')) {
// const initialVideo = fs.readFileSync('/tmp/video');
// startVideo(initialVideo);
// }
if (fs.existsSync('/selectedvideo')) {
const initialVideo = fs.readFileSync('/selectedvideo');
startVideo(initialVideo);
}
function startVideo(path) {
process = require('child_process').spawn('ffplay', ['-fs', '-loop', '2147483647', '-hide_banner', '-loglevel', 'error', path]);
process.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
const newProcess = require('child_process').spawn('ffplay', ['-fs', '-loop', '2147483647', '-hide_banner', '-an', '-loglevel', 'error', path]);
process.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
// process.stdout.on('data', (data) => {
// console.log(`stdout: ${data}`);
// });
// process.stderr.on('data', (data) => {
// console.error(`stderr: ${data}`);
// });
process.on("exit", () => {
if (!mayRestart) {
startVideo(path);
// newProcess.on("exit", (code) => {
// if (!mayRestart && code !== 0) {
// startVideo(path);
// }
// });
setTimeout(() => {
if (process) {
process.kill();
}
});
// newProcess.on("exit", (code) => {
// if (!mayRestart && code !== 0 && process === newProcess) {
// startVideo(path);
// }
// });
process = newProcess;
}, 5000);
}
fs.mkdirSync('/video', { recursive: true });
@ -109,13 +124,64 @@ app.post('/play', (req, res) => {
video = path.join('/video/', path.basename(video))
}
fs.writeFileSync('/tmp/video', video);
fs.writeFileSync('/selectedvideo', video);
startVideo(video);
res.json({ status: 'ok' });
});
app.post("/select", (req, res) => {
let video = req.query.video;
fs.writeFileSync('/overlayvideo', video);
res.json({ status: 'ok' });
});
app.post("/playoverlay", (req, res) => {
const p = require('child_process').spawn('/home/pi/video-player/play-overlay.sh');
// p.stdout.on('data', (data) => {
// console.log(`stdout: ${data}`);
// });
// p.stderr.on('data', (data) => {
// console.error(`stderr: ${data}`);
// });
res.json({ status: 'ok' });
});
app.post("/startprojector", (req, res) => {
require('child_process').spawn('sudo', ['/home/pi/video-player/start-projector.sh']);
res.json({ status: 'ok' });
});
app.post("/stopprojector", (req, res) => {
require('child_process').spawn('sudo', ['/home/pi/video-player/stop-projector.sh']);
res.json({ status: 'ok' });
});
function projectorNumberToText(number) {
switch (number) {
case '01':
return 'On';
case '02':
return 'Starting/Stopping';
case '03':
return 'Starting/Stopping';
case '04':
return 'Off';
default:
return 'Unknown';
}
}
app.get("/projectorstatus", async (req, res) => {
const res1 = await fetch('http://192.168.1.93/api/v01/control/escvp21?cmd=PWR?');
const status1 = projectorNumberToText(await res1.text());
const res2 = await fetch('http://192.168.1.67/api/v01/control/escvp21?cmd=PWR?');
const status2 = projectorNumberToText(await res2.text());
res.json({ status1, status2 });
});
app.post('/upload', function (req, res) {
if (!req.files || Object.keys(req.files).length === 0) {
@ -123,19 +189,40 @@ app.post('/upload', function (req, res) {
}
// The name of the input field (i.e. "sampleFile") is used to retrieve the uploaded file
const uploadPath = path.join(__dirname, '/public/videos/');
// const uploadPath = path.join(__dirname, '/public/videos/');
const uploadPath = "/video";
console.log(req.files.file);
req.files.file.mv(uploadPath + "video.mp4", function (err) {
req.files.file.mv(path.join(uploadPath, req.files.file.name), function (err) {
if (err) {
return res.status(500);
}
});
try {
require('child_process').spawn('sudo', ['systemctl', 'restart', 'video-player2.service']);
} catch (error) {
console.error(error);
res.redirect('/');
});
app.post("/delete", async (req, res) => {
let video = req.query.video;
await fs.rm(video);
res.json({ status: 'ok' });
});
app.get("/selectedvideo", (req, res) => {
if (fs.existsSync('/selectedvideo')) {
res.send(fs.readFileSync('/selectedvideo').toString());
}
else {
res.json("");
}
});
res.redirect('/');
});
app.get("/overlayvideo", (req, res) => {
if (fs.existsSync('/overlayvideo')) {
res.send(fs.readFileSync('/overlayvideo').toString());
}
else {
res.json("");
}
});

@ -25,13 +25,18 @@ cat smb.conf | sudo tee -a /etc/samba/smb.conf
sudo systemctl restart smbd
sudo cp auto-ssh-systemd-hosts.conf /etc/ssh/ssh_config.d/auto-ssh-systemd-hosts.conf
sudo cp video-player.service /etc/systemd/system/video-player.service
sudo cp video-player2.service /etc/systemd/system/video-player2.service
sudo cp autossh.service /etc/systemd/system/autossh.service
sudo systemctl daemon-reload
sudo systemctl enable video-player.service
sudo systemctl disable video-player2.service
sudo systemctl enable autossh.service
sudo systemctl restart video-player.service
sudo systemctl restart video-player2.service
sudo systemctl restart autossh.service
mkdir ~/.config/autostart
cp clock.desktop ~/.config/autostart/clock.desktop

@ -10,6 +10,7 @@
"license": "ISC",
"dependencies": {
"express": "^4.18.3",
"express-fileupload": "^1.5.0"
"express-fileupload": "^1.5.0",
"node-fetch": "^2.7.0"
}
}

@ -0,0 +1,9 @@
#!/bin/bash
/home/pi/video-player/relay-off.sh &
export DISPLAY=:0
ffplay -fs -autoexit $(cat /overlayvideo)
/home/pi/video-player/relay-on.sh &

@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PI Video Player</title>
<style>
#videos {
/* #videos {
display: flex;
flex-wrap: wrap;
justify-content: center;
@ -15,7 +15,7 @@
}
#videos button {
margin: 2px;
}
} */
</style>
</head>
<body>
@ -27,8 +27,68 @@
encType="multipart/form-data">
<input type="file" name="file" />
<input type='submit' value='Upload!' />
</form>
<div id="videos"></div>
</form>
<hr>
<h2>Background video</h2>
<div id="videos"></div>
<div>Currently selected video:</div>
<div id="selectedvideo"></div>
<hr>
<h2>Overlay video</h2>
<div id="overlayvideos"></div>
<button id="play" onclick="fetch(`/playoverlay`, { method: 'POST' });">Play Overlay now</button>
<div>Currently selected video:</div>
<div id="overlayvideo"></div>
<hr>
<h2>Delete videos</h2>
<div id="deletevideos"></div>
<hr>
<h2>Projector status 1</h2>
<div id="projectorstatus1"></div>
<hr>
<h2>Projector status 2</h2>
<div id="projectorstatus2"></div>
<button onclick="fetch(`/startprojector`, { method: 'POST' });">Start projectors</button>
<button onclick="fetch(`/stopprojector`, { method: 'POST' });">Stop projectors</button>
<hr>
<h2>Relay 1</h2>
<div id="relay1"></div>
<button onclick="fetch(`https://steady.bpfilip.dk/relay/on/19`);">Relay 1 ON</button>
<button onclick="fetch(`https://steady.bpfilip.dk/relay/off/19`);">Relay 1 Off</button>
<hr>
<h2>Relay 2</h2>
<div id="relay2"></div>
<button onclick="fetch(`https://steady.bpfilip.dk/relay/on/13`);">Relay 2 ON</button>
<button onclick="fetch(`https://steady.bpfilip.dk/relay/off/13`);">Relay 2 Off</button>
<hr>
<h2>Relay 3</h2>
<div id="relay3"></div>
<button onclick="fetch(`https://steady.bpfilip.dk/relay/on/6`);">Relay 3 ON</button>
<button onclick="fetch(`https://steady.bpfilip.dk/relay/off/6`);">Relay 3 Off</button>
<hr>
<h2>Relay 4</h2>
<div id="relay4"></div>
<button onclick="fetch(`https://steady.bpfilip.dk/relay/on/5`);">Relay 4 ON</button>
<button onclick="fetch(`https://steady.bpfilip.dk/relay/off/5`);">Relay 4 Off</button>
<script src="/main.js"></script>
</body>
</html>
</html>

@ -2,8 +2,14 @@ async function main() {
const response = await fetch('/videos');
const videos = await response.json();
const videoDiv = document.getElementById('videos');
const overlayVideoDiv = document.getElementById('overlayvideos');
const deleteVideoDiv = document.getElementById('deletevideos');
videoDiv.innerHTML = '';
overlayVideoDiv.innerHTML = '';
deleteVideoDiv.innerHTML = '';
console.log(videoDiv);
for (const video of videos) {
const button = document.createElement('button');
@ -11,8 +17,48 @@ async function main() {
button.addEventListener('click', () => {
fetch(`/play?video=${video.path}`, { method: 'POST' });
});
console.log(button)
videoDiv.appendChild(button);
const overlayButton = document.createElement('button');
overlayButton.textContent = video.name;
overlayButton.addEventListener('click', () => {
fetch(`/select?video=${video.path}`, { method: 'POST' });
});
overlayVideoDiv.appendChild(overlayButton);
const deleteButton = document.createElement('button');
deleteButton.textContent = video.name;
deleteButton.addEventListener('click', () => {
fetch(`/delete?video=${video.path}`, { method: 'POST' });
});
deleteVideoDiv.appendChild(deleteButton);
}
const res = await fetch('/projectorstatus');
const status = await res.json();
const status1 = document.getElementById('projectorstatus1');
const status2 = document.getElementById('projectorstatus2');
status1.textContent = status.status1;
status2.textContent = status.status2;
const selectedvideoDiv = document.getElementById('selectedvideo');
const overlayvideoDiv = document.getElementById('overlayvideo');
selectedvideoDiv.innerText = await (await fetch("/selectedvideo")).text();
overlayvideoDiv.innerText = await (await fetch("/overlayvideo")).text();
const relay1Div = document.getElementById('relay1');
const relay2Div = document.getElementById('relay2');
const relay3Div = document.getElementById('relay3');
const relay4Div = document.getElementById('relay4');
relay1Div.innerText = await (await fetch("https://steady.bpfilip.dk/relay/status/19")).text();
relay2Div.innerText = await (await fetch("https://steady.bpfilip.dk/relay/status/13")).text();
relay3Div.innerText = await (await fetch("https://steady.bpfilip.dk/relay/status/6")).text();
relay4Div.innerText = await (await fetch("https://steady.bpfilip.dk/relay/status/5")).text();
}
main();
main();

@ -0,0 +1,8 @@
#!/bin/bash
# Relay 1: GPIO 19
# Relay 2: GPIO 13
# Relay 3: GPIO 6
# Relay 4: GPIO 5
curl --retry 5 --retry-all-errors 10.242.84.110:8080/off/19

@ -0,0 +1,8 @@
#!/bin/bash
# Relay 1: GPIO 19
# Relay 2: GPIO 13
# Relay 3: GPIO 6
# Relay 4: GPIO 5
curl --retry 5 --retry-all-errors 10.242.84.110:8080/on/19

@ -0,0 +1,13 @@
tænd 16.30
30 16 * * *
film 17 tænd lys
0 17 * * *
sluk lys når video er færdig
film 18 tænd lys
0 18 * * *
sluk lys når video er færdig
film 19 tænd lys
0 19 * * *
sluk lys når video er færdig
sluk 19.30
30 19 * * *

@ -0,0 +1,3 @@
#!/bin/bash
ffplay -fs -loop 2147483647 $(cat /selectedvideo)

@ -0,0 +1,4 @@
#!/bin/bash
curl http://192.168.1.93/api/v01/control/escvp21?cmd=PWR+ON
curl http://192.168.1.67/api/v01/control/escvp21?cmd=PWR+ON

@ -0,0 +1,4 @@
#!/bin/bash
curl http://192.168.1.93/api/v01/control/escvp21?cmd=PWR+OFF
curl http://192.168.1.67/api/v01/control/escvp21?cmd=PWR+OFF

@ -3,12 +3,13 @@ Description=Video Player
After=multi-user.target
[Service]
WorkingDirectory=/home/steady/video-player
ExecStart=node /home/steady/video-player/index.js
WorkingDirectory=/home/pi/video-player
ExecStart=node /home/pi/video-player/index.js
Environment=DISPLAY=:0
Environment=AUDIODEV="hw:0,0"
User=1000
Group=1000
Restart=always
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target

@ -2,10 +2,10 @@
Description=Video Player
[Service]
WorkingDirectory=/home/steady/video-player
ExecStart=ffplay -fs -loop 2147483647 /home/steady/video-player/public/videos/video.mp4
WorkingDirectory=/home/pi/video-player
ExecStart=/home/pi/video-player/start-play.sh
Environment=DISPLAY=:0
Environment=AUDIODEV="hw:2,0"
User=1000
Group=1000
Restart=always
Restart=always

Loading…
Cancel
Save