first commit
This commit is contained in:
BIN
BPCBeep.mp3
Normal file
BIN
BPCBeep.mp3
Normal file
Binary file not shown.
BIN
PressureChange.mp3
Normal file
BIN
PressureChange.mp3
Normal file
Binary file not shown.
397
agcs-dev.html
Normal file
397
agcs-dev.html
Normal file
@@ -0,0 +1,397 @@
|
|||||||
|
<?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>
|
||||||
386
agcs.html
Normal file
386
agcs.html
Normal file
@@ -0,0 +1,386 @@
|
|||||||
|
<?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();
|
||||||
|
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>
|
||||||
391
agcs_old.html
Normal file
391
agcs_old.html
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
<?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
Normal file
400
agcs_old2.html
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
<?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>
|
||||||
84
egfh.html
Normal file
84
egfh.html
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<!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
Normal file
241
wind.html
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
<?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
Normal file
349
wind2.html
Normal file
@@ -0,0 +1,349 @@
|
|||||||
|
<?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>
|
||||||
260
wlproxy.php
Normal file
260
wlproxy.php
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
<?PHP
|
||||||
|
error_reporting(E_ERROR | E_PARSE);
|
||||||
|
|
||||||
|
// Script: Simple PHP Proxy: Get external HTML, JSON and more!
|
||||||
|
//
|
||||||
|
// *Version: 1.6, Last updated: 1/24/2009*
|
||||||
|
//
|
||||||
|
// Project Home - http://benalman.com/projects/php-simple-proxy/
|
||||||
|
// GitHub - http://github.com/cowboy/php-simple-proxy/
|
||||||
|
// Source - http://github.com/cowboy/php-simple-proxy/raw/master/ba-simple-proxy.php
|
||||||
|
//
|
||||||
|
// About: License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2010 "Cowboy" Ben Alman,
|
||||||
|
// Dual licensed under the MIT and GPL licenses.
|
||||||
|
// http://benalman.com/about/license/
|
||||||
|
//
|
||||||
|
// About: Examples
|
||||||
|
//
|
||||||
|
// This working example, complete with fully commented code, illustrates one way
|
||||||
|
// in which this PHP script can be used.
|
||||||
|
//
|
||||||
|
// Simple - http://benalman.com/code/projects/php-simple-proxy/examples/simple/
|
||||||
|
//
|
||||||
|
// About: Release History
|
||||||
|
//
|
||||||
|
// 1.6 - (1/24/2009) Now defaults to JSON mode, which can now be changed to
|
||||||
|
// native mode by specifying ?mode=native. Native and JSONP modes are
|
||||||
|
// disabled by default because of possible XSS vulnerability issues, but
|
||||||
|
// are configurable in the PHP script along with a url validation regex.
|
||||||
|
// 1.5 - (12/27/2009) Initial release
|
||||||
|
//
|
||||||
|
// Topic: GET Parameters
|
||||||
|
//
|
||||||
|
// Certain GET (query string) parameters may be passed into ba-simple-proxy.php
|
||||||
|
// to control its behavior, this is a list of these parameters.
|
||||||
|
//
|
||||||
|
// url - The remote URL resource to fetch. Any GET parameters to be passed
|
||||||
|
// through to the remote URL resource must be urlencoded in this parameter.
|
||||||
|
// mode - If mode=native, the response will be sent using the same content
|
||||||
|
// type and headers that the remote URL resource returned. If omitted, the
|
||||||
|
// response will be JSON (or JSONP). <Native requests> and <JSONP requests>
|
||||||
|
// are disabled by default, see <Configuration Options> for more information.
|
||||||
|
// callback - If specified, the response JSON will be wrapped in this named
|
||||||
|
// function call. This parameter and <JSONP requests> are disabled by
|
||||||
|
// default, see <Configuration Options> for more information.
|
||||||
|
// user_agent - This value will be sent to the remote URL request as the
|
||||||
|
// `User-Agent:` HTTP request header. If omitted, the browser user agent
|
||||||
|
// will be passed through.
|
||||||
|
// send_cookies - If send_cookies=1, all cookies will be forwarded through to
|
||||||
|
// the remote URL request.
|
||||||
|
// send_session - If send_session=1 and send_cookies=1, the SID cookie will be
|
||||||
|
// forwarded through to the remote URL request.
|
||||||
|
// full_headers - If a JSON request and full_headers=1, the JSON response will
|
||||||
|
// contain detailed header information.
|
||||||
|
// full_status - If a JSON request and full_status=1, the JSON response will
|
||||||
|
// contain detailed cURL status information, otherwise it will just contain
|
||||||
|
// the `http_code` property.
|
||||||
|
//
|
||||||
|
// Topic: POST Parameters
|
||||||
|
//
|
||||||
|
// All POST parameters are automatically passed through to the remote URL
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// Topic: JSON requests
|
||||||
|
//
|
||||||
|
// This request will return the contents of the specified url in JSON format.
|
||||||
|
//
|
||||||
|
// Request:
|
||||||
|
//
|
||||||
|
// > ba-simple-proxy.php?url=http://example.com/
|
||||||
|
//
|
||||||
|
// Response:
|
||||||
|
//
|
||||||
|
// > { "contents": "<html>...</html>", "headers": {...}, "status": {...} }
|
||||||
|
//
|
||||||
|
// JSON object properties:
|
||||||
|
//
|
||||||
|
// contents - (String) The contents of the remote URL resource.
|
||||||
|
// headers - (Object) A hash of HTTP headers returned by the remote URL
|
||||||
|
// resource.
|
||||||
|
// status - (Object) A hash of status codes returned by cURL.
|
||||||
|
//
|
||||||
|
// Topic: JSONP requests
|
||||||
|
//
|
||||||
|
// This request will return the contents of the specified url in JSONP format
|
||||||
|
// (but only if $enable_jsonp is enabled in the PHP script).
|
||||||
|
//
|
||||||
|
// Request:
|
||||||
|
//
|
||||||
|
// > ba-simple-proxy.php?url=http://example.com/&callback=foo
|
||||||
|
//
|
||||||
|
// Response:
|
||||||
|
//
|
||||||
|
// > foo({ "contents": "<html>...</html>", "headers": {...}, "status": {...} })
|
||||||
|
//
|
||||||
|
// JSON object properties:
|
||||||
|
//
|
||||||
|
// contents - (String) The contents of the remote URL resource.
|
||||||
|
// headers - (Object) A hash of HTTP headers returned by the remote URL
|
||||||
|
// resource.
|
||||||
|
// status - (Object) A hash of status codes returned by cURL.
|
||||||
|
//
|
||||||
|
// Topic: Native requests
|
||||||
|
//
|
||||||
|
// This request will return the contents of the specified url in the format it
|
||||||
|
// was received in, including the same content-type and other headers (but only
|
||||||
|
// if $enable_native is enabled in the PHP script).
|
||||||
|
//
|
||||||
|
// Request:
|
||||||
|
//
|
||||||
|
// > ba-simple-proxy.php?url=http://example.com/&mode=native
|
||||||
|
//
|
||||||
|
// Response:
|
||||||
|
//
|
||||||
|
// > <html>...</html>
|
||||||
|
//
|
||||||
|
// Topic: Notes
|
||||||
|
//
|
||||||
|
// * Assumes magic_quotes_gpc = Off in php.ini
|
||||||
|
//
|
||||||
|
// Topic: Configuration Options
|
||||||
|
//
|
||||||
|
// These variables can be manually edited in the PHP file if necessary.
|
||||||
|
//
|
||||||
|
// $enable_jsonp - Only enable <JSONP requests> if you really need to. If you
|
||||||
|
// install this script on the same server as the page you're calling it
|
||||||
|
// from, plain JSON will work. Defaults to false.
|
||||||
|
// $enable_native - You can enable <Native requests>, but you should only do
|
||||||
|
// this if you also whitelist specific URLs using $valid_url_regex, to avoid
|
||||||
|
// possible XSS vulnerabilities. Defaults to false.
|
||||||
|
// $valid_url_regex - This regex is matched against the url parameter to
|
||||||
|
// ensure that it is valid. This setting only needs to be used if either
|
||||||
|
// $enable_jsonp or $enable_native are enabled. Defaults to '/.*/' which
|
||||||
|
// validates all URLs.
|
||||||
|
//
|
||||||
|
// ############################################################################
|
||||||
|
|
||||||
|
// Change these configuration options if needed, see above descriptions for info.
|
||||||
|
$enable_jsonp = false;
|
||||||
|
$enable_native = false;
|
||||||
|
$valid_url_regex = '/.*/';
|
||||||
|
|
||||||
|
$apikey = "beliqdwnzkkeqdar4sb9xfhxzdv3rf03";
|
||||||
|
$apisecret = "zpdi1jrycd17gjmx0ldqydj9meboavwg";
|
||||||
|
|
||||||
|
$url = 'https://api.weatherlink.com/v2/' . $_GET['api'] . "?api-key=" . $apikey;
|
||||||
|
|
||||||
|
// ############################################################################
|
||||||
|
|
||||||
|
if ( !$url ) {
|
||||||
|
|
||||||
|
// Passed url not specified.
|
||||||
|
$contents = 'ERROR: url not specified';
|
||||||
|
$status = array( 'http_code' => 'ERROR' );
|
||||||
|
|
||||||
|
} else if ( !preg_match( $valid_url_regex, $url ) ) {
|
||||||
|
|
||||||
|
// Passed url doesn't match $valid_url_regex.
|
||||||
|
$contents = 'ERROR: invalid url';
|
||||||
|
$status = array( 'http_code' => 'ERROR' );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$ch = curl_init( $url );
|
||||||
|
|
||||||
|
if ( strtolower($_SERVER['REQUEST_METHOD']) == 'post' ) {
|
||||||
|
curl_setopt( $ch, CURLOPT_POST, true );
|
||||||
|
curl_setopt( $ch, CURLOPT_POSTFIELDS, $_POST );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $_GET['send_cookies'] ) {
|
||||||
|
$cookie = array();
|
||||||
|
foreach ( $_COOKIE as $key => $value ) {
|
||||||
|
$cookie[] = $key . '=' . $value;
|
||||||
|
}
|
||||||
|
if ( $_GET['send_session'] ) {
|
||||||
|
$cookie[] = SID;
|
||||||
|
}
|
||||||
|
$cookie = implode( '; ', $cookie );
|
||||||
|
|
||||||
|
curl_setopt( $ch, CURLOPT_COOKIE, $cookie );
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
|
||||||
|
curl_setopt( $ch, CURLOPT_HEADER, true );
|
||||||
|
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
|
||||||
|
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-Api-Secret: $apisecret"] );
|
||||||
|
|
||||||
|
curl_setopt( $ch, CURLOPT_USERAGENT, $_GET['user_agent'] ? $_GET['user_agent'] : $_SERVER['HTTP_USER_AGENT'] );
|
||||||
|
|
||||||
|
list( $header, $contents ) = preg_split( '/([\r\n][\r\n])\\1/', curl_exec( $ch ), 2 );
|
||||||
|
|
||||||
|
$status = curl_getinfo( $ch );
|
||||||
|
|
||||||
|
curl_close( $ch );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split header text into an array.
|
||||||
|
$header_text = preg_split( '/[\r\n]+/', $header );
|
||||||
|
|
||||||
|
if ( $_GET['mode'] == 'native' ) {
|
||||||
|
if ( !$enable_native ) {
|
||||||
|
$contents = 'ERROR: invalid mode';
|
||||||
|
$status = array( 'http_code' => 'ERROR' );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propagate headers to response.
|
||||||
|
foreach ( $header_text as $header ) {
|
||||||
|
if ( preg_match( '/^(?:Content-Type|Content-Language|Set-Cookie):/i', $header ) ) {
|
||||||
|
header( $header );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print $contents;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// $data will be serialized into JSON data.
|
||||||
|
$data = array();
|
||||||
|
|
||||||
|
// Propagate all HTTP headers into the JSON data object.
|
||||||
|
if ( $_GET['full_headers'] ) {
|
||||||
|
$data['headers'] = array();
|
||||||
|
|
||||||
|
foreach ( $header_text as $header ) {
|
||||||
|
preg_match( '/^(.+?):\s+(.*)$/', $header, $matches );
|
||||||
|
if ( $matches ) {
|
||||||
|
$data['headers'][ $matches[1] ] = $matches[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propagate all cURL request / response info to the JSON data object.
|
||||||
|
if ( $_GET['full_status'] ) {
|
||||||
|
$data['status'] = $status;
|
||||||
|
} else {
|
||||||
|
$data['status'] = array();
|
||||||
|
$data['status']['http_code'] = $status['http_code'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the JSON data object contents, decoding it from JSON if possible.
|
||||||
|
$decoded_json = json_decode( $contents );
|
||||||
|
$data['contents'] = $decoded_json ? $decoded_json : $contents;
|
||||||
|
|
||||||
|
// Generate appropriate content-type header.
|
||||||
|
$is_xhr = strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
|
||||||
|
header( 'Content-type: application/' . ( $is_xhr ? 'json' : 'x-javascript' ) );
|
||||||
|
|
||||||
|
// Get JSONP callback.
|
||||||
|
$jsonp_callback = $enable_jsonp && isset($_GET['callback']) ? $_GET['callback'] : null;
|
||||||
|
|
||||||
|
// Generate JSON/JSONP string
|
||||||
|
$json = json_encode( $data );
|
||||||
|
|
||||||
|
print $jsonp_callback ? "$jsonp_callback($json)" : $json;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
Reference in New Issue
Block a user