New files

This commit is contained in:
2025-02-21 15:33:35 +00:00
parent 2588b4dbce
commit f4ce9774a9
2 changed files with 529 additions and 0 deletions

402
agcs.html Normal file
View File

@@ -0,0 +1,402 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<style>
#messages
{
background-color:yellow;
font-size:3;
font-weight:bold;
line-height:140%;
}
#status {
background-color: #FFFFFF;
border-radius: 15px;
font-family: 'andale mono', monospace;
font-size: 16pt;
width: 610px;
margin: 5px;
text-align: center;
line-height: 35px;
}
.myDiv
{
border: 5px outset red;
/*background-color: lightblue; */
text-align: center;
width: 500px;
font: andale mono, sans-serif;
margin: auto;
}
.flex-container {
display: flex;
flex-direction: row;
justify-content: center;
/*background-color: DodgerBlue;*/
}
.flex-container > div {
background-color: #f1f1f1;
border-radius: 15px;
font-family: 'andale mono', monospace;
font-size: xx-large;
width: 300px;
margin: 5px;
text-align: center;
line-height: 50px;
}
#QNH {
background-color: #f1f1f1;
border-radius: 15px;
font-family: 'andale mono', monospace;
font-size: 64pt;
width: 300px;
margin: 5px;
text-align: center;
line-height: 75px;
}
#QFE {
background-color: #f1f1f1;
border-radius: 15px;
font-family: 'andale mono', monospace;
font-size: 64pt;
width: 300px;
margin: 5px;
text-align: center;
line-height: 75px;
}
#windSpeed {
background-color: #f1f1f1;
border-radius: 15px;
font-family: 'andale mono', monospace;
font-size: 48pt;
width: 300px;
margin: 5px;
text-align: center;
line-height: 75px;
}
#avgWindSpeed {
background-color: #f1f1f1;
border-radius: 15px;
font-family: 'andale mono', monospace;
font-size: 48pt;
width: 300px;
margin: 5px;
text-align: center;
line-height: 75px;
}
#zuluTime {
background-color: #f1f1f1;
border-radius: 15px;
font-family: 'andale mono', monospace;
font-size: 64pt;
width: 610px;
margin: 5px;
text-align: center;
line-height: 75px;
}
</style>
<head>
<title>EGFH Tower</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script>
<script type = "text/javascript">
function onConnectionLost(){
invalidateDisplay();
console.log("connection lost");
document.getElementById("status").style.backgroundColor = '#AA0000';
document.getElementById("status").innerHTML = "Connection Lost, reloading";
connected_flag=0;
setTimeout(location.reload(), reloadDelay);
}
function onFailure(message) {
invalidateDisplay();
console.log("Failed");
document.getElementById("status").style.backgroundColor = '#AA0000';
document.getElementById("status").innerHTML = "Connection Failed- Retrying";
setTimeout(MQTTconnect, reconnectTimeout);
}
function onMessageArrived(r_message){
if (r_message.destinationName == "weather/loop"){
console.log("Got LOOP " + r_message.payloadString);
loopObj = JSON.parse(r_message.payloadString);
if (loopObj.interval_minute) {
console.log("AVG Speed " + loopObj.windSpeed_knot);
console.log("AVG Dir " + loopObj.windDir);
console.log(loopObj);
//var audio = new Audio('BPCBeep.mp3');
//audio.play();
lastAvgWind = Date.now();
windAvgValid = 1;
avgWindSpeed = Number(loopObj.windSpeed_knot).toFixed(0);
roundedWind = (Math.round(loopObj.windDir / 10) * 10).toFixed(0);
avgWindDir = ('000' + roundedWind).substr(-3);
avgWindGustSpeed = Number(loopObj.windGust_knot).toFixed(0);
roundedWind = (Math.round(loopObj.windGustDir / 10) * 10).toFixed(0);
avgWindGustDir = ('000' + roundedWind).substr(-3);
updateAvgWind();
} else {
if (loopObj.windSpeed_knot) {
lastWind = Date.now();
windValid = 1;
console.log("LOOP Speed " + loopObj.windSpeed_knot);
console.log("LOOP Dir " + loopObj.windDir);
instantWindSpeed = Number(loopObj.windSpeed_knot).toFixed(0);
roundedWind = (Math.round(loopObj.windDir / 10) * 10).toFixed(0);
zeroFilledDir = ('000' + roundedWind).substr(-3);
updateWind();
}
if (loopObj.outTemp_C) {
console.log("LOOP OAT " + loopObj.outTemp_C);
document.getElementById("OAT").innerHTML = Number(loopObj.outTemp_C).toFixed(0) + " °C";
}
}
}
}
function updateWind() {
document.getElementById("windSpeed").innerHTML = zeroFilledDir + "/" + instantWindSpeed;
}
function updateAvgWind() {
document.getElementById("avgWindSpeed").innerHTML = avgWindDir + "/" + avgWindSpeed;
document.getElementById("avgWindGust").innerHTML = avgWindGustDir + "/" + avgWindGustSpeed;
}
function invalidateDisplay() {
invalidateWind();
invalidateAvgWind();
invalidateOAT();
}
function invalidateOAT() {
document.getElementById("OAT").innerHTML = "XXX";
windValid = 0;
}
function invalidateWind() {
document.getElementById("windSpeed").innerHTML = "XXX/X";
windValid = 0;
}
function invalidateAvgWind() {
document.getElementById("avgWindSpeed").innerHTML = "XXX/X";
document.getElementById("avgWindGust").innerHTML = "XXX/X";
windAvgValid = 0;
}
function onConnect() {
connected_flag=1;
document.getElementById("status").style.backgroundColor = '#00AA00';
document.getElementById("status").innerHTML = "Connected";
console.log("Connected to MQTT broker");
sub_topics()
}
function disconnect() {
if (connected_flag==1)
mqtt.disconnect();
}
function MQTTconnect() {
clean_sessions=true
var x=Math.floor(Math.random() * 10000);
var cname="wx-"+x;
mqtt = new Paho.MQTT.Client(host,cname);
var options = {
timeout: 3,
cleanSession: clean_sessions,
onSuccess: onConnect,
onFailure: onFailure,
};
mqtt.onConnectionLost = onConnectionLost;
mqtt.onMessageArrived = onMessageArrived;
mqtt.connect(options);
return false;
}
function sub_topics() {
if (connected_flag==0) {
console.log("Not Connected so can't subscribe");
return false;
}
var sqos=0;
var soptions= {
qos:sqos,
};
mqtt.subscribe(topic,soptions);
return false;
}
// TODO: This is all a bit rough and ready. The station ID is hardcoded and so are the sensor IDs
// It should really look these up each time
//
// Also what I thought was QNH is actually QFE
async function getPressure() {
const response = await fetch('/wlproxy.php?api=current/195562');
const names = await response.json();
lastPressure = Date.now();
pressureValid = 1;
QFERaw = names.contents.sensors[2].data[0].bar_absolute;
QFE = Number((QFERaw / 0.029529983071445).toFixed(0)) + qCorrection;
QNH = QFE + 11;
if (Number(QFE) < 1000) {
document.getElementById("QFE").textContent = + QFE + " hPa";
} else {
document.getElementById("QFE").textContent = QFE;
}
if (Number(QNH) < 1000) {
document.getElementById("QNH").textContent = + QNH + " hPa";
} else {
document.getElementById("QNH").textContent = QNH;
}
var ts = new Date(names.contents.sensors[0].data[0].ts * 1000);
console.log(names.contents.sensors); // Dump the whole JSON to console
}
function updateClock() {
var dt = new Date();
var h = dt.getUTCHours().toString();
h = h.length == 1 ? '0' + h : h;
var m = dt.getUTCMinutes().toString();
m = m.length == 1 ? '0' + m : m;
var s = dt.getUTCSeconds().toString();
s = s.length == 1 ? '0' + s : s;
var result = ' ' + h + ':' + m + ':' + s + " Z";
document.getElementById("zuluTime").textContent = result;
window.addEventListener( 'DOMContentLoaded', function(e) { updateClock('date_time'); } )
secs = (dt.getTime() - lastWind)/1000;
if (secs > 10 && windValid == 1) {
invalidateWind();
console.log("Invalidating instant wind due to late message")
document.getElementById("status").innerHTML = "Missing Wind message";
document.getElementById("status").style.backgroundColor = '#AA0000';
}
secs = (dt.getTime() - lastAvgWind)/1000;
if (secs > 150 && windAvgValid == 1) {
invalidateAvgWind();
console.log("Invalidating average wind due to late message")
document.getElementById("status").innerHTML = "Missing avg Wind message";
document.getElementById("status").style.backgroundColor = '#AA0000';
}
secs = (dt.getTime() - lastPressure)/1000;
if (secs > 300 && pressureValid == 1) {
pressureValid = 0;
console.log("Calling update pressure")
getPressure();
}
setTimeout( updateClock.bind( this, "zuluTime" ), 500 );
}
</script>
</head>
<body>
<script type = "text/javascript">
</script>
<br>
<div class="flex-container">
<div>QNH</div>
<div>QFE</div>
</div>
<div class="flex-container">
<div id="QNH" class="data">XXXX</div>
<div id="QFE" class="data">XXXX</div>
</div>
<br>
<div class="flex-container">
<div>Surface Wind</div>
<div>Instant Wind</div>
</div>
<div class="flex-container">
<div id="avgWindSpeed">2</div>
<div id="windSpeed">1</div>
</div>
<br>
<div class="flex-container">
<div>2min Gust</div>
<div>OAT</div>
</div>
<div class="flex-container">
<div id="avgWindGust">XXX</div>
<div id="OAT">XXX</div>
</div>
<br>
<div class="flex-container">
<div id="zuluTime">QNH: XXX</div>
</div>
<br>
<div class="flex-container">
<div id="status"></div>
</div>
<p></p>
<script>
var connected_flag=0
var mqtt;
var reconnectTimeout = 2000;
var reloadDelay = 5000;
var host="wss://wx.swansea-airport.wales/mqtt";
var qCorrection = 0; // Offset for QFE / QNH
var row=0;
var mcount=0;
var topic = "weather/#";
var windValid = 0;
var avgWindValid = 0;
var pressureValid = 0;
let lastWind = Date.now();
let lastAvgWind = Date.now();
let lastPressure = Date.now();
invalidateDisplay();
MQTTconnect();
getPressure();
updateClock();
</script>
</body>
</html>

127
diag.html Normal file
View File

@@ -0,0 +1,127 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Runway Diagram with Wind Arrow</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f4f4f4;
}
canvas {
background: white;
}
</style>
</head>
<body>
<canvas id="compass" width="300" height="300"></canvas>
<script>
const canvas = document.getElementById("compass");
const ctx = canvas.getContext("2d");
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
let windDirection = 0; // Initial wind direction in degrees
function drawCompass() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw runways
drawRunway(220, 120, 12, -20); // 22/04 runway moved to the left
drawRunway(280, 90, 8, 0, 40); // 10/28 runway moved down
// Draw wind direction arrow
drawArrow(windDirection);
}
function drawRunway(angle, length, width, xShift, yShift = 0) {
const radian = (angle - 90) * (Math.PI / 180); // Convert to radians
// Calculate runway endpoints with xShift (left/right) and yShift (up/down)
const xStart = centerX - length * Math.cos(radian) + xShift;
const yStart = centerY - length * Math.sin(radian) + yShift;
const xEnd = centerX + length * Math.cos(radian) + xShift;
const yEnd = centerY + length * Math.sin(radian) + yShift;
// Draw runway as a thick line
ctx.strokeStyle = "#333";
ctx.lineWidth = width;
ctx.beginPath();
ctx.moveTo(xStart, yStart);
ctx.lineTo(xEnd, yEnd);
ctx.stroke();
// Correctly assign runway numbers at each end
drawRunwayNumber(angle, xStart, yStart, radian, -20);
drawRunwayNumber(angle + 180, xEnd, yEnd, radian, 20);
}
function drawRunwayNumber(angle, x, y, radian, extension) {
const runwayNumber = Math.round(angle / 10) % 36; // Convert heading to runway number
// Move the number along the extended centerline
const xOffset = x + extension * Math.cos(radian);
const yOffset = y + extension * Math.sin(radian);
ctx.font = "14px Arial";
ctx.fillStyle = "black";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(runwayNumber.toString().padStart(2, "0"), xOffset, yOffset);
}
function drawArrow(angle) {
const arrowLength = 80; // Extended to pass through center
const radian = (angle + 90) * (Math.PI / 180); // Adjusted for correct direction
// Compute start and end points for the arrow
const xStart = centerX - arrowLength * Math.cos(radian);
const yStart = centerY - arrowLength * Math.sin(radian);
const xEnd = centerX + arrowLength * Math.cos(radian);
const yEnd = centerY + arrowLength * Math.sin(radian);
// Draw main arrow line
ctx.strokeStyle = "red";
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(xStart, yStart);
ctx.lineTo(xEnd, yEnd);
ctx.stroke();
// Draw arrowhead at the end
ctx.fillStyle = "red";
ctx.beginPath();
ctx.moveTo(xEnd, yEnd);
ctx.lineTo(
xEnd - 12 * Math.cos(radian - Math.PI / 6),
yEnd - 12 * Math.sin(radian - Math.PI / 6)
);
ctx.lineTo(
xEnd - 12 * Math.cos(radian + Math.PI / 6),
yEnd - 12 * Math.sin(radian + Math.PI / 6)
);
ctx.closePath();
ctx.fill();
}
function updateWindDirection(degrees) {
windDirection = degrees % 360;
drawCompass();
}
// Initial draw
drawCompass();
// Example: Update wind direction dynamically every 2 seconds
setInterval(() => {
updateWindDirection(Math.random() * 360); // Random wind direction
}, 2000);
</script>
</body>
</html>