Big cleanup
This commit is contained in:
397
agcs-dev.html
397
agcs-dev.html
@@ -1,397 +0,0 @@
|
|||||||
<?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%;
|
|
||||||
}
|
|
||||||
#myiframe {
|
|
||||||
width: 80%;
|
|
||||||
height: 500px;
|
|
||||||
border: none;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
#status
|
|
||||||
{
|
|
||||||
background-color:red;
|
|
||||||
font-size:4;
|
|
||||||
font-weight:bold;
|
|
||||||
color:white;
|
|
||||||
line-height:140%;
|
|
||||||
}
|
|
||||||
.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;
|
|
||||||
align-items: 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;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: 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"
|
|
||||||
src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
|
||||||
<script type = "text/javascript">
|
|
||||||
|
|
||||||
function onConnectionLost(){
|
|
||||||
//invalidateDisplay();
|
|
||||||
console.log("connection lost");
|
|
||||||
document.getElementById("status").innerHTML = "Connection Lost";
|
|
||||||
connected_flag=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onFailure(message) {
|
|
||||||
invalidateDisplay();
|
|
||||||
console.log("Failed");
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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").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) {
|
|
||||||
msg="Not Connected so can't subscribe"
|
|
||||||
console.log(out_msg);
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
secs = (dt.getTime() - lastAvgWind)/1000;
|
|
||||||
if (secs > 150 && windAvgValid == 1) {
|
|
||||||
invalidateAvgWind();
|
|
||||||
console.log("Invalidating average wind due to late message")
|
|
||||||
}
|
|
||||||
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>
|
|
||||||
|
|
||||||
<p></p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<div id="status">Connection Status: Not Connected</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
var connected_flag=0
|
|
||||||
var mqtt;
|
|
||||||
var reconnectTimeout = 2000;
|
|
||||||
var host="wss://wx.swansea-airport.wales/mqtt";
|
|
||||||
var qCorrection = 0; // Offset for QFE / QNH
|
|
||||||
var row=0;
|
|
||||||
var out_msg="";
|
|
||||||
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>
|
|
||||||
128
agcs.html
128
agcs.html
@@ -71,8 +71,8 @@ line-height:140%;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#windSpeed {
|
#windSpeed {
|
||||||
background-color: #f1f1f1;
|
# background-color: #f1f1f1;
|
||||||
border-radius: 15px;
|
# border-radius: 15px;
|
||||||
font-family: 'andale mono', monospace;
|
font-family: 'andale mono', monospace;
|
||||||
font-size: 48pt;
|
font-size: 48pt;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
@@ -82,8 +82,8 @@ line-height:140%;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#avgWindSpeed {
|
#avgWindSpeed {
|
||||||
background-color: #f1f1f1;
|
# background-color: #f1f1f1;
|
||||||
border-radius: 15px;
|
# border-radius: 15px;
|
||||||
font-family: 'andale mono', monospace;
|
font-family: 'andale mono', monospace;
|
||||||
font-size: 48pt;
|
font-size: 48pt;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
@@ -139,7 +139,7 @@ line-height:140%;
|
|||||||
//var audio = new Audio('BPCBeep.mp3');
|
//var audio = new Audio('BPCBeep.mp3');
|
||||||
//audio.play();
|
//audio.play();
|
||||||
lastAvgWind = Date.now();
|
lastAvgWind = Date.now();
|
||||||
windAvgValid = 1;
|
avgWindValid = 1;
|
||||||
avgWindSpeed = Number(loopObj.windSpeed_knot).toFixed(0);
|
avgWindSpeed = Number(loopObj.windSpeed_knot).toFixed(0);
|
||||||
roundedWind = (Math.round(loopObj.windDir / 10) * 10).toFixed(0);
|
roundedWind = (Math.round(loopObj.windDir / 10) * 10).toFixed(0);
|
||||||
avgWindDir = ('000' + roundedWind).substr(-3);
|
avgWindDir = ('000' + roundedWind).substr(-3);
|
||||||
@@ -169,11 +169,19 @@ line-height:140%;
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateStatus() {
|
||||||
|
if (avgWindValid == 1 && windValid == 1) {
|
||||||
|
document.getElementById("status").style.backgroundColor = '#00AA00';
|
||||||
|
document.getElementById("status").innerHTML = "OK";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateWind() {
|
function updateWind() {
|
||||||
document.getElementById("windSpeed").innerHTML = zeroFilledDir + "/" + instantWindSpeed;
|
document.getElementById("windSpeed").innerHTML = zeroFilledDir + "/" + instantWindSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAvgWind() {
|
function updateAvgWind() {
|
||||||
|
updateWindDirection(avgWindDir);
|
||||||
document.getElementById("avgWindSpeed").innerHTML = avgWindDir + "/" + avgWindSpeed;
|
document.getElementById("avgWindSpeed").innerHTML = avgWindDir + "/" + avgWindSpeed;
|
||||||
document.getElementById("avgWindGust").innerHTML = avgWindGustDir + "/" + avgWindGustSpeed;
|
document.getElementById("avgWindGust").innerHTML = avgWindGustDir + "/" + avgWindGustSpeed;
|
||||||
}
|
}
|
||||||
@@ -322,6 +330,95 @@ line-height:140%;
|
|||||||
}
|
}
|
||||||
|
|
||||||
setTimeout( updateClock.bind( this, "zuluTime" ), 500 );
|
setTimeout( updateClock.bind( this, "zuluTime" ), 500 );
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
if (avgWindValid == 1) {
|
||||||
|
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 = "18px 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -344,14 +441,10 @@ line-height:140%;
|
|||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<div>Surface Wind</div>
|
<div>Surface Wind<div id="avgWindSpeed">1</div>Instant Wind<div id="windSpeed">1</div></div>
|
||||||
<div>Instant Wind</div>
|
<div><canvas id="compass" width="300" height="300"></canvas></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-container">
|
|
||||||
<div id="avgWindSpeed">2</div>
|
|
||||||
<div id="windSpeed">1</div>
|
|
||||||
</div>
|
|
||||||
<br>
|
<br>
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<div>2min Gust</div>
|
<div>2min Gust</div>
|
||||||
@@ -375,6 +468,8 @@ line-height:140%;
|
|||||||
|
|
||||||
<p></p>
|
<p></p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var connected_flag=0
|
var connected_flag=0
|
||||||
var mqtt;
|
var mqtt;
|
||||||
@@ -392,11 +487,22 @@ let lastWind = Date.now();
|
|||||||
let lastAvgWind = Date.now();
|
let lastAvgWind = Date.now();
|
||||||
let lastPressure = Date.now();
|
let lastPressure = Date.now();
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
invalidateDisplay();
|
invalidateDisplay();
|
||||||
MQTTconnect();
|
MQTTconnect();
|
||||||
getPressure();
|
getPressure();
|
||||||
updateClock();
|
updateClock();
|
||||||
|
|
||||||
|
// Initial draw
|
||||||
|
drawCompass();
|
||||||
|
// Example: Update wind direction dynamically every 2 seconds
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
391
agcs_old.html
391
agcs_old.html
@@ -1,391 +0,0 @@
|
|||||||
<?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:red;
|
|
||||||
font-size:4;
|
|
||||||
font-weight:bold;
|
|
||||||
color:white;
|
|
||||||
line-height:140%;
|
|
||||||
}
|
|
||||||
.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 http-equiv="refresh" content="1800">
|
|
||||||
<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"
|
|
||||||
src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
|
||||||
<script type = "text/javascript">
|
|
||||||
|
|
||||||
function onConnectionLost(){
|
|
||||||
//invalidateDisplay();
|
|
||||||
console.log("connection lost");
|
|
||||||
document.getElementById("status").innerHTML = "Connection Lost";
|
|
||||||
connected_flag=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onFailure(message) {
|
|
||||||
invalidateDisplay();
|
|
||||||
console.log("Failed");
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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").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) {
|
|
||||||
msg="Not Connected so can't subscribe"
|
|
||||||
console.log(out_msg);
|
|
||||||
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();
|
|
||||||
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();
|
|
||||||
document.getElementById("status").textContent = "ERROR RECEIVING WIND DATA";
|
|
||||||
console.log("Invalidating instant wind due to late message")
|
|
||||||
}
|
|
||||||
secs = (dt.getTime() - lastAvgWind)/1000;
|
|
||||||
if (secs > 150 && windAvgValid == 1) {
|
|
||||||
invalidateAvgWind();
|
|
||||||
document.getElementById("status").textContent = "ERROR RECEIVING AVG WIND DATA";
|
|
||||||
console.log("Invalidating average wind due to late message")
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout( updateClock.bind( this, "zuluTime" ), 500 );
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<center><h1>UNDER TEST Swansea Tower Live</h1>
|
|
||||||
</center>
|
|
||||||
|
|
||||||
<script type = "text/javascript">
|
|
||||||
//ll
|
|
||||||
|
|
||||||
</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></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex-container">
|
|
||||||
<div id="avgWindGust">XXX</div>
|
|
||||||
<div id="xxx">XXX</div>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div class="flex-container">
|
|
||||||
<div id="zuluTime">QNH: XXX</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<p></p>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td id="connect" width="300" >
|
|
||||||
<form name="connform" action="" onsubmit="return MQTTconnect()">
|
|
||||||
<input name="conn" type="submit" value="Connect">
|
|
||||||
<input TYPE="button" name="discon " value="Disconnect" onclick="disconnect()">
|
|
||||||
</form>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
<div id="status">Connection Status: Not Connected</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
var connected_flag=0
|
|
||||||
var mqtt;
|
|
||||||
var reconnectTimeout = 2000;
|
|
||||||
var host="wss://wx.swansea-airport.wales/mqtt";
|
|
||||||
var qCorrection = 0; // Offset for QFE / QNH
|
|
||||||
var row=0;
|
|
||||||
var out_msg="";
|
|
||||||
var mcount=0;
|
|
||||||
var topic = "weather/#";
|
|
||||||
var windValid = 0;
|
|
||||||
var avgWindValid = 0;
|
|
||||||
let lastWind = Date.now();
|
|
||||||
let lastAvgWind = Date.now();
|
|
||||||
|
|
||||||
|
|
||||||
invalidateDisplay();
|
|
||||||
MQTTconnect();
|
|
||||||
getPressure();
|
|
||||||
updateClock();
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
400
agcs_old2.html
400
agcs_old2.html
@@ -1,400 +0,0 @@
|
|||||||
<?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:red;
|
|
||||||
font-size:4;
|
|
||||||
font-weight:bold;
|
|
||||||
color:white;
|
|
||||||
line-height:140%;
|
|
||||||
}
|
|
||||||
.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"
|
|
||||||
src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
|
||||||
<script type = "text/javascript">
|
|
||||||
|
|
||||||
function onConnectionLost(){
|
|
||||||
//invalidateDisplay();
|
|
||||||
console.log("connection lost");
|
|
||||||
document.getElementById("status").innerHTML = "Connection Lost";
|
|
||||||
connected_flag=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onFailure(message) {
|
|
||||||
invalidateDisplay();
|
|
||||||
console.log("Failed");
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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").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) {
|
|
||||||
msg="Not Connected so can't subscribe"
|
|
||||||
console.log(out_msg);
|
|
||||||
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();
|
|
||||||
document.getElementById("status").textContent = "ERROR RECEIVING WIND DATA";
|
|
||||||
console.log("Invalidating instant wind due to late message")
|
|
||||||
}
|
|
||||||
secs = (dt.getTime() - lastAvgWind)/1000;
|
|
||||||
if (secs > 150 && windAvgValid == 1) {
|
|
||||||
invalidateAvgWind();
|
|
||||||
document.getElementById("status").textContent = "ERROR RECEIVING AVG WIND DATA";
|
|
||||||
console.log("Invalidating average wind due to late message")
|
|
||||||
}
|
|
||||||
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>
|
|
||||||
<center><h1>UNDER TEST Swansea Tower Live</h1>
|
|
||||||
</center>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<p></p>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td id="connect" width="300" >
|
|
||||||
<form name="connform" action="" onsubmit="return MQTTconnect()">
|
|
||||||
<input name="conn" type="submit" value="Connect">
|
|
||||||
<input TYPE="button" name="discon " value="Disconnect" onclick="disconnect()">
|
|
||||||
</form>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
<div id="status">Connection Status: Not Connected</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
var connected_flag=0
|
|
||||||
var mqtt;
|
|
||||||
var reconnectTimeout = 2000;
|
|
||||||
var host="wss://wx.swansea-airport.wales/mqtt";
|
|
||||||
var qCorrection = 0; // Offset for QFE / QNH
|
|
||||||
var row=0;
|
|
||||||
var out_msg="";
|
|
||||||
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>
|
|
||||||
508
agcsdiag.html
508
agcsdiag.html
@@ -1,508 +0,0 @@
|
|||||||
<?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();
|
|
||||||
avgWindValid = 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 updateStatus() {
|
|
||||||
if (avgWindValid == 1 && windValid == 1) {
|
|
||||||
document.getElementById("status").style.backgroundColor = '#00AA00';
|
|
||||||
document.getElementById("status").innerHTML = "OK";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateWind() {
|
|
||||||
document.getElementById("windSpeed").innerHTML = zeroFilledDir + "/" + instantWindSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateAvgWind() {
|
|
||||||
updateWindDirection(avgWindDir);
|
|
||||||
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 );
|
|
||||||
updateStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
if (avgWindValid == 1) {
|
|
||||||
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 = "18px 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
</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 id="avgWindSpeed">1</div>Instant Wind<div id="windSpeed">1</div></div>
|
|
||||||
<div><canvas id="compass" width="300" height="300"></canvas></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();
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
invalidateDisplay();
|
|
||||||
MQTTconnect();
|
|
||||||
getPressure();
|
|
||||||
updateClock();
|
|
||||||
|
|
||||||
// Initial draw
|
|
||||||
drawCompass();
|
|
||||||
// Example: Update wind direction dynamically every 2 seconds
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
127
diag.html
127
diag.html
@@ -1,127 +0,0 @@
|
|||||||
<!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>
|
|
||||||
84
egfh.html
84
egfh.html
@@ -1,84 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en-US">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
|
|
||||||
<title>Swansea Weather</title>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
html {
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
width: 50%;
|
|
||||||
max-width: 800px;
|
|
||||||
min-width: 480px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form input[type="number"] {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.windDir {
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<h1>Swansea Weather Info</h1>
|
|
||||||
|
|
||||||
<p>Displaying both Raw and manipulated values. Wind speed is converted to kts and rounded to nearest kt. Direction padded with Zero and rounded to nearest 5 degrees</p>
|
|
||||||
<p>Note that this is obtaining data from the Davis servers in the cloud where the weather console uploads to. Currently this updates every 15(!) minutes - lets look at changing this</p>
|
|
||||||
<div class="resultParas">
|
|
||||||
<p class="Timestamp"></p>
|
|
||||||
<p class="windSpeedRaw"></p>
|
|
||||||
<p class="windSpeed"></p>
|
|
||||||
<p class="windDirRaw"></p>
|
|
||||||
<p class="windDir"></p>
|
|
||||||
<p class="qNHRaw"></p>
|
|
||||||
<p class="qNH"></p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
const windSpeedRaw = document.querySelector('.windSpeedRaw');
|
|
||||||
const windSpeed = document.querySelector('.windSpeed');
|
|
||||||
const windDirRaw = document.querySelector('.windDirRaw');
|
|
||||||
const windDir = document.querySelector('.windDir');
|
|
||||||
const QRaw = document.querySelector('.qNHRaw');
|
|
||||||
const Q = document.querySelector('.qNHRaw');
|
|
||||||
|
|
||||||
const Timestamp = document.querySelector('.Timestamp');
|
|
||||||
|
|
||||||
// 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 getWindandPressure() {
|
|
||||||
const response = await fetch('/wlproxy.php?api=current/195562');
|
|
||||||
const names = await response.json();
|
|
||||||
windSpeed.textContent = "Wind Speed 1 min avg: " + (names.contents.sensors[0].data[0].wind_speed_avg_last_1_min/1.151).toFixed(0) + " kts";
|
|
||||||
windSpeedRaw.textContent = "RAW Wind Speed 1 min avg: " + names.contents.sensors[0].data[0].wind_speed_avg_last_1_min;
|
|
||||||
windDirRaw.textContent = "RAW Last Wind Direction: " + names.contents.sensors[0].data[0].wind_dir_last;
|
|
||||||
roundedWind = (Math.round(names.contents.sensors[0].data[0].wind_dir_last / 5) * 5).toFixed(0);
|
|
||||||
zeroFilledDir = ('000' + roundedWind).substr(-3)
|
|
||||||
windDir.textContent = "Last Wind Direction: " + zeroFilledDir + " (rounded to nearest 5 degrees)";
|
|
||||||
QNHRaw = names.contents.sensors[2].data[0].bar_absolute;
|
|
||||||
QNH = (QNHRaw / 0.029529983071445).toFixed(0);
|
|
||||||
QRaw.textContent = "RAW QFE: " + QNHRaw;
|
|
||||||
Q.textContent = "QFE: " + QNH;
|
|
||||||
var ts = new Date(names.contents.sensors[0].data[0].ts * 1000);
|
|
||||||
Timestamp.textContent = ts;
|
|
||||||
console.log(names.contents.sensors); // Dump the whole JSON to console
|
|
||||||
}
|
|
||||||
|
|
||||||
getWindandPressure();
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
241
wind.html
241
wind.html
@@ -1,241 +0,0 @@
|
|||||||
<?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:red;
|
|
||||||
font-size:4;
|
|
||||||
font-weight:bold;
|
|
||||||
color:white;
|
|
||||||
line-height:140%;
|
|
||||||
}
|
|
||||||
.myDiv
|
|
||||||
{
|
|
||||||
border: 5px outset red;
|
|
||||||
background-color: lightblue;
|
|
||||||
text-align: center;
|
|
||||||
width: 500px;
|
|
||||||
font: small-caps bold 24px/1 sans-serif;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<head>
|
|
||||||
<title>EGFH Tower</title>
|
|
||||||
<meta http-equiv="refresh" content="900">
|
|
||||||
<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"
|
|
||||||
src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
|
||||||
<script type = "text/javascript">
|
|
||||||
|
|
||||||
function onConnectionLost(){
|
|
||||||
invalidateDisplay();
|
|
||||||
console.log("connection lost");
|
|
||||||
document.getElementById("status").innerHTML = "Connection Lost";
|
|
||||||
connected_flag=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onFailure(message) {
|
|
||||||
invalidateDisplay();
|
|
||||||
console.log("Failed");
|
|
||||||
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_mph);
|
|
||||||
console.log("AVG Dir " + loopObj.windDir);
|
|
||||||
avgWindSpeed = (loopObj.windSpeed_mph/1.151).toFixed(0);
|
|
||||||
roundedWind = (Math.round(loopObj.windDir / 10) * 10).toFixed(0);
|
|
||||||
avgWindDir = ('000' + roundedWind).substr(-3);
|
|
||||||
updateAvgWind();
|
|
||||||
} else {
|
|
||||||
if (loopObj.windSpeed_mph) {
|
|
||||||
console.log("LOOP Speed " + loopObj.windSpeed_mph);
|
|
||||||
console.log("LOOP Dir " + loopObj.windDir);
|
|
||||||
windSpeed = (loopObj.windSpeed_mph/1.151).toFixed(0);
|
|
||||||
roundedWind = (Math.round(loopObj.windDir / 10) * 10).toFixed(0);
|
|
||||||
zeroFilledDir = ('000' + roundedWind).substr(-3);
|
|
||||||
updateWind();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateWind() {
|
|
||||||
document.getElementById("windSpeed").innerHTML = "<h2>Instant Wind<p><h1>" + zeroFilledDir + " / " + windSpeed + " kts";
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateAvgWind() {
|
|
||||||
document.getElementById("avgWindSpeed").innerHTML = "<h2>2min Wind<p><h1>" + avgWindDir + " / " + avgWindSpeed + " kts";
|
|
||||||
}
|
|
||||||
|
|
||||||
function invalidateDisplay() {
|
|
||||||
document.getElementById("windSpeed").innerHTML = "<h2>Instant Wind<p><h1>XXX / X kts";
|
|
||||||
document.getElementById("avgWindSpeed").innerHTML = "<h2>2min Wind<p><h1>XXX / X kts";
|
|
||||||
}
|
|
||||||
|
|
||||||
function onConnect() {
|
|
||||||
|
|
||||||
connected_flag=1;
|
|
||||||
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="orderform-"+x;
|
|
||||||
mqtt = new Paho.MQTT.Client(host,port,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) {
|
|
||||||
msg="Not Connected so can't subscribe"
|
|
||||||
console.log(out_msg);
|
|
||||||
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();
|
|
||||||
QFERaw = names.contents.sensors[2].data[0].bar_absolute;
|
|
||||||
QFE = (QFERaw / 0.029529983071445).toFixed(0);
|
|
||||||
QNH = Number(QFE) + 11;
|
|
||||||
|
|
||||||
if (Number(QFE) < 1001) {
|
|
||||||
document.getElementById("QFE").innerHTML = "<h2>QFE: " + QFE + "</h2><p><h3>hectopascals</h3>";
|
|
||||||
|
|
||||||
} else {
|
|
||||||
document.getElementById("QFE").innerHTML = "<h2>QFE: " + QFE + "</h2>";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Number(QNH) < 1001) {
|
|
||||||
document.getElementById("QNH").innerHTML = "<h2>QNH: " + QNH + "</h2><p><h3>hectopascals</h3>";
|
|
||||||
|
|
||||||
} else {
|
|
||||||
document.getElementById("QNH").innerHTML = "<h2>QNH: " + QNH + "</h2>";
|
|
||||||
}
|
|
||||||
|
|
||||||
var ts = new Date(names.contents.sensors[0].data[0].ts * 1000);
|
|
||||||
console.log(names.contents.sensors); // Dump the whole JSON to console
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<center><h1>UNDER TEST Swansea Tower Live</h1>
|
|
||||||
Instant wind data is received from the sensor by the Raspberry Pi via radio reciever and updates in real time.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The Barometric data actually comes from the Davis console device indirectly via the Internet and has a 15 minute delay. There will soon be a barometric sensor connected locally to fix this.
|
|
||||||
</center>
|
|
||||||
|
|
||||||
<script type = "text/javascript">
|
|
||||||
//ll
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<p></p>
|
|
||||||
<div class="myDiv" id="windSpeed">
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
<div class="myDiv" id="avgWindSpeed"></div>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
<div class="myDiv" id="QNH">
|
|
||||||
<h2>QNH: XXX</h2>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
<div class="myDiv" id="QFE">
|
|
||||||
<h2>QFE: XXX</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td id="connect" width="300" >
|
|
||||||
<form name="connform" action="" onsubmit="return MQTTconnect()">
|
|
||||||
|
|
||||||
<input name="conn" type="submit" value="Connect">
|
|
||||||
<input TYPE="button" name="discon " value="DisConnect" onclick="disconnect()">
|
|
||||||
</form>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
<div id="status">Connection Status: Not Connected</div>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
var connected_flag=0
|
|
||||||
var mqtt;
|
|
||||||
var reconnectTimeout = 2000;
|
|
||||||
var host="192.168.24.188";
|
|
||||||
var port=9001;
|
|
||||||
var row=0;
|
|
||||||
var out_msg="";
|
|
||||||
var mcount=0;
|
|
||||||
var topic = "weather/#"
|
|
||||||
|
|
||||||
invalidateDisplay();
|
|
||||||
MQTTconnect();
|
|
||||||
getPressure();
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
349
wind2.html
349
wind2.html
@@ -1,349 +0,0 @@
|
|||||||
<?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:red;
|
|
||||||
font-size:4;
|
|
||||||
font-weight:bold;
|
|
||||||
color:white;
|
|
||||||
line-height:140%;
|
|
||||||
}
|
|
||||||
.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 http-equiv="refresh" content="900">
|
|
||||||
<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"
|
|
||||||
src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
|
||||||
<script type = "text/javascript">
|
|
||||||
|
|
||||||
function onConnectionLost(){
|
|
||||||
invalidateDisplay();
|
|
||||||
console.log("connection lost");
|
|
||||||
document.getElementById("status").innerHTML = "Connection Lost";
|
|
||||||
connected_flag=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onFailure(message) {
|
|
||||||
invalidateDisplay();
|
|
||||||
console.log("Failed");
|
|
||||||
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_mph);
|
|
||||||
console.log("AVG Dir " + loopObj.windDir);
|
|
||||||
avgWindSpeed = (loopObj.windSpeed_mph/1.151).toFixed(0);
|
|
||||||
roundedWind = (Math.round(loopObj.windDir / 10) * 10).toFixed(0);
|
|
||||||
avgWindDir = ('000' + roundedWind).substr(-3);
|
|
||||||
updateAvgWind();
|
|
||||||
} else {
|
|
||||||
if (loopObj.windSpeed_mph) {
|
|
||||||
mydate = Date.now();
|
|
||||||
console.log(mydate);
|
|
||||||
//document.getElementById("status").textContent = "Last wind msg " + mydate;
|
|
||||||
console.log("LOOP Speed " + loopObj.windSpeed_mph);
|
|
||||||
console.log("LOOP Dir " + loopObj.windDir);
|
|
||||||
windSpeed = (loopObj.windSpeed_mph/1.151).toFixed(0);
|
|
||||||
roundedWind = (Math.round(loopObj.windDir / 10) * 10).toFixed(0);
|
|
||||||
zeroFilledDir = ('000' + roundedWind).substr(-3);
|
|
||||||
updateWind();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateWind() {
|
|
||||||
document.getElementById("windSpeed").innerHTML = zeroFilledDir + "/" + windSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateAvgWind() {
|
|
||||||
document.getElementById("avgWindSpeed").innerHTML = avgWindDir + "/" + avgWindSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
function invalidateDisplay() {
|
|
||||||
document.getElementById("windSpeed").innerHTML = "XXX/X";
|
|
||||||
document.getElementById("avgWindSpeed").innerHTML = "XXX/X";
|
|
||||||
}
|
|
||||||
|
|
||||||
function onConnect() {
|
|
||||||
|
|
||||||
connected_flag=1;
|
|
||||||
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) {
|
|
||||||
msg="Not Connected so can't subscribe"
|
|
||||||
console.log(out_msg);
|
|
||||||
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();
|
|
||||||
QFERaw = names.contents.sensors[2].data[0].bar_absolute;
|
|
||||||
QFE = (QFERaw / 0.029529983071445).toFixed(0);
|
|
||||||
QNH = Number(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() - mydate;
|
|
||||||
document.getElementById("status").textContent = "Last wind msg " + (secs/1000).toFixed(1) + " seconds ago";
|
|
||||||
setTimeout( updateClock.bind( this, "zuluTime" ), 500 );
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<center><h1>UNDER TEST Swansea Tower Live</h1>
|
|
||||||
Instant wind data is received from the sensor by the Raspberry Pi via radio reciever and updates in real time.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The Barometric data actually comes from the Davis console device indirectly via the Internet and has a 15 minute delay. There will soon be a barometric sensor connected locally to fix this.
|
|
||||||
</center>
|
|
||||||
|
|
||||||
<script type = "text/javascript">
|
|
||||||
//ll
|
|
||||||
|
|
||||||
</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>2min 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 id="zuluTime">QNH: XXX</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<p></p>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td id="connect" width="300" >
|
|
||||||
<form name="connform" action="" onsubmit="return MQTTconnect()">
|
|
||||||
<input name="conn" type="submit" value="Connect">
|
|
||||||
<input TYPE="button" name="discon " value="Disconnect" onclick="disconnect()">
|
|
||||||
</form>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
<div id="status">Connection Status: Not Connected</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
var connected_flag=0
|
|
||||||
var mqtt;
|
|
||||||
var reconnectTimeout = 2000;
|
|
||||||
var host="wss://wx.swansea-airport.wales/mqtt";
|
|
||||||
var row=0;
|
|
||||||
var out_msg="";
|
|
||||||
var mcount=0;
|
|
||||||
var topic = "weather/#";
|
|
||||||
let mydate = Date.now();
|
|
||||||
|
|
||||||
invalidateDisplay();
|
|
||||||
MQTTconnect();
|
|
||||||
getPressure();
|
|
||||||
updateClock();
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Reference in New Issue
Block a user