diff options
| -rw-r--r-- | style.css | 73 | ||||
| -rw-r--r-- | weather-output-format.txt | 11 | ||||
| -rw-r--r-- | weather.html | 23 | ||||
| -rw-r--r-- | weather.js | 138 | ||||
| -rwxr-xr-x | weather.py | 64 |
5 files changed, 309 insertions, 0 deletions
diff --git a/style.css b/style.css new file mode 100644 index 0000000..c7e6703 --- /dev/null +++ b/style.css @@ -0,0 +1,73 @@ +body {
+ background-color: #bccff7;
+}
+
+#wind_dir {
+ position: absolute;
+ top: 20px;
+ left: 150px;
+ border-style: none;
+ border-width: 5px;
+}
+
+#arrow1 {
+ position: absolute;
+ top: 39px;
+ left: 167px;
+ border-style: none;
+ border-width: 5px;
+}
+
+#wind_speed {
+ position: absolute;
+ top: 20px;
+ left: 415px;
+ border-style: none;
+ border-width: 5px;
+}
+
+#arrow2 {
+ position: absolute;
+ top: 39px;
+ left: 435px;
+ border-style: none;
+ border-width: 5px;
+}
+
+#cloud_scale {
+ position: absolute;
+ top: 285px;
+ left: 150px;
+ border-style: none;
+ border-width: 5px;
+}
+
+#clouds {
+ position: absolute;
+ top: 290px;
+ left: 232px;
+ border-style: none;
+ border-width: 5px;
+}
+
+#legend {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 18px;
+ position: absolute;
+ left: 360px;
+ top: 310px;
+}
+
+#info {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 18px;
+ position: absolute;
+ left: 315px;
+ top: 295px;
+}
+
+#serverData {
+ position: absolute;
+ top: 600px;
+ left: 3px;
+}
diff --git a/weather-output-format.txt b/weather-output-format.txt new file mode 100644 index 0000000..8f03793 --- /dev/null +++ b/weather-output-format.txt @@ -0,0 +1,11 @@ +Fairoaks (EGTF) Weather Data at {time:%H:%M:%S}
+
+Cloud base (calc): {cloudbase:n} ft
+Rain: {rain} mm
+Temperature: {temperature} °C
+Humidity: {humidity_percent:.0%}
+Pressure: {pressure} hPa
+Wind: {wind_dir:n}° at {wind_speed} kts
+Gust: {gust} kts
+
+Source: London Transport Flying Club
\ No newline at end of file diff --git a/weather.html b/weather.html new file mode 100644 index 0000000..9096d40 --- /dev/null +++ b/weather.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML>
+
+<head>
+ <meta charset="utf8_general_ci" />
+ <link rel="stylesheet" type="text/css" href="style.css" />
+ <title>LTFC Weather</title>
+</head>
+
+<body>
+ <!-- This next like is for test purposes and the result includes a random number to check that the thing is sending
+ <div id="serverData">Here is where the server sent data will appear</div> -->
+
+ <canvas id="wind_dir" width="231px" height="231px"></canvas>
+ <canvas id="arrow1" width="196px" height="196px"></canvas>
+ <canvas id="wind_speed" width="231px" height="231px"></canvas>
+ <canvas id="arrow2" width="196px" height="196px"></canvas>
+ <canvas id="cloud_scale" width="520px" height="280px"></canvas>
+ <canvas id="clouds" width="57px" height="265px"></canvas>
+ <canvas id="info" width="320px" height="260px"></canvas>
+
+ <script type="text/javascript" src="weather.js"></script>
+</body>
+</html>
diff --git a/weather.js b/weather.js new file mode 100644 index 0000000..0489bc4 --- /dev/null +++ b/weather.js @@ -0,0 +1,138 @@ +window.alert("Hello");
+console.log("Hello");
+
+// this canvas defines the position of the wind rose background based on the style above
+var wd = document.getElementById("wind_dir");
+var ctx = wd.getContext("2d");
+drawing = new Image();
+drawing.src = "http://ltfc.org.uk/weather/wind_dir1.png";
+drawing.onload = function() {
+ ctx.drawImage(drawing, 0, 0);
+ ctx.font = "16px Arial";
+}
+
+// and the wind arrow - which is updated below by SSE
+var ar = document.getElementById("arrow1");
+var ctx1 = ar.getContext("2d");
+
+// wind speed background
+var ws = document.getElementById("wind_speed");
+var ctx6 = ws.getContext("2d");
+drawing6 = new Image();
+drawing6.src = "http://ltfc.org.uk/weather/wind_speed.jpg";
+drawing6.onload = function() {
+ ctx6.drawImage(drawing6, 0, 0);
+ ctx6.font = "16px Arial";
+}
+
+// wind speed arrow
+var ar1 = document.getElementById("arrow2");
+var ctx5 = ar1.getContext("2d");
+
+// cloud scale
+var cl1 = document.getElementById("cloud_scale");
+var ctx2 = cl1.getContext("2d");
+drawing2 = new Image();
+drawing2.src = "http://ltfc.org.uk/weather/cloud_scale2.png";
+drawing2.onload = function() {
+ ctx2.drawImage(drawing2, 0, 0);
+}
+
+//moving cloud graphic
+var cl2 = document.getElementById("clouds");
+var ctx3 = cl2.getContext("2d");
+
+//text info
+var c = document.getElementById("info");
+var ctx4 = c.getContext("2d");
+ctx4.fillStyle = "#000000";
+ctx4.font = "14pt Arial";
+
+//all this next stuff updates the info using server side events and send_sse.php.
+
+//create an object, passing it the name and location of the server side script
+var eSource = new EventSource("http://ltfc.org.uk/send_sse.php");
+//detect message receipt
+eSource.onmessage = function(event) {
+
+ // uncomment this next line along with the matching div at the top to test taht the event is working
+ //document.getElementById("serverData").innerHTML = event.data;
+
+ //get the data and split it down into an array
+ var arr = event.data.split(",");
+ //now we have an array filled with the info from the php file having unpacked the csv data to an array arr[x] etc. Starts at 0.
+
+ //clear the info text canvas otherwise it just keeps overlaying text on top of the last
+ ctx4.clearRect(0, 0, 320, 260);
+ ctx4.fillText('LTFC Weather Station', 20, 30);
+ // This next bit just underlines the text above - too complicated by far.
+ ctx4.beginPath();
+ ctx4.strokeStyle = "#000000";
+ ctx4.lineWidth = 2;
+ ctx4.moveTo(20, 34);
+ ctx4.lineTo(210, 34);
+ ctx4.stroke();
+ //put in names
+ ctx4.fillText('Cloudbase (calc)', 20, 65);
+ ctx4.fillText('Rain', 20, 90);
+ ctx4.fillText('Temperature', 20, 115);
+ ctx4.fillText('Gust', 20, 140);
+ ctx4.fillText('Humidity', 20, 165);
+ ctx4.fillText('Pressure', 20, 190);
+ ctx4.fillText('Time', 20, 225);
+ //put in values
+ ctx4.fillText(arr[2] + ' ft', 200, 65);
+ ctx4.fillText(arr[3] + ' mm', 200, 90);
+ ctx4.fillText(arr[4] + ' C', 200, 115);
+ ctx4.fillText(arr[5] + ' kt', 200, 140);
+ ctx4.fillText(arr[6] + '%', 200, 165);
+ ctx4.fillText(arr[7] + ' hPa', 200, 190);
+ ctx4.fillText(arr[9] + ':' + arr[10] + ':' + arr[11], 200, 225);
+
+ //cloud graphic positioning
+ //reset the canvas to no shift and blank
+ ctx3.setTransform(1, 0, 0, 1, 0, 0);
+ ctx3.clearRect(0, 0, clouds.width, clouds.height);
+ //draw clouds in correct place on graph
+ drawing3 = new Image();
+ drawing3.src = "http://ltfc.org.uk/weather/clouds1.jpg";
+ ctx3.translate(0, arr[12]);
+ drawing3.onload = function() {
+ ctx3.drawImage(drawing3, 0, 0);
+ }
+
+ //wind arrow
+ //reset the canvas to no shift and blank
+ ctx1.setTransform(1, 0, 0, 1, 0, 0);
+ ctx1.clearRect(0, 0, arrow1.width, arrow1.height);
+ //draw arrow at correct angle as calculated in php file
+ ctx1.translate(98, 98);
+ ctx1.rotate(arr[1]);
+ drawing1 = new Image();
+ drawing1.src = "http://ltfc.org.uk/weather/arrow.png";
+ drawing1.onload = function() {
+ ctx1.drawImage(drawing1, -98, -98);
+ }
+
+ //wind speed
+ //reset the canvas to no shift and blank
+ ctx5.setTransform(1, 0, 0, 1, 0, 0);
+ ctx5.clearRect(0, 0, arrow2.width, arrow2.height);
+ //draw arrow at correct angle as calculated in php file
+ ctx5.translate(98, 98);
+ ctx5.rotate(arr[0]);
+ drawing5 = new Image();
+ drawing5.src = "http://ltfc.org.uk/weather/arrow.png";
+ drawing5.onload = function() {
+ ctx5.drawImage(drawing5, -98, -98);
+ }
+ //wind dir in words
+ ctx.clearRect(135, 200, 100, 100);
+ ctx.fillText('Wind ' + arr[13] + '\xB0', 148, 225);
+
+ //wind speed in words
+ ctx6.clearRect(0, 210, 100, 100);
+ ctx6.fillText(arr[14] + 'kts', 0, 225);
+
+ //this next bracket matches the one at the top of all this stuff - function(event)
+}
\ No newline at end of file diff --git a/weather.py b/weather.py new file mode 100755 index 0000000..38ea65e --- /dev/null +++ b/weather.py @@ -0,0 +1,64 @@ +#! python
+
+import tkinter as tk
+from datetime import time
+from time import sleep
+from urllib.request import urlopen
+from urllib.error import URLError
+
+
+class Application(tk.Frame):
+ def __init__(self, master=None):
+ tk.Frame.__init__(self, master)
+ self.refresh_interval = 10
+ self.master.title('EGTF Weather')
+ self.pack()
+ self.weather_display = tk.Label(self, text='', justify='left')
+ self.weather_display.pack(side='top')
+ self.update_button = tk.Button(self, text='Update',
+ command=self.update_weather_display)
+ self.update_button.pack(side='bottom')
+ with open('./weather-output-format.txt') as f:
+ self.output_format = ''.join(f.readlines())
+ self.update_button.invoke()
+ self.after(10, self.update_button.invoke)
+
+ def update_weather_display(self):
+ try:
+ with urlopen('http://ltfc.org.uk/send_sse.php') as weather_file:
+ raw_data = weather_file.readall().decode()
+ self.refresh_interval = int(raw_data.split('\n')[0]
+ .split(':')[1]
+ .strip()) / 1000
+ data = raw_data.split('\n')[1].split(':')[1].strip().split(',')
+
+ # _ below means that I have no idea what those values could mean
+ rotate1, rotate2, cloudbase, rain, temperature, gust, \
+ humidity, pressure, _, hours, minutes, seconds, \
+ cloud_y_pos, wind_dir, wind_speed, _ = map(float, data)
+
+ self.weather_display['text'] = self.output_format.format(
+ cloudbase=cloudbase,
+ rain=rain,
+ temperature=temperature,
+ gust=gust,
+ humidity_percent=humidity / 100,
+ pressure=pressure,
+ time=time(*map(int, (hours, minutes, seconds))),
+ wind_dir=wind_dir,
+ wind_speed=wind_speed
+ )
+ except URLError as err:
+ self.weather_display['text'] += '\n'.join([
+ '', 'Update failed: network error', str(err)
+ ])
+ except ValueError as err:
+ self.weather_display['text'] += '\n'.join([
+ '', 'Update failed: got invalid data', str(err)
+ ])
+
+
+if __name__ == '__main__':
+ root = tk.Tk()
+ app = Application(root)
+ app.mainloop()
|
